mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-10 09:32:29 +01:00
Fix testpaint
This commit is contained in:
@@ -132,6 +132,9 @@ add_custom_target(g2 DEPENDS ${PROJECT} g2.dat)
|
||||
# Include tests
|
||||
if (WITH_TESTS)
|
||||
enable_testing()
|
||||
if (UNIX AND (NOT USE_MMAP) AND FORCE32)
|
||||
include("${ROOT_DIR}/test/testpaint/CMakeLists.txt" NO_POLICY_SCOPE)
|
||||
endif ()
|
||||
include("${ROOT_DIR}/test/tests/CMakeLists.txt" NO_POLICY_SCOPE)
|
||||
endif ()
|
||||
|
||||
|
||||
@@ -39,8 +39,6 @@ uint32 gPickupPeepImage;
|
||||
sint32 gPickupPeepX;
|
||||
sint32 gPickupPeepY;
|
||||
|
||||
rct_drawpixelinfo *unk_140E9A8;
|
||||
|
||||
/**
|
||||
* 12 elements from 0xF3 are the peep top colour, 12 elements from 0xCA are peep trouser colour
|
||||
*
|
||||
|
||||
@@ -269,8 +269,6 @@ extern bool gTinyFontAntiAliased;
|
||||
extern rct_drawpixelinfo gScreenDPI;
|
||||
extern rct_drawpixelinfo gWindowDPI;
|
||||
|
||||
extern rct_drawpixelinfo *unk_140E9A8;
|
||||
|
||||
//
|
||||
bool clip_drawpixelinfo(rct_drawpixelinfo *dst, rct_drawpixelinfo *src, sint32 x, sint32 y, sint32 width, sint32 height);
|
||||
void gfx_set_dirty_blocks(sint16 left, sint16 top, sint16 right, sint16 bottom);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "../common.h"
|
||||
#include "../world/map.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct rct_vehicle_colour {
|
||||
uint8 body_colour;
|
||||
uint8 trim_colour;
|
||||
@@ -75,6 +76,7 @@ typedef struct rct_ride_entry_vehicle {
|
||||
sint8* peep_loading_positions; // 0x61 , 0x7B
|
||||
uint16 peep_loading_positions_count;
|
||||
} rct_ride_entry_vehicle;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct rct_vehicle {
|
||||
uint8 sprite_identifier; // 0x00
|
||||
|
||||
@@ -4,6 +4,54 @@ if (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
message(FATAL_ERROR "Building in-source is not supported! Create a build dir and remove ${CMAKE_SOURCE_DIR}/CMakeCache.txt")
|
||||
endif ()
|
||||
|
||||
set(OPENRCT2_EXE "${ROOT_DIR}/openrct2.exe")
|
||||
add_custom_command(
|
||||
OUTPUT openrct2_text
|
||||
COMMAND dd if="${OPENRCT2_EXE}" of="${CMAKE_BINARY_DIR}/openrct2_text" bs=4096 skip=1 count=1187
|
||||
DEPENDS ${OPENRCT2_EXE}
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT openrct2_data
|
||||
COMMAND dd if="${OPENRCT2_EXE}" of="${CMAKE_BINARY_DIR}/openrct2_data" bs=4096 skip=1188 count=318
|
||||
COMMAND dd if=/dev/zero of="${CMAKE_BINARY_DIR}/openrct2_data" bs=4096 seek=318 count=2630 conv=notrunc
|
||||
COMMAND dd if="${OPENRCT2_EXE}" of="${CMAKE_BINARY_DIR}/openrct2_data" bs=4096 skip=1506 seek=2948 count=1 conv=notrunc
|
||||
DEPENDS ${OPENRCT2_EXE}
|
||||
)
|
||||
add_custom_target(segfiles DEPENDS openrct2_text openrct2_data)
|
||||
if (NOT USE_MMAP)
|
||||
set(OBJ_FORMAT "elf32-i386")
|
||||
set(LINKER_SCRIPT "ld_script_i386.xc")
|
||||
if (APPLE)
|
||||
set(RCT2_SEGMENT_LINKER_FLAGS "-sectcreate rct2_text __text ${CMAKE_BINARY_DIR}/openrct2_text -sectcreate rct2_data __data ${CMAKE_BINARY_DIR}/openrct2_data -segaddr rct2_data 0x8a4000 -segprot rct2_data rwx rwx -segaddr rct2_text 0x401000 -segprot rct2_text rwx rwx -segaddr __TEXT 0x2000000 -read_only_relocs suppress")
|
||||
else ()
|
||||
# For Linux we have to use objcopy to wrap regular binaries into a linkable
|
||||
# format. We use specific section names which are then referenced in a
|
||||
# bespoke linker script so they can be placed at predefined VMAs.
|
||||
add_custom_command(
|
||||
OUTPUT openrct2_text_section.o
|
||||
COMMAND objcopy --input binary --output ${OBJ_FORMAT} --binary-architecture i386 openrct2_text openrct2_text_section.o --rename-section .data=.rct2_text,contents,alloc,load,readonly,code
|
||||
DEPENDS segfiles
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT openrct2_data_section.o
|
||||
COMMAND objcopy --input binary --output ${OBJ_FORMAT} --binary-architecture i386 openrct2_data openrct2_data_section.o --rename-section .data=.rct2_data,contents,alloc,load,readonly,data
|
||||
DEPENDS segfiles
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
add_custom_target(linkable_sections DEPENDS openrct2_text_section.o openrct2_data_section.o)
|
||||
set_source_files_properties(
|
||||
openrct2_text_section.o openrct2_data_section.o
|
||||
PROPERTIES
|
||||
EXTERNAL_OBJECT true
|
||||
GENERATED true
|
||||
)
|
||||
# can't use GLOB here, as the files don't exist yet at cmake-time
|
||||
set(RCT2_SECTIONS "${CMAKE_BINARY_DIR}/openrct2_data_section.o" "${CMAKE_BINARY_DIR}/openrct2_text_section.o")
|
||||
set(RCT2_SEGMENT_LINKER_FLAGS "-Wl,-T,\"${ROOT_DIR}/distribution/linux/${LINKER_SCRIPT}\"")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
set(OPENRCT2_SRCPATH "${ROOT_DIR}/src/openrct2")
|
||||
file(GLOB_RECURSE ORCT2_RIDE_SOURCES "${OPENRCT2_SRCPATH}/ride/*/*.cpp")
|
||||
file(GLOB_RECURSE ORCT2_RIDE_DEP_SOURCES "${OPENRCT2_SRCPATH}/ride/ride_data.c"
|
||||
@@ -19,8 +67,13 @@ file(GLOB_RECURSE ORCT2_TESTPAINT_SOURCES "${CMAKE_CURRENT_LIST_DIR}/*.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/*.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/*.h")
|
||||
|
||||
# Disable optimizations for addresses.c for all compilers, to allow optimized
|
||||
# builds without need for -fno-omit-frame-pointer
|
||||
set_source_files_properties(${CMAKE_CURRENT_LIST_DIR}/addresses.c PROPERTIES COMPILE_FLAGS -O0)
|
||||
|
||||
add_executable(testpaint EXCLUDE_FROM_ALL ${ORCT2_RIDE_SOURCES} ${ORCT2_RIDE_DEP_SOURCES} ${ORCT2_TESTPAINT_SOURCES} ${RCT2_SECTIONS})
|
||||
target_include_directories(testpaint PRIVATE "${ROOT_DIR}/src/")
|
||||
|
||||
set_target_properties(testpaint PROPERTIES COMPILE_FLAGS "-DNO_VEHICLES -D__TESTPAINT__ -Wno-unused")
|
||||
set_target_properties(testpaint PROPERTIES LINK_FLAGS ${RCT2_SEGMENT_LINKER_FLAGS})
|
||||
add_dependencies(testpaint segfiles)
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
#pragma endregion
|
||||
|
||||
|
||||
#include "hook.h"
|
||||
#include "PaintIntercept.hpp"
|
||||
#include "FunctionCall.hpp"
|
||||
|
||||
#include <openrct2/common.h>
|
||||
#include <openrct2/rct2/hook.h>
|
||||
#include <openrct2/interface/viewport.h>
|
||||
#include <openrct2/paint/supports.h>
|
||||
#include <openrct2/sprites.h>
|
||||
@@ -233,7 +233,7 @@ namespace PaintIntercept {
|
||||
|
||||
static uint8 InterceptPaint6C(registers *regs)
|
||||
{
|
||||
if ((regs->ebp & 0x03) != get_current_rotation())
|
||||
if ((regs->ebp & 0x03) != RCT2_CurrentRotation)
|
||||
{
|
||||
// Log error
|
||||
log_error("Ebp is different from current rotation");
|
||||
@@ -273,7 +273,7 @@ namespace PaintIntercept {
|
||||
}
|
||||
|
||||
static uint8 InterceptPaintFull(uint8 function, registers *regs) {
|
||||
if ((regs->ebp & 0x03) != get_current_rotation()) {
|
||||
if ((regs->ebp & 0x03) != RCT2_CurrentRotation) {
|
||||
// Log error
|
||||
log_error("Ebp is different from current rotation");
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "hook.h"
|
||||
#include "GeneralSupportHeightCall.hpp"
|
||||
#include "Printer.hpp"
|
||||
#include "SegmentSupportHeightCall.hpp"
|
||||
@@ -27,7 +28,6 @@
|
||||
#include <openrct2/paint/supports.h>
|
||||
#include <openrct2/ride/TrackData.h>
|
||||
#include <openrct2/interface/viewport.h>
|
||||
#include <openrct2/rct2/hook.h>
|
||||
|
||||
namespace TestPaint
|
||||
{
|
||||
@@ -47,7 +47,7 @@ namespace TestPaint
|
||||
|
||||
rct_drawpixelinfo dpi = { 0 };
|
||||
dpi.zoom_level = 1;
|
||||
unk_140E9A8 = &dpi;
|
||||
RCT2_GLOBAL(0x0140E9A8, rct_drawpixelinfo *) = &dpi;
|
||||
gPaintSession.Unk140E9A8 = &dpi;
|
||||
|
||||
Ride ride = {0};
|
||||
@@ -59,10 +59,18 @@ namespace TestPaint
|
||||
rideEntry.vehicles[0] = vehicleEntry;
|
||||
|
||||
gRideList[0] = ride;
|
||||
RCT2_ADDRESS(0x013628F8, Ride)[0] = ride;
|
||||
|
||||
gRideEntries[0] = &rideEntry;
|
||||
|
||||
g141E9DB = G141E9DB_FLAG_1 | G141E9DB_FLAG_2;
|
||||
gPaintSession.Unk141E9DB = G141E9DB_FLAG_1 | G141E9DB_FLAG_2;
|
||||
|
||||
gCurrentViewportFlags = 0;
|
||||
RCT2_GLOBAL(0x0141E9E4, uint32) = 0;
|
||||
|
||||
gScenarioTicks = 0;
|
||||
RCT2_GLOBAL(0x00F663AC, uint32) = 0;
|
||||
}
|
||||
|
||||
void ResetTunnels() {
|
||||
|
||||
@@ -28,8 +28,32 @@ extern "C"
|
||||
#include <openrct2/paint/tile_element/tile_element.h>
|
||||
}
|
||||
|
||||
#define gRideEntries RCT2_ADDRESS(RCT2_ADDRESS_RIDE_ENTRIES, rct_ride_entry*)
|
||||
#define gCurrentRotation RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)
|
||||
#include "addresses.h"
|
||||
|
||||
#define gRideEntries RCT2_ADDRESS(0x009ACFA4, rct_ride_entry*)
|
||||
#define gSupportSegments RCT2_ADDRESS(0x0141E9B4, support_height)
|
||||
#define gWoodenSupportsPrependTo RCT2_GLOBAL(0x009DEA58, paint_struct *)
|
||||
#define gPaintStructs RCT2_ADDRESS(0x00EE788C, paint_entry)
|
||||
#define g_currently_drawn_item RCT2_GLOBAL(0x009DE578, void*)
|
||||
#define gEndOfPaintStructArray RCT2_GLOBAL(0x00EE7880, paint_entry *)
|
||||
#define gPaintSpritePosition RCT2_GLOBAL(0x009DE568, LocationXY16)
|
||||
#define gPaintInteractionType RCT2_GLOBAL(0x009DE570, uint8)
|
||||
#define gSupportSegments RCT2_ADDRESS(0x0141E9B4, support_height)
|
||||
#define gSupport RCT2_GLOBAL(0x0141E9D8, support_height)
|
||||
#define gWoodenSupportsPrependTo RCT2_GLOBAL(0x009DEA58, paint_struct *)
|
||||
#define gPaintMapPosition RCT2_GLOBAL(0x009DE574, LocationXY16)
|
||||
#define gLeftTunnels RCT2_ADDRESS(0x009E3138, tunnel_entry)
|
||||
#define gLeftTunnelCount RCT2_GLOBAL(0x0141F56A, uint8)
|
||||
#define gRightTunnels RCT2_ADDRESS(0x009E30B6, tunnel_entry)
|
||||
#define gRightTunnelCount RCT2_GLOBAL(0x0141F56B, uint8)
|
||||
#define gVerticalTunnelHeight RCT2_GLOBAL(0x009E323C, uint8)
|
||||
#define gSurfaceElement RCT2_GLOBAL(0x009E3250, rct_tile_element *)
|
||||
#define gDidPassSurface RCT2_GLOBAL(0x009DE57C, bool)
|
||||
#define g141E9DB RCT2_GLOBAL(0x0141E9DB, uint8)
|
||||
#define gUnk141E9DC RCT2_GLOBAL(0x0141E9DC, uint16)
|
||||
#define gTrackColours RCT2_ADDRESS(0x00F44198, uint32)
|
||||
|
||||
#define RCT2_CurrentRotation RCT2_GLOBAL(0x0141E9E0, uint8)
|
||||
|
||||
enum {
|
||||
TEST_SUCCESS,
|
||||
|
||||
@@ -166,6 +166,9 @@ public:
|
||||
Ride *ride, rct_ride_entry *rideEntry
|
||||
) override {
|
||||
ride->entrance_style = variant;
|
||||
|
||||
Ride * rct2ride = RCT2_ADDRESS(0x013628F8, Ride);
|
||||
rct2ride->entrance_style = variant;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -345,6 +348,7 @@ static uint8 TestTrackElementPaintCalls(uint8 rideType, uint8 trackType, uint8 t
|
||||
|
||||
for (int currentRotation = 0; currentRotation < 4; currentRotation++) {
|
||||
gCurrentRotation = currentRotation;
|
||||
RCT2_CurrentRotation = currentRotation;
|
||||
for (int direction = 0; direction < 4; direction++) {
|
||||
RCT2_GLOBAL(0x009DE56A, sint16) = 64; // x
|
||||
RCT2_GLOBAL(0x009DE56E, sint16) = 64; // y
|
||||
|
||||
85
test/testpaint/addresses.c
Normal file
85
test/testpaint/addresses.c
Normal file
@@ -0,0 +1,85 @@
|
||||
#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
|
||||
/*****************************************************************************
|
||||
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
||||
*
|
||||
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
||||
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* A full copy of the GNU General Public License can be found in licence.txt
|
||||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#include "addresses.h"
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#ifdef __clang__
|
||||
#define DISABLE_OPT __attribute__((noinline,optnone))
|
||||
#else
|
||||
#define DISABLE_OPT __attribute__((noinline,optimize("O0")))
|
||||
#endif // __clang__
|
||||
#else
|
||||
#define DISABLE_OPT
|
||||
#endif // defined(__GNUC__)
|
||||
|
||||
// This variable serves a purpose of identifying a crash if it has happened inside original code.
|
||||
// When switching to original code, stack frame pointer is modified and prevents breakpad from providing stack trace.
|
||||
volatile sint32 _originalAddress = 0;
|
||||
|
||||
sint32 DISABLE_OPT RCT2_CALLPROC_X(sint32 address, sint32 _eax, sint32 _ebx, sint32 _ecx, sint32 _edx, sint32 _esi, sint32 _edi, sint32 _ebp)
|
||||
{
|
||||
sint32 result = 0;
|
||||
_originalAddress = address;
|
||||
#if defined(PLATFORM_X86) && !defined(NO_RCT2)
|
||||
#ifdef _MSC_VER
|
||||
__asm {
|
||||
push ebp
|
||||
push address
|
||||
mov eax, _eax
|
||||
mov ebx, _ebx
|
||||
mov ecx, _ecx
|
||||
mov edx, _edx
|
||||
mov esi, _esi
|
||||
mov edi, _edi
|
||||
mov ebp, _ebp
|
||||
call [esp]
|
||||
lahf
|
||||
pop ebp
|
||||
pop ebp
|
||||
/* Load result with flags */
|
||||
mov result, eax
|
||||
}
|
||||
#else
|
||||
__asm__ volatile ( "\
|
||||
\n\
|
||||
push %%ebx \n\
|
||||
push %%ebp \n\
|
||||
push %[address] \n\
|
||||
mov %[eax], %%eax \n\
|
||||
mov %[ebx], %%ebx \n\
|
||||
mov %[ecx], %%ecx \n\
|
||||
mov %[edx], %%edx \n\
|
||||
mov %[esi], %%esi \n\
|
||||
mov %[edi], %%edi \n\
|
||||
mov %[ebp], %%ebp \n\
|
||||
call *(%%esp) \n\
|
||||
lahf \n\
|
||||
add $4, %%esp \n\
|
||||
pop %%ebp \n\
|
||||
pop %%ebx \n\
|
||||
/* Load result with flags */ \n\
|
||||
mov %%eax, %[result] \n\
|
||||
" : [address] "+m" (address), [eax] "+m" (_eax), [ebx] "+m" (_ebx), [ecx] "+m" (_ecx), [edx] "+m" (_edx), [esi] "+m" (_esi), [edi] "+m" (_edi), [ebp] "+m" (_ebp), [result] "+m" (result)
|
||||
:
|
||||
: "eax","ecx","edx","esi","edi","memory"
|
||||
);
|
||||
#endif
|
||||
#endif // PLATFORM_X86
|
||||
_originalAddress = 0;
|
||||
// lahf only modifies ah, zero out the rest
|
||||
return result & 0xFF00;
|
||||
}
|
||||
69
test/testpaint/addresses.h
Normal file
69
test/testpaint/addresses.h
Normal file
@@ -0,0 +1,69 @@
|
||||
|
||||
#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
|
||||
/*****************************************************************************
|
||||
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
||||
*
|
||||
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
||||
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* A full copy of the GNU General Public License can be found in licence.txt
|
||||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#ifndef _ADDRESSES_H_
|
||||
#define _ADDRESSES_H_
|
||||
|
||||
#include <openrct2/common.h>
|
||||
|
||||
#ifdef USE_MMAP
|
||||
#if defined(PLATFORM_64BIT)
|
||||
#define GOOD_PLACE_FOR_DATA_SEGMENT ((uintptr_t)0x200000000)
|
||||
#elif defined(PLATFORM_32BIT)
|
||||
#define GOOD_PLACE_FOR_DATA_SEGMENT ((uintptr_t)0x09000000)
|
||||
#else
|
||||
#error "Unknown platform"
|
||||
#endif
|
||||
#else
|
||||
#define GOOD_PLACE_FOR_DATA_SEGMENT ((uintptr_t)0x8a4000)
|
||||
#endif
|
||||
|
||||
#define RCT2_ADDRESS(address, type) ((type*)(GOOD_PLACE_FOR_DATA_SEGMENT - 0x8a4000 + (address)))
|
||||
#define RCT2_GLOBAL(address, type) (*((type*)(GOOD_PLACE_FOR_DATA_SEGMENT - 0x8a4000 + (address))))
|
||||
|
||||
#define RCT2_ADDRESS_RIDE_ENTRIES 0x009ACFA4
|
||||
#define RCT2_ADDRESS_CURRENT_ROTATION 0x0141E9E0
|
||||
#define RCT2_ADDRESS_SPRITE_LIST 0x010E63BC
|
||||
#define RCT2_ADDRESS_CURRENT_SUPPORT_SEGMENTS 0x0141E9B4
|
||||
#define RCT2_ADDRESS_PAINT_BOUNDBOX_OFFSET_X 0x009DEA52
|
||||
#define RCT2_ADDRESS_PAINT_BOUNDBOX_OFFSET_Y 0x009DEA54
|
||||
#define RCT2_ADDRESS_PAINT_BOUNDBOX_OFFSET_Z 0x009DEA56
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns the flags register
|
||||
*
|
||||
* Flags register is as follows:
|
||||
* 0bSZ0A_0P0C_0000_0000
|
||||
* S = Signed flag
|
||||
* Z = Zero flag
|
||||
* C = Carry flag
|
||||
* A = Adjust flag
|
||||
* P = Parity flag
|
||||
* All other bits are undefined.
|
||||
*/
|
||||
sint32 RCT2_CALLPROC_X(sint32 address, sint32 _eax, sint32 _ebx, sint32 _ecx, sint32 _edx, sint32 _esi, sint32 _edi, sint32 _ebp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -23,21 +23,20 @@
|
||||
#include <openrct2/world/sprite.h>
|
||||
#include <openrct2/paint/tile_element/tile_element.h>
|
||||
#include <openrct2/ride/ride.h>
|
||||
|
||||
#define RCT2_ADDRESS_SPRITE_LIST 0x010E63BC
|
||||
#include "addresses.h"
|
||||
|
||||
#define gRideEntries RCT2_ADDRESS(RCT2_ADDRESS_RIDE_ENTRIES, rct_ride_entry*)
|
||||
#define gCurrentRotation RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)
|
||||
|
||||
rct_tile_element *gTileElements = (rct_tile_element *) RCT2_ADDRESS_TILE_ELEMENTS;
|
||||
rct_tile_element **gTileElementTilePointers = (rct_tile_element **) RCT2_ADDRESS_TILE_TILE_ELEMENT_POINTERS;
|
||||
Ride *gRideList = RCT2_ADDRESS(RCT2_ADDRESS_RIDE_LIST, Ride);
|
||||
#define gTileElementTilePointers RCT2_ADDRESS(0x013CE9A4, rct_tile_element*)
|
||||
Ride gRideList[MAX_RIDES];
|
||||
rct_sprite *sprite_list = RCT2_ADDRESS(RCT2_ADDRESS_SPRITE_LIST, rct_sprite);
|
||||
sint16 gMapSizeUnits;
|
||||
sint16 gMapBaseZ;
|
||||
bool gTrackDesignSaveMode = false;
|
||||
uint8 gTrackDesignSaveRideIndex = 255;
|
||||
uint8 gClipHeight = 255;
|
||||
uint32 gCurrentViewportFlags;
|
||||
uint32 gScenarioTicks;
|
||||
uint8 gCurrentRotation;
|
||||
|
||||
const LocationXY16 TileDirectionDelta[] = {
|
||||
{-32, 0},
|
||||
|
||||
213
test/testpaint/hook.c
Normal file
213
test/testpaint/hook.c
Normal file
@@ -0,0 +1,213 @@
|
||||
#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
|
||||
/*****************************************************************************
|
||||
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
||||
*
|
||||
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
||||
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* A full copy of the GNU General Public License can be found in licence.txt
|
||||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#include <openrct2/common.h>
|
||||
|
||||
#ifndef NO_RCT2
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
#endif // _WIN32
|
||||
|
||||
#include "hook.h"
|
||||
|
||||
void* _hookTableAddress = 0;
|
||||
sint32 _hookTableOffset = 0;
|
||||
sint32 _maxHooks = 1000;
|
||||
#define HOOK_BYTE_COUNT (140)
|
||||
|
||||
registers gHookRegisters = {0};
|
||||
|
||||
// This macro writes a little-endian 4-byte long value into *data
|
||||
// It is used to avoid type punning.
|
||||
#define write_address_strictalias(data, addr) \
|
||||
*(data + 0) = ((addr) & 0x000000ff) >> 0; \
|
||||
*(data + 1) = ((addr) & 0x0000ff00) >> 8; \
|
||||
*(data + 2) = ((addr) & 0x00ff0000) >> 16; \
|
||||
*(data + 3) = ((addr) & 0xff000000) >> 24;
|
||||
|
||||
static void hookfunc(uintptr_t address, uintptr_t hookAddress, sint32 stacksize)
|
||||
{
|
||||
sint32 i = 0;
|
||||
uint8 data[HOOK_BYTE_COUNT] = {0};
|
||||
|
||||
uintptr_t registerAddress = (uintptr_t) &gHookRegisters;
|
||||
|
||||
data[i++] = 0x89; // mov [gHookRegisters], eax
|
||||
data[i++] = (0b000 << 3) | 0b101;
|
||||
write_address_strictalias(&data[i], registerAddress);
|
||||
i += 4;
|
||||
|
||||
data[i++] = 0x89; // mov [gHookRegisters + 4], ebx
|
||||
data[i++] = (0b011 << 3) | 0b101;
|
||||
write_address_strictalias(&data[i], registerAddress + 4);
|
||||
i += 4;
|
||||
|
||||
data[i++] = 0x89; // mov [gHookRegisters + 8], ecx
|
||||
data[i++] = (0b001 << 3) | 0b101;
|
||||
write_address_strictalias(&data[i], registerAddress + 8);
|
||||
i += 4;
|
||||
|
||||
data[i++] = 0x89; // mov [gHookRegisters + 12], edx
|
||||
data[i++] = (0b010 << 3) | 0b101;
|
||||
write_address_strictalias(&data[i], registerAddress + 12);
|
||||
i += 4;
|
||||
|
||||
data[i++] = 0x89; // mov [gHookRegisters + 16], esi
|
||||
data[i++] = (0b110 << 3) | 0b101;
|
||||
write_address_strictalias(&data[i], registerAddress + 16);
|
||||
i += 4;
|
||||
|
||||
data[i++] = 0x89; // mov [gHookRegisters + 20], edi
|
||||
data[i++] = (0b111 << 3) | 0b101;
|
||||
write_address_strictalias(&data[i], registerAddress + 20);
|
||||
i += 4;
|
||||
|
||||
data[i++] = 0x89; // mov [gHookRegisters + 24], ebp
|
||||
data[i++] = (0b101 << 3) | 0b101;
|
||||
write_address_strictalias(&data[i], registerAddress + 24);
|
||||
i += 4;
|
||||
|
||||
// work out distance to nearest 0xC
|
||||
// (esp - numargs * 4) & 0xC
|
||||
// move to align - 4
|
||||
// save that amount
|
||||
|
||||
// push the registers to be on the stack to access as arguments
|
||||
data[i++] = 0x68; // push gHookRegisters
|
||||
write_address_strictalias(&data[i], registerAddress);
|
||||
i += 4;
|
||||
|
||||
data[i++] = 0xE8; // call
|
||||
|
||||
write_address_strictalias(&data[i], hookAddress - address - i - 4);
|
||||
i += 4;
|
||||
|
||||
|
||||
data[i++] = 0x83; // add esp, 4
|
||||
data[i++] = 0xC4;
|
||||
data[i++] = 0x04;
|
||||
|
||||
data[i++] = 0x25; // and eax,0xff
|
||||
data[i++] = 0xff;
|
||||
data[i++] = 0x00;
|
||||
data[i++] = 0x00;
|
||||
data[i++] = 0x00;
|
||||
data[i++] = 0xc1; // shl eax, 8
|
||||
data[i++] = 0xe0;
|
||||
data[i++] = 0x08;
|
||||
data[i++] = 0x9e; // sahf
|
||||
data[i++] = 0x9c; // pushf
|
||||
|
||||
data[i++] = 0x8B; // mov eax, [gHookRegisters]
|
||||
data[i++] = (0b000 << 3) | 0b101;
|
||||
write_address_strictalias(&data[i], registerAddress);
|
||||
i += 4;
|
||||
|
||||
data[i++] = 0x8B; // mov ebx, [gHookRegisters + 4]
|
||||
data[i++] = (0b011 << 3) | 0b101;
|
||||
write_address_strictalias(&data[i], registerAddress + 4);
|
||||
i += 4;
|
||||
|
||||
data[i++] = 0x8B; // mov ecx, [gHookRegisters + 8]
|
||||
data[i++] = (0b001 << 3) | 0b101;
|
||||
write_address_strictalias(&data[i], registerAddress + 8);
|
||||
i += 4;
|
||||
|
||||
data[i++] = 0x8B; // mov edx, [gHookRegisters + 12]
|
||||
data[i++] = (0b010 << 3) | 0b101;
|
||||
write_address_strictalias(&data[i], registerAddress + 12);
|
||||
i += 4;
|
||||
|
||||
data[i++] = 0x8B; // mov esi, [gHookRegisters + 16]
|
||||
data[i++] = (0b110 << 3) | 0b101;
|
||||
write_address_strictalias(&data[i], registerAddress + 16);
|
||||
i += 4;
|
||||
|
||||
data[i++] = 0x8B; // mov edi, [gHookRegisters + 20]
|
||||
data[i++] = (0b111 << 3) | 0b101;
|
||||
write_address_strictalias(&data[i], registerAddress + 20);
|
||||
i += 4;
|
||||
|
||||
data[i++] = 0x8B; // mov ebp, [gHookRegisters + 24]
|
||||
data[i++] = (0b101 << 3) | 0b101;
|
||||
write_address_strictalias(&data[i], registerAddress + 24);
|
||||
i += 4;
|
||||
|
||||
data[i++] = 0x9d; // popf
|
||||
|
||||
data[i++] = 0xC3; // retn
|
||||
|
||||
#ifdef _WIN32
|
||||
WriteProcessMemory(GetCurrentProcess(), (LPVOID)address, data, i, 0);
|
||||
#else
|
||||
// We own the pages with PROT_WRITE | PROT_EXEC, we can simply just memcpy the data
|
||||
memcpy((void *)address, data, i);
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
void addhook(uintptr_t address, hook_function *function)
|
||||
{
|
||||
if (!_hookTableAddress) {
|
||||
size_t size = _maxHooks * HOOK_BYTE_COUNT;
|
||||
#ifdef _WIN32
|
||||
_hookTableAddress = VirtualAllocEx(GetCurrentProcess(), NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
#else
|
||||
_hookTableAddress = mmap(NULL, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (_hookTableAddress == MAP_FAILED)
|
||||
{
|
||||
perror("mmap");
|
||||
exit(1);
|
||||
}
|
||||
#endif // _WIN32
|
||||
}
|
||||
if (_hookTableOffset > _maxHooks) {
|
||||
return;
|
||||
}
|
||||
uint32 hookaddress = (uint32)_hookTableAddress + (_hookTableOffset * HOOK_BYTE_COUNT);
|
||||
uint8 data[9];
|
||||
sint32 i = 0;
|
||||
data[i++] = 0xE9; // jmp
|
||||
|
||||
write_address_strictalias(&data[i], hookaddress - address - i - 4);
|
||||
i += 4;
|
||||
|
||||
data[i++] = 0xC3; // retn
|
||||
#ifdef _WIN32
|
||||
WriteProcessMemory(GetCurrentProcess(), (LPVOID)address, data, i, 0);
|
||||
#else
|
||||
// We own the pages with PROT_WRITE | PROT_EXEC, we can simply just memcpy the data
|
||||
sint32 err = mprotect((void *)0x401000, 0x8a4000 - 0x401000, PROT_READ | PROT_WRITE);
|
||||
if (err != 0)
|
||||
{
|
||||
perror("mprotect");
|
||||
}
|
||||
|
||||
memcpy((void *)address, data, i);
|
||||
|
||||
err = mprotect((void *)0x401000, 0x8a4000 - 0x401000, PROT_READ | PROT_EXEC);
|
||||
if (err != 0)
|
||||
{
|
||||
perror("mprotect");
|
||||
}
|
||||
#endif // _WIN32
|
||||
hookfunc(hookaddress, (uintptr_t)function, 0);
|
||||
_hookTableOffset++;
|
||||
}
|
||||
|
||||
#endif
|
||||
48
test/testpaint/hook.h
Normal file
48
test/testpaint/hook.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
|
||||
/*****************************************************************************
|
||||
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
||||
*
|
||||
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
||||
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* A full copy of the GNU General Public License can be found in licence.txt
|
||||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#ifndef _HOOK_H_
|
||||
#define _HOOK_H_
|
||||
|
||||
#ifndef NO_RCT2
|
||||
|
||||
#include <openrct2/common.h>
|
||||
|
||||
enum {
|
||||
X86_FLAG_CARRY = 1 << 0,
|
||||
X86_FLAG_PARITY = 1 << 2,
|
||||
|
||||
X86_FLAG_ADJUST = 1 << 4,
|
||||
|
||||
X86_FLAG_ZERO = 1 << 6,
|
||||
X86_FLAG_SIGN = 1 << 7,
|
||||
};
|
||||
|
||||
typedef uint8 (hook_function)(registers *regs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void addhook(uintptr_t address, hook_function *function);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user