Split Up misc.cpp
All checks were successful
CI / Build (AMD64) (push) Successful in 21m28s
CI / Build (ARM64) (push) Successful in 23m24s
CI / Build (ARMHF) (push) Successful in 13m9s
CI / Test (AMD64, Server) (push) Successful in 2m14s
CI / Build Example Mods (push) Successful in 1m41s
CI / Test (ARM64, Client) (push) Successful in 4m2s
CI / Test (ARM64, Server) (push) Successful in 59s
CI / Test (AMD64, Client) (push) Successful in 6m14s
CI / Test (ARMHF, Client) (push) Successful in 4m15s
CI / Test (ARMHF, Server) (push) Successful in 1m11s
CI / Release (push) Has been skipped

This commit is contained in:
TheBrokenRail 2024-08-25 17:06:12 -04:00
parent c5937e6794
commit 8ef6e0885a
14 changed files with 988 additions and 879 deletions

View File

@ -8,6 +8,7 @@
* Proper Create New World Screen
* Proper Chat Screen
* New Feature Flags
* New Functionality
* `Animated Lava` (Enabled By Default)
* `Animated Fire` (Enabled By Default)
* `Add Cake` (Enabled By Default)
@ -39,6 +40,19 @@
* `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)

View File

@ -86,3 +86,15 @@ TRUE Stop Creative Players From Burning
TRUE Render Fire In Third-Person
TRUE Improved Water Rendering
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

View File

@ -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(

View File

@ -0,0 +1,8 @@
#pragma once
#include <symbols/minecraft.h>
extern "C" {
GuiComponent_blit_t get_blit_with_classic_hud_offset();
int get_classic_hud_y_offset(Minecraft *minecraft);
}

View File

@ -30,4 +30,5 @@ void init_override();
void init_screenshot();
void init_f3();
void init_multidraw();
void init_classic_ui();
}

View File

@ -0,0 +1,2 @@
# `classic-ui` Mod
This mod adjusts the UI to make it more similar to Java Edition.

View File

@ -0,0 +1,142 @@
#include <symbols/minecraft.h>
#include <libreborn/libreborn.h>
#include <mods/init/init.h>
#include <mods/feature/feature.h>
#include <mods/classic-ui/classic-ui.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 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 <auto *const func>
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>);
}
}

View File

@ -46,5 +46,6 @@ __attribute__((constructor)) static void init() {
init_screenshot();
init_f3();
init_multidraw();
init_classic_ui();
}
}

View File

@ -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.

352
mods/src/misc/graphics.cpp Normal file
View File

@ -0,0 +1,352 @@
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <GLES/gl.h>
#include <media-layer/core.h>
#include <mods/feature/feature.h>
#include <mods/multidraw/multidraw.h>
#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<GameRenderer_render_t, GameRenderer *, float>);
overwrite_calls(NinecraftApp_initGLStates, nop<NinecraftApp_initGLStates_t, NinecraftApp *>);
overwrite_calls(Gui_onConfigChanged, nop<Gui_onConfigChanged_t, Gui *, const Config &>);
overwrite_calls(LevelRenderer_generateSky, nop<LevelRenderer_generateSky_t, LevelRenderer *>);
}
}

View File

@ -2,3 +2,10 @@
__attribute__((visibility("internal"))) void _init_misc_logging();
__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 <typename... Args>
static void nop(__attribute__((unused)) Args... args) {
}

File diff suppressed because it is too large Load Diff

69
mods/src/misc/tinting.cpp Normal file
View File

@ -0,0 +1,69 @@
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <mods/feature/feature.h>
#include "misc-internal.h"
// Change Grass Color
static int32_t get_color(LevelSource *level_source, int32_t x, int32_t z) {
const 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, const int32_t x, __attribute__((unused)) int32_t y, const int32_t z) {
int r_sum = 0;
int g_sum = 0;
int b_sum = 0;
int color_sum = 0;
const int x_start = x - (BIOME_BLEND_SIZE / 2);
const 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++) {
const 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++;
}
}
const int r_avg = r_sum / color_sum;
const int g_avg = g_sum / color_sum;
const 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, const int32_t x, const int32_t y, const int32_t z) {
const 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;
}
}
// No Block Tinting
template <typename T>
static int32_t Tile_getColor_injection(__attribute__((unused)) std::function<int(T *, LevelSource *, int, int, int)> original, __attribute__((unused)) T *self, __attribute__((unused)) LevelSource *level_source, __attribute__((unused)) int x, __attribute__((unused)) int y, __attribute__((unused)) int z) {
return 0xffffff;
}
// Init
void _init_misc_tinting() {
// Change Grass Color
if (feature_has("Add Biome Colors To Grass", server_disabled)) {
overwrite_calls(GrassTile_getColor, GrassTile_getColor_injection);
overwrite_calls(TallGrass_getColor, TallGrass_getColor_injection);
}
// Disable Block Tinting
if (feature_has("Disable Block Tinting", server_disabled)) {
overwrite_calls(GrassTile_getColor, Tile_getColor_injection<GrassTile>);
overwrite_calls(TallGrass_getColor, Tile_getColor_injection<TallGrass>);
overwrite_calls(StemTile_getColor, Tile_getColor_injection<StemTile>);
overwrite_calls(LeafTile_getColor, Tile_getColor_injection<LeafTile>);
overwrite_calls(LiquidTile_getColor, Tile_getColor_injection<LiquidTile>);
}
}

291
mods/src/misc/ui.cpp Normal file
View File

@ -0,0 +1,291 @@
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <GLES/gl.h>
#include <SDL/SDL.h>
#include <mods/feature/feature.h>
#include <mods/classic-ui/classic-ui.h>
#include <mods/misc/misc.h>
#include "misc-internal.h"
// 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;
const ItemInstance *held_ii = inventory->getSelected();
if (held_ii) {
Item *held = Item::items[held_ii->id];
if (held->isFood() && held_ii->id) {
const int nutrition = ((FoodItem *) held)->nutrition;
const int cur_health = gui->minecraft->player->health;
const int heal_num = std::min(cur_health + nutrition, 20) - cur_health;
heal_amount = heal_amount_drawing = heal_num;
}
}
// Call original
original(gui);
}
#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 = std::min(heal_amount_drawing, heal_amount);
}
// Additional GUI Rendering
static bool hide_chat_messages = false;
bool is_in_chat = false;
static bool render_selected_item_text = false;
static void Gui_renderChatMessages_injection(Gui_renderChatMessages_t original, Gui *gui, int32_t y_offset, const uint32_t max_messages, const bool disable_fading, Font *font) {
// Handle Classic HUD
y_offset -= get_classic_hud_y_offset(gui->minecraft);
// 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
const Minecraft *minecraft = gui->minecraft;
const int32_t screen_width = minecraft->screen_width;
const 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 bool reset_selected_item_text_timer = false;
static void Gui_tick_injection(Gui_tick_t original, Gui *gui) {
// Call Original Method
original(gui);
// Handle Reset
if (render_selected_item_text && reset_selected_item_text_timer) {
// Reset
gui->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(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 = true;
}
}
// Translucent Toolbar
static void Gui_renderToolBar_injection(Gui_renderToolBar_t original, Gui *gui, const float param_1, const int32_t param_2, const int32_t param_3) {
// Call Original Method
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
original(gui, param_1, param_2, param_3);
glDisable(GL_BLEND);
}
static void Gui_renderToolBar_glColor4f_injection(const GLfloat red, const GLfloat green, const 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, const int32_t param_1, const int32_t param_2, const float param_3) {
// Fix
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Call Original Method
original(screen, param_1, param_2, param_3);
}
// 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);
}
// 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, const 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);
}
}
// Fix Furnace Visual Bug
static int FurnaceTileEntity_getLitProgress_injection(FurnaceTileEntity_getLitProgress_t original, FurnaceTileEntity *furnace, const int max) {
// Call Original Method
int ret = original(furnace, max);
// Fix Bug
if (ret > max) {
ret = max;
}
// Return
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
const 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<Button *> *rendered_buttons = &screen->rendered_buttons;
std::vector<Button *> *selectable_buttons = &screen->selectable_buttons;
Button *button = screen->server_visibility_button;
rendered_buttons->push_back(button);
selectable_buttons->push_back(button);
// Update Button Text
screen->updateServerVisibilityText();
}
}
}
// Init
void _init_misc_ui() {
// Food Overlay
if (feature_has("Food Overlay", server_disabled)) {
overwrite_calls(Gui_renderHearts, Gui_renderHearts_injection);
overwrite_call((void *) 0x266f8, (void *) Gui_renderHearts_GuiComponent_blit_overlay_empty_injection);
overwrite_call((void *) 0x267c8, (void *) Gui_renderHearts_GuiComponent_blit_overlay_hearts_injection);
}
// Render Selected Item Text + Hide Chat Messages
hide_chat_messages = feature_has("Hide Chat Messages", server_disabled);
render_selected_item_text = feature_has("Render Selected Item Text", server_disabled);
overwrite_calls(Gui_renderChatMessages, Gui_renderChatMessages_injection);
overwrite_calls(Gui_tick, Gui_tick_injection);
overwrite_calls(Inventory_selectSlot, Inventory_selectSlot_injection);
// Translucent Toolbar
if (feature_has("Translucent Toolbar", server_disabled)) {
overwrite_calls(Gui_renderToolBar, Gui_renderToolBar_injection);
overwrite_call((void *) 0x26c5c, (void *) Gui_renderToolBar_glColor4f_injection);
}
// Fix Screen Rendering When GUI is Hidden
if (feature_has("Fix Screen Rendering When Hiding HUD", server_disabled)) {
overwrite_calls(Screen_render, Screen_render_injection);
}
// Remove Invalid Item Background (A Red Background That Appears For Items That Are Not Included In The gui_blocks Atlas)
if (feature_has("Remove Invalid Item Background", server_disabled)) {
unsigned char invalid_item_background_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x63c98, invalid_item_background_patch);
}
// Close Current Screen On Death To Prevent Bugs
if (feature_has("Close Current Screen On Death", server_disabled)) {
overwrite_calls(LocalPlayer_die, LocalPlayer_die_injection);
}
// Improved Cursor Rendering
if (feature_has("Improved Cursor Rendering", server_disabled)) {
// Disable Normal Cursor Rendering
unsigned char disable_cursor_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x4a6c0, disable_cursor_patch);
// Add Custom Cursor Rendering
overwrite_calls(GameRenderer_render, GameRenderer_render_injection);
}
// Fix Furnace Visual Bug
if (feature_has("Fix Furnace Screen Visual Bug", server_disabled)) {
overwrite_calls(FurnaceTileEntity_getLitProgress, FurnaceTileEntity_getLitProgress_injection);
}
// Fix Pause Menu
if (feature_has("Fix Pause Menu", server_disabled)) {
// Add Missing Buttons To Pause Menu
overwrite_calls(PauseScreen_init, PauseScreen_init_injection);
}
// Remove Forced GUI Lag
if (feature_has("Remove Forced GUI Lag (Can Break Joining Servers)", server_enabled)) {
overwrite_calls(Common_sleepMs, nop<Common_sleepMs_t, int>);
}
// Custom GUI Scale
const char *gui_scale_str = getenv(MCPI_GUI_SCALE_ENV);
if (gui_scale_str != nullptr) {
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x173e8, nop_patch);
patch((void *) 0x173f0, nop_patch);
const float gui_scale = strtof(gui_scale_str, nullptr);
uint32_t gui_scale_raw;
memcpy(&gui_scale_raw, &gui_scale, sizeof (gui_scale_raw));
patch_address((void *) 0x17520, (void *) gui_scale_raw);
}
// Don't Wrap Text On '\r' Or '\t' Because They Are Actual Characters In MCPI
if (feature_has("Fix Text Wrapping", server_disabled)) {
patch_address(&Strings::text_wrapping_delimiter, (void *) " \n");
}
// Fix Invalid ItemInHandRenderer Texture Cache
if (feature_has("Fix Held Item Caching", server_disabled)) {
// This works by forcing MCPI to always use the branch that enables using the
// cache, but then patches that to do the opposite.
uchar ensure_equal_patch[] = {0x07, 0x00, 0x57, 0xe1}; // "cmp r7, r7"
patch((void *) 0x4b938, ensure_equal_patch);
uchar set_true_patch[] = {0x01, 0x30, 0xa0, 0x03}; // "moveq r3, #0x1"
patch((void *) 0x4b93c, set_true_patch);
}
}