diff --git a/mods/CMakeLists.txt b/mods/CMakeLists.txt index 6500981..5431e98 100644 --- a/mods/CMakeLists.txt +++ b/mods/CMakeLists.txt @@ -10,26 +10,48 @@ add_subdirectory(../core core) include_directories(include) -add_library(core SHARED src/core.c) +find_package(glfw3 3.3 REQUIRED) + +add_library(compat SHARED src/compat/compat.c) +target_link_libraries(compat feature input screenshot SDL GLESv1_CM GLESv2 X11 dl glfw Xfixes) +# Force GLESv1 Link +target_link_options(compat PRIVATE "-Wl,--no-as-needed") + +add_library(readdir SHARED src/compat/readdir.c) + +add_library(core SHARED src/core/core.c) target_link_libraries(core dl) +add_library(feature SHARED src/feature/feature.c) + 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) +target_link_libraries(server core feature 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 screenshot GLESv1_CM) +add_library(camera SHARED src/camera/camera.cpp) +target_link_libraries(camera core screenshot) -add_library(override SHARED src/override.c) +add_library(game_mode SHARED src/game_mode/game_mode.c src/game_mode/game_mode.cpp) +target_link_libraries(game_mode core) + +add_library(input SHARED src/input/input.c src/input/input.cpp) +target_link_libraries(input core feature SDL) + +add_library(util SHARED src/util/cxx11_util.cpp) + +add_library(misc SHARED src/misc/misc.c src/misc/misc.cpp) +target_link_libraries(misc core feature util) + +add_library(options SHARED src/options/options.c) +target_link_libraries(options core feature) + +add_library(override SHARED src/override/override.c) target_link_libraries(override dl) -find_package(glfw3 3.3 REQUIRED) +add_library(textures SHARED src/textures/textures.cpp) +target_link_libraries(textures core feature GLESv1_CM) -add_library(compat SHARED src/compat.c) -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") - -add_library(readdir SHARED src/readdir.c) +add_library(init SHARED src/init/init.c) +target_link_libraries(init compat server game_mode camera input misc options textures) diff --git a/mods/src/camera/camera.cpp b/mods/src/camera/camera.cpp new file mode 100644 index 0000000..001115a --- /dev/null +++ b/mods/src/camera/camera.cpp @@ -0,0 +1,40 @@ +#include + +#include "../screenshot/screenshot.h" +#include "../init/init.h" + +#include "../minecraft.h" + +// 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(); +} + +// 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; +} + +// Display Smoke From TripodCamera Higher +static void TripodCamera_tick_Level_addParticle_call_injection(unsigned char *level, std::string const& particle, float x, float y, float z, float deltaX, float deltaY, float deltaZ, int count) { + // Call Original Method + (*Level_addParticle)(level, particle, x, y + 0.5, z, deltaX, deltaY, deltaZ, count); +} + +void init_camera() { + // 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); + // Display Smoke From TripodCamera Higher + overwrite_call((void *) 0x87dc4, (void *) TripodCamera_tick_Level_addParticle_call_injection); +} \ No newline at end of file diff --git a/mods/src/compat.c b/mods/src/compat/compat.c similarity index 96% rename from mods/src/compat.c rename to mods/src/compat/compat.c index 42e85f0..831405e 100644 --- a/mods/src/compat.c +++ b/mods/src/compat/compat.c @@ -16,8 +16,10 @@ #include -#include "extra.h" -#include "screenshot/screenshot.h" +#include "../feature/feature.h" +#include "../input/input.h" +#include "../screenshot/screenshot.h" +#include "../init/init.h" static GLFWwindow *glfw_window; static Display *x11_display; @@ -125,13 +127,13 @@ static void glfw_key(__attribute__((unused)) GLFWwindow *window, int key, int sc event.key.keysym.sym = glfw_key_to_sdl_key(key); SDL_PushEvent(&event); if (key == GLFW_KEY_BACKSPACE && !up) { - extra_key_press((char) '\b'); + input_key_press((char) '\b'); } } // Pass Text To Minecraft static void glfw_char(__attribute__((unused)) GLFWwindow *window, unsigned int codepoint) { - extra_key_press((char) codepoint); + input_key_press((char) codepoint); } static double last_mouse_x = 0; @@ -281,17 +283,17 @@ HOOK(SDL_PollEvent, int, (SDL_Event *event)) { take_screenshot(); handled = 1; } else if (event->key.keysym.sym == SDLK_F1) { - extra_hide_gui(); + input_hide_gui(); handled = 1; } else if (event->key.keysym.sym == SDLK_F5) { - extra_third_person(); + input_third_person(); handled = 1; } } else if (event->type == SDL_MOUSEBUTTONDOWN || event->type == SDL_MOUSEBUTTONUP) { if (event->button.button == SDL_BUTTON_RIGHT) { - extra_set_is_right_click(event->button.state != SDL_RELEASED); + input_set_is_right_click(event->button.state != SDL_RELEASED); } else if (event->button.button == SDL_BUTTON_LEFT) { - extra_set_is_left_click(event->button.state != SDL_RELEASED); + input_set_is_left_click(event->button.state != SDL_RELEASED); } } @@ -411,8 +413,8 @@ HOOK(SDL_GetWMInfo, int, (SDL_SysWMinfo *info)) { #include // Use VirGL -__attribute__((constructor)) static void init() { - int mode = extra_get_mode(); +void init_compat() { + int mode = feature_get_mode(); if (mode != 1) { // Force Software Rendering When Not In Native Mode setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1); diff --git a/mods/src/readdir.c b/mods/src/compat/readdir.c similarity index 100% rename from mods/src/readdir.c rename to mods/src/compat/readdir.c diff --git a/mods/src/core.c b/mods/src/core/core.c similarity index 100% rename from mods/src/core.c rename to mods/src/core/core.c diff --git a/mods/src/extra.c b/mods/src/extra.c deleted file mode 100644 index 74f2d60..0000000 --- a/mods/src/extra.c +++ /dev/null @@ -1,325 +0,0 @@ -#include -#include - -#include - -#include "extra.h" -#include "server/server.h" - -#include "minecraft.h" - -static int mob_spawning = 0; -// Override Mob Spawning -static uint32_t LevelData_getSpawnMobs_injection(__attribute__((unused)) unsigned char *level_data) { - return mob_spawning; -} - -// Store Right-Click Status -static int is_right_click = 0; -void extra_set_is_right_click(int val) { - is_right_click = val; -} - -// Enable Bow & Arrow Fix -static int fix_bow = 0; - -// Store Function Input -static int hide_gui_toggle = 0; -void extra_hide_gui() { - hide_gui_toggle++; -} -static int third_person_toggle = 0; -void extra_third_person() { - third_person_toggle++; -} - -// Handle Input Fixes -static void Minecraft_tickInput_injection(unsigned char *minecraft) { - // Call Original Method - (*Minecraft_tickInput)(minecraft); - - if (fix_bow && !is_right_click) { - // GameMode Is Offset From minecraft By 0x160 - // Player Is Offset From minecraft By 0x18c - unsigned char *game_mode = *(unsigned char **) (minecraft + 0x160); - unsigned char *player = *(unsigned char **) (minecraft + 0x18c); - if (player != NULL && game_mode != NULL && (*Player_isUsingItem)(player)) { - unsigned char *game_mode_vtable = *(unsigned char **) game_mode; - GameMode_releaseUsingItem_t GameMode_releaseUsingItem = *(GameMode_releaseUsingItem_t *) (game_mode_vtable + 0x5c); - (*GameMode_releaseUsingItem)(game_mode, player); - } - } - - // Clear Unused Sign Input - extra_clear_input(); - - // Handle Functions - unsigned char *options = minecraft + 0x3c; - if (hide_gui_toggle % 2 != 0) { - // Toggle Hide GUI - *(options + 0xec) = *(options + 0xec) ^ 1; - } - hide_gui_toggle = 0; - if (third_person_toggle % 2 != 0) { - // Toggle Third Person - *(options + 0xed) = *(options + 0xed) ^ 1; - } - third_person_toggle = 0; -} - -#include - -// Block UI Interaction When Mouse Is Locked -static int32_t Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection(unsigned char *minecraft) { - if (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE) { - // Call Original Method - return (*Minecraft_isCreativeMode)(minecraft); - } else { - // Disable Item Drop Ticking - return 1; - } -} - -// Block UI Interaction When Mouse Is Locked -static void Gui_handleClick_injection(unsigned char *this, int32_t param_2, int32_t param_3, int32_t param_4) { - if (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE) { - // Call Original Method - (*Gui_handleClick)(this, param_2, param_3, param_4); - } -} - -static int is_survival = -1; - -// Patch Game Mode -static void set_is_survival(int new_is_survival) { - if (is_survival != new_is_survival) { - INFO("Setting Game Mode: %s", new_is_survival ? "Survival" : "Creative"); - - // Correct Inventpry UI - unsigned char inventory_patch[4] = {new_is_survival ? 0x00 : 0x01, 0x30, 0xa0, 0xe3}; - patch((void *) 0x16efc, inventory_patch); - - // Use Correct Size For GameMode Object - unsigned char size_patch[4] = {new_is_survival ? 0x24 : 0x18, 0x00, 0xa0, 0xe3}; - patch((void *) 0x16ee4, size_patch); - - // Replace Creator Constructor With CreativeMode Or SurvivalMode Constructor - overwrite(Creator, new_is_survival ? SurvivalMode : CreativeMode); - - is_survival = new_is_survival; - } -} - -// Handle Gamemode Switching -static void Minecraft_setIsCreativeMode_injection(unsigned char *this, int32_t new_game_mode) { - set_is_survival(!new_game_mode); - - // Call Original Method - (*Minecraft_setIsCreativeMode)(this, new_game_mode); -} - -// Get Custom Username -static char *get_username() { - char *username = getenv("MCPI_USERNAME"); - if (username == NULL) { - username = "StevePi"; - } - return username; -} - -static int fancy_graphics; -static int peaceful_mode; -static int anaglyph; -static int smooth_lighting; -// Configure Options -static void Minecraft_init_injection(unsigned char *this) { - // Call Original Method - (*Minecraft_init)(this); - - unsigned char *options = this + 0x3c; - // Enable Fancy Graphics - *(options + 0x17) = fancy_graphics; - // Enable Crosshair In Touch GUI - *(options + 0x105) = 1; - // Peaceful Mode - *(int32_t *) (options + 0xe8) = peaceful_mode ? 0 : 2; - // 3D Anaglyph - *(options + 0x15) = anaglyph; - // Smooth Lighting - *(options + 0x18) = smooth_lighting; -} - -// Is Dedicated Server -static int is_server = 0; - -// Check For Feature -int extra_has_feature(const char *name) { - char *env = is_server ? (char *) server_get_features() : getenv("MCPI_FEATURES"); - char *features = strdup(env != NULL ? env : ""); - char *tok = strtok(features, "|"); - int ret = 0; - while (tok != NULL) { - if (strcmp(tok, name) == 0) { - ret = 1; - break; - } - tok = strtok(NULL, "|"); - } - free(features); - if (!is_server) { - INFO("Feature: %s: %s", name, ret ? "Enabled" : "Disabled"); - } - return ret; -} - -// Get Graphics Mode -int extra_get_mode() { - char *mode = getenv("MCPI_MODE"); - if (mode == NULL) { - ERR("%s", "MCPI Mode Not Specified"); - } else if (strcmp("virgl", mode) == 0) { - return 0; - } else if (strcmp("native", mode) == 0) { - return 1; - } else if (strcmp("server", mode) == 0) { - return 2; - } else { - ERR("Inavlid MCPI_MODE: %s", mode); - } -} - -// Enable Touch GUI -static int32_t Minecraft_isTouchscreen_injection(__attribute__((unused)) unsigned char *minecraft) { - return 1; -} - -// Store Left Click (0 = Not Pressed, 1 = Pressed, 2 = Repeat) -// This Is Set To Repeat After First Attempted Left-Click Build Interaction -static int is_left_click = 0; -void extra_set_is_left_click(int val) { - if ((is_left_click == 0 && val == 1) || (is_left_click != 0 && val == 0) || (is_left_click == 1 && val == 2)) { - is_left_click = val; - } -} - -// Add Attacking To MouseBuildInput -static int32_t MouseBuildInput_tickBuild_injection(unsigned char *mouse_build_input, unsigned char *local_player, uint32_t *build_action_intention_return) { - // Call Original Method - int32_t ret = (*MouseBuildInput_tickBuild)(mouse_build_input, local_player, build_action_intention_return); - - // Use Attack/Place BuildActionIntention If No Other Valid BuildActionIntention Was Selected And This Was Not A Repeated Left Click - if (ret != 0 && is_left_click == 1 && *build_action_intention_return == 0xa) { - // Get Target HitResult - unsigned char *minecraft = *(unsigned char **) (local_player + 0xc90); - unsigned char *hit_result = minecraft + 0xc38; - int32_t hit_result_type = *(int32_t *) hit_result; - // Check if The Target Is An Entity Using HitResult - if (hit_result_type == 1) { - // Change BuildActionIntention To Attack/Place Mode (Place Will Not Happen Because The HitResult Is An Entity) - *build_action_intention_return = 0x8; - } - // Block Repeat Changes Without Releasing Left Click - is_left_click = 2; - } - - return ret; -} - -__attribute__((constructor)) static void init() { - is_server = extra_get_mode() == 2; - if (is_server) { - server_init(); - } - - int touch_gui = !is_server && extra_has_feature("Touch GUI"); - if (touch_gui) { - // Main UI - overwrite((void *) Minecraft_isTouchscreen, Minecraft_isTouchscreen_injection); - // Force Correct Toolbar Size - unsigned char toolbar_patch[4] = {0x01, 0x00, 0x50, 0xe3}; - patch((void *) 0x257b0, toolbar_patch); - } - - // Dynamic Game Mode Switching - set_is_survival(1); - overwrite_calls((void *) Minecraft_setIsCreativeMode, Minecraft_setIsCreativeMode_injection); - - // Disable Item Dropping Using The Cursor When Cursor Is Hidden - overwrite_call((void *) 0x27800, Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection); - // Disable Opening Inventory Using The Cursor When Cursor Is Hidden - overwrite_calls((void *) Gui_handleClick, Gui_handleClick_injection); - - // Enable Bow & Arrow Fix - fix_bow = extra_has_feature("Fix Bow & Arrow"); - // Fix Bow & Arrow + Clear Unused Sign Input - overwrite_calls((void *) Minecraft_tickInput, Minecraft_tickInput_injection); - - if (extra_has_feature("Fix Attacking")) { - // Allow Attacking Mobs - patch_address(MouseBuildInput_tickBuild_vtable_addr, (void *) MouseBuildInput_tickBuild_injection); - } - - mob_spawning = extra_has_feature("Mob Spawning"); - // Set Mob Spawning - overwrite((void *) LevelData_getSpawnMobs, LevelData_getSpawnMobs_injection); - - // Replace CreatorLevel With ServerLevel (This Fixes Beds And Mob Spawning) - unsigned char level_patch[4] = {0x68, 0x7e, 0x01, 0xeb}; - patch((void *) 0x16f84, level_patch); - - // Allocate Correct Size For ServerLevel - unsigned char level_size_patch[4] = {0x94, 0x0b, 0x00, 0x00}; - patch((void *) 0x17004, level_size_patch); - - // Enable Fancy Graphics - fancy_graphics = extra_has_feature("Fancy Graphics"); - // Peaceful Mode - peaceful_mode = extra_has_feature("Peaceful Mode"); - // 3D Anaglyph - anaglyph = extra_has_feature("3D Anaglyph"); - - // Set Options - overwrite_calls((void *) Minecraft_init, Minecraft_init_injection); - - // Allow Connecting To Non-Pi Servers - unsigned char server_patch[4] = {0x0f, 0x00, 0x00, 0xea}; - patch((void *) 0x6dc70, server_patch); - - // Change Username - const char *username; - if (is_server) { - // MOTD is Username - username = server_get_motd(); - } else { - username = get_username(); - INFO("Setting Username: %s", username); - } - if (strcmp(*default_username, "StevePi") != 0) { - ERR("%s", "Default Username Is Invalid"); - } - patch_address((void *) default_username, (void *) username); - - if (extra_has_feature("Disable Autojump By Default")) { - // Disable Autojump By Default - unsigned char autojump_patch[4] = {0x00, 0x30, 0xa0, 0xe3}; - patch((void *) 0x44b90, autojump_patch); - } - - // Show Block Outlines - int block_outlines = extra_has_feature("Show Block Outlines"); - unsigned char outline_patch[4] = {block_outlines ? !touch_gui : touch_gui, 0x00, 0x50, 0xe3}; - patch((void *) 0x4a210, outline_patch); - - if (extra_has_feature("Remove Invalid Item Background")) { - // Remove Invalid Item Background (A Red Background That Appears For Items That Are Not Obtainable Without Modding/Inventory Editing) - unsigned char invalid_item_background_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; - patch((void *) 0x63c98, invalid_item_background_patch); - } - - smooth_lighting = extra_has_feature("Smooth Lighting"); - if (smooth_lighting) { - // Enable Smooth Lighting - unsigned char smooth_lighting_patch[4] = {0x01, 0x00, 0x53, 0xe3}; - patch((void *) 0x59ea4, smooth_lighting_patch); - } -} diff --git a/mods/src/extra.cpp b/mods/src/extra.cpp deleted file mode 100644 index 4ecc496..0000000 --- a/mods/src/extra.cpp +++ /dev/null @@ -1,307 +0,0 @@ -#include -#include -#include -#include - -#include - -#include - -#include - -#include "extra.h" -#include "cxx11_util.h" -#include "screenshot/screenshot.h" - -#include "minecraft.h" - -#include - -extern "C" { - // Read Asset File - static cxx11_string AppPlatform_readAssetFile_injection(__attribute__((unused)) unsigned char *app_platform, std::string const& path) { - std::string full_path("./data/"); - full_path.append(path); - std::ifstream stream(full_path); - std::string str((std::istreambuf_iterator(stream)), std::istreambuf_iterator()); - 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) { - unsigned char *minecraft = *(unsigned char **) (local_player + 0xc90); - unsigned char *screen = (unsigned char *) ::operator new(0xd0); - screen = (*TextEditScreen)(screen, sign); - (*Minecraft_setScreen)(minecraft, screen); - } - } - - #define BACKSPACE_KEY 8 - - static int is_valid_key(char key) { - return (key >= 32 && key <= 126) || key == BACKSPACE_KEY; - } - - // Store Text Input - std::vector input; - void extra_key_press(char key) { - if (is_valid_key(key)) { - input.push_back(key); - } - } - void extra_clear_input() { - input.clear(); - } - - // Handle Text Input - static void TextEditScreen_updateEvents_injection(unsigned char *screen) { - // Call Original Method - (*Screen_updateEvents)(screen); - - if (*(char *)(screen + 4) == '\0') { - uint32_t vtable = *((uint32_t *) screen); - for (char key : input) { - if (key == BACKSPACE_KEY) { - // Handle Backspace - (*(Screen_keyPressed_t *) (vtable + 0x6c))(screen, BACKSPACE_KEY); - } else { - // Handle Nrmal Key - (*(Screen_keyboardNewChar_t *) (vtable + 0x70))(screen, key); - } - } - } - extra_clear_input(); - } - - #define ITEM_INSTANCE_SIZE 0xc - - static void inventory_add_item(unsigned char *inventory, unsigned char *item, bool is_tile) { - unsigned char *item_instance = (unsigned char *) ::operator new(ITEM_INSTANCE_SIZE); - item_instance = (*(is_tile ? ItemInstance_constructor_tile : ItemInstance_constructor_item))(item_instance, item); - (*FillingContainer_addItem)(inventory, item_instance); - } - - static int32_t Inventory_setupDefault_FillingContainer_addItem_call_injection(unsigned char *filling_container, unsigned char *item_instance) { - // Call Original - int32_t ret = (*FillingContainer_addItem)(filling_container, item_instance); - - // Add Items - inventory_add_item(filling_container, *Item_flintAndSteel, false); - inventory_add_item(filling_container, *Item_snowball, false); - inventory_add_item(filling_container, *Item_egg, false); - inventory_add_item(filling_container, *Item_shears, false); - for (int i = 0; i < 15; i++) { - unsigned char *item_instance = (unsigned char *) ::operator new(0xc); - item_instance = (*ItemInstance_constructor_item_extra)(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); - inventory_add_item(filling_container, *Tile_calmWater, true); - inventory_add_item(filling_container, *Tile_calmLava, true); - inventory_add_item(filling_container, *Tile_glowingObsidian, true); - inventory_add_item(filling_container, *Tile_web, true); - inventory_add_item(filling_container, *Tile_topSnow, true); - inventory_add_item(filling_container, *Tile_ice, true); - inventory_add_item(filling_container, *Tile_invisible_bedrock, true); - - return ret; - } - - static void Minecraft_tick_injection(unsigned char *minecraft, int32_t param_1, int32_t param_2) { - // Call Original Method - (*Minecraft_tick)(minecraft, param_1, param_2); - - // Tick Dynamic Textures - unsigned char *textures = *(unsigned char **) (minecraft + 0x164); - if (textures != NULL) { - (*Textures_tick)(textures, true); - } - } - - // Get Minecraft From Screen - static unsigned char *get_minecraft_from_screen(unsigned char *screen) { - return *(unsigned char **) (screen + 0x14); - } - - // Redirect Create World Button To SimpleLevelChooseScreen - #define WORLD_NAME "world" - #define SIMPLE_LEVEL_CHOOSE_SCREEN_SIZE 0x68 - static void SelectWorldScreen_tick_injection(unsigned char *screen) { - bool create_world = *(bool *) (screen + 0xfc); - if (create_world) { - // Get New World Name - std::string new_name; - (*SelectWorldScreen_getUniqueLevelName)(new_name, screen, WORLD_NAME); - // Create SimpleLevelChooseScreen - unsigned char *new_screen = (unsigned char *) ::operator new(SIMPLE_LEVEL_CHOOSE_SCREEN_SIZE); - (*SimpleChooseLevelScreen)(new_screen, new_name); - // Set Screen - unsigned char *minecraft = get_minecraft_from_screen(screen); - (*Minecraft_setScreen)(minecraft, new_screen); - // Finish - *(bool *) (screen + 0xf9) = true; - } else { - (*SelectWorldScreen_tick)(screen); - } - } - static void Touch_SelectWorldScreen_tick_injection(unsigned char *screen) { - bool create_world = *(bool *) (screen + 0x154); - if (create_world) { - // Get New World Name - std::string new_name; - (*Touch_SelectWorldScreen_getUniqueLevelName)(new_name, screen, WORLD_NAME); - // Create SimpleLevelChooseScreen - unsigned char *new_screen = (unsigned char *) ::operator new(SIMPLE_LEVEL_CHOOSE_SCREEN_SIZE); - (*SimpleChooseLevelScreen)(new_screen, new_name); - // Set Screen - unsigned char *minecraft = get_minecraft_from_screen(screen); - (*Minecraft_setScreen)(minecraft, new_screen); - // Finish - *(bool *) (screen + 0x151) = true; - } else { - (*Touch_SelectWorldScreen_tick)(screen); - } - } - - // 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; - } - // Display Smoke From TripodCamera Higher - static void Level_addParticle_injection(unsigned char *level, std::string const& particle, float x, float y, float z, float deltaX, float deltaY, float deltaZ, int count) { - // Call Original Method - (*Level_addParticle)(level, particle, x, y + 0.5, z, deltaX, deltaY, deltaZ, count); - } - - // Fix Grass And Leaves Inventory Rendering When The gui_blocks Atlas Is Disabled - static float ItemRenderer_renderGuiItemCorrect_injection(unsigned char *font, unsigned char *textures, unsigned char *item_instance, int32_t param_1, int32_t param_2) { - int32_t leaves_id = *(int32_t *) (*Tile_leaves + 0x8); - int32_t grass_id = *(int32_t *) (*Tile_grass + 0x8); - // Replace Rendered Item With Carried Variant - unsigned char *carried_item_instance = NULL; - if (item_instance != NULL) { - int32_t id = *(int32_t *) (item_instance + 0x4); - int32_t count = *(int32_t *) item_instance; - int32_t auxilary = *(int32_t *) (item_instance + 0x8); - if (id == leaves_id) { - carried_item_instance = (unsigned char *) ::operator new(ITEM_INSTANCE_SIZE); - (*ItemInstance_constructor_title_extra)(carried_item_instance, *Tile_leaves_carried, count, auxilary); - } else if (id == grass_id) { - carried_item_instance = (unsigned char *) ::operator new(ITEM_INSTANCE_SIZE); - (*ItemInstance_constructor_title_extra)(carried_item_instance, *Tile_grass_carried, count, auxilary); - } - } - // Fix Toolbar Rendering - GLboolean depth_test_was_enabled = glIsEnabled(GL_DEPTH_TEST); - glDisable(GL_DEPTH_TEST); - // Call Original Method - float ret = (*ItemRenderer_renderGuiItemCorrect)(font, textures, carried_item_instance != NULL ? carried_item_instance : item_instance, param_1, param_2); - // Revert GL State Changes - if (depth_test_was_enabled) { - glEnable(GL_DEPTH_TEST); - } - // Free Carried Item Instance Variant - if (carried_item_instance != NULL) { - ::operator delete(carried_item_instance); - } - // Return - return ret; - } - - // Render Selected Item Text - static void Gui_renderChatMessages_injection(unsigned char *gui, int32_t param_1, uint32_t param_2, bool param_3, unsigned char *font) { - // Call Original Method - (*Gui_renderChatMessages)(gui, param_1, param_2, param_3, font); - // Calculate Selected Item Text Scale - unsigned char *minecraft = *(unsigned char **) (gui + 0x9f4); - int32_t screen_width = *(int32_t *) (minecraft + 0x20); - float scale = ((float) screen_width) * *InvGuiScale; - // Render Selected Item Text - (*Gui_renderOnSelectItemNameText)(gui, (int32_t) scale, font, param_1 - 0x13); - } - // Reset Selected Item Text Timer On Slot Select - static bool reset_selected_item_text_timer = false; - static void Gui_tick_injection(unsigned char *gui) { - // Call Original Method - (*Gui_tick)(gui); - // Handle Reset - float *selected_item_text_timer = (float *) (gui + 0x9fc); - if (reset_selected_item_text_timer) { - // Reset - *selected_item_text_timer = 0; - reset_selected_item_text_timer = false; - } - } - // Trigger Reset Selected Item Text Timer On Slot Select - static void Inventory_selectSlot_injection(unsigned char *inventory, int32_t slot) { - // Call Original Method - (*Inventory_selectSlot)(inventory, slot); - // Trigger Reset Selected Item Text Timer - reset_selected_item_text_timer = true; - } - - __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); - // Display Smoke From TripodCamera Higher - overwrite_call((void *) 0x87dc4, (void *) Level_addParticle_injection); - - if (extra_has_feature("Fix Sign Placement")) { - // Fix Signs - patch_address(LocalPlayer_openTextEdit_vtable_addr, (void *) LocalPlayer_openTextEdit_injection); - patch_address(TextEditScreen_updateEvents_vtable_addr, (void *) TextEditScreen_updateEvents_injection); - } - - if (extra_has_feature("Expand Creative Inventory")) { - // Add Extra Items To Creative Inventory (Only Replace Specific Function Call) - overwrite_call((void *) 0x8e0fc, (void *) Inventory_setupDefault_FillingContainer_addItem_call_injection); - } - - if (extra_has_feature("Animated Water")) { - // Tick Dynamic Textures (Animated Water) - overwrite_calls((void *) Minecraft_tick, (void *) Minecraft_tick_injection); - } - - // Hijack Create World Button - patch_address(SelectWorldScreen_tick_vtable_addr, (void *) SelectWorldScreen_tick_injection); - patch_address(Touch_SelectWorldScreen_tick_vtable_addr, (void *) Touch_SelectWorldScreen_tick_injection); - // Make The SimpleChooseLevelScreen Back Button Go To SelectWorldScreen Instead Of StartMenuScreen - unsigned char simple_choose_level_screen_back_button_patch[4] = {0x05, 0x10, 0xa0, 0xe3}; - patch((void *) 0x31144, simple_choose_level_screen_back_button_patch); - - if (extra_has_feature("Disable gui_blocks Atlas")) { - // Disable gui_blocks Atlas Which Contains Pre-Rendered Textures For Blocks In The Inventory - unsigned char disable_gui_blocks_atlas_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; - patch((void *) 0x63c2c, disable_gui_blocks_atlas_patch); - // Fix Grass And Leaves Inventory Rendering When The gui_blocks Atlas Is Disabled - overwrite_calls((void *) ItemRenderer_renderGuiItemCorrect, (void *) ItemRenderer_renderGuiItemCorrect_injection); - } - - // Fix Selected Item Text - overwrite_calls((void *) Gui_renderChatMessages, (void *) Gui_renderChatMessages_injection); - overwrite_calls((void *) Gui_tick, (void *) Gui_tick_injection); - overwrite_calls((void *) Inventory_selectSlot, (void *) Inventory_selectSlot_injection); - } -} diff --git a/mods/src/extra.h b/mods/src/extra.h deleted file mode 100644 index 7be14b0..0000000 --- a/mods/src/extra.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef EXTRA_H - -#define EXTRA_H - -#ifdef __cplusplus -extern "C" { -#endif - -int extra_has_feature(const char *name); -int extra_get_mode(); - -void extra_key_press(char key); -void extra_clear_input(); - -void extra_set_is_right_click(int val); -void extra_hide_gui(); -void extra_third_person(); - -void extra_set_is_left_click(int val); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/mods/src/feature/feature.c b/mods/src/feature/feature.c new file mode 100644 index 0000000..e832131 --- /dev/null +++ b/mods/src/feature/feature.c @@ -0,0 +1,42 @@ +#include +#include + +#include + +#include "feature.h" + +// Check For Feature +int feature_has(const char *name) { + char *env = getenv("MCPI_FEATURES"); + char *features = strdup(env != NULL ? env : ""); + char *tok = strtok(features, "|"); + int ret = 0; + while (tok != NULL) { + if (strcmp(tok, name) == 0) { + ret = 1; + break; + } + tok = strtok(NULL, "|"); + } + free(features); + if (feature_get_mode() != 2) { + INFO("Feature: %s: %s", name, ret ? "Enabled" : "Disabled"); + } + return ret; +} + +// Get Graphics Mode +int feature_get_mode() { + char *mode = getenv("MCPI_MODE"); + if (mode == NULL) { + ERR("%s", "MCPI Mode Not Specified"); + } else if (strcmp("virgl", mode) == 0) { + return 0; + } else if (strcmp("native", mode) == 0) { + return 1; + } else if (strcmp("server", mode) == 0) { + return 2; + } else { + ERR("Inavlid MCPI_MODE: %s", mode); + } +} diff --git a/mods/src/feature/feature.h b/mods/src/feature/feature.h new file mode 100644 index 0000000..1315300 --- /dev/null +++ b/mods/src/feature/feature.h @@ -0,0 +1,16 @@ +#ifndef FEATURE_H + +#define FEATURE_H + +#ifdef __cplusplus +extern "C" { +#endif + +int feature_has(const char *name); +int feature_get_mode(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mods/src/game_mode/game_mode.c b/mods/src/game_mode/game_mode.c new file mode 100644 index 0000000..7cd32fd --- /dev/null +++ b/mods/src/game_mode/game_mode.c @@ -0,0 +1,57 @@ +#include + +#include "game_mode.h" +#include "../init/init.h" + +#include "../minecraft.h" + +static int is_survival = -1; + +// Patch Game Mode +static void set_is_survival(int new_is_survival) { + if (is_survival != new_is_survival) { + INFO("Setting Game Mode: %s", new_is_survival ? "Survival" : "Creative"); + + // Correct Inventpry UI + unsigned char inventory_patch[4] = {new_is_survival ? 0x00 : 0x01, 0x30, 0xa0, 0xe3}; + patch((void *) 0x16efc, inventory_patch); + + // Use Correct Size For GameMode Object + unsigned char size_patch[4] = {new_is_survival ? 0x24 : 0x18, 0x00, 0xa0, 0xe3}; + patch((void *) 0x16ee4, size_patch); + + // Replace Creator Constructor With CreativeMode Or SurvivalMode Constructor + overwrite(Creator, new_is_survival ? SurvivalMode : CreativeMode); + + is_survival = new_is_survival; + } +} + +// Handle Gamemode Switching +static void Minecraft_setIsCreativeMode_injection(unsigned char *this, int32_t new_game_mode) { + set_is_survival(!new_game_mode); + + // Call Original Method + (*Minecraft_setIsCreativeMode)(this, new_game_mode); +} + +void init_game_mode() { + // Dynamic Game Mode Switching + set_is_survival(1); + overwrite_calls((void *) Minecraft_setIsCreativeMode, Minecraft_setIsCreativeMode_injection); + + // Replace CreatorLevel With ServerLevel (This Fixes Beds And Mob Spawning) + unsigned char level_patch[4] = {0x68, 0x7e, 0x01, 0xeb}; + patch((void *) 0x16f84, level_patch); + + // Allocate Correct Size For ServerLevel + unsigned char level_size_patch[4] = {0x94, 0x0b, 0x00, 0x00}; + patch((void *) 0x17004, level_size_patch); + + // Allow Connecting To Survival Servers + unsigned char server_patch[4] = {0x0f, 0x00, 0x00, 0xea}; + patch((void *) 0x6dc70, server_patch); + + // Init C++ + init_game_mode_cpp(); +} \ No newline at end of file diff --git a/mods/src/game_mode/game_mode.cpp b/mods/src/game_mode/game_mode.cpp new file mode 100644 index 0000000..1605229 --- /dev/null +++ b/mods/src/game_mode/game_mode.cpp @@ -0,0 +1,59 @@ +#include + +#include "game_mode.h" + +#include "../minecraft.h" + +// Get Minecraft From Screen +static unsigned char *get_minecraft_from_screen(unsigned char *screen) { + return *(unsigned char **) (screen + 0x14); +} + +// Redirect Create World Button To SimpleLevelChooseScreen +#define WORLD_NAME "world" +#define SIMPLE_LEVEL_CHOOSE_SCREEN_SIZE 0x68 +static void SelectWorldScreen_tick_injection(unsigned char *screen) { + bool create_world = *(bool *) (screen + 0xfc); + if (create_world) { + // Get New World Name + std::string new_name; + (*SelectWorldScreen_getUniqueLevelName)(new_name, screen, WORLD_NAME); + // Create SimpleLevelChooseScreen + unsigned char *new_screen = (unsigned char *) ::operator new(SIMPLE_LEVEL_CHOOSE_SCREEN_SIZE); + (*SimpleChooseLevelScreen)(new_screen, new_name); + // Set Screen + unsigned char *minecraft = get_minecraft_from_screen(screen); + (*Minecraft_setScreen)(minecraft, new_screen); + // Finish + *(bool *) (screen + 0xf9) = true; + } else { + (*SelectWorldScreen_tick)(screen); + } +} +static void Touch_SelectWorldScreen_tick_injection(unsigned char *screen) { + bool create_world = *(bool *) (screen + 0x154); + if (create_world) { + // Get New World Name + std::string new_name; + (*Touch_SelectWorldScreen_getUniqueLevelName)(new_name, screen, WORLD_NAME); + // Create SimpleLevelChooseScreen + unsigned char *new_screen = (unsigned char *) ::operator new(SIMPLE_LEVEL_CHOOSE_SCREEN_SIZE); + (*SimpleChooseLevelScreen)(new_screen, new_name); + // Set Screen + unsigned char *minecraft = get_minecraft_from_screen(screen); + (*Minecraft_setScreen)(minecraft, new_screen); + // Finish + *(bool *) (screen + 0x151) = true; + } else { + (*Touch_SelectWorldScreen_tick)(screen); + } +} + +void init_game_mode_cpp() { + // Hijack Create World Button + patch_address(SelectWorldScreen_tick_vtable_addr, (void *) SelectWorldScreen_tick_injection); + patch_address(Touch_SelectWorldScreen_tick_vtable_addr, (void *) Touch_SelectWorldScreen_tick_injection); + // Make The SimpleChooseLevelScreen Back Button Go To SelectWorldScreen Instead Of StartMenuScreen + unsigned char simple_choose_level_screen_back_button_patch[4] = {0x05, 0x10, 0xa0, 0xe3}; + patch((void *) 0x31144, simple_choose_level_screen_back_button_patch); +} \ No newline at end of file diff --git a/mods/src/game_mode/game_mode.h b/mods/src/game_mode/game_mode.h new file mode 100644 index 0000000..911891a --- /dev/null +++ b/mods/src/game_mode/game_mode.h @@ -0,0 +1,15 @@ +#ifndef GAME_MODE_H + +#define GAME_MODE_H + +#ifdef __cplusplus +extern "C" { +#endif + +void init_game_mode_cpp(); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/mods/src/init/init.c b/mods/src/init/init.c new file mode 100644 index 0000000..1ad9610 --- /dev/null +++ b/mods/src/init/init.c @@ -0,0 +1,12 @@ +#include "init.h" + +__attribute__((constructor)) static void init() { + init_compat(); + init_server(); + init_game_mode(); + init_input(); + init_misc(); + init_camera(); + init_options(); + init_textures(); +} \ No newline at end of file diff --git a/mods/src/init/init.h b/mods/src/init/init.h new file mode 100644 index 0000000..d2a1fdb --- /dev/null +++ b/mods/src/init/init.h @@ -0,0 +1,22 @@ +#ifndef INIT_H + +#define INIT_H + +#ifdef __cplusplus +extern "C" { +#endif + +void init_compat(); +void init_server(); +void init_game_mode(); +void init_input(); +void init_misc(); +void init_camera(); +void init_options(); +void init_textures(); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/mods/src/input/input.c b/mods/src/input/input.c new file mode 100644 index 0000000..20ad2a7 --- /dev/null +++ b/mods/src/input/input.c @@ -0,0 +1,133 @@ +#include + +#include "../feature/feature.h" +#include "input.h" +#include "../init/init.h" + +#include "../minecraft.h" + +// Store Right-Click Status +static int is_right_click = 0; +void input_set_is_right_click(int val) { + is_right_click = val; +} + +// Enable Bow & Arrow Fix +static int fix_bow = 0; + +// Store Function Input +static int hide_gui_toggle = 0; +void input_hide_gui() { + hide_gui_toggle++; +} +static int third_person_toggle = 0; +void input_third_person() { + third_person_toggle++; +} + +// Handle Input Fixes +static void Minecraft_tickInput_injection(unsigned char *minecraft) { + // Call Original Method + (*Minecraft_tickInput)(minecraft); + + if (fix_bow && !is_right_click) { + // GameMode Is Offset From minecraft By 0x160 + // Player Is Offset From minecraft By 0x18c + unsigned char *game_mode = *(unsigned char **) (minecraft + 0x160); + unsigned char *player = *(unsigned char **) (minecraft + 0x18c); + if (player != NULL && game_mode != NULL && (*Player_isUsingItem)(player)) { + unsigned char *game_mode_vtable = *(unsigned char **) game_mode; + GameMode_releaseUsingItem_t GameMode_releaseUsingItem = *(GameMode_releaseUsingItem_t *) (game_mode_vtable + 0x5c); + (*GameMode_releaseUsingItem)(game_mode, player); + } + } + + // Clear Unused Sign Input + input_clear_input(); + + // Handle Functions + unsigned char *options = minecraft + 0x3c; + if (hide_gui_toggle % 2 != 0) { + // Toggle Hide GUI + *(options + 0xec) = *(options + 0xec) ^ 1; + } + hide_gui_toggle = 0; + if (third_person_toggle % 2 != 0) { + // Toggle Third Person + *(options + 0xed) = *(options + 0xed) ^ 1; + } + third_person_toggle = 0; +} + +#include + +// Block UI Interaction When Mouse Is Locked +static int32_t Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection(unsigned char *minecraft) { + if (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE) { + // Call Original Method + return (*Minecraft_isCreativeMode)(minecraft); + } else { + // Disable Item Drop Ticking + return 1; + } +} + +// Block UI Interaction When Mouse Is Locked +static void Gui_handleClick_injection(unsigned char *this, int32_t param_2, int32_t param_3, int32_t param_4) { + if (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE) { + // Call Original Method + (*Gui_handleClick)(this, param_2, param_3, param_4); + } +} + +// Store Left Click (0 = Not Pressed, 1 = Pressed, 2 = Repeat) +// This Is Set To Repeat After First Attempted Left-Click Build Interaction +static int is_left_click = 0; +void input_set_is_left_click(int val) { + if ((is_left_click == 0 && val == 1) || (is_left_click != 0 && val == 0) || (is_left_click == 1 && val == 2)) { + is_left_click = val; + } +} + +// Add Attacking To MouseBuildInput +static int32_t MouseBuildInput_tickBuild_injection(unsigned char *mouse_build_input, unsigned char *local_player, uint32_t *build_action_intention_return) { + // Call Original Method + int32_t ret = (*MouseBuildInput_tickBuild)(mouse_build_input, local_player, build_action_intention_return); + + // Use Attack/Place BuildActionIntention If No Other Valid BuildActionIntention Was Selected And This Was Not A Repeated Left Click + if (ret != 0 && is_left_click == 1 && *build_action_intention_return == 0xa) { + // Get Target HitResult + unsigned char *minecraft = *(unsigned char **) (local_player + 0xc90); + unsigned char *hit_result = minecraft + 0xc38; + int32_t hit_result_type = *(int32_t *) hit_result; + // Check if The Target Is An Entity Using HitResult + if (hit_result_type == 1) { + // Change BuildActionIntention To Attack/Place Mode (Place Will Not Happen Because The HitResult Is An Entity) + *build_action_intention_return = 0x8; + } + // Block Repeat Changes Without Releasing Left Click + is_left_click = 2; + } + + return ret; +} + +void init_input() { + // Disable Item Dropping Using The Cursor When Cursor Is Hidden + overwrite_call((void *) 0x27800, Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection); + // Disable Opening Inventory Using The Cursor When Cursor Is Hidden + overwrite_calls((void *) Gui_handleClick, Gui_handleClick_injection); + + // Enable Bow & Arrow Fix + fix_bow = feature_has("Fix Bow & Arrow"); + // Fix Bow & Arrow + Clear Unused Sign Input + overwrite_calls((void *) Minecraft_tickInput, Minecraft_tickInput_injection); + + if (feature_has("Fix Attacking")) { + // Allow Attacking Mobs + patch_address(MouseBuildInput_tickBuild_vtable_addr, (void *) MouseBuildInput_tickBuild_injection); + } + + // Init C++ + init_input_cpp(); +} \ No newline at end of file diff --git a/mods/src/input/input.cpp b/mods/src/input/input.cpp new file mode 100644 index 0000000..232b57b --- /dev/null +++ b/mods/src/input/input.cpp @@ -0,0 +1,63 @@ +#include + +#include + +#include "../feature/feature.h" +#include "input.h" + +#include "../minecraft.h" + +// Open Sign Screen +static void LocalPlayer_openTextEdit_injection(unsigned char *local_player, unsigned char *sign) { + if (*(int *)(sign + 0x18) == 4) { + unsigned char *minecraft = *(unsigned char **) (local_player + 0xc90); + unsigned char *screen = (unsigned char *) ::operator new(0xd0); + screen = (*TextEditScreen)(screen, sign); + (*Minecraft_setScreen)(minecraft, screen); + } +} + +#define BACKSPACE_KEY 8 + +static int is_valid_key(char key) { + return (key >= 32 && key <= 126) || key == BACKSPACE_KEY; +} + +// Store Text Input +std::vector input; +void input_key_press(char key) { + if (is_valid_key(key)) { + input.push_back(key); + } +} +void input_clear_input() { + input.clear(); +} + +// Handle Text Input +static void TextEditScreen_updateEvents_injection(unsigned char *screen) { + // Call Original Method + (*Screen_updateEvents)(screen); + + if (*(char *)(screen + 4) == '\0') { + uint32_t vtable = *((uint32_t *) screen); + for (char key : input) { + if (key == BACKSPACE_KEY) { + // Handle Backspace + (*(Screen_keyPressed_t *) (vtable + 0x6c))(screen, BACKSPACE_KEY); + } else { + // Handle Nrmal Key + (*(Screen_keyboardNewChar_t *) (vtable + 0x70))(screen, key); + } + } + } + input_clear_input(); +} + +void init_input_cpp() { + if (feature_has("Fix Sign Placement")) { + // Fix Signs + patch_address(LocalPlayer_openTextEdit_vtable_addr, (void *) LocalPlayer_openTextEdit_injection); + patch_address(TextEditScreen_updateEvents_vtable_addr, (void *) TextEditScreen_updateEvents_injection); + } +} \ No newline at end of file diff --git a/mods/src/input/input.h b/mods/src/input/input.h new file mode 100644 index 0000000..ff08737 --- /dev/null +++ b/mods/src/input/input.h @@ -0,0 +1,24 @@ +#ifndef INPUT_H + +#define INPUT_H + +#ifdef __cplusplus +extern "C" { +#endif + +void input_key_press(char key); +void input_clear_input(); + +void input_set_is_right_click(int val); +void input_hide_gui(); +void input_third_person(); + +void input_set_is_left_click(int val); + +void init_input_cpp(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mods/src/minecraft.h b/mods/src/minecraft.h index 231781a..f65413e 100644 --- a/mods/src/minecraft.h +++ b/mods/src/minecraft.h @@ -183,6 +183,8 @@ static void *Touch_SelectWorldScreen_tick_vtable_addr = (void *) 0x105780; // ItemInstance +#define ITEM_INSTANCE_SIZE 0xc + typedef unsigned char *(*ItemInstance_constructor_t)(unsigned char *item_instance, unsigned char *item); static ItemInstance_constructor_t ItemInstance_constructor_item = (ItemInstance_constructor_t) 0x9992c; static ItemInstance_constructor_t ItemInstance_constructor_tile = (ItemInstance_constructor_t) 0x998e4; @@ -289,7 +291,7 @@ static ItemRenderer_renderGuiItemCorrect_t ItemRenderer_renderGuiItemCorrect = ( #include -#include "cxx11_util.h" +#include "util/cxx11_util.h" // AppPlatform diff --git a/mods/src/misc/misc.c b/mods/src/misc/misc.c new file mode 100644 index 0000000..8101e57 --- /dev/null +++ b/mods/src/misc/misc.c @@ -0,0 +1,18 @@ +#include + +#include "../feature/feature.h" +#include "misc.h" +#include "../init/init.h" + +#include "../minecraft.h" + +void init_misc() { + if (feature_has("Remove Invalid Item Background")) { + // Remove Invalid Item Background (A Red Background That Appears For Items That Are Not Included In The gui_blocks Atlas) + unsigned char invalid_item_background_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; + patch((void *) 0x63c98, invalid_item_background_patch); + } + + // Init C++ + init_misc_cpp(); +} \ No newline at end of file diff --git a/mods/src/misc/misc.cpp b/mods/src/misc/misc.cpp new file mode 100644 index 0000000..b1cdf28 --- /dev/null +++ b/mods/src/misc/misc.cpp @@ -0,0 +1,103 @@ +#include +#include +#include + +#include + +#include "../util/cxx11_util.h" + +#include "../feature/feature.h" +#include "misc.h" + +#include "../minecraft.h" + +// Read Asset File +static cxx11_string AppPlatform_readAssetFile_injection(__attribute__((unused)) unsigned char *app_platform, std::string const& path) { + std::string full_path("./data/"); + full_path.append(path); + std::ifstream stream(full_path); + std::string str((std::istreambuf_iterator(stream)), std::istreambuf_iterator()); + return create_cxx11_string(str.c_str()); +} + +static void inventory_add_item(unsigned char *inventory, unsigned char *item, bool is_tile) { + unsigned char *item_instance = (unsigned char *) ::operator new(ITEM_INSTANCE_SIZE); + item_instance = (*(is_tile ? ItemInstance_constructor_tile : ItemInstance_constructor_item))(item_instance, item); + (*FillingContainer_addItem)(inventory, item_instance); +} + +static int32_t Inventory_setupDefault_FillingContainer_addItem_call_injection(unsigned char *filling_container, unsigned char *item_instance) { + // Call Original + int32_t ret = (*FillingContainer_addItem)(filling_container, item_instance); + + // Add Items + inventory_add_item(filling_container, *Item_flintAndSteel, false); + inventory_add_item(filling_container, *Item_snowball, false); + inventory_add_item(filling_container, *Item_egg, false); + inventory_add_item(filling_container, *Item_shears, false); + for (int i = 0; i < 15; i++) { + unsigned char *item_instance = (unsigned char *) ::operator new(0xc); + item_instance = (*ItemInstance_constructor_item_extra)(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); + inventory_add_item(filling_container, *Tile_calmWater, true); + inventory_add_item(filling_container, *Tile_calmLava, true); + inventory_add_item(filling_container, *Tile_glowingObsidian, true); + inventory_add_item(filling_container, *Tile_web, true); + inventory_add_item(filling_container, *Tile_topSnow, true); + inventory_add_item(filling_container, *Tile_ice, true); + inventory_add_item(filling_container, *Tile_invisible_bedrock, true); + + return ret; +} + +// Render Selected Item Text +static void Gui_renderChatMessages_injection(unsigned char *gui, int32_t param_1, uint32_t param_2, bool param_3, unsigned char *font) { + // Call Original Method + (*Gui_renderChatMessages)(gui, param_1, param_2, param_3, font); + // Calculate Selected Item Text Scale + unsigned char *minecraft = *(unsigned char **) (gui + 0x9f4); + int32_t screen_width = *(int32_t *) (minecraft + 0x20); + float scale = ((float) screen_width) * *InvGuiScale; + // Render Selected Item Text + (*Gui_renderOnSelectItemNameText)(gui, (int32_t) scale, font, param_1 - 0x13); +} +// Reset Selected Item Text Timer On Slot Select +static bool reset_selected_item_text_timer = false; +static void Gui_tick_injection(unsigned char *gui) { + // Call Original Method + (*Gui_tick)(gui); + // Handle Reset + float *selected_item_text_timer = (float *) (gui + 0x9fc); + if (reset_selected_item_text_timer) { + // Reset + *selected_item_text_timer = 0; + reset_selected_item_text_timer = false; + } +} +// Trigger Reset Selected Item Text Timer On Slot Select +static void Inventory_selectSlot_injection(unsigned char *inventory, int32_t slot) { + // Call Original Method + (*Inventory_selectSlot)(inventory, slot); + // Trigger Reset Selected Item Text Timer + reset_selected_item_text_timer = true; +} + +void init_misc_cpp() { + // Implement AppPlatform::readAssetFile So Translations Work + overwrite((void *) AppPlatform_readAssetFile, (void *) AppPlatform_readAssetFile_injection); + + if (feature_has("Expand Creative Inventory")) { + // Add Extra Items To Creative Inventory (Only Replace Specific Function Call) + overwrite_call((void *) 0x8e0fc, (void *) Inventory_setupDefault_FillingContainer_addItem_call_injection); + } + + // Fix Selected Item Text + overwrite_calls((void *) Gui_renderChatMessages, (void *) Gui_renderChatMessages_injection); + overwrite_calls((void *) Gui_tick, (void *) Gui_tick_injection); + overwrite_calls((void *) Inventory_selectSlot, (void *) Inventory_selectSlot_injection); +} \ No newline at end of file diff --git a/mods/src/misc/misc.h b/mods/src/misc/misc.h new file mode 100644 index 0000000..dee63ac --- /dev/null +++ b/mods/src/misc/misc.h @@ -0,0 +1,15 @@ +#ifndef MISC_H + +#define MISC_H + +#ifdef __cplusplus +extern "C" { +#endif + +void init_misc_cpp(); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/mods/src/options/options.c b/mods/src/options/options.c new file mode 100644 index 0000000..7297fed --- /dev/null +++ b/mods/src/options/options.c @@ -0,0 +1,105 @@ +#include + +#include + +#include "../feature/feature.h" +#include "../init/init.h" + +#include "../minecraft.h" + +static int mob_spawning = 0; +// Override Mob Spawning +static uint32_t LevelData_getSpawnMobs_injection(__attribute__((unused)) unsigned char *level_data) { + return mob_spawning; +} + +// Get Custom Username +static char *get_username() { + char *username = getenv("MCPI_USERNAME"); + if (username == NULL) { + username = "StevePi"; + } + return username; +} + +static int fancy_graphics; +static int peaceful_mode; +static int anaglyph; +static int smooth_lighting; +// Configure Options +static void Minecraft_init_injection(unsigned char *this) { + // Call Original Method + (*Minecraft_init)(this); + + unsigned char *options = this + 0x3c; + // Enable Fancy Graphics + *(options + 0x17) = fancy_graphics; + // Enable Crosshair In Touch GUI + *(options + 0x105) = 1; + // Peaceful Mode + *(int32_t *) (options + 0xe8) = peaceful_mode ? 0 : 2; + // 3D Anaglyph + *(options + 0x15) = anaglyph; + // Smooth Lighting + *(options + 0x18) = smooth_lighting; +} + +// Enable Touch GUI +static int32_t Minecraft_isTouchscreen_injection(__attribute__((unused)) unsigned char *minecraft) { + return 1; +} + +void init_options() { + int is_server = feature_get_mode() == 2; + + int touch_gui = feature_has("Touch GUI"); + if (touch_gui) { + // Main UI + overwrite((void *) Minecraft_isTouchscreen, Minecraft_isTouchscreen_injection); + // Force Correct Toolbar Size + unsigned char toolbar_patch[4] = {0x01, 0x00, 0x50, 0xe3}; + patch((void *) 0x257b0, toolbar_patch); + } + + mob_spawning = feature_has("Mob Spawning"); + // Set Mob Spawning + overwrite((void *) LevelData_getSpawnMobs, LevelData_getSpawnMobs_injection); + + // Enable Fancy Graphics + fancy_graphics = feature_has("Fancy Graphics"); + // Peaceful Mode + peaceful_mode = feature_has("Peaceful Mode"); + // 3D Anaglyph + anaglyph = feature_has("3D Anaglyph"); + + // Set Options + overwrite_calls((void *) Minecraft_init, Minecraft_init_injection); + + // Change Username + const char *username = get_username(); + if (!is_server) { + INFO("Setting Username: %s", username); + } + if (strcmp(*default_username, "StevePi") != 0) { + ERR("%s", "Default Username Is Invalid"); + } + patch_address((void *) default_username, (void *) username); + + if (feature_has("Disable Autojump By Default")) { + // Disable Autojump By Default + unsigned char autojump_patch[4] = {0x00, 0x30, 0xa0, 0xe3}; + patch((void *) 0x44b90, autojump_patch); + } + + // Show Block Outlines + int block_outlines = feature_has("Show Block Outlines"); + unsigned char outline_patch[4] = {block_outlines ? !touch_gui : touch_gui, 0x00, 0x50, 0xe3}; + patch((void *) 0x4a210, outline_patch); + + smooth_lighting = feature_has("Smooth Lighting"); + if (smooth_lighting) { + // Enable Smooth Lighting + unsigned char smooth_lighting_patch[4] = {0x01, 0x00, 0x53, 0xe3}; + patch((void *) 0x59ea4, smooth_lighting_patch); + } +} \ No newline at end of file diff --git a/mods/src/override.c b/mods/src/override/override.c similarity index 100% rename from mods/src/override.c rename to mods/src/override/override.c diff --git a/mods/src/server/server.cpp b/mods/src/server/server.cpp index 6522fbd..b2aa531 100644 --- a/mods/src/server/server.cpp +++ b/mods/src/server/server.cpp @@ -19,6 +19,9 @@ #include "server_properties.h" #include "playerdata.h" +#include "../feature/feature.h" +#include "../init/init.h" + #include "../minecraft.h" // Server Properties @@ -387,13 +390,13 @@ static bool RakNet_RakPeer_IsBanned_injection(__attribute__((unused)) unsigned c } } -const char *server_get_motd() { - std::string *motd = new std::string(get_server_properties().get_string("motd", DEFAULT_MOTD)); - return motd->c_str(); +static std::string get_motd() { + std::string motd(get_server_properties().get_string("motd", DEFAULT_MOTD)); + return motd; } static bool loaded_features = false; -const char *server_get_features() { +static const char *get_features() { static std::string features; if (!loaded_features) { loaded_features = true; @@ -420,7 +423,7 @@ static unsigned char get_max_players() { return (unsigned char) val; } -void server_init() { +static void server_init() { // Open Properties File std::string file(getenv("HOME")); file.append("/.minecraft/server.properties"); @@ -508,3 +511,11 @@ void server_init() { pthread_t read_stdin_thread_obj; pthread_create(&read_stdin_thread_obj, NULL, read_stdin_thread, NULL); } + +void init_server() { + if (feature_get_mode() == 2) { + server_init(); + setenv("MCPI_FEATURES", get_features(), 1); + setenv("MCPI_USERNAME", get_motd().c_str(), 1); + } +} \ No newline at end of file diff --git a/mods/src/server/server.h b/mods/src/server/server.h index dc8933c..67c1f58 100644 --- a/mods/src/server/server.h +++ b/mods/src/server/server.h @@ -4,14 +4,10 @@ #ifdef __cplusplus extern "C" { -#endif - -void server_init(); +#endif\ const char *server_get_motd(); -const char *server_get_features(); - #ifdef __cplusplus } #endif diff --git a/mods/src/textures/textures.cpp b/mods/src/textures/textures.cpp new file mode 100644 index 0000000..a07665f --- /dev/null +++ b/mods/src/textures/textures.cpp @@ -0,0 +1,69 @@ +#include + +#include + +#include "../feature/feature.h" +#include "../init/init.h" + +#include "../minecraft.h" + +static void Minecraft_tick_injection(unsigned char *minecraft, int32_t param_1, int32_t param_2) { + // Call Original Method + (*Minecraft_tick)(minecraft, param_1, param_2); + + // Tick Dynamic Textures + unsigned char *textures = *(unsigned char **) (minecraft + 0x164); + if (textures != NULL) { + (*Textures_tick)(textures, true); + } +} + +// Fix Grass And Leaves Inventory Rendering When The gui_blocks Atlas Is Disabled +static float ItemRenderer_renderGuiItemCorrect_injection(unsigned char *font, unsigned char *textures, unsigned char *item_instance, int32_t param_1, int32_t param_2) { + int32_t leaves_id = *(int32_t *) (*Tile_leaves + 0x8); + int32_t grass_id = *(int32_t *) (*Tile_grass + 0x8); + // Replace Rendered Item With Carried Variant + unsigned char *carried_item_instance = NULL; + if (item_instance != NULL) { + int32_t id = *(int32_t *) (item_instance + 0x4); + int32_t count = *(int32_t *) item_instance; + int32_t auxilary = *(int32_t *) (item_instance + 0x8); + if (id == leaves_id) { + carried_item_instance = (unsigned char *) ::operator new(ITEM_INSTANCE_SIZE); + (*ItemInstance_constructor_title_extra)(carried_item_instance, *Tile_leaves_carried, count, auxilary); + } else if (id == grass_id) { + carried_item_instance = (unsigned char *) ::operator new(ITEM_INSTANCE_SIZE); + (*ItemInstance_constructor_title_extra)(carried_item_instance, *Tile_grass_carried, count, auxilary); + } + } + // Fix Toolbar Rendering + GLboolean depth_test_was_enabled = glIsEnabled(GL_DEPTH_TEST); + glDisable(GL_DEPTH_TEST); + // Call Original Method + float ret = (*ItemRenderer_renderGuiItemCorrect)(font, textures, carried_item_instance != NULL ? carried_item_instance : item_instance, param_1, param_2); + // Revert GL State Changes + if (depth_test_was_enabled) { + glEnable(GL_DEPTH_TEST); + } + // Free Carried Item Instance Variant + if (carried_item_instance != NULL) { + ::operator delete(carried_item_instance); + } + // Return + return ret; +} + +void init_textures() { + if (feature_has("Animated Water")) { + // Tick Dynamic Textures (Animated Water) + overwrite_calls((void *) Minecraft_tick, (void *) Minecraft_tick_injection); + } + + if (feature_has("Disable gui_blocks Atlas")) { + // Disable gui_blocks Atlas Which Contains Pre-Rendered Textures For Blocks In The Inventory + unsigned char disable_gui_blocks_atlas_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; + patch((void *) 0x63c2c, disable_gui_blocks_atlas_patch); + // Fix Grass And Leaves Inventory Rendering When The gui_blocks Atlas Is Disabled + overwrite_calls((void *) ItemRenderer_renderGuiItemCorrect, (void *) ItemRenderer_renderGuiItemCorrect_injection); + } +} \ No newline at end of file diff --git a/mods/src/cxx11_util.cpp b/mods/src/util/cxx11_util.cpp similarity index 100% rename from mods/src/cxx11_util.cpp rename to mods/src/util/cxx11_util.cpp diff --git a/mods/src/cxx11_util.h b/mods/src/util/cxx11_util.h similarity index 100% rename from mods/src/cxx11_util.h rename to mods/src/util/cxx11_util.h