Merge 4222039bd0
into ef420ec6e6
This commit is contained in:
commit
f5e5e2b702
|
@ -1,6 +1,8 @@
|
|||
cmake_minimum_required(VERSION 3.9)
|
||||
cmake_policy(VERSION 3.9)
|
||||
|
||||
set(MACOSX_DEPLOYMENT_TARGET "10.14")
|
||||
|
||||
set (PROJECT openloco)
|
||||
|
||||
# Note: Searching for CCache must be before project() so project() can use CCache too
|
||||
|
@ -18,13 +20,13 @@ if (CCache_FOUND)
|
|||
endif (OPENLOCO_USE_CCACHE)
|
||||
endif (CCache_FOUND)
|
||||
|
||||
project(${PROJECT} CXX)
|
||||
project(${PROJECT} C CXX)
|
||||
|
||||
if (APPLE)
|
||||
# Detection of this variable seems to fail with CMake.
|
||||
# Since we only support 32-bit builds at the moment, fix it this way.
|
||||
# TODO: find out a proper fix for this.
|
||||
set(CMAKE_SIZEOF_VOID_P 4)
|
||||
# set(CMAKE_SIZEOF_VOID_P 4)
|
||||
endif()
|
||||
|
||||
if (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
|
@ -35,6 +37,7 @@ INCLUDE(FindPkgConfig)
|
|||
include(CheckCXXCompilerFlag)
|
||||
|
||||
option(STRICT "Build with warnings as errors" YES)
|
||||
option(I386 "Compile for native x86" ON)
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}")
|
||||
|
||||
|
@ -110,6 +113,13 @@ set(COMMON_COMPILE_OPTIONS
|
|||
set(OBJ_FORMAT "elf32-i386")
|
||||
set(LINKER_SCRIPT "ld_script_i386.xc")
|
||||
|
||||
if (I386)
|
||||
set(TARGET_M "-m32")
|
||||
else ()
|
||||
# Turn off for 64-bit builds for now
|
||||
set(COMMON_COMPILE_OPTIONS "${COMMON_COMPILE_OPTIONS} -Wno-int-to-pointer-cast")
|
||||
endif ()
|
||||
|
||||
# Handle creating the rct2 text and data files on OS X and Linux
|
||||
if (UNIX)
|
||||
set(OLOCO_EXE ${CMAKE_CURRENT_SOURCE_DIR}/loco.exe)
|
||||
|
@ -129,7 +139,19 @@ if (UNIX)
|
|||
)
|
||||
add_custom_target(segfiles DEPENDS ${OLOCO_TEXT} ${OLOCO_DATA})
|
||||
if (APPLE)
|
||||
set(LOCO_SEGMENT_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -sectcreate loco_text __text \"${OLOCO_TEXT}\" -sectcreate loco_data __data ${OLOCO_DATA} -segaddr loco_data 0x4d7000 -segprot loco_data rwx rwx -segaddr loco_text 0x401000 -segprot loco_text rwx rwx -segaddr __TEXT 0x2000000 -read_only_relocs suppress")
|
||||
set(LOCO_SEGMENT_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ")
|
||||
set(LOCO_SEGMENT_LINKER_FLAGS "${LOCO_SEGMENT_LINKER_FLAGS} -Xlinker -map -Xlinker \"${CMAKE_BINARY_DIR}/openloco.map\"")
|
||||
set(LOCO_SEGMENT_LINKER_FLAGS "${LOCO_SEGMENT_LINKER_FLAGS} -sectcreate loco_text __text \"${OLOCO_TEXT}\"")
|
||||
set(LOCO_SEGMENT_LINKER_FLAGS "${LOCO_SEGMENT_LINKER_FLAGS} -sectcreate loco_data __data \"${OLOCO_DATA}\"")
|
||||
set(LOCO_SEGMENT_LINKER_FLAGS "${LOCO_SEGMENT_LINKER_FLAGS} -segaddr loco_data 0x4d7000")
|
||||
set(LOCO_SEGMENT_LINKER_FLAGS "${LOCO_SEGMENT_LINKER_FLAGS} -segprot loco_data rwx rwx")
|
||||
# set(LOCO_SEGMENT_LINKER_FLAGS "${LOCO_SEGMENT_LINKER_FLAGS} -segaddr loco_text 0x401000")
|
||||
set(LOCO_SEGMENT_LINKER_FLAGS "${LOCO_SEGMENT_LINKER_FLAGS} -segprot loco_text rwx rwx")
|
||||
set(LOCO_SEGMENT_LINKER_FLAGS "${LOCO_SEGMENT_LINKER_FLAGS} -segaddr __TEXT 0x2000000")
|
||||
set(LOCO_SEGMENT_LINKER_FLAGS "${LOCO_SEGMENT_LINKER_FLAGS} -read_only_relocs suppress")
|
||||
if (NOT I386)
|
||||
set(LOCO_SEGMENT_LINKER_FLAGS "${LOCO_SEGMENT_LINKER_FLAGS} -pagezero_size 10000 -image_base 100000000")
|
||||
endif()
|
||||
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
|
||||
|
@ -164,8 +186,8 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEBUG=${DEBUG_LEVEL}")
|
|||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEBUG=${DEBUG_LEVEL}")
|
||||
|
||||
# add source files
|
||||
file(GLOB_RECURSE OLOCO_SOURCES "src/*.cpp")
|
||||
file(GLOB_RECURSE OLOCO_HEADERS "src/*.h" "src/*.hpp")
|
||||
file(GLOB_RECURSE OLOCO_SOURCES "src/OpenLoco/*.cpp")
|
||||
file(GLOB_RECURSE OLOCO_HEADERS "src/OpenLoco/*.h" "src/OpenLoco/*.hpp")
|
||||
|
||||
if (APPLE)
|
||||
file(GLOB_RECURSE OLOCO_MM_SOURCES "src/*.mm")
|
||||
|
@ -173,7 +195,6 @@ if (APPLE)
|
|||
endif ()
|
||||
|
||||
set(PIE_FLAG "-fno-pie")
|
||||
set(TARGET_M "-m32")
|
||||
|
||||
# Check if a flag exists and add it to the list of compiler (so, not linker) options
|
||||
function (ADD_CHECK_CXX_COMPILER_FLAG _CXXFLAGS _CACHE_VAR _FLAG)
|
||||
|
@ -204,6 +225,9 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TARGET_M} ${COMMON_COMPILE_OPTIONS}")
|
|||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${TARGET_M}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS} ${TARGET_M} ${PIE_FLAG}")
|
||||
|
||||
add_library(tinyalloc src/tinyalloc/tinyalloc.c)
|
||||
target_include_directories(tinyalloc PUBLIC src/tinyalloc/)
|
||||
|
||||
find_package(SDL2 REQUIRED)
|
||||
if (NOT SDL2_LIBRARIES)
|
||||
if (TARGET SDL2::SDL2-static)
|
||||
|
@ -233,6 +257,10 @@ if (MINGW)
|
|||
target_link_libraries(${PROJECT} winmm)
|
||||
else ()
|
||||
add_executable(${PROJECT} ${OLOCO_SOURCES} ${OLOCO_MM_SOURCES} ${LOCO_SECTIONS})
|
||||
if (NOT I386)
|
||||
find_library(UNICORN unicorn)
|
||||
target_link_libraries(${PROJECT} ${UNICORN})
|
||||
endif ()
|
||||
set_target_properties(${PROJECT} PROPERTIES LINK_FLAGS ${LOCO_SEGMENT_LINKER_FLAGS})
|
||||
endif ()
|
||||
|
||||
|
@ -240,6 +268,7 @@ target_link_libraries(${PROJECT} ${SDL2_LIBRARIES} ${SDL2_MIXER_LIBRARIES})
|
|||
target_link_libraries(${PROJECT} yaml-cpp ${YAML_CPP_LIBRARIES})
|
||||
target_link_libraries(${PROJECT} ${PNG_LIBRARIES})
|
||||
|
||||
target_link_libraries(${PROJECT} tinyalloc)
|
||||
|
||||
if (NOT MINGW)
|
||||
add_dependencies(${PROJECT} segfiles)
|
||||
|
|
|
@ -478,7 +478,7 @@ namespace OpenLoco::Audio
|
|||
auto w = WindowManager::find(WindowType::main, 0);
|
||||
if (w != nullptr)
|
||||
{
|
||||
auto viewport = w->viewports[0];
|
||||
auto viewport = w->viewports[0].get();
|
||||
if (viewport != nullptr && viewport->contains(vpos))
|
||||
{
|
||||
return viewport;
|
||||
|
@ -490,7 +490,7 @@ namespace OpenLoco::Audio
|
|||
w = WindowManager::get(i);
|
||||
if (w != nullptr && w->type != WindowType::main && w->type != WindowType::news)
|
||||
{
|
||||
auto viewport = w->viewports[0];
|
||||
auto viewport = w->viewports[0].get();
|
||||
if (viewport != nullptr && viewport->contains(vpos))
|
||||
{
|
||||
return viewport;
|
||||
|
@ -830,7 +830,7 @@ namespace OpenLoco::Audio
|
|||
auto main = WindowManager::getMainWindow();
|
||||
if (main != nullptr && main->viewports[0] != nullptr)
|
||||
{
|
||||
auto viewport = main->viewports[0];
|
||||
auto viewport = main->viewports[0].get();
|
||||
ViewportRect extendedViewport = {};
|
||||
|
||||
auto quarterWidth = viewport->view_width / 4;
|
||||
|
@ -864,7 +864,7 @@ namespace OpenLoco::Audio
|
|||
if (w->type == WindowType::news)
|
||||
continue;
|
||||
|
||||
auto viewport = w->viewports[0];
|
||||
auto viewport = w->viewports[0].get();
|
||||
if (viewport == nullptr)
|
||||
continue;
|
||||
|
||||
|
|
|
@ -317,7 +317,7 @@ namespace OpenLoco::CompanyManager
|
|||
if (main == nullptr)
|
||||
return;
|
||||
|
||||
auto viewport = main->viewports[0];
|
||||
auto viewport = main->viewports[0].get();
|
||||
if (viewport == nullptr)
|
||||
return;
|
||||
|
||||
|
|
|
@ -165,7 +165,7 @@ namespace OpenLoco::Drawing
|
|||
windowContext.height = rect.height();
|
||||
windowContext.x = rect.left();
|
||||
windowContext.y = rect.top();
|
||||
windowContext.bits = screen_info->context.bits + rect.left() + ((screen_info->context.width + screen_info->context.pitch) * rect.top());
|
||||
windowContext.bits = screen_info->context.bits.get() + rect.left() + ((screen_info->context.width + screen_info->context.pitch) * rect.top());
|
||||
windowContext.pitch = screen_info->context.width + screen_info->context.pitch - rect.width();
|
||||
windowContext.zoom_level = 0;
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace OpenLoco::Game
|
|||
Audio::pauseSound();
|
||||
setPauseFlag(1 << 2);
|
||||
Gfx::invalidateScreen();
|
||||
Ui::ProgressBar::sub_4CF63B();
|
||||
Gfx::render();
|
||||
|
||||
bool confirm = Ui::Windows::PromptBrowse::open(type, &_savePath[0], filter, titleBuffer);
|
||||
|
||||
|
@ -58,7 +58,7 @@ namespace OpenLoco::Game
|
|||
Ui::processMessagesMini();
|
||||
unsetPauseFlag(1 << 2);
|
||||
Gfx::invalidateScreen();
|
||||
Ui::ProgressBar::sub_4CF63B();
|
||||
Gfx::render();
|
||||
|
||||
return confirm;
|
||||
}
|
||||
|
|
|
@ -19,21 +19,22 @@ namespace OpenLoco::Colour
|
|||
{
|
||||
assert(i + 2170 < 2201);
|
||||
auto image = Gfx::getG1Element(2170 + i);
|
||||
_colour_map_a[i][0] = image->offset[9];
|
||||
auto offset = image->offset.get();
|
||||
_colour_map_a[i][0] = offset[9];
|
||||
|
||||
_colour_map_a[i][1] = image->offset[246];
|
||||
_colour_map_a[i][2] = image->offset[247];
|
||||
_colour_map_a[i][3] = image->offset[248];
|
||||
_colour_map_a[i][1] = offset[246];
|
||||
_colour_map_a[i][2] = offset[247];
|
||||
_colour_map_a[i][3] = offset[248];
|
||||
|
||||
_colour_map_a[i][4] = image->offset[249];
|
||||
_colour_map_a[i][5] = image->offset[250];
|
||||
_colour_map_a[i][6] = image->offset[251];
|
||||
_colour_map_a[i][7] = image->offset[252];
|
||||
_colour_map_a[i][4] = offset[249];
|
||||
_colour_map_a[i][5] = offset[250];
|
||||
_colour_map_a[i][6] = offset[251];
|
||||
_colour_map_a[i][7] = offset[252];
|
||||
|
||||
_colour_map_b[i][8 - 8] = image->offset[253];
|
||||
_colour_map_b[i][9 - 8] = image->offset[254];
|
||||
_colour_map_b[i][10 - 8] = image->offset[255];
|
||||
_colour_map_b[i][11 - 8] = image->offset[256];
|
||||
_colour_map_b[i][8 - 8] = offset[253];
|
||||
_colour_map_b[i][9 - 8] = offset[254];
|
||||
_colour_map_b[i][10 - 8] = offset[255];
|
||||
_colour_map_b[i][11 - 8] = offset[256];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace OpenLoco::Gfx
|
|||
|
||||
static loco_global<G1Element[g1_expected_count::disc + g1_count_temporary + g1_count_objects], 0x9E2424> _g1Elements;
|
||||
|
||||
static std::unique_ptr<std::byte[]> _g1Buffer;
|
||||
static std::byte* _g1Buffer;
|
||||
static loco_global<uint16_t[147], 0x050B8C8> _paletteToG1Offset;
|
||||
|
||||
static loco_global<uint16_t, 0x112C824> _currentFontFlags;
|
||||
|
@ -148,7 +148,7 @@ namespace OpenLoco::Gfx
|
|||
auto g1 = getG1Element(*g1Index);
|
||||
if (g1 != nullptr)
|
||||
{
|
||||
return PaletteMap(g1->offset, g1->height, g1->width);
|
||||
return PaletteMap(g1->offset.get(), g1->height, g1->width);
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
|
@ -201,8 +201,8 @@ namespace OpenLoco::Gfx
|
|||
auto elements = convertElements(elements32);
|
||||
|
||||
// Read element data
|
||||
auto elementData = std::make_unique<std::byte[]>(header.total_size);
|
||||
if (!readData(stream, elementData.get(), header.total_size))
|
||||
auto elementData = (std::byte*)malloc(header.total_size);
|
||||
if (!readData(stream, elementData, header.total_size))
|
||||
{
|
||||
throw std::runtime_error("Reading g1 elements failed.");
|
||||
}
|
||||
|
@ -226,10 +226,10 @@ namespace OpenLoco::Gfx
|
|||
// Adjust memory offsets
|
||||
for (auto& element : elements)
|
||||
{
|
||||
element.offset += (uintptr_t)elementData.get();
|
||||
element.offset = element.offset.get() + (uintptr_t)elementData;
|
||||
}
|
||||
|
||||
_g1Buffer = std::move(elementData);
|
||||
_g1Buffer = elementData;
|
||||
std::copy(elements.begin(), elements.end(), _g1Elements.get());
|
||||
}
|
||||
|
||||
|
@ -240,7 +240,7 @@ namespace OpenLoco::Gfx
|
|||
{
|
||||
int32_t w = context.width / (1 << context.zoom_level);
|
||||
int32_t h = context.height / (1 << context.zoom_level);
|
||||
uint8_t* ptr = context.bits;
|
||||
uint8_t* ptr = context.bits.get();
|
||||
|
||||
for (int32_t y = 0; y < h; y++)
|
||||
{
|
||||
|
@ -554,7 +554,8 @@ namespace OpenLoco::Gfx
|
|||
static void setTextColour(int colour)
|
||||
{
|
||||
auto el = &_g1Elements[ImageIds::text_palette];
|
||||
setTextColours(el->offset[colour * 4 + 0], el->offset[colour * 4 + 1], el->offset[colour * 4 + 2]);
|
||||
auto offset = el->offset.get();
|
||||
setTextColours(offset[colour * 4 + 0], offset[colour * 4 + 1], offset[colour * 4 + 2]);
|
||||
}
|
||||
|
||||
// 0x00451189
|
||||
|
@ -1386,7 +1387,7 @@ namespace OpenLoco::Gfx
|
|||
return ImageIdFlags::translucent | (colour << 19) | image;
|
||||
}
|
||||
|
||||
loco_global<uint8_t*, 0x0050B860> _50B860;
|
||||
loco_global<uint32_t, 0x0050B860> _50B860;
|
||||
loco_global<uint32_t, 0x00E04324> _E04324;
|
||||
|
||||
void drawImageSolid(Gfx::Context* context, int16_t x, int16_t y, uint32_t image, uint8_t palette_index)
|
||||
|
@ -1400,7 +1401,7 @@ namespace OpenLoco::Gfx
|
|||
|
||||
void drawImagePaletteSet(Gfx::Context* context, int16_t x, int16_t y, uint32_t image, uint8_t* palette)
|
||||
{
|
||||
_50B860 = palette;
|
||||
_50B860 = (uintptr_t)palette;
|
||||
_E04324 = 0x20000000;
|
||||
registers regs;
|
||||
regs.cx = x;
|
||||
|
@ -1417,7 +1418,7 @@ namespace OpenLoco::Gfx
|
|||
Ui::Rect intersect = oldRect.intersection(newRect);
|
||||
const auto stride = oldRect.size.width + src.pitch;
|
||||
const int16_t newPitch = stride - intersect.size.width;
|
||||
auto* newBits = src.bits + (stride * (intersect.origin.y - oldRect.origin.y) + (intersect.origin.x - oldRect.origin.x));
|
||||
auto* newBits = src.bits.get() + (stride * (intersect.origin.y - oldRect.origin.y) + (intersect.origin.x - oldRect.origin.x));
|
||||
intersect.origin.x = std::max(0, oldRect.origin.x - newRect.origin.x);
|
||||
intersect.origin.y = std::max(0, oldRect.origin.y - newRect.origin.y);
|
||||
Gfx::Context newContext{ newBits, static_cast<int16_t>(intersect.origin.x), static_cast<int16_t>(intersect.origin.y), static_cast<int16_t>(intersect.size.width), static_cast<int16_t>(intersect.size.height), newPitch, 0 };
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "../Core/Optional.hpp"
|
||||
#include "../Interop/Interop.hpp"
|
||||
#include "../OpenLoco.h"
|
||||
#include "../Types.hpp"
|
||||
#include "../Ui/Rect.h"
|
||||
|
@ -18,20 +19,20 @@ namespace OpenLoco::Gfx
|
|||
|
||||
struct Context
|
||||
{
|
||||
uint8_t* bits; // 0x00
|
||||
int16_t x; // 0x04
|
||||
int16_t y; // 0x06
|
||||
int16_t width; // 0x08
|
||||
int16_t height; // 0x0A
|
||||
int16_t pitch; // 0x0C note: this is actually (pitch - width)
|
||||
uint16_t zoom_level; // 0x0E
|
||||
loco_ptr2<uint8_t> bits; // 0x00
|
||||
int16_t x; // 0x04
|
||||
int16_t y; // 0x06
|
||||
int16_t width; // 0x08
|
||||
int16_t height; // 0x0A
|
||||
int16_t pitch; // 0x0C note: this is actually (pitch - width)
|
||||
uint16_t zoom_level; // 0x0E
|
||||
|
||||
Ui::Rect getUiRect() const;
|
||||
Ui::Rect getDrawableRect() const;
|
||||
};
|
||||
assert_struct_size(Context, 0x10);
|
||||
|
||||
Context& screenContext();
|
||||
|
||||
struct G1Header
|
||||
{
|
||||
uint32_t num_entries;
|
||||
|
@ -48,11 +49,12 @@ namespace OpenLoco::Gfx
|
|||
uint16_t flags; // 0x0C
|
||||
int16_t unused; // 0x0E
|
||||
};
|
||||
assert_struct_size(G1Element32, 0x10);
|
||||
|
||||
// A version that can be 64-bit when ready...
|
||||
struct G1Element
|
||||
{
|
||||
uint8_t* offset = nullptr;
|
||||
loco_ptr2<uint8_t> offset = nullptr;
|
||||
int16_t width = 0;
|
||||
int16_t height = 0;
|
||||
int16_t x_offset = 0;
|
||||
|
@ -73,6 +75,8 @@ namespace OpenLoco::Gfx
|
|||
}
|
||||
};
|
||||
|
||||
assert_struct_size(G1Element, 0x10);
|
||||
|
||||
#pragma pack(pop)
|
||||
namespace ImageIdFlags
|
||||
{
|
||||
|
|
|
@ -61,17 +61,17 @@ namespace OpenLoco::Gui
|
|||
{
|
||||
window->width = uiWidth;
|
||||
window->height = uiHeight;
|
||||
if (window->widgets)
|
||||
if (window->widgets.get())
|
||||
{
|
||||
window->widgets[0].right = uiWidth;
|
||||
window->widgets[0].bottom = uiHeight;
|
||||
window->widgets.get()[0].right = uiWidth;
|
||||
window->widgets.get()[0].bottom = uiHeight;
|
||||
}
|
||||
if (window->viewports[0])
|
||||
if (window->viewports[0].get())
|
||||
{
|
||||
window->viewports[0]->width = uiWidth;
|
||||
window->viewports[0]->height = uiHeight;
|
||||
window->viewports[0]->view_width = uiWidth << window->viewports[0]->zoom;
|
||||
window->viewports[0]->view_height = uiHeight << window->viewports[0]->zoom;
|
||||
window->viewports[0].get()->width = uiWidth;
|
||||
window->viewports[0].get()->height = uiHeight;
|
||||
window->viewports[0].get()->view_width = uiWidth << window->viewports[0].get()->zoom;
|
||||
window->viewports[0].get()->view_height = uiHeight << window->viewports[0].get()->zoom;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,9 @@ namespace OpenLoco::Input
|
|||
// 0x00406FEC
|
||||
void enqueueMouseButton(int32_t button)
|
||||
{
|
||||
#ifdef __i386__
|
||||
((void (*)(int))0x00406FEC)(button);
|
||||
#endif
|
||||
}
|
||||
|
||||
void sub_407218()
|
||||
|
|
|
@ -426,7 +426,7 @@ namespace OpenLoco::Input
|
|||
if (OpenLoco::isTitleMode())
|
||||
return;
|
||||
|
||||
auto viewport = main->viewports[0];
|
||||
auto viewport = main->viewports[0].get();
|
||||
if (viewport == nullptr)
|
||||
return;
|
||||
|
||||
|
@ -472,7 +472,7 @@ namespace OpenLoco::Input
|
|||
if (OpenLoco::isTitleMode())
|
||||
return;
|
||||
|
||||
auto viewport = main->viewports[0];
|
||||
auto viewport = main->viewports[0].get();
|
||||
if (viewport == nullptr)
|
||||
return;
|
||||
|
||||
|
|
|
@ -477,10 +477,10 @@ namespace OpenLoco::Input
|
|||
case MouseButton::released:
|
||||
{
|
||||
// 0x4C735D
|
||||
auto viewport = window->viewports[0];
|
||||
auto viewport = window->viewports[0].get();
|
||||
if (viewport == nullptr)
|
||||
{
|
||||
viewport = window->viewports[1];
|
||||
viewport = window->viewports[1].get();
|
||||
}
|
||||
if (viewport == nullptr)
|
||||
{
|
||||
|
@ -768,10 +768,10 @@ namespace OpenLoco::Input
|
|||
{
|
||||
// 4C74E4
|
||||
_ticksSinceDragStart += time_since_last_tick;
|
||||
auto vp = window->viewports[0];
|
||||
auto vp = window->viewports[0].get();
|
||||
if (vp == nullptr)
|
||||
{
|
||||
vp = window->viewports[1];
|
||||
vp = window->viewports[1].get();
|
||||
}
|
||||
if (vp == nullptr)
|
||||
{
|
||||
|
|
|
@ -244,7 +244,7 @@ namespace OpenLoco::Input::ShortcutManager
|
|||
if (window == nullptr)
|
||||
return;
|
||||
|
||||
auto viewport = WindowManager::getMainWindow()->viewports[0];
|
||||
auto viewport = WindowManager::getMainWindow()->viewports[0].get();
|
||||
viewport->flags ^= ViewportFlags::underground_view;
|
||||
window->invalidate();
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ namespace OpenLoco::Input::ShortcutManager
|
|||
if (window == nullptr)
|
||||
return;
|
||||
|
||||
auto viewport = WindowManager::getMainWindow()->viewports[0];
|
||||
auto viewport = WindowManager::getMainWindow()->viewports[0].get();
|
||||
viewport->flags ^= ViewportFlags::hide_foreground_tracks_roads;
|
||||
window->invalidate();
|
||||
}
|
||||
|
@ -268,7 +268,7 @@ namespace OpenLoco::Input::ShortcutManager
|
|||
if (window == nullptr)
|
||||
return;
|
||||
|
||||
auto viewport = WindowManager::getMainWindow()->viewports[0];
|
||||
auto viewport = WindowManager::getMainWindow()->viewports[0].get();
|
||||
viewport->flags ^= ViewportFlags::hide_foreground_scenery_buildings;
|
||||
window->invalidate();
|
||||
}
|
||||
|
@ -280,7 +280,7 @@ namespace OpenLoco::Input::ShortcutManager
|
|||
if (window == nullptr)
|
||||
return;
|
||||
|
||||
auto viewport = WindowManager::getMainWindow()->viewports[0];
|
||||
auto viewport = WindowManager::getMainWindow()->viewports[0].get();
|
||||
viewport->flags ^= ViewportFlags::height_marks_on_land;
|
||||
window->invalidate();
|
||||
}
|
||||
|
@ -292,7 +292,7 @@ namespace OpenLoco::Input::ShortcutManager
|
|||
if (window == nullptr)
|
||||
return;
|
||||
|
||||
auto viewport = WindowManager::getMainWindow()->viewports[0];
|
||||
auto viewport = WindowManager::getMainWindow()->viewports[0].get();
|
||||
viewport->flags ^= ViewportFlags::height_marks_on_tracks_roads;
|
||||
window->invalidate();
|
||||
}
|
||||
|
@ -304,7 +304,7 @@ namespace OpenLoco::Input::ShortcutManager
|
|||
if (window == nullptr)
|
||||
return;
|
||||
|
||||
auto viewport = WindowManager::getMainWindow()->viewports[0];
|
||||
auto viewport = WindowManager::getMainWindow()->viewports[0].get();
|
||||
viewport->flags ^= ViewportFlags::one_way_direction_arrows;
|
||||
window->invalidate();
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "../Console.h"
|
||||
#include "Interop.hpp"
|
||||
|
||||
#ifdef __i386__
|
||||
namespace OpenLoco::Interop
|
||||
{
|
||||
static void* _hookTableAddress;
|
||||
|
@ -186,6 +187,7 @@ namespace OpenLoco::Interop
|
|||
Console::error("Failed registering hook for 0x%08x. Ran out of hook table space", address);
|
||||
return;
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
// Do a few retries here. This can fail on some versions of wine which inexplicably would fail on
|
||||
// WriteProcessMemory for specific addresses that we fully own, but skipping over failing entry would work.
|
||||
bool done = false;
|
||||
|
@ -196,6 +198,13 @@ namespace OpenLoco::Interop
|
|||
uint8_t data[9];
|
||||
int32_t i = 0;
|
||||
data[i++] = 0xE9; // jmp
|
||||
=======
|
||||
int32_t ptr = (loco_ptr)_hookTableAddress;
|
||||
uint32_t hookaddress = ptr + (_hookTableOffset * HOOK_BYTE_COUNT);
|
||||
uint8_t data[9];
|
||||
int32_t i = 0;
|
||||
data[i++] = 0xE9; // jmp
|
||||
>>>>>>> f02af53d... WIP
|
||||
|
||||
WRITE_ADDRESS_STRICTALIAS(&data[i], hookaddress - address - i - 4);
|
||||
i += 4;
|
||||
|
@ -243,12 +252,12 @@ namespace OpenLoco::Interop
|
|||
#ifdef _WIN32
|
||||
_smallHooks = VirtualAllocEx(GetCurrentProcess(), NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
#else
|
||||
_smallHooks = mmap(NULL, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (_smallHooks == MAP_FAILED)
|
||||
{
|
||||
perror("mmap");
|
||||
exit(1);
|
||||
}
|
||||
_smallHooks = mmap(NULL, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (_smallHooks == MAP_FAILED)
|
||||
{
|
||||
perror("mmap");
|
||||
exit(1);
|
||||
}
|
||||
#endif // _WIN32
|
||||
_offset = static_cast<uint8_t*>(_smallHooks);
|
||||
}
|
||||
|
@ -306,3 +315,4 @@ namespace OpenLoco::Interop
|
|||
writeMemory(address, buffer.data(), buffer.size());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <cstring>
|
||||
#include <system_error>
|
||||
#ifndef _WIN32
|
||||
#include <cinttypes>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
@ -41,6 +42,10 @@ using namespace OpenLoco;
|
|||
|
||||
#define STUB() Console::logVerbose(__FUNCTION__)
|
||||
|
||||
#ifdef __i386__
|
||||
namespace compat = std;
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define STDCALL __stdcall
|
||||
#define CDECL __cdecl
|
||||
|
@ -51,6 +56,13 @@ using namespace OpenLoco;
|
|||
#error Unknown compiler, please define STDCALL and CDECL
|
||||
#endif
|
||||
|
||||
#ifdef __x86_64__
|
||||
#undef STDCALL
|
||||
#define STDCALL
|
||||
#undef CDECL
|
||||
#define CDECL
|
||||
#endif
|
||||
|
||||
#pragma warning(push)
|
||||
// MSVC ignores C++17's [[maybe_unused]] attribute on functions, so just disable the warning
|
||||
#pragma warning(disable : 4505) // unreferenced local function has been removed.
|
||||
|
@ -86,11 +98,6 @@ static int32_t CDECL audioIsChannelPlaying(int a0)
|
|||
}
|
||||
|
||||
#ifdef _NO_LOCO_WIN32_
|
||||
static void STDCALL fn_40447f()
|
||||
{
|
||||
STUB();
|
||||
return;
|
||||
}
|
||||
|
||||
static void STDCALL fn_404b68(int a0, int a1, int a2, int a3)
|
||||
{
|
||||
|
@ -123,7 +130,7 @@ static void CDECL fn_4054a3(const palette_entry_t* palette, int32_t index, int32
|
|||
}
|
||||
|
||||
FORCE_ALIGN_ARG_POINTER
|
||||
static bool STDCALL fn_4054b9()
|
||||
static bool STDCALL fn_40726d()
|
||||
{
|
||||
STUB();
|
||||
return true;
|
||||
|
@ -149,18 +156,6 @@ static void STDCALL fn_4078be()
|
|||
return;
|
||||
}
|
||||
|
||||
static void STDCALL fn_4078fe()
|
||||
{
|
||||
STUB();
|
||||
return;
|
||||
}
|
||||
|
||||
static void STDCALL fn_407b26()
|
||||
{
|
||||
STUB();
|
||||
return;
|
||||
}
|
||||
|
||||
///region Progress bar
|
||||
|
||||
static void CDECL fn_4080bb(char* lpWindowName, uint32_t a1)
|
||||
|
@ -186,35 +181,41 @@ static void CDECL fn_4081ad(int32_t wParam)
|
|||
|
||||
///endregion
|
||||
|
||||
struct FileWrapper
|
||||
{
|
||||
FILE* file;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
FORCE_ALIGN_ARG_POINTER
|
||||
static uint32_t CDECL fn_FileSeekSet(FILE* a0, int32_t distance)
|
||||
static uint32_t CDECL fn_FileSeekSet(FileWrapper* a0, int32_t distance)
|
||||
{
|
||||
Console::logVerbose("seek %d bytes from start", distance);
|
||||
fseek(a0, distance, SEEK_SET);
|
||||
return ftell(a0);
|
||||
fseek(a0->file, distance, SEEK_SET);
|
||||
return ftell(a0->file);
|
||||
}
|
||||
|
||||
FORCE_ALIGN_ARG_POINTER
|
||||
static uint32_t CDECL fn_FileSeekFromCurrent(FILE* a0, int32_t distance)
|
||||
static uint32_t CDECL fn_FileSeekFromCurrent(FileWrapper* a0, int32_t distance)
|
||||
{
|
||||
Console::logVerbose("seek %d bytes from current", distance);
|
||||
fseek(a0, distance, SEEK_CUR);
|
||||
return ftell(a0);
|
||||
fseek(a0->file, distance, SEEK_CUR);
|
||||
return ftell(a0->file);
|
||||
}
|
||||
|
||||
FORCE_ALIGN_ARG_POINTER
|
||||
static uint32_t CDECL fn_FileSeekFromEnd(FILE* a0, int32_t distance)
|
||||
static uint32_t CDECL fn_FileSeekFromEnd(FileWrapper* a0, int32_t distance)
|
||||
{
|
||||
Console::logVerbose("seek %d bytes from end", distance);
|
||||
fseek(a0, distance, SEEK_END);
|
||||
return ftell(a0);
|
||||
fseek(a0->file, distance, SEEK_END);
|
||||
return ftell(a0->file);
|
||||
}
|
||||
|
||||
FORCE_ALIGN_ARG_POINTER
|
||||
static int32_t CDECL fn_FileRead(FILE* a0, char* buffer, int32_t size)
|
||||
static int32_t CDECL fn_FileRead(FileWrapper* a0, char* buffer, int32_t size)
|
||||
{
|
||||
Console::logVerbose("read %d bytes (%d)", size, fileno(a0));
|
||||
size = fread(buffer, 1, size, a0);
|
||||
Console::logVerbose("read %d bytes (%d)", size, fileno(a0->file));
|
||||
size = fread(buffer, 1, size, a0->file);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
@ -336,29 +337,27 @@ static void CDECL fn_FindClose(Session* data)
|
|||
}
|
||||
|
||||
FORCE_ALIGN_ARG_POINTER
|
||||
static void* CDECL fn_malloc(uint32_t size)
|
||||
static uint32_t CDECL fn_malloc(uint32_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
void* pVoid = malloc(size);
|
||||
Console::log("Allocated 0x%X bytes at 0x%" PRIXPTR, size, (uintptr_t)pVoid);
|
||||
return (loco_ptr)pVoid;
|
||||
}
|
||||
|
||||
FORCE_ALIGN_ARG_POINTER
|
||||
static void* CDECL fn_realloc(void* block, uint32_t size)
|
||||
static uint32_t CDECL fn_realloc(void* block, uint32_t size)
|
||||
{
|
||||
return realloc(block, size);
|
||||
Console::log("Reallocated %" PRIXPTR " to 0x%X bytes", (uintptr_t)block, size);
|
||||
return (loco_ptr)realloc(block, size);
|
||||
}
|
||||
|
||||
#ifdef _NO_LOCO_WIN32_
|
||||
FORCE_ALIGN_ARG_POINTER
|
||||
static void CDECL fn_free(void* block)
|
||||
{
|
||||
return free(block);
|
||||
}
|
||||
|
||||
#ifdef _NO_LOCO_WIN32_
|
||||
static void STDCALL fn_dump(uint32_t address)
|
||||
{
|
||||
Console::log("Missing hook: 0x%x", address);
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
DS_OK = 0,
|
||||
|
@ -401,13 +400,15 @@ static bool STDCALL lib_DeleteFileA(char* lpFileName)
|
|||
|
||||
FORCE_ALIGN_ARG_POINTER
|
||||
static bool STDCALL lib_WriteFile(
|
||||
FILE* hFile,
|
||||
FileWrapper* hFile,
|
||||
char* buffer,
|
||||
size_t nNumberOfBytesToWrite,
|
||||
uint32_t* lpNumberOfBytesWritten,
|
||||
uintptr_t lpOverlapped)
|
||||
{
|
||||
*lpNumberOfBytesWritten = fwrite(buffer, 1, nNumberOfBytesToWrite, hFile);
|
||||
auto str = std::string(buffer, nNumberOfBytesToWrite);
|
||||
size_t i = fwrite(buffer, 1, nNumberOfBytesToWrite, hFile->file);
|
||||
*lpNumberOfBytesWritten = i;
|
||||
Console::logVerbose("WriteFile(%s)", buffer);
|
||||
|
||||
return true;
|
||||
|
@ -453,7 +454,10 @@ static int32_t STDCALL lib_CreateFileA(
|
|||
return -1;
|
||||
}
|
||||
|
||||
return (int32_t)pFILE;
|
||||
auto wrapper = new FileWrapper;
|
||||
wrapper->file = pFILE;
|
||||
wrapper->name = lpFileName;
|
||||
return (loco_ptr)wrapper;
|
||||
}
|
||||
|
||||
FORCE_ALIGN_ARG_POINTER
|
||||
|
@ -484,9 +488,9 @@ static void* STDCALL lib_CreateMutexA(uintptr_t lmMutexAttributes, bool bInitial
|
|||
FORCE_ALIGN_ARG_POINTER
|
||||
static bool STDCALL lib_CloseHandle(void* hObject)
|
||||
{
|
||||
auto file = (FILE*)hObject;
|
||||
auto file = (FileWrapper*)hObject;
|
||||
|
||||
return fclose(file) == 0;
|
||||
return fclose(file->file) == 0;
|
||||
}
|
||||
|
||||
FORCE_ALIGN_ARG_POINTER
|
||||
|
@ -504,9 +508,9 @@ static void registerMemoryHooks()
|
|||
|
||||
// Hook Locomotion's alloc / free routines so that we don't
|
||||
// allocate a block in one module and freeing it in another.
|
||||
writeJmp(0x4d1401, (void*)&fn_malloc);
|
||||
writeJmp(0x4D1B28, (void*)&fn_realloc);
|
||||
writeJmp(0x4D1355, (void*)&fn_free);
|
||||
hookFunction(0x4d1401, CallingConvention::cdecl, 1, (void (*)()) & fn_malloc);
|
||||
hookFunction(0x4D1B28, CallingConvention::cdecl, 2, (void (*)()) & fn_realloc);
|
||||
hookFunction(0x4D1355, CallingConvention::cdecl, 1, (void (*)()) & fn_free);
|
||||
}
|
||||
|
||||
#ifdef _NO_LOCO_WIN32_
|
||||
|
@ -514,54 +518,53 @@ static void registerNoWin32Hooks()
|
|||
{
|
||||
using namespace OpenLoco::Interop;
|
||||
|
||||
writeJmp(0x40447f, (void*)&fn_40447f);
|
||||
writeJmp(0x404b68, (void*)&fn_404b68);
|
||||
writeJmp(0x404e8c, (void*)&getNumDSoundDevices);
|
||||
writeJmp(0x4054b9, (void*)&fn_4054b9);
|
||||
writeJmp(0x4064fa, (void*)&fn0);
|
||||
writeJmp(0x4054a3, (void*)&fn_4054a3);
|
||||
writeJmp(0x4072ec, (void*)&fn0);
|
||||
writeJmp(0x4078be, (void*)&fn_4078be);
|
||||
writeJmp(0x4078fe, (void*)&fn_4078fe);
|
||||
writeJmp(0x407b26, (void*)&fn_407b26);
|
||||
writeJmp(0x4080bb, (void*)&fn_4080bb);
|
||||
writeJmp(0x408163, (void*)&fn_408163);
|
||||
writeJmp(0x40817b, (void*)&fn_40817b);
|
||||
writeJmp(0x4081ad, (void*)&fn_4081ad);
|
||||
writeJmp(0x4081c5, (void*)&fn_FileSeekSet);
|
||||
writeJmp(0x4081d8, (void*)&fn_FileSeekFromCurrent);
|
||||
writeJmp(0x4081eb, (void*)&fn_FileSeekFromEnd);
|
||||
writeJmp(0x4081fe, (void*)&fn_FileRead);
|
||||
writeJmp(0x40830e, (void*)&fn_FindFirstFile);
|
||||
writeJmp(0x40831d, (void*)&fn_FindNextFile);
|
||||
writeJmp(0x40832c, (void*)&fn_FindClose);
|
||||
writeJmp(0x4d0fac, (void*)&fn_DirectSoundEnumerateA);
|
||||
hookFunction(0x404b68, CallingConvention::stdcall, 4, (void (*)()) & fn_404b68);
|
||||
hookFunction(0x404e8c, CallingConvention::stdcall, 0, (void (*)()) & getNumDSoundDevices);
|
||||
hookFunction(0x4064fa, CallingConvention::stdcall, 0, (void (*)()) & fn0);
|
||||
hookFunction(0x40726d, CallingConvention::stdcall, 0, (void (*)()) & fn_40726d);
|
||||
hookFunction(0x4054a3, CallingConvention::cdecl, 3, (void (*)()) & fn_4054a3);
|
||||
hookFunction(0x4072ec, CallingConvention::stdcall, 0, (void (*)()) & fn0);
|
||||
hookFunction(0x4078be, CallingConvention::stdcall, 0, (void (*)()) & fn_4078be);
|
||||
hookFunction(0x4080bb, CallingConvention::cdecl, 2, (void (*)()) & fn_4080bb);
|
||||
hookFunction(0x408163, CallingConvention::cdecl, 0, (void (*)()) & fn_408163);
|
||||
hookFunction(0x40817b, CallingConvention::cdecl, 1, (void (*)()) & fn_40817b);
|
||||
hookFunction(0x4081ad, CallingConvention::cdecl, 1, (void (*)()) & fn_4081ad);
|
||||
hookFunction(0x4081c5, CallingConvention::cdecl, 2, (void (*)()) & fn_FileSeekSet);
|
||||
hookFunction(0x4081d8, CallingConvention::cdecl, 2, (void (*)()) & fn_FileSeekFromCurrent);
|
||||
hookFunction(0x4081eb, CallingConvention::cdecl, 2, (void (*)()) & fn_FileSeekFromEnd);
|
||||
hookFunction(0x4081fe, CallingConvention::cdecl, 3, (void (*)()) & fn_FileRead);
|
||||
hookFunction(0x40830e, CallingConvention::cdecl, 2, (void (*)()) & fn_FindFirstFile);
|
||||
hookFunction(0x40831d, CallingConvention::cdecl, 2, (void (*)()) & fn_FindNextFile);
|
||||
hookFunction(0x40832c, CallingConvention::cdecl, 1, (void (*)()) & fn_FindClose);
|
||||
hookFunction(0x4d0fac, CallingConvention::stdcall, 2, (void (*)()) & fn_DirectSoundEnumerateA);
|
||||
|
||||
// fill DLL hooks for ease of debugging
|
||||
for (int i = 0x4d7000; i <= 0x4d72d8; i += 4)
|
||||
for (uint32_t address = 0x4d7000; address <= 0x4d72d8; address += 4)
|
||||
{
|
||||
hookDump(i, (void*)&fn_dump);
|
||||
hookLibrary(address, [address]() {
|
||||
Console::log("Missing hook: 0x%x", address);
|
||||
});
|
||||
}
|
||||
|
||||
// dsound.dll
|
||||
hookLib(0x4d7024, (void*)&lib_DirectSoundCreate);
|
||||
hookLibrary(0x4d7024, CallingConvention::stdcall, 3, (void (*)()) & lib_DirectSoundCreate);
|
||||
|
||||
// gdi32.dll
|
||||
hookLib(0x4d7078, (void*)&lib_CreateRectRgn);
|
||||
hookLibrary(0x4d7078, CallingConvention::stdcall, 4, (void (*)()) & lib_CreateRectRgn);
|
||||
|
||||
// kernel32.dll
|
||||
hookLib(0x4d70e0, (void*)&lib_CreateMutexA);
|
||||
hookLib(0x4d70e4, (void*)&lib_OpenMutexA);
|
||||
hookLib(0x4d70f0, (void*)&lib_WriteFile);
|
||||
hookLib(0x4d70f4, (void*)&lib_DeleteFileA);
|
||||
hookLib(0x4d70f8, (void*)&lib_SetFileAttributesA);
|
||||
hookLib(0x4d70fC, (void*)&lib_CreateFileA);
|
||||
hookLibrary(0x4d70e0, CallingConvention::stdcall, 3, (void (*)()) & lib_CreateMutexA);
|
||||
hookLibrary(0x4d70e4, CallingConvention::stdcall, 3, (void (*)()) & lib_OpenMutexA);
|
||||
hookLibrary(0x4d70f0, CallingConvention::stdcall, 5, (void (*)()) & lib_WriteFile);
|
||||
hookLibrary(0x4d70f4, CallingConvention::stdcall, 1, (void (*)()) & lib_DeleteFileA);
|
||||
hookLibrary(0x4d70f8, CallingConvention::stdcall, 2, (void (*)()) & lib_SetFileAttributesA);
|
||||
hookLibrary(0x4d70fC, CallingConvention::stdcall, 7, (void (*)()) & lib_CreateFileA);
|
||||
|
||||
// user32.dll
|
||||
hookLib(0x4d71e8, (void*)&lib_PostQuitMessage);
|
||||
hookLib(0x4d714c, (void*)&lib_CloseHandle);
|
||||
hookLib(0x4d7248, (void*)&lib_GetUpdateRgn);
|
||||
hookLib(0x4d72b0, (void*)&lib_timeGetTime);
|
||||
hookLibrary(0x4d71e8, CallingConvention::stdcall, 1, (void (*)()) & lib_PostQuitMessage);
|
||||
hookLibrary(0x4d714c, CallingConvention::stdcall, 1, (void (*)()) & lib_CloseHandle);
|
||||
hookLibrary(0x4d7248, CallingConvention::stdcall, 3, (void (*)()) & lib_GetUpdateRgn);
|
||||
hookLibrary(0x4d72b0, CallingConvention::stdcall, 0, (void (*)()) & lib_timeGetTime);
|
||||
}
|
||||
#endif // _NO_LOCO_WIN32_
|
||||
|
||||
|
@ -586,11 +589,11 @@ static void registerAudioHooks()
|
|||
{
|
||||
using namespace OpenLoco::Interop;
|
||||
|
||||
writeJmp(0x0040194E, (void*)&audioLoadChannel);
|
||||
writeJmp(0x00401999, (void*)&audioPlayChannel);
|
||||
writeJmp(0x00401A05, (void*)&audioStopChannel);
|
||||
writeJmp(0x00401AD3, (void*)&audioSetChannelVolume);
|
||||
writeJmp(0x00401B10, (void*)&audioIsChannelPlaying);
|
||||
hookFunction(0x0040194E, CallingConvention::cdecl, 5, (void (*)()) & audioLoadChannel);
|
||||
hookFunction(0x00401999, CallingConvention::cdecl, 5, (void (*)()) & audioPlayChannel);
|
||||
hookFunction(0x00401A05, CallingConvention::cdecl, 5, (void (*)()) & audioStopChannel);
|
||||
hookFunction(0x00401AD3, CallingConvention::cdecl, 2, (void (*)()) & audioSetChannelVolume);
|
||||
hookFunction(0x00401B10, CallingConvention::cdecl, 1, (void (*)()) & audioIsChannelPlaying);
|
||||
|
||||
writeRet(0x0048AB36);
|
||||
writeRet(0x00404B40);
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#include "emu.h"
|
||||
#include <algorithm>
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <unicorn/unicorn.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef NOMINMAX
|
||||
|
@ -14,8 +16,12 @@
|
|||
#include "../Console.h"
|
||||
#include "Interop.hpp"
|
||||
|
||||
#define _LOG_INTEROP_CALLS_ 1
|
||||
|
||||
#pragma warning(disable : 4731) // frame pointer register 'ebp' modified by inline assembly code
|
||||
#ifdef __i386__
|
||||
#define PLATFORM_X86
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#ifdef __clang__
|
||||
|
@ -86,7 +92,11 @@ namespace OpenLoco::Interop
|
|||
);
|
||||
// clang-format on
|
||||
#endif
|
||||
#endif // PLATFORM_X86
|
||||
#else // PLATFORM_X86
|
||||
|
||||
emu::call(address, _eax, _ebx, _ecx, _edx, _esi, _edi, _ebp);
|
||||
|
||||
#endif
|
||||
_originalAddress = 0;
|
||||
// lahf only modifies ah, zero out the rest
|
||||
return result & 0xFF00;
|
||||
|
@ -96,7 +106,7 @@ namespace OpenLoco::Interop
|
|||
static int32_t DISABLE_OPT callByRef(int32_t address, int32_t* _eax, int32_t* _ebx, int32_t* _ecx, int32_t* _edx, int32_t* _esi, int32_t* _edi, int32_t* _ebp)
|
||||
{
|
||||
#ifdef _LOG_INTEROP_CALLS_
|
||||
OpenLoco::Console::group("0x%x", address);
|
||||
OpenLoco::Console::group("call 0x%x", address);
|
||||
#endif
|
||||
int32_t result = 0;
|
||||
_originalAddress = address;
|
||||
|
@ -249,10 +259,14 @@ namespace OpenLoco::Interop
|
|||
);
|
||||
// clang-format on
|
||||
#endif
|
||||
#endif // PLATFORM_X86
|
||||
#else // PLATFORM_X86
|
||||
|
||||
emu::call(address, _eax, _ebx, _ecx, _edx, _esi, _edi, _ebp);
|
||||
#endif
|
||||
_originalAddress = 0;
|
||||
|
||||
#ifdef _LOG_INTEROP_CALLS_
|
||||
OpenLoco::Console::log("Returning %x", address);
|
||||
OpenLoco::Console::groupEnd();
|
||||
#endif
|
||||
// lahf only modifies ah, zero out the rest
|
||||
|
@ -303,7 +317,7 @@ namespace OpenLoco::Interop
|
|||
}
|
||||
#else
|
||||
// We own the pages with PROT_WRITE | PROT_EXEC, we can simply just memcpy the data
|
||||
std::memcpy(data, (void*)address, size);
|
||||
std::memcpy(data, (void*)(uintptr_t)address, size);
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
|
@ -317,7 +331,7 @@ namespace OpenLoco::Interop
|
|||
}
|
||||
#else
|
||||
// We own the pages with PROT_WRITE | PROT_EXEC, we can simply just memcpy the data
|
||||
std::memcpy((void*)address, data, size);
|
||||
std::memcpy((void*)(uintptr_t)address, data, size);
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
|
|
|
@ -1,26 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "../Utility/String.hpp"
|
||||
#include "i386.h"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#if defined(__i386__)
|
||||
#define assert_struct_size(x, y) static_assert(sizeof(x) == (y), "Improper struct size")
|
||||
#else
|
||||
#define assert_struct_size(x, y)
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || (defined(__GNUC__) && !defined(__MINGW32__))
|
||||
#define FORCE_ALIGN_ARG_POINTER __attribute__((force_align_arg_pointer))
|
||||
#else
|
||||
#define FORCE_ALIGN_ARG_POINTER
|
||||
#endif
|
||||
|
||||
constexpr int32_t DEFAULT_REG_VAL = 0xCCCCCCCC;
|
||||
|
||||
namespace OpenLoco::Interop
|
||||
{
|
||||
template<typename T = void>
|
||||
|
@ -51,71 +44,6 @@ namespace OpenLoco::Interop
|
|||
};
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
/**
|
||||
* x86 register structure, only used for easy interop to Locomotion code.
|
||||
*/
|
||||
struct registers
|
||||
{
|
||||
union
|
||||
{
|
||||
int32_t eax{ DEFAULT_REG_VAL };
|
||||
int16_t ax;
|
||||
struct
|
||||
{
|
||||
int8_t al;
|
||||
int8_t ah;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t ebx{ DEFAULT_REG_VAL };
|
||||
int16_t bx;
|
||||
struct
|
||||
{
|
||||
int8_t bl;
|
||||
int8_t bh;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t ecx{ DEFAULT_REG_VAL };
|
||||
int16_t cx;
|
||||
struct
|
||||
{
|
||||
int8_t cl;
|
||||
int8_t ch;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t edx{ DEFAULT_REG_VAL };
|
||||
int16_t dx;
|
||||
struct
|
||||
{
|
||||
int8_t dl;
|
||||
int8_t dh;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t esi{ DEFAULT_REG_VAL };
|
||||
int16_t si;
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t edi{ DEFAULT_REG_VAL };
|
||||
int16_t di;
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t ebp{ DEFAULT_REG_VAL };
|
||||
int16_t bp;
|
||||
};
|
||||
};
|
||||
assert_struct_size(registers, 7 * 4);
|
||||
#pragma pack(pop)
|
||||
|
||||
#ifndef USE_MMAP
|
||||
constexpr uintptr_t GOOD_PLACE_FOR_DATA_SEGMENT = 0x008A4000;
|
||||
#else
|
||||
|
@ -405,17 +333,6 @@ namespace OpenLoco::Interop
|
|||
void readMemory(uint32_t address, void* data, size_t size);
|
||||
void writeMemory(uint32_t address, const void* data, size_t size);
|
||||
|
||||
using hook_function = uint8_t (*)(registers& regs);
|
||||
|
||||
void registerHook(uintptr_t address, hook_function function);
|
||||
void writeRet(uint32_t address);
|
||||
void writeJmp(uint32_t address, void* fn);
|
||||
void writeNop(uint32_t address, size_t count);
|
||||
void hookDump(uint32_t address, void* fn);
|
||||
void hookLib(uint32_t address, void* fn);
|
||||
|
||||
void registerHooks();
|
||||
void loadSections();
|
||||
}
|
||||
|
||||
// these safe string function convenience overloads are located in this header, rather than in Utility/String.hpp,
|
||||
|
|
|
@ -0,0 +1,746 @@
|
|||
#ifndef __i386__
|
||||
#include "emu.h"
|
||||
#include "../OpenLoco.h"
|
||||
#include "i386.h"
|
||||
#include <cstdio>
|
||||
#include <unicorn/unicorn.h>
|
||||
#include <unicorn/x86.h>
|
||||
|
||||
#include "../Console.h"
|
||||
#include "Interop.hpp"
|
||||
#include <cassert>
|
||||
#include <cinttypes>
|
||||
#include <map>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#include <tinyalloc.h>
|
||||
}
|
||||
|
||||
uint32_t heapStart = 0x20000000;
|
||||
uint32_t heapSize = 1024 * 1024 * 512; // 16MiB
|
||||
void* heap;
|
||||
|
||||
namespace OpenLoco::Interop
|
||||
{
|
||||
struct InteropFunction
|
||||
{
|
||||
void (*function)();
|
||||
hook_function hookFunction;
|
||||
CallingConvention convention;
|
||||
size_t argumentCount;
|
||||
std::function<void()> simple;
|
||||
};
|
||||
|
||||
std::vector<InteropFunction> _newHooks;
|
||||
static bool _log = false;
|
||||
|
||||
std::map<uint32_t, InteropFunction> _hooks;
|
||||
std::map<uint32_t, InteropFunction> _libraryHooks;
|
||||
|
||||
constexpr uint32_t executionEnd = 0xfffff000;
|
||||
|
||||
void* hookMem;
|
||||
uintptr_t hookMemCur;
|
||||
|
||||
const uint32_t hookMemStart = 0x10000000;
|
||||
const uint32_t hookMemSize = 0x1000;
|
||||
|
||||
static const int softwareInterruptNumber = 0x80;
|
||||
|
||||
uintptr_t stackStart = 0xA0000000;
|
||||
uint32_t stackSize = 16 * 1024 * 1024;
|
||||
void* stack;
|
||||
|
||||
static uint32_t _esp;
|
||||
|
||||
void emu_init()
|
||||
{
|
||||
auto fh = fopen("/Users/hamster/Projects/OpenLoco/Wissel/cmake-build-x64/openloco_text", "r");
|
||||
auto test = mmap((void*)(uintptr_t)0x401000, 0xD6000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fileno(fh), 0);
|
||||
if (test == MAP_FAILED)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
hookMem = malloc(0x1000);
|
||||
hookMemCur = reinterpret_cast<uintptr_t>(hookMem);
|
||||
|
||||
stack = mmap((void*)stackStart, stackSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
OpenLoco::Console::log("allocated stack space from 0x%" PRIXPTR " to 0x%" PRIXPTR, (uintptr_t)stack, (uintptr_t)stack + stackSize);
|
||||
|
||||
_esp = stackStart + stackSize;
|
||||
}
|
||||
|
||||
static void write_address_strictalias(uint8_t* data, uint32_t addr)
|
||||
{
|
||||
*(data + 0) = ((addr)&0x000000ff) >> 0;
|
||||
*(data + 1) = ((addr)&0x0000ff00) >> 8;
|
||||
*(data + 2) = ((addr)&0x00ff0000) >> 16;
|
||||
*(data + 3) = ((addr)&0xff000000) >> 24;
|
||||
}
|
||||
|
||||
// Callback for tracing all kinds of memory errors
|
||||
static void UcErrorHook(uc_engine* uc, uc_mem_type type, uint64_t address, int size, int64_t value, void* user_data)
|
||||
{
|
||||
/*
|
||||
FIXME: type is one of
|
||||
UC_MEM_READ_UNMAPPED = 19, // Unmapped memory is read from
|
||||
UC_MEM_WRITE_UNMAPPED = 20, // Unmapped memory is written to
|
||||
UC_MEM_FETCH_UNMAPPED = 21, // Unmapped memory is fetched
|
||||
UC_MEM_WRITE_PROT = 22, // Write to write protected, but mapped, memory
|
||||
UC_MEM_READ_PROT = 23, // Read from read protected, but mapped, memory
|
||||
UC_MEM_FETCH_PROT = 24, // Fetch from non-executable, but mapped, memory
|
||||
*/
|
||||
OpenLoco::Console::log("Unicorn-Engine error of type %d at 0x%" PRIx64 ", size = 0x%" PRIX32 "\n", type, address, size);
|
||||
|
||||
std::byte buffer[8] = {};
|
||||
uc_mem_read(uc, 0x50B864, buffer, 8);
|
||||
uc_emu_stop(uc);
|
||||
|
||||
// ThreadContext ctx;
|
||||
// TransferContext(&ctx, false);
|
||||
// PrintContext(&ctx);
|
||||
|
||||
std::map<int, std::string> data = {
|
||||
{ UC_X86_REG_EIP, "EIP" },
|
||||
{ UC_X86_REG_EAX, "EAX" },
|
||||
{ UC_X86_REG_EBX, "EBX" },
|
||||
{ UC_X86_REG_ECX, "ECX" },
|
||||
{ UC_X86_REG_EDX, "EDX" },
|
||||
{ UC_X86_REG_EDI, "EDI" },
|
||||
{ UC_X86_REG_ESI, "ESI" },
|
||||
{ UC_X86_REG_EBP, "EBP" },
|
||||
{ UC_X86_REG_ESP, "ESP" },
|
||||
};
|
||||
|
||||
for (auto const& x : data)
|
||||
{
|
||||
int eip;
|
||||
auto succ = uc_reg_read(uc, x.first, &eip);
|
||||
printf(" %s: %X (%d)\n", x.second.c_str(), eip, succ);
|
||||
}
|
||||
|
||||
uint32_t esp;
|
||||
uc_reg_read(uc, UC_X86_REG_ESP, &esp);
|
||||
for (int i = -32; i < 32; i++)
|
||||
{
|
||||
uint32_t val;
|
||||
uintptr_t addr = esp - i * 4;
|
||||
auto succ = uc_mem_read(uc, addr, &val, sizeof val);
|
||||
if (addr >= stackStart + stackSize)
|
||||
continue;
|
||||
;
|
||||
if (addr < stackStart)
|
||||
continue;
|
||||
printf("Stack [%X] = %X (%d) %X\n", addr, val, succ, *((uint32_t*)addr));
|
||||
}
|
||||
|
||||
uc_mem_region* regions;
|
||||
uint32_t regionCount;
|
||||
auto err = uc_mem_regions(uc, ®ions, ®ionCount);
|
||||
|
||||
for (int i = 0; i < regionCount; i++)
|
||||
{
|
||||
printf("%08X | %08X | ", regions[i].begin, regions[i].end);
|
||||
if (regions[i].perms & UC_PROT_READ)
|
||||
{
|
||||
printf("R");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" ");
|
||||
}
|
||||
if (regions[i].perms & UC_PROT_WRITE)
|
||||
{
|
||||
printf("W");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" ");
|
||||
}
|
||||
if (regions[i].perms & UC_PROT_EXEC)
|
||||
{
|
||||
printf("X");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
assert(false);
|
||||
}
|
||||
|
||||
uint64_t lastEIP;
|
||||
|
||||
static void hook_code(uc_engine* uc, uint64_t address, uint32_t size, void* user_data)
|
||||
{
|
||||
lastEIP = address;
|
||||
OpenLoco::Console::log("* %p\n", (void*)address);
|
||||
}
|
||||
|
||||
void registerHook(uintptr_t address, hook_function function)
|
||||
{
|
||||
auto newIndex = _newHooks.size();
|
||||
|
||||
InteropFunction item = {};
|
||||
item.convention = CallingConvention::sawyer;
|
||||
item.hookFunction = function;
|
||||
_newHooks.push_back(item);
|
||||
|
||||
uint8_t assembly[8] = {};
|
||||
|
||||
// push imm32
|
||||
assembly[0] = 0x68;
|
||||
write_address_strictalias(&assembly[1], newIndex);
|
||||
|
||||
// int imm8
|
||||
assembly[5] = 0xCD;
|
||||
assembly[6] = softwareInterruptNumber;
|
||||
|
||||
// ret
|
||||
assembly[7] = 0xC3;
|
||||
|
||||
writeMemory(address, assembly, sizeof(assembly));
|
||||
}
|
||||
|
||||
void writeRet(uint32_t address) {}
|
||||
void writeJmp(uint32_t address, void* fn) {}
|
||||
void writeNop(uint32_t address, size_t count) {}
|
||||
void hookDump(uint32_t address, void* fn) {}
|
||||
|
||||
void hookLibrary(uint32_t address, CallingConvention convention, size_t arguments, void (*fn)())
|
||||
{
|
||||
auto newIndex = _newHooks.size();
|
||||
|
||||
InteropFunction item = {};
|
||||
item.convention = convention;
|
||||
item.argumentCount = arguments;
|
||||
item.function = fn;
|
||||
_newHooks.push_back(item);
|
||||
|
||||
uint8_t assembly[8] = {};
|
||||
|
||||
// push imm32
|
||||
assembly[0] = 0x68;
|
||||
write_address_strictalias(&assembly[1], newIndex);
|
||||
|
||||
// int imm8
|
||||
assembly[5] = 0xCD;
|
||||
assembly[6] = softwareInterruptNumber;
|
||||
|
||||
// ret
|
||||
assembly[7] = 0xC3;
|
||||
|
||||
uint32_t data = hookMemStart + (hookMemCur - reinterpret_cast<uintptr_t>(hookMem));
|
||||
writeMemory(address, &data, sizeof(data));
|
||||
|
||||
memcpy((void*)hookMemCur, assembly, sizeof(assembly));
|
||||
hookMemCur += sizeof(assembly);
|
||||
}
|
||||
|
||||
void hookLibrary(uint32_t address, std::function<void()> fn)
|
||||
{
|
||||
auto newIndex = _newHooks.size();
|
||||
|
||||
InteropFunction item = {};
|
||||
item.simple = fn;
|
||||
_newHooks.push_back(item);
|
||||
|
||||
uint8_t assembly[8] = {};
|
||||
|
||||
// push imm32
|
||||
assembly[0] = 0x68;
|
||||
write_address_strictalias(&assembly[1], newIndex);
|
||||
|
||||
// int imm8
|
||||
assembly[5] = 0xCD;
|
||||
assembly[6] = softwareInterruptNumber;
|
||||
|
||||
// ret
|
||||
assembly[7] = 0xC3;
|
||||
|
||||
uint32_t data = hookMemStart + (hookMemCur - reinterpret_cast<uintptr_t>(hookMem));
|
||||
writeMemory(address, &data, sizeof(data));
|
||||
|
||||
memcpy((void*)hookMemCur, assembly, sizeof(assembly));
|
||||
hookMemCur += sizeof(assembly);
|
||||
}
|
||||
|
||||
void hookFunction(uint32_t address, CallingConvention convention, size_t arguments, void (*fn)())
|
||||
{
|
||||
auto newIndex = _newHooks.size();
|
||||
|
||||
InteropFunction item = {};
|
||||
item.convention = convention;
|
||||
item.argumentCount = arguments;
|
||||
item.function = fn;
|
||||
_newHooks.push_back(item);
|
||||
|
||||
uint8_t assembly[8] = {};
|
||||
|
||||
// push imm32
|
||||
assembly[0] = 0x68;
|
||||
write_address_strictalias(&assembly[1], newIndex);
|
||||
|
||||
// int imm8
|
||||
assembly[5] = 0xCD;
|
||||
assembly[6] = softwareInterruptNumber;
|
||||
|
||||
// ret
|
||||
assembly[7] = 0xC3;
|
||||
|
||||
writeMemory(address, assembly, sizeof(assembly));
|
||||
}
|
||||
|
||||
static uint32_t pop(uc_engine* uc)
|
||||
{
|
||||
uint32_t esp;
|
||||
uc_reg_read(uc, UC_X86_REG_ESP, &esp);
|
||||
|
||||
uint32_t value;
|
||||
uc_mem_read(uc, esp, &value, 4);
|
||||
|
||||
esp += 4;
|
||||
uc_reg_write(uc, UC_X86_REG_ESP, &esp);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint32_t push(uc_engine* uc, uint32_t value)
|
||||
{
|
||||
uint32_t esp;
|
||||
uc_reg_read(uc, UC_X86_REG_ESP, &esp);
|
||||
|
||||
esp -= 4;
|
||||
uc_reg_write(uc, UC_X86_REG_ESP, &esp);
|
||||
|
||||
uc_mem_write(uc, esp, &value, 4);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void hook_interrupt(uc_engine* uc, uint32_t intno, void* user_data)
|
||||
{
|
||||
if (intno != softwareInterruptNumber)
|
||||
return;
|
||||
|
||||
uint32_t index = pop(uc);
|
||||
Console::log("Interupt 0x%X (%d)", intno, index);
|
||||
|
||||
auto& hook = _newHooks[index];
|
||||
|
||||
if (hook.convention == CallingConvention::sawyer)
|
||||
{
|
||||
uint32_t backupEsp = _esp;
|
||||
uc_reg_read(uc, UC_X86_REG_ESP, &_esp);
|
||||
|
||||
registers regs = {};
|
||||
uc_reg_read(uc, UC_X86_REG_EAX, ®s.eax);
|
||||
uc_reg_read(uc, UC_X86_REG_EBX, ®s.ebx);
|
||||
uc_reg_read(uc, UC_X86_REG_ECX, ®s.ecx);
|
||||
uc_reg_read(uc, UC_X86_REG_EDX, ®s.edx);
|
||||
uc_reg_read(uc, UC_X86_REG_ESI, ®s.esi);
|
||||
uc_reg_read(uc, UC_X86_REG_EDI, ®s.edi);
|
||||
uc_reg_read(uc, UC_X86_REG_EBP, ®s.ebp);
|
||||
|
||||
hook.hookFunction(regs);
|
||||
|
||||
uc_reg_write(uc, UC_X86_REG_EAX, ®s.eax);
|
||||
uc_reg_write(uc, UC_X86_REG_EBX, ®s.ebx);
|
||||
uc_reg_write(uc, UC_X86_REG_ECX, ®s.ecx);
|
||||
uc_reg_write(uc, UC_X86_REG_EDX, ®s.edx);
|
||||
uc_reg_write(uc, UC_X86_REG_ESI, ®s.esi);
|
||||
uc_reg_write(uc, UC_X86_REG_EDI, ®s.edi);
|
||||
uc_reg_write(uc, UC_X86_REG_EBP, ®s.ebp);
|
||||
|
||||
_esp = backupEsp;
|
||||
return;
|
||||
}
|
||||
|
||||
if (hook.simple != nullptr)
|
||||
{
|
||||
hook.simple();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t retaddr = pop(uc);
|
||||
uint32_t retVal;
|
||||
switch (hook.argumentCount)
|
||||
{
|
||||
case 0:
|
||||
retVal = ((uint32_t(*)())hook.function)();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
uint32_t arg1 = pop(uc);
|
||||
retVal = ((uint32_t(*)(uint32_t))hook.function)(arg1);
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
uint32_t arg1 = pop(uc);
|
||||
uint32_t arg2 = pop(uc);
|
||||
retVal = ((uint32_t(*)(uint32_t, uint32_t))hook.function)(arg1, arg2);
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
uint32_t arg1 = pop(uc);
|
||||
uint32_t arg2 = pop(uc);
|
||||
uint32_t arg3 = pop(uc);
|
||||
retVal = ((uint32_t(*)(uint32_t, uint32_t, uint32_t))hook.function)(arg1, arg2, arg3);
|
||||
break;
|
||||
}
|
||||
|
||||
case 5:
|
||||
{
|
||||
uint32_t arg1 = pop(uc);
|
||||
uint32_t arg2 = pop(uc);
|
||||
uint32_t arg3 = pop(uc);
|
||||
uint32_t arg4 = pop(uc);
|
||||
uint32_t arg5 = pop(uc);
|
||||
retVal = ((uint32_t(*)(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t))hook.function)(arg1, arg2, arg3, arg4, arg5);
|
||||
break;
|
||||
}
|
||||
|
||||
case 7:
|
||||
{
|
||||
uint32_t arg1 = pop(uc);
|
||||
uint32_t arg2 = pop(uc);
|
||||
uint32_t arg3 = pop(uc);
|
||||
uint32_t arg4 = pop(uc);
|
||||
uint32_t arg5 = pop(uc);
|
||||
uint32_t arg6 = pop(uc);
|
||||
uint32_t arg7 = pop(uc);
|
||||
retVal = ((uint32_t(*)(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t))hook.function)(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (hook.convention == CallingConvention::cdecl)
|
||||
{
|
||||
for (size_t i = 0; i < hook.argumentCount; i++)
|
||||
{
|
||||
push(uc, 0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
uc_reg_write(uc, UC_X86_REG_EAX, &retVal);
|
||||
push(uc, retaddr);
|
||||
}
|
||||
|
||||
namespace emu
|
||||
{
|
||||
static uc_engine* initialise()
|
||||
{
|
||||
uc_engine* uc = nullptr;
|
||||
uc_err err;
|
||||
|
||||
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
||||
if (err)
|
||||
{
|
||||
throw std::runtime_error("Failed on uc_open() with error returned " + std::to_string(err) + ": " + std::string(uc_strerror(err)));
|
||||
}
|
||||
|
||||
// Add hooks to catch errors
|
||||
uc_hook errorHooks[2];
|
||||
{
|
||||
// Hook for memory access on unmapped memory
|
||||
uc_hook_add(uc, &errorHooks[0], UC_HOOK_MEM_UNMAPPED, (void*)UcErrorHook, nullptr, 0, -1);
|
||||
|
||||
// Hook for memory access on protected memory
|
||||
uc_hook_add(uc, &errorHooks[1], UC_HOOK_MEM_PROT, (void*)UcErrorHook, nullptr, 0, -1);
|
||||
}
|
||||
|
||||
if (_log)
|
||||
{
|
||||
uc_hook hook2;
|
||||
uc_hook_add(uc, &hook2, UC_HOOK_CODE, (void*)hook_code, NULL, 0, -1);
|
||||
}
|
||||
|
||||
uc_hook hook1;
|
||||
uc_hook_add(uc, &hook1, UC_HOOK_INTR, (void*)hook_interrupt, NULL, 0, -1);
|
||||
|
||||
uc_mem_map_ptr(uc, 0x2000000, 0x1000000, UC_PROT_READ | UC_PROT_EXEC, (void*)0x2000000);
|
||||
uc_mem_map_ptr(uc, 0x401000, 0x4d7000 - 0x401000, UC_PROT_READ | UC_PROT_EXEC, (void*)0x401000);
|
||||
uc_mem_map_ptr(uc, 0x4d7000, 0x1162000 - 0x4d7000, UC_PROT_READ | UC_PROT_WRITE, (void*)0x4d7000);
|
||||
uc_mem_map_ptr(uc, (uintptr_t)heap, heapSize, UC_PROT_READ | UC_PROT_WRITE, heap);
|
||||
|
||||
uc_mem_map_ptr(uc, hookMemStart, hookMemSize, UC_PROT_READ | UC_PROT_EXEC, hookMem);
|
||||
|
||||
uc_mem_map_ptr(uc, stackStart, stackSize, UC_PROT_READ | UC_PROT_WRITE, (void*)stack);
|
||||
|
||||
uc_mem_map(uc, executionEnd, 0x1000, UC_PROT_ALL);
|
||||
|
||||
return uc;
|
||||
}
|
||||
|
||||
static int depth = 0;
|
||||
void log()
|
||||
{
|
||||
_log = true;
|
||||
}
|
||||
|
||||
void call(uint32_t address, int32_t* _eax, int32_t* _ebx, int32_t* _ecx, int32_t* _edx, int32_t* _esi, int32_t* _edi, int32_t* _ebp)
|
||||
{
|
||||
auto uc = initialise();
|
||||
|
||||
if (false)
|
||||
{
|
||||
uc_hook hook1;
|
||||
uc_hook_add(uc, &hook1, UC_HOOK_CODE, (void*)hook_code, NULL, 0, -1);
|
||||
}
|
||||
|
||||
depth++;
|
||||
|
||||
uint32_t espStart = _esp;
|
||||
uc_reg_write(uc, UC_X86_REG_ESP, &espStart);
|
||||
|
||||
uc_reg_write(uc, UC_X86_REG_EAX, _eax);
|
||||
uc_reg_write(uc, UC_X86_REG_EBX, _ebx);
|
||||
uc_reg_write(uc, UC_X86_REG_ECX, _ecx);
|
||||
uc_reg_write(uc, UC_X86_REG_EDX, _edx);
|
||||
uc_reg_write(uc, UC_X86_REG_ESI, _esi);
|
||||
uc_reg_write(uc, UC_X86_REG_EDI, _edi);
|
||||
uc_reg_write(uc, UC_X86_REG_EBP, _ebp);
|
||||
|
||||
// Push return address to stack
|
||||
push(uc, executionEnd);
|
||||
|
||||
auto err = uc_emu_start(uc, address, executionEnd, 0, 0);
|
||||
|
||||
if (err)
|
||||
{
|
||||
throw std::runtime_error("Failed on uc_emu_start() with error returned " + std::to_string(err) + ": " + std::string(uc_strerror(err)));
|
||||
}
|
||||
|
||||
uint32_t espEnd;
|
||||
uc_reg_read(uc, UC_X86_REG_ESP, &espEnd);
|
||||
|
||||
assert(espEnd == espStart);
|
||||
|
||||
uc_reg_read(uc, UC_X86_REG_EAX, _eax);
|
||||
uc_reg_read(uc, UC_X86_REG_EBX, _ebx);
|
||||
uc_reg_read(uc, UC_X86_REG_ECX, _ecx);
|
||||
uc_reg_read(uc, UC_X86_REG_EDX, _edx);
|
||||
uc_reg_read(uc, UC_X86_REG_ESI, _esi);
|
||||
uc_reg_read(uc, UC_X86_REG_EDI, _edi);
|
||||
uc_reg_read(uc, UC_X86_REG_EBP, _ebp);
|
||||
|
||||
uc_close(uc);
|
||||
|
||||
depth--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
extern "C" {
|
||||
int has_hook(void* emu)
|
||||
{
|
||||
uint32_t address =0;
|
||||
|
||||
auto it = _hooks.find(address);
|
||||
if (it == _hooks.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
printf(" hook @ 0x%X\n", address);
|
||||
|
||||
uint32_t retaddr = pop_long(emu);
|
||||
uint32_t retVal;
|
||||
|
||||
switch (it->second.argumentCount)
|
||||
{
|
||||
case 0:
|
||||
retVal = ((uint32_t(*)())it->second.function)();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
uint32_t arg1 = pop_long(emu);
|
||||
retVal = ((uint32_t(*)(uint32_t))it->second.function)(arg1);
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
uint32_t arg1 = pop_long(emu);
|
||||
uint32_t arg2 = pop_long(emu);
|
||||
retVal = ((uint32_t(*)(uint32_t, uint32_t))it->second.function)(arg1, arg2);
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
uint32_t arg1 = pop_long(emu);
|
||||
uint32_t arg2 = pop_long(emu);
|
||||
uint32_t arg3 = pop_long(emu);
|
||||
retVal = ((uint32_t(*)(uint32_t, uint32_t, uint32_t))it->second.function)(arg1, arg2, arg3);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (it->second.convention == openloco::interop::CallingConvention::cdecl)
|
||||
{
|
||||
for (int i = 0; i < it->second.argumentCount; i++)
|
||||
{
|
||||
push_long(emu, 0xFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
emu->x86.R_EAX = retVal;
|
||||
emu->x86.R_EIP = retaddr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int has_lib_hook(x86emu_t* emu, uint32_t addr)
|
||||
{
|
||||
auto it = _libraryHooks.find(addr);
|
||||
if (it == _libraryHooks.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
printf(" hook @ 0x%X\n", addr);
|
||||
|
||||
uint32_t retVal;
|
||||
|
||||
switch (it->second.argumentCount)
|
||||
{
|
||||
case 0:
|
||||
retVal = ((uint32_t(*)())it->second.function)();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
uint32_t arg1 = pop_long(emu);
|
||||
retVal = ((uint32_t(*)(uint32_t))it->second.function)(arg1);
|
||||
break;
|
||||
}
|
||||
|
||||
case 7:
|
||||
{
|
||||
uint32_t arg1 = pop_long(emu);
|
||||
uint32_t arg2 = pop_long(emu);
|
||||
uint32_t arg3 = pop_long(emu);
|
||||
uint32_t arg4 = pop_long(emu);
|
||||
uint32_t arg5 = pop_long(emu);
|
||||
uint32_t arg6 = pop_long(emu);
|
||||
uint32_t arg7 = pop_long(emu);
|
||||
retVal = ((uint32_t(*)(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t))it->second.function)(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (it->second.convention == openloco::interop::CallingConvention::cdecl)
|
||||
{
|
||||
for (int i = 0; i < it->second.argumentCount; i++)
|
||||
{
|
||||
push_long(emu, 0xFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
emu->x86.R_EAX = retVal;
|
||||
return 1;
|
||||
}
|
||||
}*/
|
||||
|
||||
//void * operator new(std::size_t n) noexcept(false)
|
||||
//{
|
||||
// return malloc(n);
|
||||
//}
|
||||
//void operator delete(void * p) throw()
|
||||
//{
|
||||
// free(p);
|
||||
//}
|
||||
|
||||
static bool initialized = false;
|
||||
|
||||
void init()
|
||||
{
|
||||
heap = mmap((void*)heapStart, heapSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||
if (heap == MAP_FAILED)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
auto heapEnd = (void*)(heapStart + heapSize);
|
||||
auto success = ta_init(heap, heapEnd, 1024 * 1024, 16, 32);
|
||||
if (!success)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
OpenLoco::Console::log("Initialized heap from %p to %p\n", heapStart, heapEnd);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
extern "C" void* malloc(size_t);
|
||||
extern "C" void* calloc(size_t, size_t);
|
||||
extern "C" void free(void*);
|
||||
extern "C" void* realloc(void* ptr, size_t size);
|
||||
|
||||
void* malloc(size_t size)
|
||||
{
|
||||
if (!initialized)
|
||||
init();
|
||||
return ta_alloc(size);
|
||||
}
|
||||
|
||||
void* calloc(size_t nitems, size_t size)
|
||||
{
|
||||
if (!initialized)
|
||||
init();
|
||||
|
||||
return malloc(size * nitems);
|
||||
}
|
||||
|
||||
void free(void* ptr)
|
||||
{
|
||||
if (!initialized)
|
||||
init();
|
||||
|
||||
ta_free(ptr);
|
||||
}
|
||||
|
||||
void* realloc(void* ptr, size_t size)
|
||||
{
|
||||
if (!initialized)
|
||||
init();
|
||||
|
||||
ta_free(ptr);
|
||||
return ta_alloc(size);
|
||||
}
|
||||
|
||||
void* operator new(size_t count)
|
||||
{
|
||||
void* pVoid = malloc(count);
|
||||
return pVoid;
|
||||
}
|
||||
|
||||
void operator delete(void* p) noexcept
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,7 @@
|
|||
#include <cstdint>
|
||||
|
||||
namespace OpenLoco::Interop::emu
|
||||
{
|
||||
void log();
|
||||
void call(uint32_t address, int32_t* _eax, int32_t* _ebx, int32_t* _ecx, int32_t* _edx, int32_t* _esi, int32_t* _edi, int32_t* _ebp);
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <unicorn/unicorn.h>
|
||||
|
||||
//#if defined(__i386__)
|
||||
#define assert_struct_size(x, y) static_assert(sizeof(x) == (y), "Improper struct size")
|
||||
//#else
|
||||
//#define assert_struct_size(x, y)
|
||||
//#endif
|
||||
|
||||
constexpr int32_t DEFAULT_REG_VAL = 0xCCCCCCCC;
|
||||
|
||||
namespace OpenLoco::Interop
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
/**
|
||||
* x86 register structure, only used for easy interop to Locomotion code.
|
||||
*/
|
||||
struct registers
|
||||
{
|
||||
union
|
||||
{
|
||||
int32_t eax{ DEFAULT_REG_VAL };
|
||||
int16_t ax;
|
||||
struct
|
||||
{
|
||||
int8_t al;
|
||||
int8_t ah;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t ebx{ DEFAULT_REG_VAL };
|
||||
int16_t bx;
|
||||
struct
|
||||
{
|
||||
int8_t bl;
|
||||
int8_t bh;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t ecx{ DEFAULT_REG_VAL };
|
||||
int16_t cx;
|
||||
struct
|
||||
{
|
||||
int8_t cl;
|
||||
int8_t ch;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t edx{ DEFAULT_REG_VAL };
|
||||
int16_t dx;
|
||||
struct
|
||||
{
|
||||
int8_t dl;
|
||||
int8_t dh;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t esi{ DEFAULT_REG_VAL };
|
||||
int16_t si;
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t edi{ DEFAULT_REG_VAL };
|
||||
int16_t di;
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t ebp{ DEFAULT_REG_VAL };
|
||||
int16_t bp;
|
||||
};
|
||||
};
|
||||
assert_struct_size(registers, 7 * 4);
|
||||
#pragma pack(pop)
|
||||
|
||||
using hook_function = uint8_t (*)(registers& regs);
|
||||
|
||||
void registerHook(uintptr_t address, hook_function function);
|
||||
void writeRet(uint32_t address);
|
||||
void writeJmp(uint32_t address, void* fn);
|
||||
void writeNop(uint32_t address, size_t count);
|
||||
void hookDump(uint32_t address, void* fn);
|
||||
void hookLib(uint32_t address, void* fn);
|
||||
|
||||
void emu_init();
|
||||
void registerHooks();
|
||||
void loadSections();
|
||||
|
||||
enum CallingConvention
|
||||
{
|
||||
cdecl,
|
||||
stdcall,
|
||||
sawyer,
|
||||
};
|
||||
|
||||
void hookFunction(uint32_t address, CallingConvention convention, size_t arguments, void (*)());
|
||||
void hookLibrary(uint32_t address, CallingConvention convention, size_t arguments, void (*)());
|
||||
void hookLibrary(uint32_t address, std::function<void()>);
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
#include "Intro.h"
|
||||
#include "Gui.h"
|
||||
#include "Interop/Interop.hpp"
|
||||
#include "Station.h"
|
||||
#include "Title.h"
|
||||
|
||||
using namespace OpenLoco::Interop;
|
||||
|
||||
|
@ -22,9 +25,57 @@ namespace OpenLoco::Intro
|
|||
_state = (uint8_t)state;
|
||||
}
|
||||
|
||||
static bool _50C196 = false;
|
||||
static int _50C190 = 0;
|
||||
|
||||
// 0x0046AE0C
|
||||
void update()
|
||||
{
|
||||
call(0x0046AE0C);
|
||||
addr<0x0005252E0, int32_t>() = 1;
|
||||
|
||||
switch (state())
|
||||
{
|
||||
case State::none:
|
||||
case State::begin:
|
||||
case State::state_8:
|
||||
case State::state_9:
|
||||
// TODO: implement
|
||||
break;
|
||||
|
||||
case State::end:
|
||||
Gfx::clear(Gfx::screenContext(), 0xA0B0C0D0);
|
||||
if (_50C196)
|
||||
{
|
||||
_50C196 = false;
|
||||
}
|
||||
state(State::done);
|
||||
_50C190 = 0;
|
||||
break;
|
||||
|
||||
case State::done:
|
||||
state(State::none);
|
||||
call(0x004523F4);
|
||||
addr<0x0005252E0, int32_t>() = 0;
|
||||
Gfx::invalidateScreen();
|
||||
initialiseViewports();
|
||||
Gui::init();
|
||||
Title::reset();
|
||||
break;
|
||||
}
|
||||
|
||||
OpenLoco::sub_431695(0);
|
||||
return;
|
||||
//
|
||||
// return;
|
||||
// switch (state())
|
||||
// {
|
||||
//
|
||||
// case State::none: break;
|
||||
// case State::begin: break;
|
||||
// case State::state_8: break;
|
||||
// case State::state_9: break;
|
||||
// case State::end: break;
|
||||
// }
|
||||
// call(0x0046AE0C);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace OpenLoco::Intro
|
|||
state_8 = 8,
|
||||
state_9 = 9,
|
||||
end = 254,
|
||||
done = 255,
|
||||
};
|
||||
|
||||
bool isActive();
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace OpenLoco::StringManager
|
|||
const uint16_t TOWN_NAMES_START = 0x9EE7;
|
||||
const uint16_t TOWN_NAMES_END = TOWN_NAMES_START + NUM_TOWN_NAMES;
|
||||
|
||||
static loco_global<char* [0xFFFF], 0x005183FC> _strings;
|
||||
static loco_global<loco_ptr2<char>[0xFFFF], 0x005183FC> _strings;
|
||||
static loco_global<char[NUM_USER_STRINGS][USER_STRING_SIZE], 0x0095885C> _userStrings;
|
||||
|
||||
static std::map<int32_t, string_id> day_to_string = {
|
||||
|
@ -91,7 +91,7 @@ namespace OpenLoco::StringManager
|
|||
|
||||
const char* getString(string_id id)
|
||||
{
|
||||
char* str = _strings[id];
|
||||
char* str = _strings[id].get();
|
||||
return str;
|
||||
}
|
||||
|
||||
|
@ -550,6 +550,7 @@ namespace OpenLoco::StringManager
|
|||
const char* sourceStr = getString(id);
|
||||
if (sourceStr == nullptr)
|
||||
{
|
||||
return buffer;
|
||||
throw std::runtime_error("Got a nullptr for string id " + std::to_string(id) + " -- cowardly refusing");
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace OpenLoco::Map
|
|||
}
|
||||
else
|
||||
{
|
||||
auto* unkVariation = buildingObj->variationsArr10[variation()];
|
||||
auto* unkVariation = (uint8_t*)(uintptr_t)buildingObj->variationsArr10[variation()];
|
||||
if (unkVariation[age() + 1] != 0xFF)
|
||||
{
|
||||
newUnk5u = 0;
|
||||
|
@ -57,7 +57,8 @@ namespace OpenLoco::Map
|
|||
auto totalHeight = 3;
|
||||
for (; *unkVariation != 0xFF; unkVariation++)
|
||||
{
|
||||
totalHeight += buildingObj->varationHeights[*unkVariation];
|
||||
uint8_t* vars = (uint8_t*)(uintptr_t)buildingObj->varationHeights;
|
||||
totalHeight += vars[*unkVariation];
|
||||
}
|
||||
Ui::ViewportManager::invalidate(loc, baseZ() * 4, clearZ() * 4, ZoomLevel::quarter);
|
||||
|
||||
|
|
|
@ -8,11 +8,33 @@
|
|||
|
||||
using namespace OpenLoco::Interop;
|
||||
|
||||
template<typename T>
|
||||
class Pointer
|
||||
{
|
||||
private:
|
||||
uint32_t _ptr;
|
||||
|
||||
public:
|
||||
Pointer(void* ptr)
|
||||
{
|
||||
_ptr = (uint32_t)(uintptr_t)ptr;
|
||||
}
|
||||
|
||||
operator T*() const { return (T*)(uintptr_t)_ptr; }
|
||||
|
||||
friend bool operator==(Pointer<T>& lhs, void* rhs)
|
||||
{
|
||||
return lhs._ptr == (uint32_t)(uintptr_t)rhs;
|
||||
}
|
||||
};
|
||||
|
||||
assert_struct_size(Pointer<int>, 4);
|
||||
|
||||
namespace OpenLoco::Map::TileManager
|
||||
{
|
||||
static loco_global<TileElement*, 0x005230C8> _elements;
|
||||
static loco_global<TileElement* [0x30004], 0x00E40134> _tiles;
|
||||
static loco_global<TileElement*, 0x00F00134> _elementsEnd;
|
||||
static loco_global<Pointer<TileElement>, 0x005230C8> _elements;
|
||||
static loco_global<Pointer<TileElement>[0x30004], 0x00E40134> _tiles;
|
||||
static loco_global<Pointer<TileElement>, 0x00F00134> _elementsEnd;
|
||||
static loco_global<coord_t, 0x00F24486> _mapSelectionAX;
|
||||
static loco_global<coord_t, 0x00F24488> _mapSelectionBX;
|
||||
static loco_global<coord_t, 0x00F2448A> _mapSelectionAY;
|
||||
|
@ -34,7 +56,7 @@ namespace OpenLoco::Map::TileManager
|
|||
|
||||
stdx::span<TileElement> getElements()
|
||||
{
|
||||
return stdx::span<TileElement>(_elements, getElementsEnd());
|
||||
return stdx::span<TileElement>((TileElement*)*_elements, getElementsEnd());
|
||||
}
|
||||
|
||||
void setMapSelectionArea(const Pos2& locA, const Pos2& locB)
|
||||
|
@ -62,12 +84,12 @@ namespace OpenLoco::Map::TileManager
|
|||
|
||||
TileElement* getElementsEnd()
|
||||
{
|
||||
return _elementsEnd;
|
||||
return *_elementsEnd;
|
||||
}
|
||||
|
||||
void setElements(stdx::span<TileElement> elements)
|
||||
{
|
||||
TileElement* dst = _elements;
|
||||
TileElement* dst = *_elements;
|
||||
std::memset(dst, 0, maxElements * sizeof(TileElement));
|
||||
std::memcpy(dst, elements.data(), elements.size_bytes());
|
||||
TileManager::updateTilePointers();
|
||||
|
@ -82,13 +104,13 @@ namespace OpenLoco::Map::TileManager
|
|||
|
||||
TileElement** getElementIndex()
|
||||
{
|
||||
return _tiles.get();
|
||||
return (TileElement**)_tiles.get();
|
||||
}
|
||||
|
||||
Tile get(TilePos2 pos)
|
||||
{
|
||||
size_t index = (pos.y << 9) | pos.x;
|
||||
auto data = _tiles[index];
|
||||
auto data = (TileElement*)_tiles[index];
|
||||
if (data == InvalidTile)
|
||||
{
|
||||
data = nullptr;
|
||||
|
@ -273,7 +295,7 @@ namespace OpenLoco::Map::TileManager
|
|||
{
|
||||
clearTilePointers();
|
||||
|
||||
TileElement* el = _elements;
|
||||
TileElement* el = *_elements;
|
||||
for (tile_coord_t y = 0; y < map_rows; y++)
|
||||
{
|
||||
for (tile_coord_t x = 0; x < map_columns; x++)
|
||||
|
@ -317,11 +339,11 @@ namespace OpenLoco::Map::TileManager
|
|||
}
|
||||
|
||||
// Copy organised elements back to original element buffer
|
||||
std::memcpy(_elements, tempBuffer.data(), numElements * sizeof(TileElement));
|
||||
std::memcpy(*_elements, tempBuffer.data(), numElements * sizeof(TileElement));
|
||||
|
||||
// Zero all unused elements
|
||||
auto remainingElements = maxElements - numElements;
|
||||
std::memset(_elements + numElements, 0, remainingElements * sizeof(TileElement));
|
||||
std::memset(*_elements + numElements, 0, remainingElements * sizeof(TileElement));
|
||||
|
||||
updateTilePointers();
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "../Graphics/Colour.h"
|
||||
#include "../Interop/Interop.hpp"
|
||||
#include "../Localisation/StringManager.h"
|
||||
|
||||
namespace OpenLoco
|
||||
|
@ -24,9 +25,9 @@ namespace OpenLoco
|
|||
string_id name;
|
||||
uint8_t pad_02[0x07 - 0x02];
|
||||
uint8_t numVariations; //0x7
|
||||
uint8_t* varationHeights; // 0x8
|
||||
uint32_t varationHeights; // 0x8
|
||||
uint8_t pad_0C[0x10 - 0x0C];
|
||||
uint8_t* variationsArr10[32]; // 0x10
|
||||
uint32_t variationsArr10[32]; // 0x10
|
||||
uint32_t colours; // 0x90
|
||||
uint16_t designedYear; // 0x94
|
||||
uint16_t obsoleteYear; // 0x96
|
||||
|
@ -45,5 +46,5 @@ namespace OpenLoco
|
|||
void drawDescription(Gfx::Context& context, const int16_t x, const int16_t y, [[maybe_unused]] const int16_t width) const;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
static_assert(sizeof(BuildingObject) == 0xAE);
|
||||
assert_struct_size(BuildingObject, 0xAE);
|
||||
}
|
||||
|
|
|
@ -27,53 +27,75 @@ namespace OpenLoco::ObjectManager
|
|||
{
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(ObjectEntry2) == 0x14);
|
||||
assert_struct_size(ObjectEntry2, 0x14);
|
||||
|
||||
struct ObjectRepositoryItem
|
||||
{
|
||||
Object** objects;
|
||||
ObjectEntry2* object_entry_extendeds;
|
||||
loco_ptr2<loco_ptr2<Object>> objects;
|
||||
loco_ptr2<ObjectEntry2> object_entry_extendeds;
|
||||
};
|
||||
assert_struct_size(ObjectRepositoryItem, 8);
|
||||
#pragma pack(pop)
|
||||
|
||||
template<typename T>
|
||||
class Pointer
|
||||
{
|
||||
private:
|
||||
uint32_t _ptr;
|
||||
|
||||
public:
|
||||
Pointer(void* ptr)
|
||||
{
|
||||
_ptr = (uint32_t)(uintptr_t)ptr;
|
||||
}
|
||||
|
||||
operator T*() const { return (T*)(uintptr_t)_ptr; }
|
||||
|
||||
friend bool operator==(Pointer<T>& lhs, void* rhs)
|
||||
{
|
||||
return lhs._ptr == (uint32_t)(uintptr_t)rhs;
|
||||
}
|
||||
};
|
||||
|
||||
assert_struct_size(Pointer<int>, 4);
|
||||
|
||||
loco_global<ObjectEntry2[maxObjects], 0x1125A90> objectEntries;
|
||||
loco_global<ObjectRepositoryItem[64], 0x4FE0B8> object_repository;
|
||||
loco_global<Object* [maxObjects], 0x0050C3D0> _allObjects;
|
||||
loco_global<InterfaceSkinObject* [1], 0x0050C3D0> _interfaceObjects;
|
||||
loco_global<SoundObject* [128], 0x0050C3D4> _soundObjects;
|
||||
loco_global<CurrencyObject* [1], 0x0050C5D4> _currencyObjects;
|
||||
loco_global<SteamObject* [32], 0x0050C5D8> _steamObjects;
|
||||
loco_global<RockObject* [8], 0x0050C658> _rockObjects;
|
||||
loco_global<WaterObject* [1], 0x0050C678> _waterObjects;
|
||||
loco_global<LandObject* [32], 0x0050C67C> _landObjects;
|
||||
loco_global<TownNamesObject* [1], 0x0050C6FC> _townNamesObjects;
|
||||
loco_global<CargoObject* [32], 0x0050C700> _cargoObjects;
|
||||
loco_global<WallObject* [32], 0x0050C780> _wallObjects;
|
||||
loco_global<TrainSignalObject* [16], 0x0050C800> _trainSignalObjects;
|
||||
loco_global<LevelCrossingObject* [4], 0x0050C840> _levelCrossingObjects;
|
||||
loco_global<StreetLightObject* [1], 0x0050C850> _streetLightObjects;
|
||||
loco_global<TunnelObject* [16], 0x0050C854> _tunnelObjects;
|
||||
loco_global<BridgeObject* [8], 0x0050C894> _bridgeObjects;
|
||||
loco_global<TrainStationObject* [16], 0x0050C8B4> _trainStationObjects;
|
||||
loco_global<TrackExtraObject* [8], 0x0050C8F4> _trackExtraObjects;
|
||||
loco_global<TrackObject* [8], 0x0050C914> _trackObjects;
|
||||
loco_global<RoadStationObject* [16], 0x0050C934> _roadStationObjects;
|
||||
loco_global<RoadExtraObject* [4], 0x0050C974> _roadExtraObjects;
|
||||
loco_global<RoadObject* [8], 0x0050C984> _roadObjects;
|
||||
loco_global<AirportObject* [8], 0x0050C9A4> _airportObjects;
|
||||
loco_global<DockObject* [8], 0x0050C9C4> _dockObjects;
|
||||
loco_global<VehicleObject* [224], 0x0050C9E4> _vehicleObjects;
|
||||
loco_global<TreeObject* [64], 0x0050CD64> _treeObjects;
|
||||
loco_global<SnowObject* [1], 0x0050CE64> _snowObjects;
|
||||
loco_global<ClimateObject* [1], 0x0050CE68> _climateObjects;
|
||||
loco_global<HillShapesObject* [1], 0x0050CE6C> _hillShapeObjects;
|
||||
loco_global<BuildingObject* [128], 0x0050CE70> _buildingObjects;
|
||||
loco_global<ScaffoldingObject* [1], 0x0050D070> _scaffoldingObjects;
|
||||
loco_global<IndustryObject* [16], 0x0050D074> _industryObjects;
|
||||
loco_global<RegionObject* [1], 0x0050D0B4> _regionObjects;
|
||||
loco_global<CompetitorObject* [32], 0x0050D0B8> _competitorObjects;
|
||||
loco_global<ScenarioTextObject* [1], 0x0050D138> _scenarioTextObjects;
|
||||
loco_global<Pointer<Object>[maxObjects], 0x0050C3D0> _allObjects;
|
||||
loco_global<Pointer<InterfaceSkinObject>[1], 0x0050C3D0> _interfaceObjects;
|
||||
loco_global<Pointer<SoundObject>[128], 0x0050C3D4> _soundObjects;
|
||||
loco_global<Pointer<CurrencyObject>[1], 0x0050C5D4> _currencyObjects;
|
||||
loco_global<Pointer<SteamObject>[32], 0x0050C5D8> _steamObjects;
|
||||
loco_global<Pointer<RockObject>[8], 0x0050C658> _rockObjects;
|
||||
loco_global<Pointer<WaterObject>[1], 0x0050C678> _waterObjects;
|
||||
loco_global<Pointer<LandObject>[32], 0x0050C67C> _landObjects;
|
||||
loco_global<Pointer<TownNamesObject>[1], 0x0050C6FC> _townNamesObjects;
|
||||
loco_global<Pointer<CargoObject>[32], 0x0050C700> _cargoObjects;
|
||||
loco_global<Pointer<WallObject>[32], 0x0050C780> _wallObjects;
|
||||
loco_global<Pointer<TrainSignalObject>[16], 0x0050C800> _trainSignalObjects;
|
||||
loco_global<Pointer<LevelCrossingObject>[4], 0x0050C840> _levelCrossingObjects;
|
||||
loco_global<Pointer<StreetLightObject>[1], 0x0050C850> _streetLightObjects;
|
||||
loco_global<Pointer<TunnelObject>[16], 0x0050C854> _tunnelObjects;
|
||||
loco_global<Pointer<BridgeObject>[8], 0x0050C894> _bridgeObjects;
|
||||
loco_global<Pointer<TrainStationObject>[16], 0x0050C8B4> _trainStationObjects;
|
||||
loco_global<Pointer<TrackExtraObject>[8], 0x0050C8F4> _trackExtraObjects;
|
||||
loco_global<Pointer<TrackObject>[8], 0x0050C914> _trackObjects;
|
||||
loco_global<Pointer<RoadStationObject>[16], 0x0050C934> _roadStationObjects;
|
||||
loco_global<Pointer<RoadExtraObject>[4], 0x0050C974> _roadExtraObjects;
|
||||
loco_global<Pointer<RoadObject>[8], 0x0050C984> _roadObjects;
|
||||
loco_global<Pointer<AirportObject>[8], 0x0050C9A4> _airportObjects;
|
||||
loco_global<Pointer<DockObject>[8], 0x0050C9C4> _dockObjects;
|
||||
loco_global<Pointer<VehicleObject>[224], 0x0050C9E4> _vehicleObjects;
|
||||
loco_global<Pointer<TreeObject>[64], 0x0050CD64> _treeObjects;
|
||||
loco_global<Pointer<SnowObject>[1], 0x0050CE64> _snowObjects;
|
||||
loco_global<Pointer<ClimateObject>[1], 0x0050CE68> _climateObjects;
|
||||
loco_global<Pointer<HillShapesObject>[1], 0x0050CE6C> _hillShapeObjects;
|
||||
loco_global<Pointer<BuildingObject>[128], 0x0050CE70> _buildingObjects;
|
||||
loco_global<Pointer<ScaffoldingObject>[1], 0x0050D070> _scaffoldingObjects;
|
||||
loco_global<Pointer<IndustryObject>[16], 0x0050D074> _industryObjects;
|
||||
loco_global<Pointer<RegionObject>[1], 0x0050D0B4> _regionObjects;
|
||||
loco_global<Pointer<CompetitorObject>[32], 0x0050D0B8> _competitorObjects;
|
||||
loco_global<Pointer<ScenarioTextObject>[1], 0x0050D138> _scenarioTextObjects;
|
||||
|
||||
loco_global<uint32_t, 0x0050D154> _totalNumImages;
|
||||
|
||||
|
@ -384,7 +406,7 @@ namespace OpenLoco::ObjectManager
|
|||
return entry;
|
||||
}
|
||||
|
||||
static loco_global<std::byte*, 0x0050D13C> _installedObjectList;
|
||||
static loco_global<Pointer<std::byte>, 0x0050D13C> _installedObjectList;
|
||||
static loco_global<uint32_t, 0x0112A110> _installedObjectCount;
|
||||
|
||||
uint32_t getNumInstalledObjects()
|
||||
|
@ -394,7 +416,7 @@ namespace OpenLoco::ObjectManager
|
|||
|
||||
std::vector<std::pair<uint32_t, ObjectIndexEntry>> getAvailableObjects(ObjectType type)
|
||||
{
|
||||
auto ptr = (std::byte*)_installedObjectList;
|
||||
auto ptr = (std::byte*)*_installedObjectList;
|
||||
std::vector<std::pair<uint32_t, ObjectIndexEntry>> list;
|
||||
|
||||
for (uint32_t i = 0; i < _installedObjectCount; i++)
|
||||
|
@ -445,10 +467,10 @@ namespace OpenLoco::ObjectManager
|
|||
auto maxObjectsForType = getMaxObjects(objectType);
|
||||
for (size_t i = 0; i < maxObjectsForType; i++)
|
||||
{
|
||||
auto obj = typedObjectList.objects[i];
|
||||
auto obj = typedObjectList.objects.get()[i].get();
|
||||
if (obj != nullptr && obj != reinterpret_cast<Object*>(-1))
|
||||
{
|
||||
const auto& objHeader = typedObjectList.object_entry_extendeds[i];
|
||||
const auto& objHeader = typedObjectList.object_entry_extendeds.get()[i];
|
||||
if (objHeader.isCustom())
|
||||
{
|
||||
if (header == objHeader)
|
||||
|
@ -600,7 +622,7 @@ namespace OpenLoco::ObjectManager
|
|||
size_t index = 0;
|
||||
for (; index < getMaxObjects(type); ++index)
|
||||
{
|
||||
if (getRepositoryItem(type).objects[index] == reinterpret_cast<Object*>(-1))
|
||||
if (getRepositoryItem(type).objects[index].get() == reinterpret_cast<Object*>(-1))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "../Core/Optional.hpp"
|
||||
#include "../Core/Span.hpp"
|
||||
#include "../Interop/Interop.hpp"
|
||||
#include "../Ui/Types.hpp"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
@ -136,7 +137,7 @@ namespace OpenLoco
|
|||
return std::memcmp(this, &rhs, sizeof(ObjectHeader)) == 0;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(ObjectHeader) == 0x10);
|
||||
assert_struct_size(ObjectHeader, 0x10);
|
||||
|
||||
/**
|
||||
* Represents an index into the entire loaded object array. Not an index for
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace OpenLoco
|
|||
loco_global<HINSTANCE, 0x0113E0B4> ghInstance;
|
||||
loco_global<LPSTR, 0x00525348> glpCmdLine;
|
||||
#else
|
||||
loco_global<char*, 0x00525348> glpCmdLine;
|
||||
loco_global<uint32_t, 0x00525348> glpCmdLine;
|
||||
#endif
|
||||
|
||||
loco_global<char[256], 0x005060D0> gCDKey;
|
||||
|
@ -130,13 +130,15 @@ namespace OpenLoco
|
|||
|
||||
const char* lpCmdLine()
|
||||
{
|
||||
return glpCmdLine;
|
||||
return (char*)(uintptr_t)glpCmdLine;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
void lpCmdLine(const char* path)
|
||||
{
|
||||
glpCmdLine = strdup(path);
|
||||
char* p2 = (char*)malloc(strlen(path) + 1);
|
||||
strcpy(p2, path);
|
||||
glpCmdLine = (uint32_t)(uintptr_t)p2;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -258,37 +260,29 @@ namespace OpenLoco
|
|||
|
||||
static bool sub_4054B9()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
registers regs;
|
||||
call(0x004054B9, regs);
|
||||
return regs.eax != 0;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _NO_LOCO_WIN32_
|
||||
/**
|
||||
* Use this to allocate memory that will be freed in vanilla code or via loco_free.
|
||||
*/
|
||||
[[maybe_unused]] static void* malloc(size_t size)
|
||||
static void get_system_info()
|
||||
{
|
||||
return ((void* (*)(size_t))0x004D1401)(size);
|
||||
#ifdef _WIN32
|
||||
call(0x004078FE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to reallocate memory that will be freed in vanilla code or via loco_free.
|
||||
*/
|
||||
[[maybe_unused]] static void* realloc(void* address, size_t size)
|
||||
static void sub_407B26()
|
||||
{
|
||||
return ((void* (*)(void*, size_t))0x004D1B28)(address, size);
|
||||
#ifdef _WIN32
|
||||
call(0x00407B26);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to free up memory allocated in vanilla code or via loco_malloc / loco_realloc.
|
||||
*/
|
||||
[[maybe_unused]] static void free(void* address)
|
||||
{
|
||||
((void (*)(void*))0x004D1355)(address);
|
||||
}
|
||||
#endif // _NO_LOCO_WIN32_
|
||||
|
||||
static void sub_4062D1()
|
||||
{
|
||||
call(0x004062D1);
|
||||
|
@ -296,7 +290,9 @@ namespace OpenLoco
|
|||
|
||||
static void sub_406417()
|
||||
{
|
||||
#ifdef __i386__
|
||||
((void (*)())0x00406417)();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void sub_40567E()
|
||||
|
@ -316,15 +312,23 @@ namespace OpenLoco
|
|||
|
||||
static bool sub_4034FC(int32_t& a, int32_t& b)
|
||||
{
|
||||
#ifdef __i386__
|
||||
auto result = ((int32_t(*)(int32_t&, int32_t&))(0x004034FC))(a, b);
|
||||
return result != 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// 0x00407FFD
|
||||
static bool isAlreadyRunning(const char* mutexName)
|
||||
{
|
||||
#ifdef __i386__
|
||||
auto result = ((int32_t(*)(const char*))(0x00407FFD))(mutexName);
|
||||
return result != 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// 0x004BE621
|
||||
|
@ -410,11 +414,18 @@ namespace OpenLoco
|
|||
autosaveReset();
|
||||
}
|
||||
|
||||
/**
|
||||
* 0x004078BE
|
||||
*/
|
||||
static void getSystemTime()
|
||||
{
|
||||
}
|
||||
|
||||
static void initialise()
|
||||
{
|
||||
std::srand(std::time(0));
|
||||
addr<0x0050C18C, int32_t>() = addr<0x00525348, int32_t>();
|
||||
call(0x004078BE);
|
||||
getSystemTime();
|
||||
call(0x004BF476);
|
||||
Environment::resolvePaths();
|
||||
Localisation::enumerateLanguages();
|
||||
|
@ -441,7 +452,7 @@ namespace OpenLoco
|
|||
initialiseViewports();
|
||||
Title::sub_4284C8();
|
||||
call(0x004969DA);
|
||||
call(0x0043C88C);
|
||||
Scenario::reset();
|
||||
setScreenFlag(ScreenFlags::initialised);
|
||||
#ifdef _SHOW_INTRO_
|
||||
Intro::state(Intro::State::begin);
|
||||
|
@ -1179,8 +1190,8 @@ namespace OpenLoco
|
|||
if (sub_4054B9())
|
||||
{
|
||||
Ui::createWindow(cfg.display);
|
||||
call(0x004078FE);
|
||||
call(0x00407B26);
|
||||
get_system_info();
|
||||
// call(0x00407B26);
|
||||
Ui::initialiseInput();
|
||||
Audio::initialiseDSound();
|
||||
run();
|
||||
|
|
|
@ -30,6 +30,107 @@ namespace OpenLoco
|
|||
constexpr uint16_t pauseOverrideEnabled = 1 << 8; // new in OpenLoco
|
||||
}
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct loco_ptr
|
||||
{
|
||||
uintptr_t _ptr;
|
||||
loco_ptr(const void* x)
|
||||
{
|
||||
_ptr = reinterpret_cast<uintptr_t>(x);
|
||||
}
|
||||
loco_ptr(int32_t x)
|
||||
{
|
||||
_ptr = x;
|
||||
}
|
||||
operator int32_t() const
|
||||
{
|
||||
assert(_ptr < UINT32_MAX);
|
||||
return (int32_t)_ptr;
|
||||
}
|
||||
operator uint32_t() const
|
||||
{
|
||||
assert(_ptr < UINT32_MAX);
|
||||
return (uint32_t)_ptr;
|
||||
}
|
||||
#ifndef __i386__
|
||||
operator uintptr_t() const
|
||||
{
|
||||
return _ptr;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
template<typename T>
|
||||
class loco_ptr4
|
||||
{
|
||||
public:
|
||||
uint32_t ptr;
|
||||
loco_ptr4(uint32_t ptr)
|
||||
: ptr(ptr)
|
||||
{
|
||||
}
|
||||
loco_ptr4(T* ptr = nullptr)
|
||||
{
|
||||
assert((uintptr_t)ptr < UINT32_MAX);
|
||||
this->ptr = static_cast<uint32_t>((uintptr_t)ptr);
|
||||
}
|
||||
|
||||
T* get()
|
||||
{
|
||||
return (T*)(uintptr_t)ptr;
|
||||
}
|
||||
|
||||
T* get() const
|
||||
{
|
||||
return (T*)(uintptr_t)ptr;
|
||||
}
|
||||
|
||||
T* operator*() const
|
||||
{
|
||||
return this->get();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class loco_ptr2
|
||||
{
|
||||
public:
|
||||
uint32_t ptr;
|
||||
loco_ptr2(uint32_t ptr)
|
||||
: ptr(ptr)
|
||||
{
|
||||
}
|
||||
loco_ptr2(T* ptr = nullptr)
|
||||
{
|
||||
assert((uintptr_t)ptr < UINT32_MAX);
|
||||
this->ptr = static_cast<uint32_t>((uintptr_t)ptr);
|
||||
}
|
||||
|
||||
T* get()
|
||||
{
|
||||
return (T*)(uintptr_t)ptr;
|
||||
}
|
||||
|
||||
T* get() const
|
||||
{
|
||||
return (T*)(uintptr_t)ptr;
|
||||
}
|
||||
|
||||
T* operator*() const
|
||||
{
|
||||
return this->get();
|
||||
}
|
||||
|
||||
// Not allowed on void. No idea how enable_if is supposed to work.
|
||||
T& operator[](int index)
|
||||
{
|
||||
return get()[index];
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(loco_ptr2<int>) == 4);
|
||||
|
||||
extern const char version[];
|
||||
|
||||
std::string getVersionInfo();
|
||||
|
@ -70,3 +171,12 @@ namespace OpenLoco
|
|||
|
||||
void sub_444387();
|
||||
}
|
||||
|
||||
#ifndef __i386__
|
||||
namespace compat
|
||||
{
|
||||
void* malloc(size_t size);
|
||||
void free(void* ptr);
|
||||
void* realloc(void* ptr, size_t size);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "Paint.h"
|
||||
#include "../Graphics/Gfx.h"
|
||||
#include "../Interop/Interop.hpp"
|
||||
#include "../Interop/emu.h"
|
||||
#include "../Map/Tile.h"
|
||||
#include "../StationManager.h"
|
||||
#include "../TownManager.h"
|
||||
|
@ -130,8 +131,8 @@ namespace OpenLoco::Paint
|
|||
}
|
||||
_quadrantBackIndex = -1;
|
||||
_quadrantFrontIndex = 0;
|
||||
_lastPaintString = 0;
|
||||
_paintStringHead = 0;
|
||||
_lastPaintString = nullptr;
|
||||
_paintStringHead = nullptr;
|
||||
}
|
||||
|
||||
// 0x0045A6CA
|
||||
|
@ -159,6 +160,7 @@ namespace OpenLoco::Paint
|
|||
// 0x00461CF8
|
||||
static void paintTileElements(PaintSession& session, const Map::Pos2& loc)
|
||||
{
|
||||
emu::log();
|
||||
registers regs{};
|
||||
regs.eax = loc.x;
|
||||
regs.ecx = loc.y;
|
||||
|
@ -321,7 +323,7 @@ namespace OpenLoco::Paint
|
|||
do
|
||||
{
|
||||
ps = psNext;
|
||||
psNext = psNext->nextQuadrantPS;
|
||||
psNext = psNext->nextQuadrantPS.get();
|
||||
if (psNext == nullptr)
|
||||
return ps;
|
||||
} while (quadrantIndex > psNext->quadrantIndex);
|
||||
|
@ -331,7 +333,7 @@ namespace OpenLoco::Paint
|
|||
auto* psTemp = ps;
|
||||
do
|
||||
{
|
||||
ps = ps->nextQuadrantPS;
|
||||
ps = ps->nextQuadrantPS.get();
|
||||
if (ps == nullptr)
|
||||
break;
|
||||
|
||||
|
@ -354,7 +356,7 @@ namespace OpenLoco::Paint
|
|||
{
|
||||
while (true)
|
||||
{
|
||||
psNext = ps->nextQuadrantPS;
|
||||
psNext = ps->nextQuadrantPS.get();
|
||||
if (psNext == nullptr)
|
||||
return psCache;
|
||||
if (psNext->quadrantFlags & QuadrantFlags::bigger)
|
||||
|
@ -372,7 +374,7 @@ namespace OpenLoco::Paint
|
|||
while (true)
|
||||
{
|
||||
ps = psNext;
|
||||
psNext = psNext->nextQuadrantPS;
|
||||
psNext = psNext->nextQuadrantPS.get();
|
||||
if (psNext == nullptr)
|
||||
break;
|
||||
if (psNext->quadrantFlags & QuadrantFlags::bigger)
|
||||
|
@ -387,7 +389,7 @@ namespace OpenLoco::Paint
|
|||
if (compareResult)
|
||||
{
|
||||
ps->nextQuadrantPS = psNext->nextQuadrantPS;
|
||||
PaintStruct* ps_temp2 = psTemp->nextQuadrantPS;
|
||||
PaintStruct* ps_temp2 = psTemp->nextQuadrantPS.get();
|
||||
psTemp->nextQuadrantPS = psNext;
|
||||
psNext->nextQuadrantPS = ps_temp2;
|
||||
psNext = ps;
|
||||
|
@ -417,10 +419,10 @@ namespace OpenLoco::Paint
|
|||
// 0x0045E7B5
|
||||
void PaintSession::arrangeStructs()
|
||||
{
|
||||
_paintHead = _nextFreePaintStruct;
|
||||
_nextFreePaintStruct++;
|
||||
_paintHead = _nextFreePaintStruct->get();
|
||||
_nextFreePaintStruct = _nextFreePaintStruct->get() + 1;
|
||||
|
||||
PaintStruct* ps = &(*_paintHead)->basic;
|
||||
PaintStruct* ps = &(_paintHead->get())->basic;
|
||||
ps->nextQuadrantPS = nullptr;
|
||||
|
||||
uint32_t quadrantIndex = _quadrantBackIndex;
|
||||
|
@ -438,14 +440,14 @@ namespace OpenLoco::Paint
|
|||
do
|
||||
{
|
||||
ps = psNext;
|
||||
psNext = psNext->nextQuadrantPS;
|
||||
psNext = psNext->nextQuadrantPS.get();
|
||||
|
||||
} while (psNext != nullptr);
|
||||
}
|
||||
} while (++quadrantIndex <= _quadrantFrontIndex);
|
||||
|
||||
PaintStruct* psCache = arrangeStructsHelper(
|
||||
&(*_paintHead)->basic, _quadrantBackIndex & 0xFFFF, QuadrantFlags::next, currentRotation);
|
||||
&(_paintHead->get())->basic, _quadrantBackIndex & 0xFFFF, QuadrantFlags::next, currentRotation);
|
||||
|
||||
quadrantIndex = _quadrantBackIndex;
|
||||
while (++quadrantIndex < _quadrantFrontIndex)
|
||||
|
@ -541,7 +543,7 @@ namespace OpenLoco::Paint
|
|||
{
|
||||
InteractionArg info{};
|
||||
|
||||
for (auto* ps = (*_paintHead)->basic.nextQuadrantPS; ps != nullptr; ps = ps->nextQuadrantPS)
|
||||
for (auto* ps = (_paintHead->get())->basic.nextQuadrantPS.get(); ps != nullptr; ps = ps->nextQuadrantPS.get())
|
||||
{
|
||||
auto* tempPS = ps;
|
||||
auto* nextPS = ps;
|
||||
|
@ -555,10 +557,10 @@ namespace OpenLoco::Paint
|
|||
info = { *ps };
|
||||
}
|
||||
}
|
||||
nextPS = ps->children;
|
||||
nextPS = ps->children.get();
|
||||
}
|
||||
|
||||
for (auto* attachedPS = ps->attachedPS; attachedPS != nullptr; attachedPS = attachedPS->next)
|
||||
for (auto* attachedPS = ps->attachedPS.get(); attachedPS != nullptr; attachedPS = attachedPS->next.get())
|
||||
{
|
||||
if (isSpriteInteractedWith(getContext(), attachedPS->imageId, { static_cast<int16_t>(attachedPS->x + ps->x), static_cast<int16_t>(attachedPS->y + ps->y) }))
|
||||
{
|
||||
|
@ -584,7 +586,7 @@ namespace OpenLoco::Paint
|
|||
return interaction;
|
||||
}
|
||||
|
||||
auto rect = (*_context)->getDrawableRect();
|
||||
auto rect = (*_context->get()).getDrawableRect();
|
||||
|
||||
for (auto& station : StationManager::stations())
|
||||
{
|
||||
|
@ -593,7 +595,7 @@ namespace OpenLoco::Paint
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!station.labelFrame.contains(rect, (*_context)->zoom_level))
|
||||
if (!station.labelFrame.contains(rect, (*_context->get()).zoom_level))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -616,11 +618,11 @@ namespace OpenLoco::Paint
|
|||
return interaction;
|
||||
}
|
||||
|
||||
auto rect = (*_context)->getDrawableRect();
|
||||
auto rect = _context->get()->getDrawableRect();
|
||||
|
||||
for (auto& town : TownManager::towns())
|
||||
{
|
||||
if (!town.labelFrame.contains(rect, (*_context)->zoom_level))
|
||||
if (!town.labelFrame.contains(rect, (*_context->get()).zoom_level))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include "../Interop/Interop.hpp"
|
||||
#include "../Map/Map.hpp"
|
||||
#include "../OpenLoco.h"
|
||||
#include "../Types.hpp"
|
||||
|
||||
namespace OpenLoco::Map
|
||||
|
@ -41,20 +42,20 @@ namespace OpenLoco::Paint
|
|||
int16_t y; // 0x0A
|
||||
uint8_t flags; // 0x0C
|
||||
uint8_t pad_0D;
|
||||
AttachedPaintStruct* next; // 0x0E
|
||||
loco_ptr2<AttachedPaintStruct> next; // 0x0E
|
||||
};
|
||||
assert_struct_size(AttachedPaintStruct, 0x12);
|
||||
|
||||
struct PaintStringStruct
|
||||
{
|
||||
string_id stringId; // 0x00
|
||||
PaintStringStruct* next; // 0x02
|
||||
int16_t x; // 0x06
|
||||
int16_t y; // 0x08
|
||||
uint16_t args[7]; // 0x0A
|
||||
string_id stringId; // 0x00
|
||||
loco_ptr2<PaintStringStruct> next; // 0x02
|
||||
int16_t x; // 0x06
|
||||
int16_t y; // 0x08
|
||||
uint16_t args[7]; // 0x0A
|
||||
uint8_t pad_18[0x1A - 0x18];
|
||||
uint8_t* yOffsets; // 0x1A
|
||||
uint16_t colour; // 0x1E
|
||||
loco_ptr2<uint8_t> yOffsets; // 0x1A
|
||||
uint16_t colour; // 0x1E
|
||||
};
|
||||
assert_struct_size(PaintStringStruct, 0x20);
|
||||
|
||||
|
@ -90,9 +91,9 @@ namespace OpenLoco::Paint
|
|||
uint16_t quadrantIndex; // 0x18
|
||||
uint8_t flags;
|
||||
uint8_t quadrantFlags; // 0x1B
|
||||
AttachedPaintStruct* attachedPS; // 0x1C
|
||||
PaintStruct* children; // 0x20
|
||||
PaintStruct* nextQuadrantPS; // 0x24
|
||||
loco_ptr2<AttachedPaintStruct> attachedPS; // 0x1C
|
||||
loco_ptr2<PaintStruct> children; // 0x20
|
||||
loco_ptr2<PaintStruct> nextQuadrantPS; // 0x24
|
||||
Ui::ViewportInteraction::InteractionItem type; // 0x28
|
||||
uint8_t var_29;
|
||||
uint16_t pad_2A;
|
||||
|
@ -100,8 +101,8 @@ namespace OpenLoco::Paint
|
|||
coord_t map_y; // 0x2E
|
||||
union
|
||||
{
|
||||
Map::TileElement* tileElement; // 0x30 (or entity pointer)
|
||||
EntityBase* entity; // 0x30
|
||||
loco_ptr2<Map::TileElement> tileElement; // 0x30 (or entity pointer)
|
||||
loco_ptr2<EntityBase> entity; // 0x30
|
||||
};
|
||||
};
|
||||
assert_struct_size(PaintStruct, 0x34);
|
||||
|
@ -125,7 +126,7 @@ namespace OpenLoco::Paint
|
|||
[[nodiscard]] Ui::ViewportInteraction::InteractionArg getNormalInteractionInfo(const uint32_t flags);
|
||||
[[nodiscard]] Ui::ViewportInteraction::InteractionArg getStationNameInteractionInfo(const uint32_t flags);
|
||||
[[nodiscard]] Ui::ViewportInteraction::InteractionArg getTownNameInteractionInfo(const uint32_t flags);
|
||||
Gfx::Context* getContext() { return _context; }
|
||||
Gfx::Context* getContext() { return _context->get(); }
|
||||
uint8_t getRotation() { return currentRotation; }
|
||||
// TileElement or Entity
|
||||
void setCurrentItem(void* item) { _currentItem = item; }
|
||||
|
@ -206,22 +207,22 @@ namespace OpenLoco::Paint
|
|||
private:
|
||||
void generateTilesAndEntities(GenerationParameters&& p);
|
||||
|
||||
inline static Interop::loco_global<Gfx::Context*, 0x00E0C3E0> _context;
|
||||
inline static Interop::loco_global<loco_ptr2<Gfx::Context>, 0x00E0C3E0> _context;
|
||||
inline static Interop::loco_global<PaintEntry[4000], 0x00E0C410> _paintEntries;
|
||||
inline static Interop::loco_global<PaintStruct* [1024], 0x00E3F0C0> _quadrants;
|
||||
inline static Interop::loco_global<uint32_t, 0x00E400C0> _quadrantBackIndex;
|
||||
inline static Interop::loco_global<uint32_t, 0x00E400C4> _quadrantFrontIndex;
|
||||
inline static Interop::loco_global<const void*, 0x00E4F0B4> _currentlyDrawnItem;
|
||||
inline static Interop::loco_global<PaintEntry*, 0x00E0C404> _endOfPaintStructArray;
|
||||
inline static Interop::loco_global<PaintEntry*, 0x00E0C408> _paintHead;
|
||||
inline static Interop::loco_global<PaintEntry*, 0x00E0C40C> _nextFreePaintStruct;
|
||||
inline static Interop::loco_global<loco_ptr4<void>, 0x00E4F0B4> _currentlyDrawnItem;
|
||||
inline static Interop::loco_global<loco_ptr2<PaintEntry>, 0x00E0C404> _endOfPaintStructArray;
|
||||
inline static Interop::loco_global<loco_ptr2<PaintEntry>, 0x00E0C408> _paintHead;
|
||||
inline static Interop::loco_global<loco_ptr2<PaintEntry>, 0x00E0C40C> _nextFreePaintStruct;
|
||||
inline static Interop::loco_global<coord_t, 0x00E3F090> _spritePositionX;
|
||||
inline static Interop::loco_global<coord_t, 0x00E3F096> _spritePositionY;
|
||||
inline static Interop::loco_global<PaintStruct*, 0x00E40120> _lastPS;
|
||||
inline static Interop::loco_global<loco_ptr2<PaintStruct>, 0x00E40120> _lastPS;
|
||||
inline static Interop::loco_global<Ui::ViewportInteraction::InteractionItem, 0x00E3F0AC> _itemType;
|
||||
inline static Interop::loco_global<void*, 0x00E3F0B4> _currentItem;
|
||||
inline static Interop::loco_global<PaintStringStruct*, 0x00E40118> _paintStringHead;
|
||||
inline static Interop::loco_global<PaintStringStruct*, 0x00E4011C> _lastPaintString;
|
||||
inline static Interop::loco_global<loco_ptr4<void>, 0x00E3F0B4> _currentItem;
|
||||
inline static Interop::loco_global<loco_ptr2<PaintStringStruct>, 0x00E40118> _paintStringHead;
|
||||
inline static Interop::loco_global<loco_ptr2<PaintStringStruct>, 0x00E4011C> _lastPaintString;
|
||||
inline static Interop::loco_global<Map::Pos2, 0x00E3F0B0> _mapPosition;
|
||||
uint8_t currentRotation; // new field set from 0x00E3F0B8 but split out into this struct as seperate item
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
#include <limits.h>
|
||||
#include <mach-o/dyld.h>
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AppKit/NSOpenPanel.h>
|
||||
|
||||
namespace OpenLoco::platform
|
||||
{
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#ifndef _WIN32
|
||||
|
||||
#include "Platform.h"
|
||||
#include "../Console.h"
|
||||
#include "../Interop/Interop.hpp"
|
||||
#include "../OpenLoco.h"
|
||||
#include "Platform.h"
|
||||
#include <iostream>
|
||||
#include <pwd.h>
|
||||
#include <time.h>
|
||||
|
@ -22,6 +22,7 @@
|
|||
|
||||
int main(int argc, const char** argv)
|
||||
{
|
||||
OpenLoco::Interop::emu_init();
|
||||
OpenLoco::Interop::loadSections();
|
||||
OpenLoco::lpCmdLine((char*)argv[0]);
|
||||
OpenLoco::main();
|
||||
|
|
|
@ -88,9 +88,9 @@ namespace OpenLoco::S5
|
|||
{
|
||||
for (auto viewport : w->viewports)
|
||||
{
|
||||
if (viewport != nullptr)
|
||||
if (viewport.get() != nullptr)
|
||||
{
|
||||
viewport->render(context);
|
||||
viewport.get()->render(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ namespace OpenLoco::S5
|
|||
static std::unique_ptr<S5File> prepareSaveFile(SaveFlags flags, const std::vector<ObjectHeader>& requiredObjects, const std::vector<ObjectHeader>& packedObjects)
|
||||
{
|
||||
auto mainWindow = WindowManager::getMainWindow();
|
||||
auto savedView = mainWindow != nullptr ? mainWindow->viewports[0]->toSavedView() : SavedViewSimple();
|
||||
auto savedView = mainWindow != nullptr ? mainWindow->viewports[0].get()->toSavedView() : SavedViewSimple();
|
||||
|
||||
auto file = std::make_unique<S5File>();
|
||||
file->header = prepareHeader(flags, packedObjects.size());
|
||||
|
|
|
@ -204,7 +204,7 @@ namespace OpenLoco::Scenario
|
|||
{
|
||||
S5::getOptions().scenarioFlags &= ~(Scenario::flags::landscape_generation_done);
|
||||
Ui::WindowManager::invalidate(Ui::WindowType::landscapeGeneration, 0);
|
||||
call(0x0043C88C);
|
||||
Scenario::reset();
|
||||
S5::getOptions().madeAnyChanges = 0;
|
||||
addr<0x00F25374, uint8_t>() = 0;
|
||||
Gfx::invalidateScreen();
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace OpenLoco::Title
|
|||
|
||||
// Explicit deduction guide (not needed as of C++20)
|
||||
template<class... Ts>
|
||||
overloaded(Ts...)->overloaded<Ts...>;
|
||||
overloaded(Ts...) -> overloaded<Ts...>;
|
||||
|
||||
static const TitleSequence _titleSequence = {
|
||||
MoveStep{ 231, 160 },
|
||||
|
@ -145,7 +145,7 @@ namespace OpenLoco::Title
|
|||
}
|
||||
|
||||
// 0x00444357
|
||||
static void reset()
|
||||
void reset()
|
||||
{
|
||||
_sequenceIterator = _titleSequence.begin();
|
||||
_waitCounter = 0;
|
||||
|
@ -204,44 +204,47 @@ namespace OpenLoco::Title
|
|||
return;
|
||||
|
||||
auto& command = *_sequenceIterator++;
|
||||
stdx::visit(overloaded{
|
||||
[](WaitStep step) {
|
||||
// This loop slightly deviates from the original, subtract 1 tick to make up for it.
|
||||
_waitCounter = step.duration - 1;
|
||||
},
|
||||
[](ReloadStep step) {
|
||||
reload();
|
||||
},
|
||||
[](MoveStep step) {
|
||||
if (addr<0x00525E28, uint32_t>() & 1)
|
||||
{
|
||||
auto pos = Map::Pos2(step) + Map::Pos2(16, 16);
|
||||
auto height = Map::TileManager::getHeight(pos);
|
||||
auto main = Ui::WindowManager::getMainWindow();
|
||||
if (main != nullptr)
|
||||
{
|
||||
auto pos3d = Map::Pos3(pos.x, pos.y, height.landHeight);
|
||||
main->viewportCentreOnTile(pos3d);
|
||||
main->flags &= ~Ui::WindowFlags::scrolling_to_location;
|
||||
main->viewportsUpdatePosition();
|
||||
}
|
||||
}
|
||||
},
|
||||
[](RotateStep step) {
|
||||
if (addr<0x00525E28, uint32_t>() & 1)
|
||||
{
|
||||
auto main = Ui::WindowManager::getMainWindow();
|
||||
if (main != nullptr)
|
||||
{
|
||||
main->viewportRotateRight();
|
||||
}
|
||||
}
|
||||
},
|
||||
[](ResetStep step) {
|
||||
_sequenceIterator = _titleSequence.begin();
|
||||
},
|
||||
},
|
||||
command);
|
||||
// std::visit(overloaded{
|
||||
// [](WaitStep step) {
|
||||
// // This loop slightly deviates from the original, subtract 1 tick to make up for it.
|
||||
// _waitCounter = step.duration - 1;
|
||||
// },
|
||||
// [](ReloadStep step) {
|
||||
// loadTitle();
|
||||
// Gfx::invalidateScreen();
|
||||
// resetScreenAge();
|
||||
// addr<0x50C19A, uint16_t>() = 55000;
|
||||
// },
|
||||
// [](MoveStep step) {
|
||||
// if (addr<0x00525E28, uint32_t>() & 1)
|
||||
// {
|
||||
// auto pos = Map::map_pos(step) + Map::map_pos(16, 16);
|
||||
// auto height = Map::TileManager::getHeight(pos);
|
||||
// auto main = Ui::WindowManager::getMainWindow();
|
||||
// if (main != nullptr)
|
||||
// {
|
||||
// auto pos3d = Map::map_pos3(pos.x, pos.y, height.landHeight);
|
||||
// main->viewportCentreOnTile(pos3d);
|
||||
// main->flags &= ~Ui::WindowFlags::scrolling_to_location;
|
||||
// main->viewportsUpdatePosition();
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// [](RotateStep step) {
|
||||
// if (addr<0x00525E28, uint32_t>() & 1)
|
||||
// {
|
||||
// auto main = Ui::WindowManager::getMainWindow();
|
||||
// if (main != nullptr)
|
||||
// {
|
||||
// main->viewportRotateRight();
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// [](ResetStep step) {
|
||||
// _sequenceIterator = _titleSequence.begin();
|
||||
// },
|
||||
// },
|
||||
// command);
|
||||
} while (_waitCounter == 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace OpenLoco::Title
|
||||
{
|
||||
void reset();
|
||||
void registerHooks();
|
||||
void start();
|
||||
void sub_4284C8();
|
||||
|
|
|
@ -206,6 +206,16 @@ namespace OpenLoco::Ui
|
|||
palette = SDL_AllocPalette(256);
|
||||
set_palette_callback = updatePalette;
|
||||
|
||||
SDL_Color base[256];
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
base[i].r = i * 10;
|
||||
base[i].g = i * 10;
|
||||
base[i].b = i * 10;
|
||||
base[i].a = 0;
|
||||
}
|
||||
SDL_SetPaletteColors(palette, base, 0, 256);
|
||||
|
||||
update(desc.width, desc.height);
|
||||
#endif
|
||||
}
|
||||
|
@ -411,7 +421,7 @@ namespace OpenLoco::Ui
|
|||
int32_t pitch = surface->pitch;
|
||||
|
||||
Gfx::Context context{};
|
||||
context.bits = new uint8_t[surface->pitch * height];
|
||||
context.bits = (uint8_t*)malloc(surface->pitch * height);
|
||||
context.width = width;
|
||||
context.height = height;
|
||||
context.pitch = pitch - width;
|
||||
|
@ -505,9 +515,9 @@ namespace OpenLoco::Ui
|
|||
|
||||
// Copy pixels from the virtual screen buffer to the surface
|
||||
auto& context = Gfx::screenContext();
|
||||
if (context.bits != nullptr)
|
||||
if (context.bits.get() != nullptr)
|
||||
{
|
||||
std::memcpy(surface->pixels, context.bits, surface->pitch * surface->h);
|
||||
std::memcpy(surface->pixels, context.bits.get(), surface->pitch * surface->h);
|
||||
}
|
||||
|
||||
// Unlock the surface
|
||||
|
|
|
@ -57,12 +57,6 @@ namespace OpenLoco::Ui::ProgressBar
|
|||
call(0x004CF631, regs);
|
||||
}
|
||||
|
||||
// 0x004CF63B
|
||||
void sub_4CF63B()
|
||||
{
|
||||
call(0x004CF63B);
|
||||
}
|
||||
|
||||
// 0x004CF621
|
||||
// eax: value
|
||||
void setProgress(int32_t value)
|
||||
|
|
|
@ -8,7 +8,6 @@ namespace OpenLoco::Ui::ProgressBar
|
|||
{
|
||||
void begin(std::string_view string);
|
||||
void begin(string_id stringId);
|
||||
void sub_4CF63B();
|
||||
void setProgress(int32_t value);
|
||||
void end();
|
||||
void registerHooks();
|
||||
|
|
|
@ -99,7 +99,7 @@ namespace OpenLoco::Input
|
|||
png_set_IHDR(png_ptr, info_ptr, context.width, context.height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
||||
uint8_t* data = context.bits;
|
||||
uint8_t* data = context.bits.get();
|
||||
for (int y = 0; y < context.height; y++)
|
||||
{
|
||||
png_write_row(png_ptr, data);
|
||||
|
|
|
@ -190,7 +190,7 @@ namespace OpenLoco::Ui::ScrollView
|
|||
*output_y = y;
|
||||
*output_scroll_area = ScrollPart::none;
|
||||
|
||||
for (const auto* winWidget = window->widgets; winWidget != widget; winWidget++)
|
||||
for (const auto* winWidget = &window->widgets[0]; winWidget != widget; winWidget++)
|
||||
{
|
||||
if (winWidget->type == WidgetType::scrollview)
|
||||
{
|
||||
|
|
|
@ -31,7 +31,7 @@ using namespace OpenLoco::Interop;
|
|||
namespace OpenLoco::Ui::ViewportInteraction
|
||||
{
|
||||
InteractionArg::InteractionArg(const Paint::PaintStruct& ps)
|
||||
: object(ps.entity)
|
||||
: object(ps.entity.get())
|
||||
, type(ps.type)
|
||||
, unkBh(ps.var_29)
|
||||
{
|
||||
|
@ -368,7 +368,7 @@ namespace OpenLoco::Ui::ViewportInteraction
|
|||
if (window == nullptr)
|
||||
return InteractionArg{};
|
||||
|
||||
auto viewport = window->viewports[0];
|
||||
auto viewport = window->viewports[0].get();
|
||||
if (viewport == nullptr)
|
||||
return InteractionArg{};
|
||||
|
||||
|
@ -883,8 +883,9 @@ namespace OpenLoco::Ui::ViewportInteraction
|
|||
auto w = WindowManager::findAt(screenPos);
|
||||
if (w != nullptr)
|
||||
{
|
||||
for (auto vp : w->viewports)
|
||||
for (auto vp2 : w->viewports)
|
||||
{
|
||||
auto vp = vp2.get();
|
||||
if (vp != nullptr && vp->containsUi({ screenPos.x, screenPos.y }))
|
||||
{
|
||||
if (vp->flags & ViewportFlags::hide_foreground_scenery_buildings)
|
||||
|
@ -984,8 +985,9 @@ namespace OpenLoco::Ui::ViewportInteraction
|
|||
}
|
||||
|
||||
Viewport* chosenV = nullptr;
|
||||
for (auto vp : w->viewports)
|
||||
for (auto vp2 : w->viewports)
|
||||
{
|
||||
auto vp = vp2.get();
|
||||
if (vp == nullptr)
|
||||
continue;
|
||||
|
||||
|
|
|
@ -581,7 +581,7 @@ namespace OpenLoco::Ui::WindowManager
|
|||
auto mainWindow = getMainWindow();
|
||||
if (mainWindow != nullptr)
|
||||
{
|
||||
return mainWindow->viewports[0];
|
||||
return mainWindow->viewports[0].get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -732,7 +732,7 @@ namespace OpenLoco::Ui::WindowManager
|
|||
if (w->number != number)
|
||||
continue;
|
||||
|
||||
auto widget = w->widgets[widget_index];
|
||||
auto widget = w->widgets.get()[widget_index];
|
||||
|
||||
if (widget.left != -2)
|
||||
{
|
||||
|
@ -821,7 +821,7 @@ namespace OpenLoco::Ui::WindowManager
|
|||
{
|
||||
const auto shiftRight = 20 - w->x;
|
||||
w->x = 20;
|
||||
for (auto* vp : w->viewports)
|
||||
for (auto vp : w->viewports)
|
||||
{
|
||||
if (vp != nullptr)
|
||||
{
|
||||
|
@ -1145,7 +1145,12 @@ namespace OpenLoco::Ui::WindowManager
|
|||
void drawSingle(Gfx::Context* _context, Window* w, int32_t left, int32_t top, int32_t right, int32_t bottom)
|
||||
{
|
||||
// Copy context so we can crop it
|
||||
auto context = *_context;
|
||||
// auto context = *_context;
|
||||
|
||||
auto dpi2 = (Gfx::Context*)malloc(sizeof(Gfx::Context));
|
||||
memcpy(dpi2, _context, sizeof(Gfx::Context));
|
||||
|
||||
auto& context = *dpi2;
|
||||
|
||||
// Clamp left to 0
|
||||
int32_t overflow = left - context.x;
|
||||
|
@ -1156,7 +1161,7 @@ namespace OpenLoco::Ui::WindowManager
|
|||
if (context.width <= 0)
|
||||
return;
|
||||
context.pitch += overflow;
|
||||
context.bits += overflow;
|
||||
context.bits = context.bits.get() + overflow;
|
||||
}
|
||||
|
||||
// Clamp width to right
|
||||
|
@ -1177,7 +1182,7 @@ namespace OpenLoco::Ui::WindowManager
|
|||
context.height -= overflow;
|
||||
if (context.height <= 0)
|
||||
return;
|
||||
context.bits += (context.width + context.pitch) * overflow;
|
||||
context.bits = context.bits.get() + (context.width + context.pitch) * overflow;
|
||||
}
|
||||
|
||||
// Clamp height to bottom
|
||||
|
@ -1212,6 +1217,8 @@ namespace OpenLoco::Ui::WindowManager
|
|||
|
||||
w->callPrepareDraw();
|
||||
w->callDraw(&context);
|
||||
|
||||
free(dpi2);
|
||||
}
|
||||
|
||||
// 0x004CD3D0
|
||||
|
@ -1460,7 +1467,7 @@ namespace OpenLoco::Ui::WindowManager
|
|||
{
|
||||
int widgetIndex = -1;
|
||||
int scrollIndex = -1;
|
||||
for (Widget* widget = window->widgets; widget->type != WidgetType::end; widget++)
|
||||
for (auto widget = window->widgets.get(); widget->type != WidgetType::end; widget++)
|
||||
{
|
||||
widgetIndex++;
|
||||
|
||||
|
@ -1630,7 +1637,7 @@ namespace OpenLoco::Ui::WindowManager
|
|||
if (w->viewports[0] == nullptr)
|
||||
continue;
|
||||
|
||||
auto viewport = w->viewports[0];
|
||||
auto viewport = w->viewports[0].get();
|
||||
if (viewport->zoom != 0)
|
||||
continue;
|
||||
|
||||
|
@ -1656,10 +1663,10 @@ namespace OpenLoco::Ui::WindowManager
|
|||
if ((w->flags & WindowFlags::transparent) == 0)
|
||||
continue;
|
||||
|
||||
if (viewport == w->viewports[0])
|
||||
if (viewport == w->viewports[0].get())
|
||||
continue;
|
||||
|
||||
if (viewport == w->viewports[1])
|
||||
if (viewport == w->viewports[1].get())
|
||||
continue;
|
||||
|
||||
if (viewport->x + viewport->width <= w->x)
|
||||
|
@ -1731,8 +1738,8 @@ namespace OpenLoco::Ui::WindowManager
|
|||
height += tmargin + bmargin;
|
||||
|
||||
int32_t stride = _bitsContext.width + _bitsContext.pitch;
|
||||
uint8_t* to = _bitsContext.bits + y * stride + x;
|
||||
uint8_t* from = _bitsContext.bits + (y - dy) * stride + x - dx;
|
||||
uint8_t* to = _bitsContext.bits.get() + y * stride + x;
|
||||
uint8_t* from = _bitsContext.bits.get() + (y - dy) * stride + x - dx;
|
||||
|
||||
if (dy > 0)
|
||||
{
|
||||
|
@ -1764,7 +1771,7 @@ namespace OpenLoco::Ui::WindowManager
|
|||
if (window != nullptr)
|
||||
{
|
||||
// skip current window and non-intersecting windows
|
||||
if (viewport == window->viewports[0] || viewport == window->viewports[1] || viewport->x + viewport->width <= window->x || viewport->x >= window->x + window->width || viewport->y + viewport->height <= window->y || viewport->y >= window->y + window->height)
|
||||
if (viewport == window->viewports[0].get() || viewport == window->viewports[1].get() || viewport->x + viewport->width <= window->x || viewport->x >= window->x + window->width || viewport->y + viewport->height <= window->y || viewport->y >= window->y + window->height)
|
||||
{
|
||||
size_t nextWindowIndex = WindowManager::indexOf(window) + 1;
|
||||
auto nextWindow = nextWindowIndex >= count() ? nullptr : get(nextWindowIndex);
|
||||
|
@ -1888,7 +1895,7 @@ namespace OpenLoco::Ui::WindowManager
|
|||
if (window == nullptr)
|
||||
return;
|
||||
|
||||
auto viewport = window->viewports[0];
|
||||
auto viewport = window->viewports[0].get();
|
||||
bool flagsChanged = false;
|
||||
|
||||
switch (visibility)
|
||||
|
@ -2038,11 +2045,11 @@ namespace OpenLoco::Ui::Windows
|
|||
auto window = WindowManager::getMainWindow();
|
||||
if (window != nullptr)
|
||||
{
|
||||
if (!(window->viewports[0]->flags & ViewportFlags::gridlines_on_landscape))
|
||||
if (!(window->viewports[0].get()->flags & ViewportFlags::gridlines_on_landscape))
|
||||
{
|
||||
window->invalidate();
|
||||
}
|
||||
window->viewports[0]->flags |= ViewportFlags::gridlines_on_landscape;
|
||||
window->viewports[0].get()->flags |= ViewportFlags::gridlines_on_landscape;
|
||||
}
|
||||
}
|
||||
_gridlinesState++;
|
||||
|
@ -2059,11 +2066,11 @@ namespace OpenLoco::Ui::Windows
|
|||
auto window = WindowManager::getMainWindow();
|
||||
if (window != nullptr)
|
||||
{
|
||||
if ((window->viewports[0]->flags & ViewportFlags::gridlines_on_landscape) != 0)
|
||||
if ((window->viewports[0].get()->flags & ViewportFlags::gridlines_on_landscape) != 0)
|
||||
{
|
||||
window->invalidate();
|
||||
}
|
||||
window->viewports[0]->flags &= ~ViewportFlags::gridlines_on_landscape;
|
||||
window->viewports[0].get()->flags &= ~ViewportFlags::gridlines_on_landscape;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2077,9 +2084,9 @@ namespace OpenLoco::Ui::Windows
|
|||
auto mainWindow = WindowManager::getMainWindow();
|
||||
if (mainWindow != nullptr)
|
||||
{
|
||||
if (!(mainWindow->viewports[0]->flags & ViewportFlags::one_way_direction_arrows))
|
||||
if (!(mainWindow->viewports[0].get()->flags & ViewportFlags::one_way_direction_arrows))
|
||||
{
|
||||
mainWindow->viewports[0]->flags |= ViewportFlags::one_way_direction_arrows;
|
||||
mainWindow->viewports[0].get()->flags |= ViewportFlags::one_way_direction_arrows;
|
||||
mainWindow->invalidate();
|
||||
}
|
||||
}
|
||||
|
@ -2096,9 +2103,9 @@ namespace OpenLoco::Ui::Windows
|
|||
auto mainWindow = WindowManager::getMainWindow();
|
||||
if (mainWindow != nullptr)
|
||||
{
|
||||
if ((mainWindow->viewports[0]->flags & ViewportFlags::one_way_direction_arrows))
|
||||
if ((mainWindow->viewports[0].get()->flags & ViewportFlags::one_way_direction_arrows))
|
||||
{
|
||||
mainWindow->viewports[0]->flags &= ~ViewportFlags::one_way_direction_arrows;
|
||||
mainWindow->viewports[0].get()->flags &= ~ViewportFlags::one_way_direction_arrows;
|
||||
mainWindow->invalidate();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,9 @@ namespace OpenLoco
|
|||
#elif defined(OPENLOCO_BRANCH)
|
||||
OPENLOCO_BRANCH
|
||||
#endif
|
||||
#if __x86_64__
|
||||
",x86-64"
|
||||
#endif
|
||||
#ifndef NDEBUG
|
||||
", DEBUG"
|
||||
#endif
|
||||
|
|
|
@ -43,7 +43,8 @@ namespace OpenLoco::Ui::ViewportManager
|
|||
|
||||
static Viewport* initViewport(Ui::Point origin, Ui::Size size, ZoomLevel zoom)
|
||||
{
|
||||
auto vp = _viewports.emplace_back(std::make_unique<Viewport>()).get();
|
||||
auto vp = new Viewport();
|
||||
_viewports.emplace_back(std::unique_ptr<Viewport>(vp));
|
||||
|
||||
vp->x = origin.x;
|
||||
vp->y = origin.y;
|
||||
|
@ -67,7 +68,7 @@ namespace OpenLoco::Ui::ViewportManager
|
|||
static void focusViewportOn(Window* w, int index, EntityId_t dx)
|
||||
{
|
||||
assert(index >= 0 && index < viewportsPerWindow);
|
||||
Viewport* viewport = w->viewports[index];
|
||||
Viewport* viewport = w->viewports[index].get();
|
||||
|
||||
w->viewport_configurations[index].viewport_target_sprite = dx;
|
||||
|
||||
|
@ -83,7 +84,7 @@ namespace OpenLoco::Ui::ViewportManager
|
|||
static void focusViewportOn(Window* w, int index, Map::Pos3 tile)
|
||||
{
|
||||
assert(index >= 0 && index < viewportsPerWindow);
|
||||
Viewport* viewport = w->viewports[index];
|
||||
Viewport* viewport = w->viewports[index].get();
|
||||
|
||||
w->viewport_configurations[index].viewport_target_sprite = 0xFFFF;
|
||||
|
||||
|
|
|
@ -189,7 +189,7 @@ namespace OpenLoco::Ui
|
|||
// 0x004CF487
|
||||
void Widget::drawViewportCentreButton(Gfx::Context* context, const Window* window, const WidgetIndex_t widgetIndex)
|
||||
{
|
||||
auto& widget = window->widgets[widgetIndex];
|
||||
auto widget = window->widgets[widgetIndex];
|
||||
if (Input::isHovering(window->type, window->number, widgetIndex))
|
||||
{
|
||||
Gfx::drawRect(*context, widget.left + window->x, widget.top + window->y, widget.width(), widget.height(), 0x2000000 | 54);
|
||||
|
@ -827,7 +827,7 @@ namespace OpenLoco::Ui
|
|||
cropped.x = l;
|
||||
cropped.pitch += offset;
|
||||
|
||||
cropped.bits += offset;
|
||||
cropped.bits = cropped.bits.get() + offset;
|
||||
}
|
||||
|
||||
int16_t bp = cropped.x + cropped.width - r;
|
||||
|
@ -844,7 +844,7 @@ namespace OpenLoco::Ui
|
|||
cropped.y = t;
|
||||
|
||||
int aex = (cropped.pitch + cropped.width) * offset;
|
||||
cropped.bits += aex;
|
||||
cropped.bits = cropped.bits.get() + aex;
|
||||
}
|
||||
|
||||
bp = cropped.y + cropped.height - b;
|
||||
|
@ -961,7 +961,7 @@ namespace OpenLoco::Ui
|
|||
// 0x004CF194
|
||||
void Widget::drawTab(Window* w, Gfx::Context* ctx, int32_t imageId, WidgetIndex_t index)
|
||||
{
|
||||
auto widget = &w->widgets[index];
|
||||
auto widget = &w->widgets.get()[index];
|
||||
|
||||
Ui::Point pos = {};
|
||||
pos.x = widget->left + w->x;
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace OpenLoco::Ui
|
|||
template<typename T>
|
||||
static bool isInteropEvent(T e)
|
||||
{
|
||||
return (uint32_t)e < 0x004D7000;
|
||||
return (uintptr_t)e < 0x004D7000;
|
||||
}
|
||||
|
||||
Window::Window(Ui::Point position, Ui::Size size)
|
||||
|
@ -111,10 +111,10 @@ namespace OpenLoco::Ui
|
|||
// 0x0045A0B3
|
||||
void Window::drawViewports(Gfx::Context* context)
|
||||
{
|
||||
if (viewports[0] != nullptr)
|
||||
if (viewports[0].get() != nullptr)
|
||||
viewports[0]->render(context);
|
||||
|
||||
if (viewports[1] != nullptr)
|
||||
if (viewports[1].get() != nullptr)
|
||||
viewports[1]->render(context);
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ namespace OpenLoco::Ui
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
Viewport* vp = w->viewports[0];
|
||||
Viewport* vp = w->viewports[0].get();
|
||||
if (vp == nullptr)
|
||||
{
|
||||
return std::nullopt;
|
||||
|
@ -276,7 +276,7 @@ namespace OpenLoco::Ui
|
|||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
Viewport* viewport = this->viewports[i];
|
||||
Viewport* viewport = this->viewports[i].get();
|
||||
ViewportConfig* config = &this->viewport_configurations[i];
|
||||
|
||||
if (viewport == nullptr)
|
||||
|
@ -517,7 +517,7 @@ namespace OpenLoco::Ui
|
|||
|
||||
// Get viewport coordinates centring around the tile.
|
||||
auto base_height = TileManager::getHeight({ *map_x, *map_y }).landHeight;
|
||||
Viewport* v = this->viewports[0];
|
||||
Viewport* v = this->viewports[0].get();
|
||||
const auto dest = v->centre2dCoordinates({ *map_x, *map_y, base_height });
|
||||
|
||||
// Rebase mouse position onto centre of window, and compensate for zoom level.
|
||||
|
@ -547,7 +547,7 @@ namespace OpenLoco::Ui
|
|||
// 0x004C6827
|
||||
void Window::viewportCentreOnTile(const Map::Pos3& loc)
|
||||
{
|
||||
auto viewport = this->viewports[0];
|
||||
auto viewport = this->viewports[0].get();
|
||||
if (viewport == nullptr)
|
||||
return;
|
||||
|
||||
|
@ -583,7 +583,7 @@ namespace OpenLoco::Ui
|
|||
|
||||
void Window::viewportCentreMain()
|
||||
{
|
||||
if (viewports[0] == nullptr || saved_view.isEmpty())
|
||||
if (viewports[0].get() == nullptr || saved_view.isEmpty())
|
||||
return;
|
||||
|
||||
auto main = WindowManager::getMainWindow();
|
||||
|
@ -607,7 +607,7 @@ namespace OpenLoco::Ui
|
|||
{
|
||||
// Get viewport coordinates centring around the tile.
|
||||
auto base_height = TileManager::getHeight({ map_x, map_y }).landHeight;
|
||||
Viewport* v = this->viewports[0];
|
||||
Viewport* v = this->viewports[0].get();
|
||||
const auto dest = v->centre2dCoordinates({ map_x, map_y, base_height });
|
||||
|
||||
// Get mouse position to offset against.
|
||||
|
@ -625,7 +625,7 @@ namespace OpenLoco::Ui
|
|||
|
||||
void Window::viewportFocusOnEntity(uint16_t targetEntity)
|
||||
{
|
||||
if (viewports[0] == nullptr || saved_view.isEmpty())
|
||||
if (viewports[0].get() == nullptr || saved_view.isEmpty())
|
||||
return;
|
||||
|
||||
viewport_configurations[0].viewport_target_sprite = targetEntity;
|
||||
|
@ -633,7 +633,7 @@ namespace OpenLoco::Ui
|
|||
|
||||
bool Window::viewportIsFocusedOnEntity() const
|
||||
{
|
||||
if (viewports[0] == nullptr || saved_view.isEmpty())
|
||||
if (viewports[0].get() == nullptr || saved_view.isEmpty())
|
||||
return false;
|
||||
|
||||
return viewport_configurations[0].viewport_target_sprite != EntityId::null;
|
||||
|
@ -641,7 +641,7 @@ namespace OpenLoco::Ui
|
|||
|
||||
void Window::viewportUnfocusFromEntity()
|
||||
{
|
||||
if (viewports[0] == nullptr || saved_view.isEmpty())
|
||||
if (viewports[0].get() == nullptr || saved_view.isEmpty())
|
||||
return;
|
||||
|
||||
if (viewport_configurations[0].viewport_target_sprite == EntityId::null)
|
||||
|
@ -654,7 +654,7 @@ namespace OpenLoco::Ui
|
|||
|
||||
void Window::viewportZoomSet(int8_t zoomLevel, bool toCursor)
|
||||
{
|
||||
Viewport* v = this->viewports[0];
|
||||
Viewport* v = this->viewports[0].get();
|
||||
ViewportConfig* vc = &this->viewport_configurations[0];
|
||||
|
||||
zoomLevel = std::clamp<int8_t>(zoomLevel, 0, 3);
|
||||
|
@ -703,19 +703,19 @@ namespace OpenLoco::Ui
|
|||
// 0x0045EFDB
|
||||
void Window::viewportZoomIn(bool toCursor)
|
||||
{
|
||||
if (this->viewports[0] == nullptr)
|
||||
if (this->viewports[0].get() == nullptr)
|
||||
return;
|
||||
|
||||
this->viewportZoomSet(this->viewports[0]->zoom - 1, toCursor);
|
||||
this->viewportZoomSet(this->viewports[0].get()->zoom - 1, toCursor);
|
||||
}
|
||||
|
||||
// 0x0045F015
|
||||
void Window::viewportZoomOut(bool toCursor)
|
||||
{
|
||||
if (this->viewports[0] == nullptr)
|
||||
if (this->viewports[0].get() == nullptr)
|
||||
return;
|
||||
|
||||
this->viewportZoomSet(this->viewports[0]->zoom + 1, toCursor);
|
||||
this->viewportZoomSet(this->viewports[0].get()->zoom + 1, toCursor);
|
||||
}
|
||||
|
||||
// 0x0045F04F
|
||||
|
@ -736,9 +736,9 @@ namespace OpenLoco::Ui
|
|||
|
||||
void Window::viewportRemove(const uint8_t viewportId)
|
||||
{
|
||||
if (viewports[viewportId] != nullptr)
|
||||
if (viewports[viewportId].get() != nullptr)
|
||||
{
|
||||
viewports[viewportId]->width = 0;
|
||||
viewports[viewportId].get()->width = 0;
|
||||
viewports[viewportId] = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -746,7 +746,7 @@ namespace OpenLoco::Ui
|
|||
// 0x004421FB
|
||||
void Window::viewportFromSavedView(const SavedViewSimple& savedView)
|
||||
{
|
||||
auto viewport = viewports[0];
|
||||
auto viewport = viewports[0].get();
|
||||
if (viewport != nullptr)
|
||||
{
|
||||
auto& config = viewport_configurations[0];
|
||||
|
@ -789,16 +789,16 @@ namespace OpenLoco::Ui
|
|||
this->x += dx;
|
||||
this->y += dy;
|
||||
|
||||
if (this->viewports[0] != nullptr)
|
||||
if (this->viewports[0].get() != nullptr)
|
||||
{
|
||||
this->viewports[0]->x += dx;
|
||||
this->viewports[0]->y += dy;
|
||||
this->viewports[0].get()->x += dx;
|
||||
this->viewports[0].get()->y += dy;
|
||||
}
|
||||
|
||||
if (this->viewports[1] != nullptr)
|
||||
if (this->viewports[1].get() != nullptr)
|
||||
{
|
||||
this->viewports[1]->x += dx;
|
||||
this->viewports[1]->y += dy;
|
||||
this->viewports[1].get()->x += dx;
|
||||
this->viewports[1].get()->y += dy;
|
||||
}
|
||||
|
||||
this->invalidate();
|
||||
|
@ -839,16 +839,16 @@ namespace OpenLoco::Ui
|
|||
this->y += offset.y;
|
||||
this->invalidate();
|
||||
|
||||
if (this->viewports[0] != nullptr)
|
||||
if (this->viewports[0].get() != nullptr)
|
||||
{
|
||||
this->viewports[0]->x += offset.x;
|
||||
this->viewports[0]->y += offset.y;
|
||||
this->viewports[0].get()->x += offset.x;
|
||||
this->viewports[0].get()->y += offset.y;
|
||||
}
|
||||
|
||||
if (this->viewports[1] != nullptr)
|
||||
if (this->viewports[1].get() != nullptr)
|
||||
{
|
||||
this->viewports[1]->x += offset.x;
|
||||
this->viewports[1]->y += offset.y;
|
||||
this->viewports[1].get()->x += offset.x;
|
||||
this->viewports[1].get()->y += offset.y;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -913,8 +913,7 @@ namespace OpenLoco::Ui
|
|||
if (isInteropEvent(event_handlers->on_close))
|
||||
{
|
||||
registers regs;
|
||||
regs.esi = X86Pointer(this);
|
||||
call((uint32_t)this->event_handlers->on_close, regs);
|
||||
// call((uint32_t)this->event_handlers->on_close, regs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -930,7 +929,7 @@ namespace OpenLoco::Ui
|
|||
{
|
||||
registers regs;
|
||||
regs.esi = X86Pointer(this);
|
||||
call((uint32_t)this->event_handlers->on_periodic_update, regs);
|
||||
// call((uint32_t)this->event_handlers->on_periodic_update, regs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1016,7 +1015,7 @@ namespace OpenLoco::Ui
|
|||
regs.bx = yPos;
|
||||
regs.dx = widget_index;
|
||||
regs.esi = X86Pointer(this);
|
||||
call((uint32_t)this->event_handlers->on_tool_down, regs);
|
||||
// call((uint32_t)this->event_handlers->on_tool_down, regs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1035,7 +1034,7 @@ namespace OpenLoco::Ui
|
|||
regs.bx = yPos;
|
||||
regs.dx = widget_index;
|
||||
regs.esi = X86Pointer(this);
|
||||
call((uint32_t)this->event_handlers->toolDragContinue, regs);
|
||||
// call((uint32_t)this->event_handlers->toolDragContinue, regs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1052,7 +1051,7 @@ namespace OpenLoco::Ui
|
|||
registers regs;
|
||||
regs.dx = widget_index;
|
||||
regs.esi = X86Pointer(this);
|
||||
call((uint32_t)this->event_handlers->toolDragEnd, regs);
|
||||
// call((uint32_t)this->event_handlers->toolDragEnd, regs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1069,7 +1068,7 @@ namespace OpenLoco::Ui
|
|||
registers regs;
|
||||
regs.dx = widget_index;
|
||||
regs.esi = X86Pointer(this);
|
||||
call((uint32_t)this->event_handlers->on_tool_abort, regs);
|
||||
// call((uint32_t)this->event_handlers->on_tool_abort, regs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1088,7 +1087,7 @@ namespace OpenLoco::Ui
|
|||
regs.cx = yPos;
|
||||
regs.edi = (int32_t)fallback;
|
||||
regs.esi = X86Pointer(this);
|
||||
call(reinterpret_cast<uint32_t>(this->event_handlers->event_15), regs);
|
||||
// call(reinterpret_cast<uint32_t>(this->event_handlers->event_15), regs);
|
||||
|
||||
*out = regs.bl;
|
||||
|
||||
|
@ -1155,7 +1154,7 @@ namespace OpenLoco::Ui
|
|||
{
|
||||
registers regs;
|
||||
regs.esi = X86Pointer(this);
|
||||
call((uint32_t)event_handlers->on_resize, regs);
|
||||
// call((uint32_t)event_handlers->on_resize, regs);
|
||||
return (Window*)regs.esi;
|
||||
}
|
||||
|
||||
|
@ -1174,7 +1173,7 @@ namespace OpenLoco::Ui
|
|||
regs.edx = widget_index;
|
||||
regs.esi = X86Pointer(this);
|
||||
regs.edi = X86Pointer(&this->widgets[widget_index]);
|
||||
call((uint32_t)this->event_handlers->event_03, regs);
|
||||
// call((uint32_t)this->event_handlers->event_03, regs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1192,7 +1191,7 @@ namespace OpenLoco::Ui
|
|||
regs.edx = widget_index;
|
||||
regs.esi = X86Pointer(this);
|
||||
regs.edi = X86Pointer(&this->widgets[widget_index]);
|
||||
call((uint32_t)this->event_handlers->on_mouse_down, regs);
|
||||
// call((uint32_t)this->event_handlers->on_mouse_down, regs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1210,7 +1209,7 @@ namespace OpenLoco::Ui
|
|||
regs.ax = item_index;
|
||||
regs.edx = widget_index;
|
||||
regs.esi = X86Pointer(this);
|
||||
call((uint32_t)this->event_handlers->on_dropdown, regs);
|
||||
// call((uint32_t)this->event_handlers->on_dropdown, regs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1227,7 +1226,7 @@ namespace OpenLoco::Ui
|
|||
registers regs;
|
||||
regs.eax = scrollIndex;
|
||||
regs.esi = X86Pointer(this);
|
||||
call((uint32_t)this->event_handlers->get_scroll_size, regs);
|
||||
// call((uint32_t)this->event_handlers->get_scroll_size, regs);
|
||||
*scrollWidth = regs.cx;
|
||||
*scrollHeight = regs.dx;
|
||||
return;
|
||||
|
@ -1248,7 +1247,7 @@ namespace OpenLoco::Ui
|
|||
regs.esi = X86Pointer(this);
|
||||
regs.cx = xPos;
|
||||
regs.dx = yPos;
|
||||
call((uint32_t)this->event_handlers->scroll_mouse_down, regs);
|
||||
// call((uint32_t)this->event_handlers->scroll_mouse_down, regs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1267,7 +1266,7 @@ namespace OpenLoco::Ui
|
|||
regs.esi = X86Pointer(this);
|
||||
regs.cx = xPos;
|
||||
regs.dx = yPos;
|
||||
call((uint32_t)this->event_handlers->scroll_mouse_drag, regs);
|
||||
// call((uint32_t)this->event_handlers->scroll_mouse_drag, regs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1286,7 +1285,7 @@ namespace OpenLoco::Ui
|
|||
regs.esi = X86Pointer(this);
|
||||
regs.cx = xPos;
|
||||
regs.dx = yPos;
|
||||
call((uint32_t)this->event_handlers->scroll_mouse_over, regs);
|
||||
// call((uint32_t)this->event_handlers->scroll_mouse_over, regs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1339,7 +1338,7 @@ namespace OpenLoco::Ui
|
|||
registers regs;
|
||||
regs.ax = widget_index;
|
||||
regs.esi = X86Pointer(this);
|
||||
call((int32_t)this->event_handlers->tooltip, regs);
|
||||
// call((int32_t)this->event_handlers->tooltip, regs);
|
||||
auto args = FormatArguments();
|
||||
if (regs.ax == (int16_t)StringIds::null)
|
||||
return {};
|
||||
|
@ -1360,7 +1359,7 @@ namespace OpenLoco::Ui
|
|||
regs.cx = xPos;
|
||||
regs.dx = yPos;
|
||||
regs.esi = X86Pointer(this);
|
||||
call(reinterpret_cast<int32_t>(this->event_handlers->on_move), regs);
|
||||
// call(reinterpret_cast<int32_t>(this->event_handlers->on_move), regs);
|
||||
}
|
||||
this->event_handlers->on_move(*this, xPos, yPos);
|
||||
}
|
||||
|
@ -1374,10 +1373,11 @@ namespace OpenLoco::Ui
|
|||
{
|
||||
registers regs;
|
||||
regs.esi = X86Pointer(this);
|
||||
call((int32_t)this->event_handlers->prepare_draw, regs);
|
||||
// call((int32_t)this->event_handlers->prepare_draw, regs);
|
||||
return;
|
||||
}
|
||||
|
||||
auto handlers = event_handlers.get();
|
||||
event_handlers->prepare_draw(this);
|
||||
}
|
||||
|
||||
|
@ -1391,7 +1391,7 @@ namespace OpenLoco::Ui
|
|||
registers regs;
|
||||
regs.esi = X86Pointer(this);
|
||||
regs.edi = X86Pointer(context);
|
||||
call((int32_t)this->event_handlers->draw, regs);
|
||||
// call((int32_t)this->event_handlers->draw, regs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1409,7 +1409,7 @@ namespace OpenLoco::Ui
|
|||
regs.ax = scrollIndex;
|
||||
regs.esi = X86Pointer(this);
|
||||
regs.edi = X86Pointer(context);
|
||||
call((int32_t)event_handlers->draw_scroll, regs);
|
||||
// call((int32_t)event_handlers->draw_scroll, regs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1449,7 +1449,7 @@ namespace OpenLoco::Ui
|
|||
uint8_t scrollviewIndex = 0;
|
||||
for (WidgetIndex_t widgetIndex = 0; widgetIndex < 64; widgetIndex++)
|
||||
{
|
||||
auto widget = &this->widgets[widgetIndex];
|
||||
auto widget = &this->widgets.get()[widgetIndex];
|
||||
|
||||
if (widget->type == WidgetType::end)
|
||||
{
|
||||
|
|
|
@ -144,7 +144,7 @@ namespace OpenLoco::Ui
|
|||
void (*scroll_mouse_over)(Ui::Window* window, int16_t x, int16_t y, uint8_t scroll_index);
|
||||
void (*text_input)(Window*, WidgetIndex_t, const char*);
|
||||
void (*viewport_rotate)(Window*);
|
||||
uint32_t event_22;
|
||||
uintptr_t event_22;
|
||||
std::optional<FormatArguments> (*tooltip)(Window*, WidgetIndex_t);
|
||||
Ui::CursorId (*cursor)(Window*, int16_t, int16_t, int16_t, Ui::CursorId);
|
||||
void (*on_move)(Window&, const int16_t x, const int16_t y);
|
||||
|
@ -241,28 +241,84 @@ namespace OpenLoco::Ui
|
|||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class loco_ptr3
|
||||
{
|
||||
private:
|
||||
uint32_t _ptr;
|
||||
|
||||
public:
|
||||
loco_ptr3(uintptr_t ptr)
|
||||
{
|
||||
_ptr = ptr;
|
||||
}
|
||||
loco_ptr3(std::nullptr_t aNullptr)
|
||||
{
|
||||
_ptr = 0;
|
||||
}
|
||||
|
||||
loco_ptr3(T* ptr = nullptr)
|
||||
{
|
||||
_ptr = static_cast<uint32_t>((uintptr_t)ptr);
|
||||
}
|
||||
|
||||
T* get()
|
||||
{
|
||||
return (T*)(uintptr_t)_ptr;
|
||||
}
|
||||
T* operator->()
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
const T* get() const
|
||||
{
|
||||
return (T*)(uintptr_t)_ptr;
|
||||
}
|
||||
|
||||
T& operator[](int index)
|
||||
{
|
||||
return get()[index];
|
||||
}
|
||||
|
||||
const T& operator[](int index) const
|
||||
{
|
||||
return get()[index];
|
||||
}
|
||||
|
||||
bool operator==(const void* other)
|
||||
{
|
||||
return this->get() == other;
|
||||
}
|
||||
|
||||
bool operator!=(const void* other)
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
struct Window
|
||||
{
|
||||
WindowEventList* event_handlers; // 0x00
|
||||
Ui::Viewport* viewports[2] = { nullptr, nullptr }; // 0x04
|
||||
uint64_t enabled_widgets = 0; // 0x0C
|
||||
uint64_t disabled_widgets = 0; // 0x14
|
||||
uint64_t activated_widgets = 0; // 0x1C
|
||||
uint64_t holdable_widgets = 0; // 0x24
|
||||
Widget* widgets; // 0x2C
|
||||
int16_t x; // 0x30
|
||||
int16_t y; // 0x32
|
||||
uint16_t width; // 0x34
|
||||
uint16_t height; // 0x36
|
||||
uint16_t min_width; // 0x38
|
||||
uint16_t max_width; // 0x3a
|
||||
uint16_t min_height; // 0x3c
|
||||
uint16_t max_height; // 0x3e
|
||||
WindowNumber_t number = 0; // 0x40
|
||||
uint32_t flags; // 0x42
|
||||
ScrollArea scroll_areas[2]; // 0x46
|
||||
int16_t row_info[1000]; // 0x6A
|
||||
uint16_t row_count; // 0x83A
|
||||
loco_ptr3<WindowEventList> event_handlers; // 0x00
|
||||
loco_ptr3<Ui::Viewport> viewports[2] = { nullptr, nullptr }; // 0x04
|
||||
uint64_t enabled_widgets = 0; // 0x0C
|
||||
uint64_t disabled_widgets = 0; // 0x14
|
||||
uint64_t activated_widgets = 0; // 0x1C
|
||||
uint64_t holdable_widgets = 0; // 0x24
|
||||
loco_ptr3<Widget> widgets; // 0x2C
|
||||
int16_t x; // 0x30
|
||||
int16_t y; // 0x32
|
||||
uint16_t width; // 0x34
|
||||
uint16_t height; // 0x36
|
||||
uint16_t min_width; // 0x38
|
||||
uint16_t max_width; // 0x3a
|
||||
uint16_t min_height; // 0x3c
|
||||
uint16_t max_height; // 0x3e
|
||||
WindowNumber_t number = 0; // 0x40
|
||||
uint32_t flags; // 0x42
|
||||
ScrollArea scroll_areas[2]; // 0x46
|
||||
int16_t row_info[1000]; // 0x6A
|
||||
uint16_t row_count; // 0x83A
|
||||
uint16_t var_83C;
|
||||
uint16_t row_height; // 0x83E
|
||||
int16_t row_hover = -1; // 0x840
|
||||
|
@ -277,13 +333,13 @@ namespace OpenLoco::Ui
|
|||
uint16_t var_858 = 0;
|
||||
union
|
||||
{
|
||||
std::byte* object; // 0x85A union
|
||||
loco_ptr2<std::byte> object; // 0x85A union
|
||||
struct
|
||||
{
|
||||
int16_t var_85A;
|
||||
int16_t var_85C;
|
||||
};
|
||||
uintptr_t info;
|
||||
uint32_t info;
|
||||
};
|
||||
uint8_t pad_85E[0x870 - 0x85E];
|
||||
uint16_t current_tab = 0; // 0x870
|
||||
|
|
|
@ -601,9 +601,9 @@ namespace OpenLoco::Ui::Windows::BuildVehicle
|
|||
WindowManager::invalidate(WindowType::topToolbar, 0);
|
||||
}
|
||||
|
||||
auto curViewport = window->viewports[0];
|
||||
window->viewports[0] = 0;
|
||||
if (curViewport != 0)
|
||||
auto curViewport = window->viewports[0].get();
|
||||
window->viewports[0] = nullptr;
|
||||
if (curViewport != nullptr)
|
||||
{
|
||||
curViewport->width = 0;
|
||||
}
|
||||
|
@ -1285,7 +1285,7 @@ namespace OpenLoco::Ui::Windows::BuildVehicle
|
|||
static void setTransportTypeTabs(Ui::Window* window)
|
||||
{
|
||||
auto disabledWidgets = window->disabled_widgets >> widx::tab_build_new_trains;
|
||||
auto widget = window->widgets + widx::tab_build_new_trains;
|
||||
auto widget = &window->widgets[widx::tab_build_new_trains];
|
||||
auto tabWidth = widget->right - widget->left;
|
||||
auto tabX = widget->left;
|
||||
for (auto i = 0; i <= widx::tab_build_new_ships - widx::tab_build_new_trains; ++i, ++widget)
|
||||
|
|
|
@ -237,7 +237,7 @@ namespace OpenLoco::Ui::Windows::CompanyFaceSelection
|
|||
const auto width = self->width - self->widgets[widx::scrollview].right - 6;
|
||||
auto str = const_cast<char*>(StringManager::getString(StringIds::buffer_2039));
|
||||
*str++ = ControlCodes::window_colour_2;
|
||||
auto objectPtr = self->object;
|
||||
auto objectPtr = self->object.get();
|
||||
strcpy(str, ObjectManager::ObjectIndexEntry::read(&objectPtr)._name);
|
||||
Gfx::drawStringCentredClipped(*context, x, y, width, Colour::black, StringIds::buffer_2039);
|
||||
}
|
||||
|
|
|
@ -680,7 +680,7 @@ namespace OpenLoco::Ui::Windows::CompanyList
|
|||
auto companyId = company.id();
|
||||
auto companyColour = CompanyManager::getCompanyColour(companyId);
|
||||
|
||||
_graphYData[count] = reinterpret_cast<uint32_t>(&company.performance_index_history[0]);
|
||||
// _graphYData[count] = reinterpret_cast<uint32_t>(&company.performance_index_history[0]);
|
||||
_graphDataStart[count] = maxHistorySize - company.history_size;
|
||||
_graphLineColour[count] = Colour::getShade(companyColour, 6);
|
||||
_graphItemId[count] = companyId;
|
||||
|
@ -771,7 +771,7 @@ namespace OpenLoco::Ui::Windows::CompanyList
|
|||
auto companyId = company.id();
|
||||
auto companyColour = CompanyManager::getCompanyColour(companyId);
|
||||
|
||||
_graphYData[count] = reinterpret_cast<uint32_t>(&company.cargo_units_delivered_history[0]);
|
||||
// _graphYData[count] = reinterpret_cast<uint32_t>(&company.cargo_units_delivered_history[0]);
|
||||
_graphDataStart[count] = maxHistorySize - company.history_size;
|
||||
_graphLineColour[count] = Colour::getShade(companyColour, 6);
|
||||
_graphItemId[count] = companyId;
|
||||
|
@ -862,7 +862,7 @@ namespace OpenLoco::Ui::Windows::CompanyList
|
|||
auto companyId = company.id();
|
||||
auto companyColour = CompanyManager::getCompanyColour(companyId);
|
||||
|
||||
_graphYData[count] = reinterpret_cast<uint32_t>(&company.cargo_units_distance_history[0]);
|
||||
// _graphYData[count] = reinterpret_cast<uint32_t>(&company.cargo_units_distance_history[0]);
|
||||
_graphDataStart[count] = maxHistorySize - company.history_size;
|
||||
_graphLineColour[count] = Colour::getShade(companyColour, 6);
|
||||
_graphItemId[count] = companyId;
|
||||
|
@ -953,7 +953,7 @@ namespace OpenLoco::Ui::Windows::CompanyList
|
|||
auto companyId = company.id();
|
||||
auto companyColour = CompanyManager::getCompanyColour(companyId);
|
||||
|
||||
_graphYData[count] = reinterpret_cast<uint32_t>(&company.companyValueHistory[0]);
|
||||
// _graphYData[count] = reinterpret_cast<uint32_t>(&company.companyValueHistory[0]);
|
||||
_graphDataStart[count] = maxHistorySize - company.history_size;
|
||||
_graphLineColour[count] = Colour::getShade(companyColour, 6);
|
||||
_graphItemId[count] = companyId;
|
||||
|
@ -1072,7 +1072,7 @@ namespace OpenLoco::Ui::Windows::CompanyList
|
|||
|
||||
auto colour = _cargoLineColour[i];
|
||||
|
||||
_graphYData[count] = reinterpret_cast<uint32_t>(&_deliveredCargoPayment[i][0]);
|
||||
// _graphYData[count] = reinterpret_cast<uint32_t>(&_deliveredCargoPayment[i][0]);
|
||||
_graphDataStart[count] = 0;
|
||||
_graphLineColour[count] = Colour::getShade(colour, 6);
|
||||
_graphItemId[count] = i;
|
||||
|
|
|
@ -382,7 +382,7 @@ namespace OpenLoco::Ui::Windows::CompanyWindow
|
|||
if (self->viewports[0] != nullptr)
|
||||
{
|
||||
Ui::Size proposedDims(self->width - 123, self->height - 59);
|
||||
auto& viewport = self->viewports[0];
|
||||
auto viewport = self->viewports[0].get();
|
||||
if (proposedDims.width != viewport->width || proposedDims.height != viewport->height)
|
||||
{
|
||||
viewport->width = proposedDims.width;
|
||||
|
|
|
@ -204,7 +204,7 @@ namespace OpenLoco::Ui::Windows::Construction
|
|||
// 0x004A0EAD
|
||||
Window* openAtTrack(Window* main, TrackElement* track, const Pos2 pos)
|
||||
{
|
||||
auto* viewport = main->viewports[0];
|
||||
auto* viewport = main->viewports[0].get();
|
||||
_backupTileElement = *reinterpret_cast<TileElement*>(track);
|
||||
auto* copyElement = (*_backupTileElement).asTrack();
|
||||
if (copyElement == nullptr)
|
||||
|
@ -299,7 +299,7 @@ namespace OpenLoco::Ui::Windows::Construction
|
|||
// 0x004A147F
|
||||
Window* openAtRoad(Window* main, RoadElement* road, const Pos2 pos)
|
||||
{
|
||||
auto* viewport = main->viewports[0];
|
||||
auto* viewport = main->viewports[0].get();
|
||||
_backupTileElement = *reinterpret_cast<TileElement*>(road);
|
||||
auto* copyElement = (*_backupTileElement).asRoad();
|
||||
if (copyElement == nullptr)
|
||||
|
|
|
@ -1240,7 +1240,7 @@ namespace OpenLoco::Ui::Windows::MapWindow
|
|||
if (window == nullptr)
|
||||
return;
|
||||
|
||||
auto viewport = window->viewports[0];
|
||||
auto viewport = window->viewports[0].get();
|
||||
|
||||
if (viewport == nullptr)
|
||||
return;
|
||||
|
@ -1517,7 +1517,7 @@ namespace OpenLoco::Ui::Windows::MapWindow
|
|||
if (mainWindow == nullptr)
|
||||
return;
|
||||
|
||||
auto viewport = mainWindow->viewports[0];
|
||||
auto viewport = mainWindow->viewports[0].get();
|
||||
|
||||
if (viewport == nullptr)
|
||||
return;
|
||||
|
|
|
@ -507,9 +507,9 @@ namespace OpenLoco::Ui::Windows::ObjectSelectionWindow
|
|||
drawTabs(self, context);
|
||||
|
||||
bool doDefault = true;
|
||||
if (self->object != nullptr)
|
||||
if (self->object.get() != nullptr)
|
||||
{
|
||||
auto objectPtr = self->object;
|
||||
auto objectPtr = self->object.get();
|
||||
auto var = ObjectManager::ObjectIndexEntry::read(&objectPtr)._header;
|
||||
if (var->getType() != ObjectType::townNames && var->getType() != ObjectType::climate)
|
||||
{
|
||||
|
@ -547,7 +547,7 @@ namespace OpenLoco::Ui::Windows::ObjectSelectionWindow
|
|||
return;
|
||||
|
||||
{
|
||||
auto objectPtr = self->object;
|
||||
auto objectPtr = self->object.get();
|
||||
|
||||
drawPreviewImage(
|
||||
ObjectManager::ObjectIndexEntry::read(&objectPtr)._header,
|
||||
|
@ -565,7 +565,7 @@ namespace OpenLoco::Ui::Windows::ObjectSelectionWindow
|
|||
auto buffer = const_cast<char*>(StringManager::getString(StringIds::buffer_2039));
|
||||
|
||||
*buffer++ = ControlCodes::window_colour_2;
|
||||
auto objectPtr = self->object;
|
||||
auto objectPtr = self->object.get();
|
||||
|
||||
strncpy(buffer, ObjectManager::ObjectIndexEntry::read(&objectPtr)._name, 510);
|
||||
|
||||
|
@ -573,7 +573,7 @@ namespace OpenLoco::Ui::Windows::ObjectSelectionWindow
|
|||
}
|
||||
|
||||
{
|
||||
auto objectPtr = self->object;
|
||||
auto objectPtr = self->object.get();
|
||||
|
||||
drawDescription(
|
||||
ObjectManager::ObjectIndexEntry::read(&objectPtr)._header,
|
||||
|
@ -602,7 +602,7 @@ namespace OpenLoco::Ui::Windows::ObjectSelectionWindow
|
|||
|
||||
uint8_t textColour = ControlCodes::colour_black;
|
||||
|
||||
auto objectPtr = self.object;
|
||||
auto objectPtr = self.object.get();
|
||||
if (objectPtr != nullptr)
|
||||
{
|
||||
auto windowObjectName = ObjectManager::ObjectIndexEntry::read(&objectPtr)._name;
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace OpenLoco::Ui::Windows::ProgressBar
|
|||
|
||||
_progressBarValue = value;
|
||||
WindowManager::invalidate(WindowType::progressBar);
|
||||
Ui::ProgressBar::sub_4CF63B();
|
||||
Gfx::render();
|
||||
}
|
||||
|
||||
// 0x004CF78A
|
||||
|
|
|
@ -242,7 +242,7 @@ namespace OpenLoco::Ui::Windows::Town
|
|||
|
||||
uint16_t newHeight = self->height - 59;
|
||||
|
||||
auto& viewport = self->viewports[0];
|
||||
auto viewport = self->viewports[0].get();
|
||||
if (newWidth != viewport->width || newHeight != viewport->height)
|
||||
{
|
||||
viewport->width = newWidth;
|
||||
|
|
|
@ -493,7 +493,7 @@ namespace OpenLoco::Ui::Windows::VehicleList
|
|||
static void setTransportTypeTabs(Window* self)
|
||||
{
|
||||
auto disabledWidgets = self->disabled_widgets >> Widx::tab_trains;
|
||||
auto widget = self->widgets + Widx::tab_trains;
|
||||
auto widget = &self->widgets[Widx::tab_trains];
|
||||
auto tabWidth = widget->right - widget->left;
|
||||
auto tabX = widget->left;
|
||||
for (auto i = 0; i <= Widx::tab_ships - Widx::tab_trains; ++i, ++widget)
|
||||
|
|
|
@ -0,0 +1,270 @@
|
|||
#include "tinyalloc.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef TA_DEBUG
|
||||
extern void print_s(char *);
|
||||
extern void print_i(size_t);
|
||||
#else
|
||||
#define print_s(X)
|
||||
#define print_i(X)
|
||||
#endif
|
||||
|
||||
typedef struct Block Block;
|
||||
|
||||
struct Block {
|
||||
void *addr;
|
||||
Block *next;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
Block *free; // first free block
|
||||
Block *used; // first used block
|
||||
Block *fresh; // first available blank block
|
||||
size_t top; // top free addr
|
||||
} Heap;
|
||||
|
||||
static Heap *heap = NULL;
|
||||
static void *heap_limit = NULL;
|
||||
static size_t heap_split_thresh;
|
||||
static size_t heap_alignment;
|
||||
static size_t heap_max_blocks;
|
||||
|
||||
/**
|
||||
* If compaction is enabled, inserts block
|
||||
* into free list, sorted by addr.
|
||||
* If disabled, add block has new head of
|
||||
* the free list.
|
||||
*/
|
||||
static void insert_block(Block *block) {
|
||||
#ifndef TA_DISABLE_COMPACT
|
||||
Block *ptr = heap->free;
|
||||
Block *prev = NULL;
|
||||
while (ptr != NULL) {
|
||||
if ((size_t)block->addr <= (size_t)ptr->addr) {
|
||||
print_s("insert");
|
||||
print_i((size_t)ptr);
|
||||
break;
|
||||
}
|
||||
prev = ptr;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
if (prev != NULL) {
|
||||
if (ptr == NULL) {
|
||||
print_s("new tail");
|
||||
}
|
||||
prev->next = block;
|
||||
} else {
|
||||
print_s("new head");
|
||||
heap->free = block;
|
||||
}
|
||||
block->next = ptr;
|
||||
#else
|
||||
block->next = heap->free;
|
||||
heap->free = block;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef TA_DISABLE_COMPACT
|
||||
static void release_blocks(Block *scan, Block *to) {
|
||||
Block *scan_next;
|
||||
while (scan != to) {
|
||||
print_s("release");
|
||||
print_i((size_t)scan);
|
||||
scan_next = scan->next;
|
||||
scan->next = heap->fresh;
|
||||
heap->fresh = scan;
|
||||
scan->addr = 0;
|
||||
scan->size = 0;
|
||||
scan = scan_next;
|
||||
}
|
||||
}
|
||||
|
||||
static void compact() {
|
||||
Block *ptr = heap->free;
|
||||
Block *prev;
|
||||
Block *scan;
|
||||
while (ptr != NULL) {
|
||||
prev = ptr;
|
||||
scan = ptr->next;
|
||||
while (scan != NULL &&
|
||||
(size_t)prev->addr + prev->size == (size_t)scan->addr) {
|
||||
print_s("merge");
|
||||
print_i((size_t)scan);
|
||||
prev = scan;
|
||||
scan = scan->next;
|
||||
}
|
||||
if (prev != ptr) {
|
||||
size_t new_size =
|
||||
(size_t)prev->addr - (size_t)ptr->addr + prev->size;
|
||||
print_s("new size");
|
||||
print_i(new_size);
|
||||
ptr->size = new_size;
|
||||
Block *next = prev->next;
|
||||
// make merged blocks available
|
||||
release_blocks(ptr->next, prev->next);
|
||||
// relink
|
||||
ptr->next = next;
|
||||
}
|
||||
ptr = ptr->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ta_init(const void *base, const void *limit, const size_t heap_blocks, const size_t split_thresh, const size_t alignment) {
|
||||
heap = (Heap *)base;
|
||||
heap_limit = limit;
|
||||
heap_split_thresh = split_thresh;
|
||||
heap_alignment = alignment;
|
||||
heap_max_blocks = heap_blocks;
|
||||
|
||||
heap->free = NULL;
|
||||
heap->used = NULL;
|
||||
heap->fresh = (Block *)(heap + 1);
|
||||
heap->top = (size_t)(heap->fresh + heap_blocks);
|
||||
|
||||
Block *block = heap->fresh;
|
||||
size_t i = heap_max_blocks - 1;
|
||||
while (i--) {
|
||||
block->next = block + 1;
|
||||
block++;
|
||||
}
|
||||
block->next = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ta_free(void *free) {
|
||||
Block *block = heap->used;
|
||||
Block *prev = NULL;
|
||||
while (block != NULL) {
|
||||
if (free == block->addr) {
|
||||
if (prev) {
|
||||
prev->next = block->next;
|
||||
} else {
|
||||
heap->used = block->next;
|
||||
}
|
||||
insert_block(block);
|
||||
#ifndef TA_DISABLE_COMPACT
|
||||
compact();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
prev = block;
|
||||
block = block->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Block *alloc_block(size_t num) {
|
||||
Block *ptr = heap->free;
|
||||
Block *prev = NULL;
|
||||
size_t top = heap->top;
|
||||
num = (num + heap_alignment - 1) & -heap_alignment;
|
||||
while (ptr != NULL) {
|
||||
const int is_top = ((size_t)ptr->addr + ptr->size >= top) && ((size_t)ptr->addr + num <= heap_limit);
|
||||
if (is_top || ptr->size >= num) {
|
||||
if (prev != NULL) {
|
||||
prev->next = ptr->next;
|
||||
} else {
|
||||
heap->free = ptr->next;
|
||||
}
|
||||
ptr->next = heap->used;
|
||||
heap->used = ptr;
|
||||
if (is_top) {
|
||||
print_s("resize top block");
|
||||
ptr->size = num;
|
||||
heap->top = (size_t)ptr->addr + num;
|
||||
#ifndef TA_DISABLE_SPLIT
|
||||
} else if (heap->fresh != NULL) {
|
||||
size_t excess = ptr->size - num;
|
||||
if (excess >= heap_split_thresh) {
|
||||
ptr->size = num;
|
||||
Block *split = heap->fresh;
|
||||
heap->fresh = split->next;
|
||||
split->addr = (void *)((size_t)ptr->addr + num);
|
||||
print_s("split");
|
||||
print_i((size_t)split->addr);
|
||||
split->size = excess;
|
||||
insert_block(split);
|
||||
#ifndef TA_DISABLE_COMPACT
|
||||
compact();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
prev = ptr;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
// no matching free blocks
|
||||
// see if any other blocks available
|
||||
size_t new_top = top + num;
|
||||
if (heap->fresh != NULL && new_top <= heap_limit) {
|
||||
ptr = heap->fresh;
|
||||
heap->fresh = ptr->next;
|
||||
ptr->addr = (void *)top;
|
||||
ptr->next = heap->used;
|
||||
ptr->size = num;
|
||||
heap->used = ptr;
|
||||
heap->top = new_top;
|
||||
return ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *ta_alloc(size_t num) {
|
||||
Block *block = alloc_block(num);
|
||||
if (block != NULL) {
|
||||
return block->addr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void memclear(void *ptr, size_t num) {
|
||||
size_t *ptrw = (size_t *)ptr;
|
||||
size_t numw = (num & -sizeof(size_t)) / sizeof(size_t);
|
||||
while (numw--) {
|
||||
*ptrw++ = 0;
|
||||
}
|
||||
num &= (sizeof(size_t) - 1);
|
||||
uint8_t *ptrb = (uint8_t *)ptrw;
|
||||
while (num--) {
|
||||
*ptrb++ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void *ta_calloc(size_t num, size_t size) {
|
||||
num *= size;
|
||||
Block *block = alloc_block(num);
|
||||
if (block != NULL) {
|
||||
memclear(block->addr, num);
|
||||
return block->addr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t count_blocks(Block *ptr) {
|
||||
size_t num = 0;
|
||||
while (ptr != NULL) {
|
||||
num++;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
size_t ta_num_free() {
|
||||
return count_blocks(heap->free);
|
||||
}
|
||||
|
||||
size_t ta_num_used() {
|
||||
return count_blocks(heap->used);
|
||||
}
|
||||
|
||||
size_t ta_num_fresh() {
|
||||
return count_blocks(heap->fresh);
|
||||
}
|
||||
|
||||
bool ta_check() {
|
||||
return heap_max_blocks == ta_num_free() + ta_num_used() + ta_num_fresh();
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
bool ta_init(const void *base, const void *limit, const size_t heap_blocks, const size_t split_thresh, const size_t alignment);
|
||||
void *ta_alloc(size_t num);
|
||||
void *ta_calloc(size_t num, size_t size);
|
||||
bool ta_free(void *ptr);
|
||||
|
||||
size_t ta_num_free();
|
||||
size_t ta_num_used();
|
||||
size_t ta_num_fresh();
|
||||
bool ta_check();
|
Loading…
Reference in New Issue