From 8ef6e0885a78c60372f66a316abffc74c98b4e09 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Sun, 25 Aug 2024 17:06:12 -0400 Subject: [PATCH] Split Up misc.cpp --- docs/CHANGELOG.md | 76 +- launcher/src/client/available-feature-flags | 14 +- mods/CMakeLists.txt | 5 + mods/include/mods/classic-ui/classic-ui.h | 8 + mods/include/mods/init/init.h | 1 + mods/src/classic-ui/README.md | 2 + mods/src/classic-ui/classic-ui.cpp | 142 ++++ mods/src/init/init.cpp | 1 + mods/src/misc/README.md | 2 +- mods/src/misc/graphics.cpp | 352 ++++++++ mods/src/misc/misc-internal.h | 9 +- mods/src/misc/misc.cpp | 895 ++------------------ mods/src/misc/tinting.cpp | 69 ++ mods/src/misc/ui.cpp | 291 +++++++ 14 files changed, 988 insertions(+), 879 deletions(-) create mode 100644 mods/include/mods/classic-ui/classic-ui.h create mode 100644 mods/src/classic-ui/README.md create mode 100644 mods/src/classic-ui/classic-ui.cpp create mode 100644 mods/src/misc/graphics.cpp create mode 100644 mods/src/misc/tinting.cpp create mode 100644 mods/src/misc/ui.cpp diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index c82f210bb5..991dfad677 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -8,37 +8,51 @@ * Proper Create New World Screen * Proper Chat Screen * New Feature Flags - * `Animated Lava` (Enabled By Default) - * `Animated Fire` (Enabled By Default) - * `Add Cake` (Enabled By Default) - * `Use Java Beta 1.3 Light Ramp` (Enabled By Default) - * `Send Full Level When Hosting Game` (Enabled By Default) - * `Food Overlay` (Disabled By Default) - * `Add Splashes` (Enabled By Default) - * `Display Date In Select World Screen` (Enabled By Default) - * `Optimized Chunk Sorting` (Enabled By Default) - * `Fix Held Item Caching` (Enabled By Default) - * `Add Reborn Info To Options` (Enabled By Default) - * `Log FPS` (Disabled By Default) - * `Add Welcome Screen` (Enabled By Default) - * `F3 Debug Information` (Enabled By Default) - * `Multidraw Rendering` (Enabled By Default) - * `Add Missing Language Strings` (Enabled By Default) - * `Fix Pigmen Burning In The Sun` (Enabled By Default) - * `Fix Carried Grass's Bottom Texture` (Enabled By Default) - * `Hide Crosshair In Third-Person` (Enabled By Default) - * `Fix Camera Legs` (Enabled By Default) - * `Implement Crafting Remainders` (Enabled By Default) - * `Fix Door Duplication` (Enabled By Default) - * `Fix Cobweb Lighting` (Enabled By Default) - * `Fix Sneaking Syncing` (Enabled By Default) - * `Fix Fire Immunity` (Enabled By Default) - * `Fix Fire Syncing` (Enabled By Default) - * `Fix Sunlight Not Properly Setting Mobs On Fire` (Enabled By Default) - * `Stop Creative Players From Burning` (Enabled By Default) - * `Render Fire In Third-Person` (Enabled By Default) - * `Improved Water Rendering` (Enabled By Default) - * `Classic Item Count UI` (Enabled By Default) + * New Functionality + * `Animated Lava` (Enabled By Default) + * `Animated Fire` (Enabled By Default) + * `Add Cake` (Enabled By Default) + * `Use Java Beta 1.3 Light Ramp` (Enabled By Default) + * `Send Full Level When Hosting Game` (Enabled By Default) + * `Food Overlay` (Disabled By Default) + * `Add Splashes` (Enabled By Default) + * `Display Date In Select World Screen` (Enabled By Default) + * `Optimized Chunk Sorting` (Enabled By Default) + * `Fix Held Item Caching` (Enabled By Default) + * `Add Reborn Info To Options` (Enabled By Default) + * `Log FPS` (Disabled By Default) + * `Add Welcome Screen` (Enabled By Default) + * `F3 Debug Information` (Enabled By Default) + * `Multidraw Rendering` (Enabled By Default) + * `Add Missing Language Strings` (Enabled By Default) + * `Fix Pigmen Burning In The Sun` (Enabled By Default) + * `Fix Carried Grass's Bottom Texture` (Enabled By Default) + * `Hide Crosshair In Third-Person` (Enabled By Default) + * `Fix Camera Legs` (Enabled By Default) + * `Implement Crafting Remainders` (Enabled By Default) + * `Fix Door Duplication` (Enabled By Default) + * `Fix Cobweb Lighting` (Enabled By Default) + * `Fix Sneaking Syncing` (Enabled By Default) + * `Fix Fire Immunity` (Enabled By Default) + * `Fix Fire Syncing` (Enabled By Default) + * `Fix Sunlight Not Properly Setting Mobs On Fire` (Enabled By Default) + * `Stop Creative Players From Burning` (Enabled By Default) + * `Render Fire In Third-Person` (Enabled By Default) + * `Improved Water Rendering` (Enabled By Default) + * `Classic Item Count UI` (Enabled By Default) + * Existing Functionality (All Enabled By Default) + * `Fix Screen Rendering When Hiding HUD` + * `Sanitize Usernames` + * `Patch RakNet Security Bug` + * `Log RakNet Startup Errors` + * `Prevent Unnecessary Server Pinging` + * `Proper OpenGL Buffer Generation` + * `Fix Furnace Screen Visual Bug` + * `Fix Text Wrapping` + * `Fullscreen Support` + * `Always Save Chest Tile Entities` + * `Fix Transferring Durability When Using Items` + * `Fix Switching Perspective While Sneaking` * Split Up `Remove Creative Mode Restrictions` Feature Flag * `Remove Creative Mode Restrictions` (Disabled By Default) * `Display Slot Count In Creative Mode` (Disabled By Default) diff --git a/launcher/src/client/available-feature-flags b/launcher/src/client/available-feature-flags index c0eecc36b5..0433f9d36f 100644 --- a/launcher/src/client/available-feature-flags +++ b/launcher/src/client/available-feature-flags @@ -85,4 +85,16 @@ TRUE Fix Sunlight Not Properly Setting Mobs On Fire TRUE Stop Creative Players From Burning TRUE Render Fire In Third-Person TRUE Improved Water Rendering -TRUE Classic Item Count UI \ No newline at end of file +TRUE Classic Item Count UI +TRUE Fix Screen Rendering When Hiding HUD +TRUE Sanitize Usernames +TRUE Patch RakNet Security Bug +TRUE Log RakNet Startup Errors +TRUE Prevent Unnecessary Server Pinging +TRUE Proper OpenGL Buffer Generation +TRUE Fix Furnace Screen Visual Bug +TRUE Fix Text Wrapping +TRUE Fullscreen Support +TRUE Always Save Chest Tile Entities +TRUE Fix Transferring Durability When Using Items +TRUE Fix Switching Perspective While Sneaking \ No newline at end of file diff --git a/mods/CMakeLists.txt b/mods/CMakeLists.txt index 1aa5ed1b62..80aed67c4e 100644 --- a/mods/CMakeLists.txt +++ b/mods/CMakeLists.txt @@ -29,6 +29,9 @@ set(SRC src/misc/misc.cpp src/misc/logging.cpp src/misc/api.cpp + src/misc/graphics.cpp + src/misc/ui.cpp + src/misc/tinting.cpp # options src/options/options.cpp src/options/ui.cpp @@ -93,6 +96,8 @@ set(SRC src/multidraw/glue.cpp src/multidraw/buffer.cpp src/multidraw/storage.cpp + # classic-ui + src/classic-ui/classic-ui.cpp ) # Install Splashes install( diff --git a/mods/include/mods/classic-ui/classic-ui.h b/mods/include/mods/classic-ui/classic-ui.h new file mode 100644 index 0000000000..159c7b2fe6 --- /dev/null +++ b/mods/include/mods/classic-ui/classic-ui.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +extern "C" { +GuiComponent_blit_t get_blit_with_classic_hud_offset(); +int get_classic_hud_y_offset(Minecraft *minecraft); +} \ No newline at end of file diff --git a/mods/include/mods/init/init.h b/mods/include/mods/init/init.h index ca6ae43003..994d396af6 100644 --- a/mods/include/mods/init/init.h +++ b/mods/include/mods/init/init.h @@ -30,4 +30,5 @@ void init_override(); void init_screenshot(); void init_f3(); void init_multidraw(); +void init_classic_ui(); } diff --git a/mods/src/classic-ui/README.md b/mods/src/classic-ui/README.md new file mode 100644 index 0000000000..7834fc1faf --- /dev/null +++ b/mods/src/classic-ui/README.md @@ -0,0 +1,2 @@ +# `classic-ui` Mod +This mod adjusts the UI to make it more similar to Java Edition. \ No newline at end of file diff --git a/mods/src/classic-ui/classic-ui.cpp b/mods/src/classic-ui/classic-ui.cpp new file mode 100644 index 0000000000..f384b6c712 --- /dev/null +++ b/mods/src/classic-ui/classic-ui.cpp @@ -0,0 +1,142 @@ +#include +#include + +#include +#include +#include + +// Classic HUD +#define DEFAULT_HUD_PADDING 2 +#define NEW_HUD_PADDING 1 +#define HUD_ELEMENT_WIDTH 82 +#define HUD_ELEMENT_HEIGHT 9 +#define TOOLBAR_HEIGHT 22 +#define SLOT_WIDTH 20 +#define DEFAULT_BUBBLES_PADDING 1 +#define NUMBER_OF_SLOTS 9 +static bool use_classic_hud = false; +static void Gui_renderHearts_GuiComponent_blit_hearts_injection(GuiComponent *component, int32_t x_dest, int32_t y_dest, int32_t x_src, int32_t y_src, int32_t width_dest, int32_t height_dest, int32_t width_src, int32_t height_src) { + const Minecraft *minecraft = ((Gui *) component)->minecraft; + x_dest -= DEFAULT_HUD_PADDING; + const float width = float(minecraft->screen_width) * Gui::InvGuiScale; + const float height = float(minecraft->screen_height) * Gui::InvGuiScale; + x_dest += int32_t(width - (NUMBER_OF_SLOTS * SLOT_WIDTH)) / 2; + y_dest -= DEFAULT_HUD_PADDING; + y_dest += int32_t(height) - HUD_ELEMENT_HEIGHT - TOOLBAR_HEIGHT - NEW_HUD_PADDING; + // Call Original Method + component->blit(x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src); +} +GuiComponent_blit_t get_blit_with_classic_hud_offset() { + return use_classic_hud ? Gui_renderHearts_GuiComponent_blit_hearts_injection : GuiComponent_blit->get(false); +} +static void Gui_renderHearts_GuiComponent_blit_armor_injection(Gui *component, int32_t x_dest, int32_t y_dest, int32_t x_src, int32_t y_src, int32_t width_dest, int32_t height_dest, int32_t width_src, int32_t height_src) { + const Minecraft *minecraft = component->minecraft; + x_dest -= DEFAULT_HUD_PADDING + HUD_ELEMENT_WIDTH; + const float width = float(minecraft->screen_width) * Gui::InvGuiScale; + const float height = float(minecraft->screen_height) * Gui::InvGuiScale; + x_dest += int32_t(width) - ((int32_t(width) - (NUMBER_OF_SLOTS * SLOT_WIDTH)) / 2) - HUD_ELEMENT_WIDTH; + y_dest -= DEFAULT_HUD_PADDING; + y_dest += int32_t(height) - HUD_ELEMENT_HEIGHT - TOOLBAR_HEIGHT - NEW_HUD_PADDING; + // Call Original Method + component->blit(x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src); +} +static void Gui_renderBubbles_GuiComponent_blit_injection(Gui *component, int32_t x_dest, int32_t y_dest, int32_t x_src, int32_t y_src, int32_t width_dest, int32_t height_dest, int32_t width_src, int32_t height_src) { + const Minecraft *minecraft = component->minecraft; + x_dest -= DEFAULT_HUD_PADDING; + const float width = float(minecraft->screen_width) * Gui::InvGuiScale; + const float height = float(minecraft->screen_height) * Gui::InvGuiScale; + x_dest += int32_t(width - (NUMBER_OF_SLOTS * SLOT_WIDTH)) / 2; + y_dest -= DEFAULT_HUD_PADDING + DEFAULT_BUBBLES_PADDING + HUD_ELEMENT_HEIGHT; + y_dest += int32_t(height) - HUD_ELEMENT_HEIGHT - TOOLBAR_HEIGHT - HUD_ELEMENT_HEIGHT - NEW_HUD_PADDING; + // Call Original Method + component->blit(x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src); +} +int get_classic_hud_y_offset(Minecraft *minecraft) { + int ret = 0; + if (use_classic_hud && !minecraft->isCreativeMode()) { + ret += (HUD_ELEMENT_HEIGHT * 2) + NEW_HUD_PADDING; + } + return ret; +} + +// Classic Slot Count Location +static void Gui_renderSlotText_injection_common(Gui *self, const ItemInstance *item, float x, float y, const bool param_1, const bool param_2) { + // Position + x += 17; + y += 9; + // Call Original Method + self->renderSlotText(item, x, y, param_1, param_2); +} +static void Gui_renderSlotText_injection_furnace(Gui *self, const ItemInstance *item, float x, float y, const bool param_1, const bool param_2) { + // Position + x += 4; + y += 5; + // Call Original Method + Gui_renderSlotText_injection_common(self, item, x, y, param_1, param_2); +} +static void unscale_slot_text(float &x, float &y) { + const float factor = 0.5f * Gui::GuiScale; + x /= factor; + y /= factor; +} +static void Gui_renderSlotText_injection_classic_inventory(Gui *self, const ItemInstance *item, float x, float y, const bool param_1, const bool param_2) { + // Position + unscale_slot_text(x, y); + // Call Original Method + Gui_renderSlotText_injection_common(self, item, x, y, param_1, param_2); +} +static void Gui_renderSlotText_injection_toolbar(Gui *self, const ItemInstance *item, float x, float y, const bool param_1, const bool param_2) { + // Position + y--; + unscale_slot_text(x, y); + // Call Original Method + Gui_renderSlotText_injection_common(self, item, x, y, param_1, param_2); +} +static void Gui_renderSlotText_injection_inventory(Gui *self, const ItemInstance *item, float x, float y, const bool param_1, const bool param_2) { + // Position + unscale_slot_text(x, y); + x++; + y++; + // Call Original Method + Gui_renderSlotText_injection_common(self, item, x, y, param_1, param_2); +} +template +static void Gui_renderSlotText_Font_draw_injection(Font *self, const char *raw_string, float x, float y, uint color) { + // Fix X + std::string string = raw_string; + x -= self->width(string); + // Fix Color + if (color == 0xffcccccc) { + color = 0xffffffff; + } + // Call + (*func)->get(false)(self, string, x, y, color); +} + +// Init +void init_classic_ui() { + // Classic HUD + if (feature_has("Classic HUD", server_disabled)) { + use_classic_hud = true; + overwrite_call((void *) 0x26758, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection); + overwrite_call((void *) 0x2656c, (void *) Gui_renderHearts_GuiComponent_blit_armor_injection); + overwrite_call((void *) 0x268c4, (void *) Gui_renderBubbles_GuiComponent_blit_injection); + overwrite_call((void *) 0x266f8, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection); + overwrite_call((void *) 0x267c8, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection); + } + + // Classic Slot Count Location + if (feature_has("Classic Item Count UI", server_disabled)) { + unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" + patch((void *) 0x27074, nop_patch); + patch((void *) 0x33984, nop_patch); + patch((void *) 0x1e424, nop_patch); + overwrite_call((void *) 0x1e4b8, (void *) Gui_renderSlotText_injection_inventory); + overwrite_call((void *) 0x27100, (void *) Gui_renderSlotText_injection_toolbar); + overwrite_call((void *) 0x339b4, (void *) Gui_renderSlotText_injection_classic_inventory); + overwrite_call((void *) 0x2b268, (void *) Gui_renderSlotText_injection_furnace); + overwrite_call((void *) 0x320c4, (void *) Gui_renderSlotText_injection_furnace); + overwrite_call((void *) 0x25e84, (void *) Gui_renderSlotText_Font_draw_injection<&Font_draw>); + overwrite_call((void *) 0x25e74, (void *) Gui_renderSlotText_Font_draw_injection<&Font_drawShadow>); + } +} \ No newline at end of file diff --git a/mods/src/init/init.cpp b/mods/src/init/init.cpp index bffb9fb64b..5afd16f515 100644 --- a/mods/src/init/init.cpp +++ b/mods/src/init/init.cpp @@ -46,5 +46,6 @@ __attribute__((constructor)) static void init() { init_screenshot(); init_f3(); init_multidraw(); + init_classic_ui(); } } diff --git a/mods/src/misc/README.md b/mods/src/misc/README.md index 620d2b259e..9404b5e84f 100644 --- a/mods/src/misc/README.md +++ b/mods/src/misc/README.md @@ -1,6 +1,6 @@ # `misc` Mod This mod has several miscellaneous mods that are too small to be their own mod, including: -* Rendering text above the hotbar when an item is selected. +* Rendering text above the toolbar when an item is selected. * Sanitizing player usernames for invalid characters. * Removing the red background from unobtainable items in the inventory. * Loading the bundled language file. diff --git a/mods/src/misc/graphics.cpp b/mods/src/misc/graphics.cpp new file mode 100644 index 0000000000..50b8e2d00e --- /dev/null +++ b/mods/src/misc/graphics.cpp @@ -0,0 +1,352 @@ +#include +#include + +#include +#include + +#include +#include + +#include "misc-internal.h" + +// Properly Generate Buffers +static void anGenBuffers_injection(__attribute__((unused)) Common_anGenBuffers_t original, const int32_t count, uint32_t *buffers) { + if (!reborn_is_headless()) { + glGenBuffers(count, buffers); + } +} + +// Custom Outline Color +static void LevelRenderer_render_AABB_glColor4f_injection(__attribute__((unused)) GLfloat red, __attribute__((unused)) GLfloat green, __attribute__((unused)) GLfloat blue, __attribute__((unused)) GLfloat alpha) { + // Set Color + glColor4f(0, 0, 0, 0.4); + + // Find Line Width + const char *custom_line_width = getenv(MCPI_BLOCK_OUTLINE_WIDTH_ENV); + float line_width; + if (custom_line_width != nullptr) { + // Custom + line_width = strtof(custom_line_width, nullptr); + } else { + // Guess + line_width = 1.5f / Gui::InvGuiScale; + } + // Clamp Line Width + float range[2]; + glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range); + if (range[1] < line_width) { + line_width = range[1]; + } else if (range[0] > line_width) { + line_width = range[0]; + } + // Set Line Width + glLineWidth(line_width); +} + +// Java Light Ramp +static void Dimension_updateLightRamp_injection(__attribute__((unused)) Dimension_updateLightRamp_t original, Dimension *self) { + // https://github.com/ReMinecraftPE/mcpe/blob/d7a8b6baecf8b3b050538abdbc976f690312aa2d/source/world/level/Dimension.cpp#L92-L105 + for (int i = 0; i <= 15; i++) { + const float f1 = 1.0f - (((float) i) / 15.0f); + self->light_ramp[i] = ((1.0f - f1) / (f1 * 3.0f + 1.0f)) * (1.0f - 0.1f) + 0.1f; + // Default Light Ramp: + // float fVar4 = 1.0 - ((float) i * 0.0625); + // self->light_ramp[i] = ((1.0 - fVar4) / (fVar4 * 3.0 + 1.0)) * 0.95 + 0.15; + } +} + +// Sort Chunks +struct chunk_data { + Chunk *chunk; + float distance; +}; +#define MAX_CHUNKS_SIZE 24336 +static chunk_data data[MAX_CHUNKS_SIZE]; +static void sort_chunks(Chunk **chunks_begin, Chunk **chunks_end, const DistanceChunkSorter sorter) { + // Calculate Distances + const int chunks_size = chunks_end - chunks_begin; + if (chunks_size > MAX_CHUNKS_SIZE) { + IMPOSSIBLE(); + } + for (int i = 0; i < chunks_size; i++) { + Chunk *chunk = chunks_begin[i]; + float distance = chunk->distanceToSqr((Entity *) sorter.mob); + if ((1024.0 <= distance) && chunk->y < 0x40) { + distance *= 10.0; + } + data[i].chunk = chunk; + data[i].distance = distance; + } + + // Sort + std::sort(data, data + chunks_size, [](chunk_data &a, chunk_data &b) { + return a.distance < b.distance; + }); + for (int i = 0; i < chunks_size; i++) { + chunks_begin[i] = data[i].chunk; + } +} + +// Fire Rendering +static void EntityRenderDispatcher_render_EntityRenderer_render_injection(EntityRenderer *self, Entity *entity, float x, float y, float z, float rot, float unknown) { + // Call Original Method + self->render(entity, x, y, z, rot, unknown); + + // Render Fire + if (entity->isOnFire()) { + // Here Be Decompiled Code + y -= entity->height_offset; + const int texture = Tile::fire->texture; + const int xt = (texture & 0xf) << 4; + const int yt = texture & 0xf0; + glPushMatrix(); + glTranslatef(x, y, z); + const float s = entity->hitbox_width * 1.4f; + glScalef(s, s, s); + self->bindTexture("terrain.png"); + Tesselator &t = Tesselator::instance; + float r = 0.5f; + float h = entity->hitbox_height / s; + float yo = entity->y - entity->height_offset - entity->hitbox.y1; + float player_rot_y = EntityRenderer::entityRenderDispatcher->player_rot_y; + if (EntityRenderer::entityRenderDispatcher->minecraft->options.third_person == 2) { + // Handle Front-Facing + player_rot_y -= 180.f; + } + glRotatef(-player_rot_y, 0, 1, 0); + glTranslatef(0, 0, -0.3f + float(int(h)) * 0.02f); + glColor4f(1, 1, 1, 1); + float zo = 0; + int ss = 0; + t.begin(7); + while (h > 0) { + constexpr float xo = 0.0f; + float u0; + float u1; + float v0; + float v1; + if (ss % 2 == 0) { + u0 = float(xt) / 256.0f; + u1 = (float(xt) + 15.99f) / 256.0f; + v0 = float(yt) / 256.0f; + v1 = (float(yt) + 15.99f) / 256.0f; + } else { + u0 = float(xt) / 256.0f; + u1 = (float(xt) + 15.99f) / 256.0f; + v0 = (float(yt) + 16) / 256.0f; + v1 = (float(yt) + 16 + 15.99f) / 256.0f; + } + if (ss / 2 % 2 == 0) { + std::swap(u1, u0); + } + t.vertexUV(r - xo, 0 - yo, zo, u1, v1); + t.vertexUV(-r - xo, 0 - yo, zo, u0, v1); + t.vertexUV(-r - xo, 1.4f - yo, zo, u0, v0); + t.vertexUV(r - xo, 1.4f - yo, zo, u1, v0); + h -= 0.45f; + yo -= 0.45f; + r *= 0.9f; + zo += 0.03f; + ss++; + } + t.draw(); + glPopMatrix(); + } +} + +// Nicer Water Rendering +static bool game_render_anaglyph_color_mask[4]; +static void GameRenderer_render_glColorMask_injection(const bool red, const bool green, const bool blue, const bool alpha) { + game_render_anaglyph_color_mask[0] = red; + game_render_anaglyph_color_mask[1] = green; + game_render_anaglyph_color_mask[2] = blue; + game_render_anaglyph_color_mask[3] = alpha; + glColorMask(red, green, blue, alpha); +} +static int GameRenderer_render_LevelRenderer_render_injection(LevelRenderer *self, Mob *mob, int param_1, float delta) { + glColorMask(false, false, false, false); + const int water_chunks = self->render(mob, param_1, delta); + glColorMask(true, true, true, true); + if (self->minecraft->options.anaglyph_3d) { + glColorMask(game_render_anaglyph_color_mask[0], game_render_anaglyph_color_mask[1], game_render_anaglyph_color_mask[2], game_render_anaglyph_color_mask[3]); + } + if (water_chunks > 0) { + LevelRenderer_renderSameAsLast(self, delta); + } + return water_chunks; +} + +// Fix grass_carried's Bottom Texture +static int CarriedTile_getTexture2_injection(CarriedTile_getTexture2_t original, CarriedTile *self, const int face, const int metadata) { + if (face == 0) return 2; + return original(self, face, metadata); +} + +// Fix Graphics Bug When Switching To First-Person While Sneaking +static void PlayerRenderer_render_injection(PlayerRenderer *model_renderer, Entity *entity, const float param_2, const float param_3, const float param_4, const float param_5, const float param_6) { + HumanoidMobRenderer_vtable_base->render((HumanoidMobRenderer *) model_renderer, entity, param_2, param_3, param_4, param_5, param_6); + HumanoidModel *model = model_renderer->model; + model->is_sneaking = false; +} + +// 3D Chests +static int32_t Tile_getRenderShape_injection(Tile *tile) { + if (tile == Tile::chest) { + // Don't Render "Simple" Chest Model + return -1; + } else { + // Call Original Method + return tile->getRenderShape(); + } +} +static ChestTileEntity *ChestTileEntity_injection(ChestTileEntity_constructor_t original, ChestTileEntity *tile_entity) { + // Call Original Method + original(tile_entity); + + // Enable Renderer + tile_entity->renderer_id = 1; + + // Return + return tile_entity; +} +static bool is_rendering_chest = false; +static void ModelPart_render_injection(ModelPart *model_part, float scale) { + // Start + is_rendering_chest = true; + + // Call Original Method + model_part->render(scale); + + // Stop + is_rendering_chest = false; +} +static void Tesselator_vertexUV_injection(Tesselator_vertexUV_t original, Tesselator *tesselator, const float x, const float y, const float z, const float u, float v) { + // Fix Chest Texture + if (is_rendering_chest) { + v /= 2; + } + + // Call Original Method + original(tesselator, x, y, z, u, v); +} +static bool ChestTileEntity_shouldSave_injection(__attribute__((unused)) ChestTileEntity_shouldSave_t original, __attribute__((unused)) ChestTileEntity *tile_entity) { + return true; +} + +// Animated 3D Chest +static ContainerMenu *ContainerMenu_injection(ContainerMenu_constructor_t original, ContainerMenu *container_menu, Container *container, const int32_t param_1) { + // Call Original Method + original(container_menu, container, param_1); + + // Play Animation + const ChestTileEntity *tile_entity = (ChestTileEntity *) (((unsigned char *) container) - offsetof(ChestTileEntity, container)); + const bool is_client = tile_entity->is_client; + if (!is_client) { + container->startOpen(); + } + + // Return + return container_menu; +} +static ContainerMenu *ContainerMenu_destructor_injection(ContainerMenu_destructor_complete_t original, ContainerMenu *container_menu) { + // Play Animation + Container *container = container_menu->container; + const ChestTileEntity *tile_entity = (ChestTileEntity *) (((unsigned char *) container) - offsetof(ChestTileEntity, container)); + const bool is_client = tile_entity->is_client; + if (!is_client) { + container->stopOpen(); + } + + // Call Original Method + return original(container_menu); +} + +// Init +void _init_misc_graphics() { + // Disable V-Sync + if (feature_has("Disable V-Sync", server_enabled)) { + media_disable_vsync(); + } + + // Force EGL + if (feature_has("Force EGL", server_disabled)) { + media_force_egl(); + } + + // Properly Generate Buffers + if (feature_has("Proper OpenGL Buffer Generation", server_enabled)) { + overwrite_calls(Common_anGenBuffers, anGenBuffers_injection); + } + + // Replace Block Highlight With Outline + if (feature_has("Replace Block Highlight With Outline", server_disabled)) { + overwrite_calls(LevelRenderer_renderHitSelect, [](__attribute__((unused)) LevelRenderer_renderHitSelect_t original, LevelRenderer *self, Player *player, const HitResult &hit_result, int i, void *vp, float f) { + self->renderHitOutline(player, hit_result, i, vp, f); + }); + unsigned char fix_outline_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" + patch((void *) 0x4d830, fix_outline_patch); + overwrite_call((void *) 0x4d764, (void *) LevelRenderer_render_AABB_glColor4f_injection); + } + + // Java Light Ramp + if (feature_has("Use Java Beta 1.3 Light Ramp", server_disabled)) { + overwrite_calls(Dimension_updateLightRamp, Dimension_updateLightRamp_injection); + } + + // Replace 2011 std::sort With Optimized(TM) Code + if (feature_has("Optimized Chunk Sorting", server_enabled)) { + overwrite_calls_manual((void *) 0x51fac, (void *) sort_chunks); + } + + // Render Fire In Third-Person + if (feature_has("Render Fire In Third-Person", server_disabled)) { + overwrite_call((void *) 0x606c0, (void *) EntityRenderDispatcher_render_EntityRenderer_render_injection); + } + + // Slightly Nicer Water Rendering + if (feature_has("Improved Water Rendering", server_disabled)) { + overwrite_call((void *) 0x49ed4, (void *) GameRenderer_render_glColorMask_injection); + overwrite_call((void *) 0x4a18c, (void *) GameRenderer_render_LevelRenderer_render_injection); + unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" + patch((void *) 0x4a12c, nop_patch); + } + + // Fix grass_carried's Bottom Texture + if (feature_has("Fix Carried Grass's Bottom Texture", server_disabled)) { + overwrite_calls(CarriedTile_getTexture2, CarriedTile_getTexture2_injection); + } + + // Fix Graphics Bug When Switching To First-Person While Sneaking + if (feature_has("Fix Switching Perspective While Sneaking", server_disabled)) { + patch_vtable(PlayerRenderer_render, PlayerRenderer_render_injection); + } + + // 3D Chests + if (feature_has("3D Chest Model", server_disabled)) { + overwrite_call((void *) 0x5e830, (void *) Tile_getRenderShape_injection); + overwrite_calls(ChestTileEntity_constructor, ChestTileEntity_injection); + overwrite_call((void *) 0x6655c, (void *) ModelPart_render_injection); + overwrite_call((void *) 0x66568, (void *) ModelPart_render_injection); + overwrite_call((void *) 0x66574, (void *) ModelPart_render_injection); + overwrite_calls(Tesselator_vertexUV, Tesselator_vertexUV_injection); + unsigned char chest_model_patch[4] = {0x13, 0x20, 0xa0, 0xe3}; // "mov r2, #0x13" + patch((void *) 0x66fc8, chest_model_patch); + unsigned char chest_color_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" + patch((void *) 0x66404, chest_color_patch); + + // Animation + overwrite_calls(ContainerMenu_constructor, ContainerMenu_injection); + overwrite_calls(ContainerMenu_destructor_complete, ContainerMenu_destructor_injection); + } + if (feature_has("Always Save Chest Tile Entities", server_enabled)) { + overwrite_calls(ChestTileEntity_shouldSave, ChestTileEntity_shouldSave_injection); + } + + // Don't Render Game In Headless Mode + if (reborn_is_headless()) { + overwrite_calls(GameRenderer_render, nop); + overwrite_calls(NinecraftApp_initGLStates, nop); + overwrite_calls(Gui_onConfigChanged, nop); + overwrite_calls(LevelRenderer_generateSky, nop); + } +} \ No newline at end of file diff --git a/mods/src/misc/misc-internal.h b/mods/src/misc/misc-internal.h index aad93ac7b7..25926d3912 100644 --- a/mods/src/misc/misc-internal.h +++ b/mods/src/misc/misc-internal.h @@ -1,4 +1,11 @@ #pragma once __attribute__((visibility("internal"))) void _init_misc_logging(); -__attribute__((visibility("internal"))) void _init_misc_api(); \ No newline at end of file +__attribute__((visibility("internal"))) void _init_misc_api(); +__attribute__((visibility("internal"))) void _init_misc_graphics(); +__attribute__((visibility("internal"))) void _init_misc_ui(); +__attribute__((visibility("internal"))) void _init_misc_tinting(); + +template +static void nop(__attribute__((unused)) Args... args) { +} \ No newline at end of file diff --git a/mods/src/misc/misc.cpp b/mods/src/misc/misc.cpp index 5009e8b9d5..134dc621f8 100644 --- a/mods/src/misc/misc.cpp +++ b/mods/src/misc/misc.cpp @@ -7,205 +7,21 @@ #include #include #include -#include #include +#include +#include #include #include -#include -#include - #include #include #include #include -#include #include "misc-internal.h" -// Classic HUD -#define DEFAULT_HUD_PADDING 2 -#define NEW_HUD_PADDING 1 -#define HUD_ELEMENT_WIDTH 82 -#define HUD_ELEMENT_HEIGHT 9 -#define TOOLBAR_HEIGHT 22 -#define SLOT_WIDTH 20 -#define DEFAULT_BUBBLES_PADDING 1 -#define NUMBER_OF_SLOTS 9 -static int use_classic_hud = 0; -static void Gui_renderHearts_GuiComponent_blit_hearts_injection(GuiComponent *component, int32_t x_dest, int32_t y_dest, int32_t x_src, int32_t y_src, int32_t width_dest, int32_t height_dest, int32_t width_src, int32_t height_src) { - Minecraft *minecraft = ((Gui *) component)->minecraft; - x_dest -= DEFAULT_HUD_PADDING; - float width = ((float) minecraft->screen_width) * Gui::InvGuiScale; - float height = ((float) minecraft->screen_height) * Gui::InvGuiScale; - x_dest += (width - (NUMBER_OF_SLOTS * SLOT_WIDTH)) / 2; - y_dest -= DEFAULT_HUD_PADDING; - y_dest += height - HUD_ELEMENT_HEIGHT - TOOLBAR_HEIGHT - NEW_HUD_PADDING; - // Call Original Method - component->blit(x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src); -} -static void Gui_renderHearts_GuiComponent_blit_armor_injection(Gui *component, int32_t x_dest, int32_t y_dest, int32_t x_src, int32_t y_src, int32_t width_dest, int32_t height_dest, int32_t width_src, int32_t height_src) { - Minecraft *minecraft = component->minecraft; - x_dest -= DEFAULT_HUD_PADDING + HUD_ELEMENT_WIDTH; - float width = ((float) minecraft->screen_width) * Gui::InvGuiScale; - float height = ((float) minecraft->screen_height) * Gui::InvGuiScale; - x_dest += width - ((width - (NUMBER_OF_SLOTS * SLOT_WIDTH)) / 2) - HUD_ELEMENT_WIDTH; - y_dest -= DEFAULT_HUD_PADDING; - y_dest += height - HUD_ELEMENT_HEIGHT - TOOLBAR_HEIGHT - NEW_HUD_PADDING; - // Call Original Method - component->blit(x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src); -} -static void Gui_renderBubbles_GuiComponent_blit_injection(Gui *component, int32_t x_dest, int32_t y_dest, int32_t x_src, int32_t y_src, int32_t width_dest, int32_t height_dest, int32_t width_src, int32_t height_src) { - Minecraft *minecraft = component->minecraft; - x_dest -= DEFAULT_HUD_PADDING; - float width = ((float) minecraft->screen_width) * Gui::InvGuiScale; - float height = ((float) minecraft->screen_height) * Gui::InvGuiScale; - x_dest += (width - (NUMBER_OF_SLOTS * SLOT_WIDTH)) / 2; - y_dest -= DEFAULT_HUD_PADDING + DEFAULT_BUBBLES_PADDING + HUD_ELEMENT_HEIGHT; - y_dest += height - HUD_ELEMENT_HEIGHT - TOOLBAR_HEIGHT - HUD_ELEMENT_HEIGHT - NEW_HUD_PADDING; - // Call Original Method - component->blit(x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src); -} - -// Heart Food Overlay -static int heal_amount = 0, heal_amount_drawing = 0; -static void Gui_renderHearts_injection(Gui_renderHearts_t original, Gui *gui) { - // Get heal_amount - heal_amount = heal_amount_drawing = 0; - - Inventory *inventory = gui->minecraft->player->inventory; - ItemInstance *held_ii = inventory->getSelected(); - if (held_ii) { - Item *held = Item::items[held_ii->id]; - if (held->isFood() && held_ii->id) { - int nutrition = ((FoodItem *) held)->nutrition; - int cur_health = gui->minecraft->player->health; - int heal_num = fmin(cur_health + nutrition, 20) - cur_health; - heal_amount = heal_amount_drawing = heal_num; - } - } - - // Call original - original(gui); -} -static GuiComponent_blit_t get_blit_with_classic_hud_offset() { - return use_classic_hud ? Gui_renderHearts_GuiComponent_blit_hearts_injection : GuiComponent_blit->get(false); -} -#define PINK_HEART_FULL 70 -#define PINK_HEART_HALF 79 -static void Gui_renderHearts_GuiComponent_blit_overlay_empty_injection(Gui *gui, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t w1, int32_t h1, int32_t w2, int32_t h2) { - // Call Original Method - get_blit_with_classic_hud_offset()((GuiComponent *) gui, x1, y1, x2, y2, w1, h1, w2, h2); - // Render The Overlay - if (heal_amount_drawing == 1) { - // Half Heart - get_blit_with_classic_hud_offset()((GuiComponent *) gui, x1, y1, PINK_HEART_HALF, 0, w1, h1, w2, h2); - heal_amount_drawing = 0; - } else if (heal_amount_drawing > 0) { - // Full Heart - get_blit_with_classic_hud_offset()((GuiComponent *) gui, x1, y1, PINK_HEART_FULL, 0, w1, h1, w2, h2); - heal_amount_drawing -= 2; - } -} -static void Gui_renderHearts_GuiComponent_blit_overlay_hearts_injection(Gui *gui, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t w1, int32_t h1, int32_t w2, int32_t h2) { - // Offset the overlay - if (x2 == 52) { - heal_amount_drawing += 2; - } else if (x2 == 61 && heal_amount) { - // Half heart, flipped - get_blit_with_classic_hud_offset()((GuiComponent *) gui, x1, y1, PINK_HEART_FULL, 0, w1, h1, w2, h2); - heal_amount_drawing += 1; - } - // Call Original Method - get_blit_with_classic_hud_offset()((GuiComponent *) gui, x1, y1, x2, y2, w1, h1, w2, h2); - heal_amount_drawing = fmin(heal_amount_drawing, heal_amount); -} - -// Additional GUI Rendering -static int hide_chat_messages = 0; -bool is_in_chat = false; -static int render_selected_item_text = 0; -static void Gui_renderChatMessages_injection(Gui_renderChatMessages_t original, Gui *gui, int32_t y_offset, uint32_t max_messages, bool disable_fading, Font *font) { - // Handle Classic HUD - if (use_classic_hud) { - Minecraft *minecraft = gui->minecraft; - if (!minecraft->isCreativeMode()) { - y_offset -= (HUD_ELEMENT_HEIGHT * 2) + NEW_HUD_PADDING; - } - } - - // Call Original Method - if (!hide_chat_messages && (!is_in_chat || disable_fading)) { - original(gui, y_offset, max_messages, disable_fading, font); - } - - // Render Selected Item Text - if (render_selected_item_text && !disable_fading) { - // Fix GL Mode - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - // Calculate Selected Item Text Scale - Minecraft *minecraft = gui->minecraft; - int32_t screen_width = minecraft->screen_width; - float scale = ((float) screen_width) * Gui::InvGuiScale; - // Render Selected Item Text - gui->renderOnSelectItemNameText((int32_t) scale, font, y_offset - 0x13); - } -} -// Reset Selected Item Text Timer On Slot Select -static uint32_t reset_selected_item_text_timer = 0; -static void Gui_tick_injection(Gui_tick_t original, Gui *gui) { - // Call Original Method - original(gui); - - // Handle Reset - if (render_selected_item_text) { - float *selected_item_text_timer = &gui->selected_item_text_timer; - if (reset_selected_item_text_timer) { - // Reset - *selected_item_text_timer = 0; - reset_selected_item_text_timer = 0; - } - } -} -// Trigger Reset Selected Item Text Timer On Slot Select -static void Inventory_selectSlot_injection(Inventory_selectSlot_t original, Inventory *inventory, int32_t slot) { - // Call Original Method - original(inventory, slot); - - // Trigger Reset Selected Item Text Timer - if (render_selected_item_text) { - reset_selected_item_text_timer = 1; - } -} - -// Translucent Toolbar -static void Gui_renderToolBar_injection(Gui_renderToolBar_t original, Gui *gui, float param_1, int32_t param_2, int32_t param_3) { - // Call Original Method - bool was_blend_enabled = glIsEnabled(GL_BLEND); - if (!was_blend_enabled) { - glEnable(GL_BLEND); - } - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - original(gui, param_1, param_2, param_3); - if (!was_blend_enabled) { - glDisable(GL_BLEND); - } -} -static void Gui_renderToolBar_glColor4f_injection(GLfloat red, GLfloat green, GLfloat blue, __attribute__((unused)) GLfloat alpha) { - // Fix Alpha - glColor4f(red, green, blue, 1.0f); -} - -// Fix Screen Rendering When GUI is Hidden -static void Screen_render_injection(Screen_render_t original, Screen *screen, int32_t param_1, int32_t param_2, float param_3) { - // Fix - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - // Call Original Method - original(screen, param_1, param_2, param_3); -} - // Sanitize Username #define MAX_USERNAME_LENGTH 16 static void LoginPacket_read_injection(LoginPacket_read_t original, LoginPacket *packet, RakNet_BitStream *bit_stream) { @@ -215,8 +31,8 @@ static void LoginPacket_read_injection(LoginPacket_read_t original, LoginPacket // Prepare RakNet_RakString *rak_string = &packet->username; // Get Original Username - RakNet_RakString_SharedString *shared_string = rak_string->sharedString; - char *c_str = shared_string->c_str; + const RakNet_RakString_SharedString *shared_string = rak_string->sharedString; + const char *c_str = shared_string->c_str; // Sanitize char *new_username = strdup(c_str); ALLOC_CHECK(new_username); @@ -250,12 +66,11 @@ static const char *RAKNET_ERROR_NAMES[] = { "Failed Test Send", "Port Cannot Be 0", "Failed To Create Network Thread", - "Couldn't Generate GUID", "Unknown" }; static RakNet_StartupResult RakNetInstance_host_RakNet_RakPeer_Startup_injection(RakNet_RakPeer *rak_peer, unsigned short maxConnections, unsigned char *socketDescriptors, uint32_t socketDescriptorCount, int32_t threadPriority) { // Call Original Method - RakNet_StartupResult result = rak_peer->Startup(maxConnections, socketDescriptors, socketDescriptorCount, threadPriority); + const RakNet_StartupResult result = rak_peer->Startup(maxConnections, socketDescriptors, socketDescriptorCount, threadPriority); // Print Error if (result != RAKNET_STARTED) { @@ -276,21 +91,11 @@ static RakNetInstance *RakNetInstance_injection(RakNetInstance_constructor_t ori return result; } -// Close Current Screen On Death To Prevent Bugs -static void LocalPlayer_die_injection(LocalPlayer_die_t original, LocalPlayer *entity, Entity *cause) { - // Close Screen - Minecraft *minecraft = entity->minecraft; - minecraft->setScreen(nullptr); - - // Call Original Method - original(entity, cause); -} - // Fix Furnace Not Checking Item Auxiliary When Inserting New Item static int32_t FurnaceScreen_handleAddItem_injection(FurnaceScreen_handleAddItem_t original, FurnaceScreen *furnace_screen, int32_t slot, const ItemInstance *item) { // Get Existing Item FurnaceTileEntity *tile_entity = furnace_screen->tile_entity; - ItemInstance *existing_item = tile_entity->getItem(slot); + const ItemInstance *existing_item = tile_entity->getItem(slot); // Check Item int valid; @@ -318,37 +123,16 @@ static int32_t FurnaceScreen_handleAddItem_injection(FurnaceScreen_handleAddItem } } -// Custom Cursor Rendering -// -// The default behavior for Touch GUI is to only render the cursor when the mouse is clicking, this fixes that. -// This also makes the cursor always render if the mouse is unlocked, instead of just when there is a Screen showing. -static void GameRenderer_render_injection(GameRenderer_render_t original, GameRenderer *game_renderer, float param_1) { - // Call Original Method - original(game_renderer, param_1); - - // Check If Cursor Should Render - if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF) { - // Fix GL Mode - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - // Get X And Y - float x = Mouse::getX() * Gui::InvGuiScale; - float y = Mouse::getY() * Gui::InvGuiScale; - // Render Cursor - Minecraft *minecraft = game_renderer->minecraft; - Common::renderCursor(x, y, minecraft); - } -} - // Get Real Selected Slot int32_t misc_get_real_selected_slot(Player *player) { // Get Selected Slot - Inventory *inventory = player->inventory; + const Inventory *inventory = player->inventory; int32_t selected_slot = inventory->selectedSlot; // Linked Slots - int32_t linked_slots_length = inventory->linked_slots_length; + const int32_t linked_slots_length = inventory->linked_slots_length; if (selected_slot < linked_slots_length) { - int32_t *linked_slots = inventory->linked_slots; + const int32_t *linked_slots = inventory->linked_slots; selected_slot = linked_slots[selected_slot]; } @@ -356,26 +140,12 @@ int32_t misc_get_real_selected_slot(Player *player) { return selected_slot; } -// Properly Generate Buffers -static void anGenBuffers_injection(__attribute__((unused)) Common_anGenBuffers_t original, const int32_t count, uint32_t *buffers) { - if (!reborn_is_headless()) { - glGenBuffers(count, buffers); - } -} - -// Fix Graphics Bug When Switching To First-Person While Sneaking -static void PlayerRenderer_render_injection(PlayerRenderer *model_renderer, Entity *entity, float param_2, float param_3, float param_4, float param_5, float param_6) { - HumanoidMobRenderer_vtable_base->render((HumanoidMobRenderer *) model_renderer, entity, param_2, param_3, param_4, param_5, param_6); - HumanoidModel *model = model_renderer->model; - model->is_sneaking = false; -} - // Custom API Port HOOK(bind, int, (int sockfd, const struct sockaddr *addr, socklen_t addrlen)) { const sockaddr *new_addr = addr; sockaddr_in in_addr = {}; if (addr->sa_family == AF_INET) { - in_addr = *(const struct sockaddr_in *) new_addr; + in_addr = *(const sockaddr_in *) new_addr; if (in_addr.sin_port == ntohs(4711)) { const char *new_port_str = getenv(MCPI_API_PORT_ENV); long int new_port; @@ -383,51 +153,12 @@ HOOK(bind, int, (int sockfd, const struct sockaddr *addr, socklen_t addrlen)) { in_addr.sin_port = htons(new_port); } } - new_addr = (const struct sockaddr *) &in_addr; + new_addr = (const sockaddr *) &in_addr; } ensure_bind(); return real_bind(sockfd, new_addr, addrlen); } -// Change Grass Color -static int32_t get_color(LevelSource *level_source, int32_t x, int32_t z) { - Biome *biome = level_source->getBiome(x, z); - if (biome == nullptr) { - return 0; - } - return biome->color; -} -#define BIOME_BLEND_SIZE 7 -static int32_t GrassTile_getColor_injection(__attribute__((unused)) GrassTile_getColor_t original, __attribute__((unused)) GrassTile *tile, LevelSource *level_source, int32_t x, __attribute__((unused)) int32_t y, int32_t z) { - int r_sum = 0; - int g_sum = 0; - int b_sum = 0; - int color_sum = 0; - int x_start = x - (BIOME_BLEND_SIZE / 2); - int z_start = z - (BIOME_BLEND_SIZE / 2); - for (int x_offset = 0; x_offset < BIOME_BLEND_SIZE; x_offset++) { - for (int z_offset = 0; z_offset < BIOME_BLEND_SIZE; z_offset++) { - int32_t color = get_color(level_source, x_start + x_offset, z_start + z_offset); - r_sum += (color >> 16) & 0xff; - g_sum += (color >> 8) & 0xff; - b_sum += color & 0xff; - color_sum++; - } - } - int r_avg = r_sum / color_sum; - int g_avg = g_sum / color_sum; - int b_avg = b_sum / color_sum; - return (r_avg << 16) | (g_avg << 8) | b_avg; -} -static int32_t TallGrass_getColor_injection(TallGrass_getColor_t original, TallGrass *tile, LevelSource *level_source, int32_t x, int32_t y, int32_t z) { - int32_t original_color = original(tile, level_source, x, y, z); - if (original_color == 0x339933) { - return GrassTile_getColor_injection(nullptr, nullptr, level_source, x, y, z); - } else { - return original_color; - } -} - // Generate Caves static void RandomLevelSource_buildSurface_injection(RandomLevelSource_buildSurface_t original, RandomLevelSource *random_level_source, int32_t chunk_x, int32_t chunk_y, unsigned char *chunk_data, Biome **biomes) { // Call Original Method @@ -443,12 +174,6 @@ static void RandomLevelSource_buildSurface_injection(RandomLevelSource_buildSurf cave_feature->apply((ChunkSource *) random_level_source, level, chunk_x, chunk_y, chunk_data, 0); } -// No Block Tinting -template -static int32_t Tile_getColor_injection(__attribute__((unused)) std::function original, __attribute__((unused)) T *self, __attribute__((unused)) LevelSource *level_source, __attribute__((unused)) int x, __attribute__((unused)) int y, __attribute__((unused)) int z) { - return 0xffffff; -} - // Disable Hostile AI In Creative Mode static Entity *PathfinderMob_findAttackTarget_injection(PathfinderMob *mob) { // Call Original Method @@ -461,9 +186,9 @@ static Entity *PathfinderMob_findAttackTarget_injection(PathfinderMob *mob) { // Check If Creative Mode if (target != nullptr && target->isPlayer()) { - Player *player = (Player *) target; - Inventory *inventory = player->inventory; - bool is_creative = inventory->is_creative; + const Player *player = (Player *) target; + const Inventory *inventory = player->inventory; + const bool is_creative = inventory->is_creative; if (is_creative) { target = nullptr; } @@ -473,122 +198,9 @@ static Entity *PathfinderMob_findAttackTarget_injection(PathfinderMob *mob) { return target; } -// 3D Chests -static int32_t Tile_getRenderShape_injection(Tile *tile) { - if (tile == Tile::chest) { - // Don't Render "Simple" Chest Model - return -1; - } else { - // Call Original Method - return tile->getRenderShape(); - } -} -static ChestTileEntity *ChestTileEntity_injection(ChestTileEntity_constructor_t original, ChestTileEntity *tile_entity) { - // Call Original Method - original(tile_entity); - - // Enable Renderer - tile_entity->renderer_id = 1; - - // Return - return tile_entity; -} -static bool is_rendering_chest = false; -static void ModelPart_render_injection(ModelPart *model_part, float scale) { - // Start - is_rendering_chest = true; - - // Call Original Method - model_part->render(scale); - - // Stop - is_rendering_chest = false; -} -static void Tesselator_vertexUV_injection(Tesselator_vertexUV_t original, Tesselator *tesselator, float x, float y, float z, float u, float v) { - // Fix Chest Texture - if (is_rendering_chest) { - v /= 2; - } - - // Call Original Method - original(tesselator, x, y, z, u, v); -} -static bool ChestTileEntity_shouldSave_injection(__attribute__((unused)) ChestTileEntity_shouldSave_t original, __attribute__((unused)) ChestTileEntity *tile_entity) { - return true; -} - -// Animated 3D Chest -static ContainerMenu *ContainerMenu_injection(ContainerMenu_constructor_t original, ContainerMenu *container_menu, Container *container, int32_t param_1) { - // Call Original Method - original(container_menu, container, param_1); - - // Play Animation - ChestTileEntity *tile_entity = (ChestTileEntity *) (((unsigned char *) container) - offsetof(ChestTileEntity, container)); - bool is_client = tile_entity->is_client; - if (!is_client) { - container->startOpen(); - } - - // Return - return container_menu; -} -static ContainerMenu *ContainerMenu_destructor_injection(ContainerMenu_destructor_complete_t original, ContainerMenu *container_menu) { - // Play Animation - Container *container = container_menu->container; - ChestTileEntity *tile_entity = (ChestTileEntity *) (((unsigned char *) container) - offsetof(ChestTileEntity, container)); - bool is_client = tile_entity->is_client; - if (!is_client) { - container->stopOpen(); - } - - // Call Original Method - return original(container_menu); -} - -// Custom Outline Color -static void LevelRenderer_render_AABB_glColor4f_injection(__attribute__((unused)) GLfloat red, __attribute__((unused)) GLfloat green, __attribute__((unused)) GLfloat blue, __attribute__((unused)) GLfloat alpha) { - // Set Color - glColor4f(0, 0, 0, 0.4); - - // Find Line Width - char *custom_line_width = getenv(MCPI_BLOCK_OUTLINE_WIDTH_ENV); - float line_width; - if (custom_line_width != nullptr) { - // Custom - line_width = strtof(custom_line_width, nullptr); - } else { - // Guess - line_width = 1.5f / Gui::InvGuiScale; - } - // Clamp Line Width - float range[2]; - glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range); - if (range[1] < line_width) { - line_width = range[1]; - } else if (range[0] > line_width) { - line_width = range[0]; - } - // Set Line Width - glLineWidth(line_width); -} - -// Fix Furnace Visual Bug -static int FurnaceTileEntity_getLitProgress_injection(FurnaceTileEntity_getLitProgress_t original, FurnaceTileEntity *furnace, int max) { - // Call Original Method - int ret = original(furnace, max); - - // Fix Bug - if (ret > max) { - ret = max; - } - - // Return - return ret; -} - // Fix used items transferring durability static int selected_slot = -1; -static void Player_startUsingItem_injection(Player_startUsingItem_t original, Player *self, ItemInstance *item_instance, int time) { +static void Player_startUsingItem_injection(Player_startUsingItem_t original, Player *self, ItemInstance *item_instance, const int time) { selected_slot = self->inventory->selectedSlot; original(self, item_instance, time); } @@ -599,18 +211,6 @@ static void Player_stopUsingItem_injection(Player_stopUsingItem_t original, Play original(self); } -// Java Light Ramp -static void Dimension_updateLightRamp_injection(__attribute__((unused)) Dimension_updateLightRamp_t original, Dimension *self) { - // https://github.com/ReMinecraftPE/mcpe/blob/d7a8b6baecf8b3b050538abdbc976f690312aa2d/source/world/level/Dimension.cpp#L92-L105 - for (int i = 0; i <= 15; i++) { - float f1 = 1.0f - (((float) i) / 15.0f); - self->light_ramp[i] = ((1.0f - f1) / (f1 * 3.0f + 1.0f)) * (1.0f - 0.1f) + 0.1f; - // Default Light Ramp: - // float fVar4 = 1.0 - ((float) i * 0.0625); - // self->light_ramp[i] = ((1.0 - fVar4) / (fVar4 * 3.0 + 1.0)) * 0.95 + 0.15; - } -} - // Read Asset File static AppPlatform_readAssetFile_return_value AppPlatform_readAssetFile_injection(__attribute__((unused)) AppPlatform_readAssetFile_t original, __attribute__((unused)) AppPlatform *app_platform, const std::string &path) { // Open File @@ -631,38 +231,15 @@ static AppPlatform_readAssetFile_return_value AppPlatform_readAssetFile_injectio stream.close(); // Return String AppPlatform_readAssetFile_return_value ret; - ret.length = len; + ret.length = int(len); ret.data = strdup(buf); return ret; } -// Add Missing Buttons To Pause Menu -static void PauseScreen_init_injection(PauseScreen_init_t original, PauseScreen *screen) { - // Call Original Method - original(screen); - - // Check If Server - Minecraft *minecraft = screen->minecraft; - RakNetInstance *rak_net_instance = minecraft->rak_net_instance; - if (rak_net_instance != nullptr) { - if (rak_net_instance->isServer()) { - // Add Button - std::vector