diff --git a/mods/CMakeLists.txt b/mods/CMakeLists.txt index ec265a883..1cc6c2404 100644 --- a/mods/CMakeLists.txt +++ b/mods/CMakeLists.txt @@ -16,13 +16,16 @@ target_link_libraries(core dl) add_library(server SHARED src/server/server.cpp src/server/server_properties.cpp src/server/playerdata.cpp) target_link_libraries(server core dl SDL pthread) +add_library(screenshot SHARED src/screenshot/screenshot.c) +target_link_libraries(screenshot GLESv1_CM freeimage) + add_library(extra SHARED src/extra.c src/extra.cpp src/cxx11_util.cpp) -target_link_libraries(extra core dl server) +target_link_libraries(extra core dl server screenshot) find_package(glfw3 3.3 REQUIRED) add_library(compat SHARED src/compat.c) -target_link_libraries(compat core extra SDL GLESv1_CM GLESv2 X11 dl freeimage glfw Xfixes) +target_link_libraries(compat core extra screenshot SDL GLESv1_CM GLESv2 X11 dl glfw Xfixes) # Force GLESv1 Link target_link_options(compat PRIVATE "-Wl,--no-as-needed") diff --git a/mods/src/compat.c b/mods/src/compat.c index 40240246f..fb2381339 100644 --- a/mods/src/compat.c +++ b/mods/src/compat.c @@ -1,10 +1,7 @@ #define _GNU_SOURCE -#include #include -#include - #define GLFW_EXPOSE_NATIVE_X11 #define GLFW_INCLUDE_ES1 #include @@ -20,6 +17,7 @@ #include #include "extra.h" +#include "screenshot/screenshot.h" static GLFWwindow *glfw_window; static Display *x11_display; @@ -185,8 +183,6 @@ static void glfw_scroll(__attribute__((unused)) GLFWwindow *window, __attribute_ // Init GLFW HOOK(SDL_WM_SetCaption, void, (const char *title, __attribute__((unused)) const char *icon)) { - FreeImage_Initialise(0); - // Don't Enable GLFW In Server Mode if (!is_server) { glfwSetErrorCallback(glfw_error); @@ -256,63 +252,6 @@ static void toggle_fullscreen() { is_fullscreen = !is_fullscreen; } -// 4 (Year + 1 (Hyphen) + 2 (Month) + 1 (Hyphen) + 2 (Day) + 1 (Underscore) + 2 (Hour) + 1 (Period) + 2 (Minute) + 1 (Period) + 2 (Second) + 1 (Terminator) -#define TIME_SIZE 20 - -// Take Screenshot -static void screenshot() { - time_t rawtime; - struct tm *timeinfo; - - time(&rawtime); - timeinfo = localtime(&rawtime); - char time[TIME_SIZE]; - strftime(time, TIME_SIZE, "%Y-%m-%d_%H.%M.%S", timeinfo); - - char *screenshots = NULL; - asprintf(&screenshots, "%s/.minecraft/screenshots", getenv("HOME")); - - int num = 1; - char *file = NULL; - asprintf(&file, "%s/%s.png", screenshots, time); - while (access(file, F_OK) != -1) { - asprintf(&file, "%s/%s-%i.png", screenshots, time, num); - num++; - } - - int width; - int height; - glfwGetWindowSize(glfw_window, &width, &height); - - int line_size = width * 3; - int size = height * line_size; - - unsigned char pixels[size]; - glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels); - -#if SDL_BYTEORDER == SDL_LIL_ENDIAN - // Swap Red And Blue - for (int i = 0; i < (size / 3); i++) { - int pixel = i * 3; - int red = pixels[pixel]; - int blue = pixels[pixel + 2]; - pixels[pixel] = blue; - pixels[pixel + 2] = red; - } -#endif - - FIBITMAP *image = FreeImage_ConvertFromRawBits(pixels, width, height, line_size, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, 0); - if (!FreeImage_Save(FIF_PNG, image, file, 0)) { - INFO("Screenshot Failed: %s", file); - } else { - INFO("Screenshot Saved: %s", file); - } - FreeImage_Unload(image); - - free(file); - free(screenshots); -} - // Intercept SDL Events HOOK(SDL_PollEvent, int, (SDL_Event *event)) { // Process GLFW Events @@ -339,7 +278,7 @@ HOOK(SDL_PollEvent, int, (SDL_Event *event)) { toggle_fullscreen(); handled = 1; } else if (event->key.keysym.sym == SDLK_F2) { - screenshot(); + take_screenshot(); handled = 1; } else if (event->key.keysym.sym == SDLK_F1) { extra_hide_gui(); diff --git a/mods/src/extra.cpp b/mods/src/extra.cpp index b27683bbb..00e0cb1de 100644 --- a/mods/src/extra.cpp +++ b/mods/src/extra.cpp @@ -9,6 +9,7 @@ #include "extra.h" #include "cxx11_util.h" +#include "screenshot/screenshot.h" #include "minecraft.h" @@ -24,6 +25,11 @@ extern "C" { return create_cxx11_string(str.c_str()); } + // Take Screenshot Using TripodCamera + static void AppPlatform_linux_saveScreenshot_injection(__attribute__((unused)) unsigned char *app_platform, __attribute__((unused)) std::string const& param1, __attribute__((unused)) std::string const& param_2) { + take_screenshot(); + } + // Open Sign Screen static void LocalPlayer_openTextEdit_injection(unsigned char *local_player, unsigned char *sign) { if (*(int *)(sign + 0x18) == 4) { @@ -91,6 +97,7 @@ extern "C" { item_instance = (*ItemInstance_damage)(item_instance, *item_dye_powder, 1, i); (*FillingContainer_addItem)(filling_container, item_instance); } + inventory_add_item(filling_container, *item_camera, false); // Add Tiles inventory_add_item(filling_container, *tile_water, true); inventory_add_item(filling_container, *tile_lava, true); @@ -160,9 +167,27 @@ extern "C" { } } + // Enable TripodCameraRenderer + static unsigned char *EntityRenderDispatcher_injection(unsigned char *dispatcher) { + // Call Original Method + (*EntityRenderDispatcher)(dispatcher); + + // Register TripodCameraRenderer + unsigned char *renderer = (unsigned char *) ::operator new(0x193); + (*TripodCameraRenderer)(renderer); + (*EntityRenderDispatcher_assign)(dispatcher, (unsigned char) 0x5, renderer); + + return dispatcher; + } + __attribute((constructor)) static void init() { // Implement AppPlatform::readAssetFile So Translations Work overwrite((void *) AppPlatform_readAssetFile, (void *) AppPlatform_readAssetFile_injection); + // Implement AppPlatform_linux::saveScreenshot So Cameras Work + patch_address(AppPlatform_linux_saveScreenshot_vtable_addr, (void *) AppPlatform_linux_saveScreenshot_injection); + + // Enable TripodCameraRenderer + overwrite_calls((void *) EntityRenderDispatcher, (void *) EntityRenderDispatcher_injection); if (extra_has_feature("Fix Sign Placement")) { // Fix Signs diff --git a/mods/src/minecraft.h b/mods/src/minecraft.h index 499840324..b22be3a0f 100644 --- a/mods/src/minecraft.h +++ b/mods/src/minecraft.h @@ -16,6 +16,7 @@ static unsigned char **item_snowball = (unsigned char **) 0x17bbb0; static unsigned char **item_shears = (unsigned char **) 0x17bbf0; static unsigned char **item_egg = (unsigned char **) 0x17bbd0; static unsigned char **item_dye_powder = (unsigned char **) 0x17bbe0; +static unsigned char **item_camera = (unsigned char **) 0x17bc14; static unsigned char **tile_water = (unsigned char **) 0x181b3c; static unsigned char **tile_lava = (unsigned char **) 0x181cc8; @@ -246,6 +247,19 @@ static NbtIo_read_t NbtIo_read = (NbtIo_read_t) 0xb98cc; typedef void (*Inventory_clearInventoryWithDefault_t)(unsigned char *inventory); static Inventory_clearInventoryWithDefault_t Inventory_clearInventoryWithDefault = (Inventory_clearInventoryWithDefault_t) 0x8e7c8; +// TripodCameraRenderer + +typedef unsigned char *(*TripodCameraRenderer_t)(unsigned char *renderer); +static TripodCameraRenderer_t TripodCameraRenderer = (TripodCameraRenderer_t) 0x6583c; + +// EntityRenderDispatcher + +typedef unsigned char *(*EntityRenderDispatcher_t)(unsigned char *dispatcher); +static EntityRenderDispatcher_t EntityRenderDispatcher = (EntityRenderDispatcher_t) 0x6096c; + +typedef void (*EntityRenderDispatcher_assign_t)(unsigned char *dispatcher, unsigned char entity_id, unsigned char *renderer); +static EntityRenderDispatcher_assign_t EntityRenderDispatcher_assign = (EntityRenderDispatcher_assign_t) 0x6094c; + // Method That Require C++ Types #ifdef __cplusplus @@ -255,6 +269,9 @@ static Inventory_clearInventoryWithDefault_t Inventory_clearInventoryWithDefault // AppPlatform +typedef void (*AppPlatform_saveScreenshot_t)(unsigned char *app_platform, std::string const& param1, std::string const& param_2); +static void *AppPlatform_linux_saveScreenshot_vtable_addr = (void *) 0x102160; + typedef cxx11_string (*AppPlatform_readAssetFile_t)(unsigned char *app_platform, std::string const& path); static AppPlatform_readAssetFile_t AppPlatform_readAssetFile = (AppPlatform_readAssetFile_t) 0x12b10; diff --git a/mods/src/screenshot/screenshot.c b/mods/src/screenshot/screenshot.c new file mode 100644 index 000000000..cf77f247f --- /dev/null +++ b/mods/src/screenshot/screenshot.c @@ -0,0 +1,79 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include + +#include + +#include + +#include + +#include "screenshot.h" + +// 4 (Year + 1 (Hyphen) + 2 (Month) + 1 (Hyphen) + 2 (Day) + 1 (Underscore) + 2 (Hour) + 1 (Period) + 2 (Minute) + 1 (Period) + 2 (Second) + 1 (Terminator) +#define TIME_SIZE 20 + +// Take Screenshot +void take_screenshot() { + time_t rawtime; + struct tm *timeinfo; + + time(&rawtime); + timeinfo = localtime(&rawtime); + char time[TIME_SIZE]; + strftime(time, TIME_SIZE, "%Y-%m-%d_%H.%M.%S", timeinfo); + + char *screenshots = NULL; + asprintf(&screenshots, "%s/.minecraft/screenshots", getenv("HOME")); + + int num = 1; + char *file = NULL; + asprintf(&file, "%s/%s.png", screenshots, time); + while (access(file, F_OK) != -1) { + asprintf(&file, "%s/%s-%i.png", screenshots, time, num); + num++; + } + + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + int x = viewport[0]; + int y = viewport[1]; + int width = viewport[2]; + int height = viewport[3]; + + int line_size = width * 3; + int size = height * line_size; + + unsigned char pixels[size]; + glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels); + +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + // Swap Red And Blue + for (int i = 0; i < (size / 3); i++) { + int pixel = i * 3; + int red = pixels[pixel]; + int blue = pixels[pixel + 2]; + pixels[pixel] = blue; + pixels[pixel + 2] = red; + } +#endif + + FIBITMAP *image = FreeImage_ConvertFromRawBits(pixels, width, height, line_size, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, 0); + if (!FreeImage_Save(FIF_PNG, image, file, 0)) { + INFO("Screenshot Failed: %s", file); + } else { + INFO("Screenshot Saved: %s", file); + } + FreeImage_Unload(image); + + free(file); + free(screenshots); +} + +// Init FreeImage +__attribute__((constructor)) static void init() { + FreeImage_Initialise(0); +} \ No newline at end of file diff --git a/mods/src/screenshot/screenshot.h b/mods/src/screenshot/screenshot.h new file mode 100644 index 000000000..45773a3ed --- /dev/null +++ b/mods/src/screenshot/screenshot.h @@ -0,0 +1,15 @@ +#ifndef SCREENSHOT_H + +#define SCREENSHOT_H + +#ifdef __cplusplus +extern "C" { +#endif + +void take_screenshot(); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file