2024-04-02 19:22:01 -04:00
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstring>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <cmath>
|
2020-12-02 18:18:49 -05:00
|
|
|
#include <string>
|
|
|
|
#include <fstream>
|
|
|
|
#include <streambuf>
|
2024-02-08 00:34:43 -05:00
|
|
|
#include <algorithm>
|
2020-12-02 18:18:49 -05:00
|
|
|
|
2024-04-02 19:22:01 -04:00
|
|
|
#include <GLES/gl.h>
|
2020-12-02 18:18:49 -05:00
|
|
|
|
2021-01-27 16:26:19 -05:00
|
|
|
#include <libreborn/libreborn.h>
|
2021-09-11 23:18:12 -04:00
|
|
|
#include <symbols/minecraft.h>
|
2020-12-02 18:18:49 -05:00
|
|
|
|
2024-04-02 19:22:01 -04:00
|
|
|
#include <SDL/SDL.h>
|
|
|
|
#include <media-layer/core.h>
|
|
|
|
|
|
|
|
#include <mods/init/init.h>
|
2022-06-25 17:30:08 -04:00
|
|
|
#include <mods/feature/feature.h>
|
|
|
|
#include "misc-internal.h"
|
|
|
|
#include <mods/misc/misc.h>
|
2020-12-02 18:18:49 -05:00
|
|
|
|
2024-04-02 19:22:01 -04:00
|
|
|
// 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;
|
2024-05-04 20:46:15 -04:00
|
|
|
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;
|
2024-04-02 19:22:01 -04:00
|
|
|
x_dest -= DEFAULT_HUD_PADDING;
|
2024-05-17 02:52:55 -04:00
|
|
|
float width = ((float) minecraft->screen_width) * Gui::InvGuiScale;
|
|
|
|
float height = ((float) minecraft->screen_height) * Gui::InvGuiScale;
|
2024-04-02 19:22:01 -04:00
|
|
|
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
|
2024-05-04 20:46:15 -04:00
|
|
|
component->blit(x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
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;
|
2024-05-17 02:52:55 -04:00
|
|
|
float width = ((float) minecraft->screen_width) * Gui::InvGuiScale;
|
|
|
|
float height = ((float) minecraft->screen_height) * Gui::InvGuiScale;
|
2024-04-02 19:22:01 -04:00
|
|
|
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
|
2024-05-04 20:46:15 -04:00
|
|
|
component->blit(x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
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;
|
2024-05-17 02:52:55 -04:00
|
|
|
float width = ((float) minecraft->screen_width) * Gui::InvGuiScale;
|
|
|
|
float height = ((float) minecraft->screen_height) * Gui::InvGuiScale;
|
2024-04-02 19:22:01 -04:00
|
|
|
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
|
2024-05-04 20:46:15 -04:00
|
|
|
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;
|
2024-05-15 05:02:19 -04:00
|
|
|
ItemInstance *held_ii = inventory->getSelected();
|
2024-05-04 20:46:15 -04:00
|
|
|
if (held_ii) {
|
2024-05-17 02:52:55 -04:00
|
|
|
Item *held = Item::items[held_ii->id];
|
2024-05-15 05:02:19 -04:00
|
|
|
if (held->isFood() && held_ii->id) {
|
2024-05-04 20:46:15 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
#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);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Additional GUI Rendering
|
|
|
|
static int hide_chat_messages = 0;
|
2024-05-04 20:46:15 -04:00
|
|
|
bool is_in_chat = false;
|
2024-04-02 19:22:01 -04:00
|
|
|
static int render_selected_item_text = 0;
|
2024-04-03 03:19:12 -04:00
|
|
|
static void Gui_renderChatMessages_injection(Gui_renderChatMessages_t original, Gui *gui, int32_t y_offset, uint32_t max_messages, bool disable_fading, Font *font) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// Handle Classic HUD
|
|
|
|
if (use_classic_hud) {
|
|
|
|
Minecraft *minecraft = gui->minecraft;
|
|
|
|
if (!Minecraft_isCreativeMode(minecraft)) {
|
|
|
|
y_offset -= (HUD_ELEMENT_HEIGHT * 2) + NEW_HUD_PADDING;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call Original Method
|
|
|
|
if (!hide_chat_messages && !is_in_chat) {
|
2024-04-03 03:19:12 -04:00
|
|
|
original(gui, y_offset, max_messages, disable_fading, font);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Render Selected Item Text
|
|
|
|
if (render_selected_item_text) {
|
|
|
|
// 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;
|
2024-05-17 02:52:55 -04:00
|
|
|
float scale = ((float) screen_width) * Gui::InvGuiScale;
|
2024-04-02 19:22:01 -04:00
|
|
|
// Render Selected Item Text
|
2024-05-15 05:02:19 -04:00
|
|
|
gui->renderOnSelectItemNameText((int32_t) scale, font, y_offset - 0x13);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Reset Selected Item Text Timer On Slot Select
|
|
|
|
static uint32_t reset_selected_item_text_timer = 0;
|
2024-04-03 03:19:12 -04:00
|
|
|
static void Gui_tick_injection(Gui_tick_t original, Gui *gui) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// Call Original Method
|
2024-04-03 03:19:12 -04:00
|
|
|
original(gui);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// 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
|
2024-04-03 03:19:12 -04:00
|
|
|
static void Inventory_selectSlot_injection(Inventory_selectSlot_t original, Inventory *inventory, int32_t slot) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// Call Original Method
|
2024-04-03 03:19:12 -04:00
|
|
|
original(inventory, slot);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Trigger Reset Selected Item Text Timer
|
|
|
|
if (render_selected_item_text) {
|
|
|
|
reset_selected_item_text_timer = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Translucent Toolbar
|
2024-04-03 03:19:12 -04:00
|
|
|
static void Gui_renderToolBar_injection(Gui_renderToolBar_t original, Gui *gui, float param_1, int32_t param_2, int32_t param_3) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// Call Original Method
|
2024-06-15 08:52:15 -04:00
|
|
|
bool was_blend_enabled = glIsEnabled(GL_BLEND);
|
2024-04-02 19:22:01 -04:00
|
|
|
if (!was_blend_enabled) {
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
}
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
2024-04-03 03:19:12 -04:00
|
|
|
original(gui, param_1, param_2, param_3);
|
2024-04-02 19:22:01 -04:00
|
|
|
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
|
2024-04-03 03:19:12 -04:00
|
|
|
static void Screen_render_injection(Screen_render_t original, Screen *screen, int32_t param_1, int32_t param_2, float param_3) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// Fix
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
// Call Original Method
|
2024-04-03 03:19:12 -04:00
|
|
|
original(screen, param_1, param_2, param_3);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Sanitize Username
|
|
|
|
#define MAX_USERNAME_LENGTH 16
|
2024-04-03 03:19:12 -04:00
|
|
|
static void LoginPacket_read_injection(LoginPacket_read_t original, LoginPacket *packet, RakNet_BitStream *bit_stream) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// Call Original Method
|
2024-04-03 03:19:12 -04:00
|
|
|
original(packet, bit_stream);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
// Sanitize
|
|
|
|
char *new_username = strdup(c_str);
|
|
|
|
ALLOC_CHECK(new_username);
|
2024-06-16 00:47:36 -04:00
|
|
|
sanitize_string(new_username, MAX_USERNAME_LENGTH, 0);
|
2024-04-02 19:22:01 -04:00
|
|
|
// Set New Username
|
2024-05-15 05:02:19 -04:00
|
|
|
rak_string->Assign(new_username);
|
2024-04-02 19:22:01 -04:00
|
|
|
// Free
|
|
|
|
free(new_username);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fix RakNet::RakString Security Bug
|
|
|
|
//
|
|
|
|
// RakNet::RakString's format constructor is often given unsanitized user input and is never used for formatting,
|
|
|
|
// this is a massive security risk, allowing clients to run arbitrary format specifiers, this disables the
|
|
|
|
// formatting functionality.
|
|
|
|
static RakNet_RakString *RakNet_RakString_injection(RakNet_RakString *rak_string, const char *format, ...) {
|
|
|
|
// Call Original Method
|
2024-05-15 05:08:39 -04:00
|
|
|
return RakNet_RakString_constructor(rak_string, "%s", format);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Print Error Message If RakNet Startup Fails
|
|
|
|
static const char *RAKNET_ERROR_NAMES[] = {
|
|
|
|
"Success",
|
|
|
|
"Already Started",
|
|
|
|
"Invalid Socket Descriptors",
|
|
|
|
"Invalid Max Connections",
|
|
|
|
"Socket Family Not Supported",
|
|
|
|
"Part Already In Use",
|
|
|
|
"Failed To Bind Port",
|
|
|
|
"Failed Test Send",
|
|
|
|
"Port Cannot Be 0",
|
|
|
|
"Failed To Create Network Thread",
|
|
|
|
"Couldn't Generate GUID",
|
|
|
|
"Unknown"
|
|
|
|
};
|
2024-06-15 08:52:15 -04:00
|
|
|
#define CONDITIONAL_ERR(is_error, ...) \
|
|
|
|
{ \
|
|
|
|
if ((is_error)) { \
|
|
|
|
ERR(__VA_ARGS__); \
|
|
|
|
} else { \
|
|
|
|
WARN(__VA_ARGS__); \
|
|
|
|
} \
|
|
|
|
}
|
2024-04-02 19:22:01 -04:00
|
|
|
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
|
2024-05-15 05:02:19 -04:00
|
|
|
RakNet_StartupResult result = rak_peer->Startup(maxConnections, socketDescriptors, socketDescriptorCount, threadPriority);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Print Error
|
|
|
|
if (result != RAKNET_STARTED) {
|
2024-06-15 08:52:15 -04:00
|
|
|
CONDITIONAL_ERR(reborn_is_server(), "Failed To Start RakNet: %s", RAKNET_ERROR_NAMES[result]);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Return
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fix Bug Where RakNetInstance Starts Pinging Potential Servers Before The "Join Game" Screen Is Opened
|
2024-04-03 03:19:12 -04:00
|
|
|
static RakNetInstance *RakNetInstance_injection(RakNetInstance_constructor_t original, RakNetInstance *rak_net_instance) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// Call Original Method
|
2024-04-03 03:19:12 -04:00
|
|
|
RakNetInstance *result = original(rak_net_instance);
|
2024-04-02 19:22:01 -04:00
|
|
|
// Fix
|
|
|
|
rak_net_instance->pinging_for_hosts = 0;
|
|
|
|
// Return
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close Current Screen On Death To Prevent Bugs
|
2024-04-03 03:19:12 -04:00
|
|
|
static void LocalPlayer_die_injection(LocalPlayer_die_t original, LocalPlayer *entity, Entity *cause) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// Close Screen
|
|
|
|
Minecraft *minecraft = entity->minecraft;
|
2024-05-15 05:02:19 -04:00
|
|
|
minecraft->setScreen(nullptr);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Call Original Method
|
2024-04-03 03:19:12 -04:00
|
|
|
original(entity, cause);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fix Furnace Not Checking Item Auxiliary When Inserting New Item
|
2024-04-03 03:19:12 -04:00
|
|
|
static int32_t FurnaceScreen_handleAddItem_injection(FurnaceScreen_handleAddItem_t original, FurnaceScreen *furnace_screen, int32_t slot, ItemInstance *item) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// Get Existing Item
|
|
|
|
FurnaceTileEntity *tile_entity = furnace_screen->tile_entity;
|
2024-05-15 05:02:19 -04:00
|
|
|
ItemInstance *existing_item = tile_entity->getItem(slot);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Check Item
|
|
|
|
int valid;
|
|
|
|
if (item->id == existing_item->id && item->auxiliary == existing_item->auxiliary) {
|
|
|
|
// Item Matches, Is Valid
|
|
|
|
valid = 1;
|
|
|
|
} else {
|
|
|
|
// Item Doesn't Match, Check If Existing Item Is Empty
|
|
|
|
if ((existing_item->id | existing_item->count | existing_item->auxiliary) == 0) {
|
|
|
|
// Existing Item Is Empty, Is Valid
|
|
|
|
valid = 1;
|
|
|
|
} else {
|
|
|
|
// Existing Item Isn't Empty, Isn't Valid
|
|
|
|
valid = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call Original Method
|
|
|
|
if (valid) {
|
|
|
|
// Valid
|
2024-04-03 03:19:12 -04:00
|
|
|
return original(furnace_screen, slot, item);
|
2024-04-02 19:22:01 -04:00
|
|
|
} else {
|
|
|
|
// Invalid
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
2024-04-03 03:19:12 -04:00
|
|
|
static void GameRenderer_render_injection(GameRenderer_render_t original, GameRenderer *game_renderer, float param_1) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// Call Original Method
|
2024-04-03 03:19:12 -04:00
|
|
|
original(game_renderer, param_1);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// 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
|
2024-05-17 02:52:55 -04:00
|
|
|
float x = Mouse::getX() * Gui::InvGuiScale;
|
|
|
|
float y = Mouse::getY() * Gui::InvGuiScale;
|
2024-04-02 19:22:01 -04:00
|
|
|
// Render Cursor
|
|
|
|
Minecraft *minecraft = game_renderer->minecraft;
|
2024-05-15 05:02:19 -04:00
|
|
|
Common::renderCursor(x, y, minecraft);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get Real Selected Slot
|
|
|
|
int32_t misc_get_real_selected_slot(Player *player) {
|
|
|
|
// Get Selected Slot
|
|
|
|
Inventory *inventory = player->inventory;
|
|
|
|
int32_t selected_slot = inventory->selectedSlot;
|
|
|
|
|
|
|
|
// Linked Slots
|
|
|
|
int32_t linked_slots_length = inventory->linked_slots_length;
|
|
|
|
if (selected_slot < linked_slots_length) {
|
|
|
|
int32_t *linked_slots = inventory->linked_slots;
|
|
|
|
selected_slot = linked_slots[selected_slot];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return
|
|
|
|
return selected_slot;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Properly Generate Buffers
|
|
|
|
static void anGenBuffers_injection(int32_t count, uint32_t *buffers) {
|
2024-06-15 08:52:15 -04:00
|
|
|
if (!reborn_is_headless()) {
|
|
|
|
glGenBuffers(count, buffers);
|
|
|
|
}
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fix Graphics Bug When Switching To First-Person While Sneaking
|
2024-04-03 03:19:12 -04:00
|
|
|
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_render_vtable_addr)((HumanoidMobRenderer *) model_renderer, entity, param_2, param_3, param_4, param_5, param_6);
|
2024-04-02 19:22:01 -04:00
|
|
|
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;
|
|
|
|
if (in_addr.sin_port == ntohs(4711)) {
|
|
|
|
const char *new_port_str = getenv("MCPI_API_PORT");
|
|
|
|
long int new_port;
|
|
|
|
if (new_port_str != nullptr && (new_port = strtol(new_port_str, nullptr, 0)) != 0L) {
|
|
|
|
in_addr.sin_port = htons(new_port);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
new_addr = (const struct 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) {
|
2024-05-15 05:02:19 -04:00
|
|
|
Biome *biome = level_source->getBiome(x, z);
|
2024-04-02 19:22:01 -04:00
|
|
|
if (biome == nullptr) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return biome->color;
|
|
|
|
}
|
|
|
|
#define BIOME_BLEND_SIZE 7
|
2024-05-04 20:46:15 -04:00
|
|
|
static int32_t GrassTile_getColor_injection(__attribute__((unused)) GrassTile *tile, LevelSource *level_source, int32_t x, __attribute__((unused)) int32_t y, int32_t z) {
|
2024-04-02 19:22:01 -04:00
|
|
|
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;
|
|
|
|
}
|
2024-04-03 03:19:12 -04:00
|
|
|
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);
|
2024-04-02 19:22:01 -04:00
|
|
|
if (original_color == 0x339933) {
|
2024-05-04 20:46:15 -04:00
|
|
|
return GrassTile_getColor_injection(nullptr, level_source, x, y, z);
|
2024-04-02 19:22:01 -04:00
|
|
|
} else {
|
|
|
|
return original_color;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate Caves
|
2024-04-03 03:19:12 -04:00
|
|
|
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) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// Call Original Method
|
2024-04-03 03:19:12 -04:00
|
|
|
original(random_level_source, chunk_x, chunk_y, chunk_data, biomes);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Get Level
|
|
|
|
Level *level = random_level_source->level;
|
|
|
|
|
|
|
|
// Get Cave Feature
|
|
|
|
LargeCaveFeature *cave_feature = &random_level_source->cave_feature;
|
|
|
|
|
|
|
|
// Generate
|
2024-05-15 05:02:19 -04:00
|
|
|
cave_feature->apply((ChunkSource *) random_level_source, level, chunk_x, chunk_y, chunk_data, 0);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// No Block Tinting
|
2024-05-24 04:44:53 -04:00
|
|
|
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) {
|
2024-04-02 19:22:01 -04:00
|
|
|
return 0xffffff;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disable Hostile AI In Creative Mode
|
|
|
|
static Entity *PathfinderMob_findAttackTarget_injection(PathfinderMob *mob) {
|
|
|
|
// Call Original Method
|
2024-05-15 05:02:19 -04:00
|
|
|
Entity *target = mob->findAttackTarget();
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Only modify the AI of monsters
|
2024-05-15 05:02:19 -04:00
|
|
|
if (mob->getCreatureBaseType() != 1) {
|
2024-04-02 19:22:01 -04:00
|
|
|
return target;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check If Creative Mode
|
2024-05-15 05:02:19 -04:00
|
|
|
if (target != nullptr && target->isPlayer()) {
|
2024-04-02 19:22:01 -04:00
|
|
|
Player *player = (Player *) target;
|
|
|
|
Inventory *inventory = player->inventory;
|
|
|
|
bool is_creative = inventory->is_creative;
|
|
|
|
if (is_creative) {
|
|
|
|
target = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return
|
|
|
|
return target;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 3D Chests
|
|
|
|
static int32_t Tile_getRenderShape_injection(Tile *tile) {
|
2024-05-17 02:52:55 -04:00
|
|
|
if (tile == Tile::chest) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// Don't Render "Simple" Chest Model
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
// Call Original Method
|
2024-05-15 05:02:19 -04:00
|
|
|
return tile->getRenderShape();
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
}
|
2024-04-03 03:19:12 -04:00
|
|
|
static ChestTileEntity *ChestTileEntity_injection(ChestTileEntity_constructor_t original, ChestTileEntity *tile_entity) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// Call Original Method
|
2024-04-03 03:19:12 -04:00
|
|
|
original(tile_entity);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// 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
|
2024-05-15 05:02:19 -04:00
|
|
|
model_part->render(scale);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Stop
|
|
|
|
is_rendering_chest = false;
|
|
|
|
}
|
2024-04-03 03:19:12 -04:00
|
|
|
static void Tesselator_vertexUV_injection(Tesselator_vertexUV_t original, Tesselator *tesselator, float x, float y, float z, float u, float v) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// Fix Chest Texture
|
|
|
|
if (is_rendering_chest) {
|
|
|
|
v /= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call Original Method
|
2024-04-03 03:19:12 -04:00
|
|
|
original(tesselator, x, y, z, u, v);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
2024-06-12 02:33:29 -04:00
|
|
|
static bool ChestTileEntity_shouldSave_injection(__attribute__((unused)) ChestTileEntity_shouldSave_t original, __attribute__((unused)) ChestTileEntity *tile_entity) {
|
2024-04-02 19:22:01 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Animated 3D Chest
|
2024-04-03 03:19:12 -04:00
|
|
|
static ContainerMenu *ContainerMenu_injection(ContainerMenu_constructor_t original, ContainerMenu *container_menu, Container *container, int32_t param_1) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// Call Original Method
|
2024-04-03 03:19:12 -04:00
|
|
|
original(container_menu, container, param_1);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Play Animation
|
|
|
|
ChestTileEntity *tile_entity = (ChestTileEntity *) (((unsigned char *) container) - offsetof(ChestTileEntity, container));
|
|
|
|
bool is_client = tile_entity->is_client;
|
|
|
|
if (!is_client) {
|
2024-05-15 05:02:19 -04:00
|
|
|
container->startOpen();
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Return
|
|
|
|
return container_menu;
|
|
|
|
}
|
2024-04-03 03:19:12 -04:00
|
|
|
static ContainerMenu *ContainerMenu_destructor_injection(ContainerMenu_destructor_complete_t original, ContainerMenu *container_menu) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// 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) {
|
2024-05-15 05:02:19 -04:00
|
|
|
container->stopOpen();
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Call Original Method
|
2024-04-03 03:19:12 -04:00
|
|
|
return original(container_menu);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Custom Outline Color
|
2024-06-15 08:52:15 -04:00
|
|
|
static void LevelRenderer_render_AABB_glColor4f_injection(__attribute__((unused)) GLfloat red, __attribute__((unused)) GLfloat green, __attribute__((unused)) GLfloat blue, __attribute__((unused)) GLfloat alpha) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// Set Color
|
|
|
|
glColor4f(0, 0, 0, 0.4);
|
|
|
|
|
|
|
|
// Find Line Width
|
|
|
|
char *custom_line_width = getenv("MCPI_BLOCK_OUTLINE_WIDTH");
|
|
|
|
float line_width;
|
|
|
|
if (custom_line_width != nullptr) {
|
|
|
|
// Custom
|
|
|
|
line_width = strtof(custom_line_width, nullptr);
|
|
|
|
} else {
|
|
|
|
// Guess
|
2024-05-17 02:52:55 -04:00
|
|
|
line_width = 1.5f / Gui::InvGuiScale;
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
// 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
|
2024-04-03 03:19:12 -04:00
|
|
|
static int FurnaceTileEntity_getLitProgress_injection(FurnaceTileEntity_getLitProgress_t original, FurnaceTileEntity *furnace, int max) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// Call Original Method
|
2024-04-03 03:19:12 -04:00
|
|
|
int ret = original(furnace, max);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Fix Bug
|
|
|
|
if (ret > max) {
|
|
|
|
ret = max;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fix used items transferring durability
|
|
|
|
static int selected_slot = -1;
|
2024-04-03 03:19:12 -04:00
|
|
|
static void Player_startUsingItem_injection(Player_startUsingItem_t original, Player *self, ItemInstance *item_instance, int time) {
|
2024-04-02 19:22:01 -04:00
|
|
|
selected_slot = self->inventory->selectedSlot;
|
2024-04-03 03:19:12 -04:00
|
|
|
original(self, item_instance, time);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
2024-04-03 03:19:12 -04:00
|
|
|
static void Player_stopUsingItem_injection(Player_stopUsingItem_t original, Player *self) {
|
2024-04-02 19:22:01 -04:00
|
|
|
if (selected_slot != self->inventory->selectedSlot) {
|
|
|
|
self->itemBeingUsed.id = 0;
|
|
|
|
}
|
2024-04-03 03:19:12 -04:00
|
|
|
original(self);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Java Light Ramp
|
2024-05-04 20:46:15 -04:00
|
|
|
static void Dimension_updateLightRamp_injection(__attribute__((unused)) Dimension_updateLightRamp_t original, Dimension *self) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-02 18:18:49 -05:00
|
|
|
// Read Asset File
|
2024-05-04 20:46:15 -04:00
|
|
|
static AppPlatform_readAssetFile_return_value AppPlatform_readAssetFile_injection(__attribute__((unused)) AppPlatform_readAssetFile_t original, __attribute__((unused)) AppPlatform *app_platform, std::string *path) {
|
2023-11-11 00:44:26 -05:00
|
|
|
// Open File
|
2024-05-04 20:46:15 -04:00
|
|
|
std::ifstream stream("data/" + *path, std::ios_base::binary | std::ios_base::ate);
|
2023-11-11 00:44:26 -05:00
|
|
|
if (!stream) {
|
|
|
|
// Does Not Exist
|
|
|
|
AppPlatform_readAssetFile_return_value ret;
|
|
|
|
ret.length = -1;
|
2024-04-02 19:22:01 -04:00
|
|
|
ret.data = nullptr;
|
2023-11-11 00:44:26 -05:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
// Read File
|
2024-04-02 19:22:01 -04:00
|
|
|
std::streamoff len = stream.tellg();
|
2023-09-24 23:06:23 -04:00
|
|
|
char *buf = new char[len];
|
2024-04-02 19:22:01 -04:00
|
|
|
ALLOC_CHECK(buf);
|
|
|
|
stream.seekg(0, std::ifstream::beg);
|
2023-09-24 23:06:23 -04:00
|
|
|
stream.read(buf, len);
|
2023-11-11 00:44:26 -05:00
|
|
|
stream.close();
|
2020-12-04 12:17:51 -05:00
|
|
|
// Return String
|
|
|
|
AppPlatform_readAssetFile_return_value ret;
|
2023-09-24 23:07:30 -04:00
|
|
|
ret.length = len;
|
|
|
|
ret.data = strdup(buf);
|
2020-12-04 12:17:51 -05:00
|
|
|
return ret;
|
2020-12-02 18:18:49 -05:00
|
|
|
}
|
|
|
|
|
2022-04-11 22:52:38 -04:00
|
|
|
// Add Missing Buttons To Pause Menu
|
2024-04-03 03:19:12 -04:00
|
|
|
static void PauseScreen_init_injection(PauseScreen_init_t original, PauseScreen *screen) {
|
2022-04-11 22:52:38 -04:00
|
|
|
// Call Original Method
|
2024-04-03 03:19:12 -04:00
|
|
|
original(screen);
|
2022-04-11 22:52:38 -04:00
|
|
|
|
|
|
|
// Check If Server
|
2024-01-06 06:30:23 -05:00
|
|
|
Minecraft *minecraft = screen->minecraft;
|
|
|
|
RakNetInstance *rak_net_instance = minecraft->rak_net_instance;
|
2024-04-02 19:22:01 -04:00
|
|
|
if (rak_net_instance != nullptr) {
|
2024-05-15 05:02:19 -04:00
|
|
|
if (rak_net_instance->isServer()) {
|
2022-04-11 22:52:38 -04:00
|
|
|
// Add Button
|
2024-01-06 06:30:23 -05:00
|
|
|
std::vector<Button *> *rendered_buttons = &screen->rendered_buttons;
|
|
|
|
std::vector<Button *> *selectable_buttons = &screen->selectable_buttons;
|
|
|
|
Button *button = screen->server_visibility_button;
|
2022-04-11 22:52:38 -04:00
|
|
|
rendered_buttons->push_back(button);
|
|
|
|
selectable_buttons->push_back(button);
|
|
|
|
|
|
|
|
// Update Button Text
|
2024-05-15 05:02:19 -04:00
|
|
|
screen->updateServerVisibilityText();
|
2022-04-11 22:52:38 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-07 06:47:46 +00:00
|
|
|
// Implement crafting remainders
|
|
|
|
void PaneCraftingScreen_craftSelectedItem_PaneCraftingScreen_recheckRecipes_injection(PaneCraftingScreen *self) {
|
|
|
|
// Check for crafting remainders
|
|
|
|
CItem *item = self->item;
|
|
|
|
for (size_t i = 0; i < item->ingredients.size(); i++) {
|
|
|
|
ItemInstance requested_item_instance = item->ingredients[i].requested_item;
|
2024-05-17 02:52:55 -04:00
|
|
|
Item *requested_item = Item::items[requested_item_instance.id];
|
2024-05-15 05:02:19 -04:00
|
|
|
ItemInstance *craftingRemainingItem = requested_item->getCraftingRemainingItem(&requested_item_instance);
|
2024-04-02 19:22:01 -04:00
|
|
|
if (craftingRemainingItem != nullptr) {
|
2024-02-07 06:47:46 +00:00
|
|
|
// Add or drop remainder
|
|
|
|
LocalPlayer *player = self->minecraft->player;
|
2024-05-15 05:02:19 -04:00
|
|
|
if (!player->inventory->add(craftingRemainingItem)) {
|
2024-02-07 06:47:46 +00:00
|
|
|
// Drop
|
2024-05-15 05:02:19 -04:00
|
|
|
player->drop(craftingRemainingItem, false);
|
2024-02-07 06:47:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Call Original Method
|
2024-05-15 05:02:19 -04:00
|
|
|
self->recheckRecipes();
|
2024-02-07 06:47:46 +00:00
|
|
|
}
|
|
|
|
|
2024-05-04 20:46:15 -04:00
|
|
|
ItemInstance *Item_getCraftingRemainingItem_injection(__attribute__((unused)) Item_getCraftingRemainingItem_t original, Item *self, ItemInstance *item_instance) {
|
2024-04-02 19:22:01 -04:00
|
|
|
if (self->craftingRemainingItem != nullptr) {
|
2024-05-17 00:36:28 -04:00
|
|
|
ItemInstance *ret = new ItemInstance;
|
2024-02-07 06:47:46 +00:00
|
|
|
ret->id = self->craftingRemainingItem->id;
|
|
|
|
ret->count = item_instance->count;
|
|
|
|
ret->auxiliary = 0;
|
|
|
|
return ret;
|
|
|
|
}
|
2024-04-02 19:22:01 -04:00
|
|
|
return nullptr;
|
2024-02-07 06:47:46 +00:00
|
|
|
}
|
|
|
|
|
2024-02-08 00:34:43 -05:00
|
|
|
// Sort Chunks
|
|
|
|
struct chunk_data {
|
|
|
|
Chunk *chunk;
|
|
|
|
float distance;
|
|
|
|
};
|
|
|
|
#define MAX_CHUNKS_SIZE 24336
|
2024-03-19 00:12:23 -04:00
|
|
|
static chunk_data data[MAX_CHUNKS_SIZE];
|
2024-02-08 00:34:43 -05:00
|
|
|
static void sort_chunks(Chunk **chunks_begin, Chunk **chunks_end, DistanceChunkSorter sorter) {
|
|
|
|
// Calculate Distances
|
|
|
|
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];
|
2024-05-15 05:02:19 -04:00
|
|
|
float distance = chunk->distanceToSqr((Entity *) sorter.mob);
|
2024-02-08 00:34:43 -05:00
|
|
|
if ((1024.0 <= distance) && chunk->y < 0x40) {
|
2024-04-02 19:22:01 -04:00
|
|
|
distance *= 10.0;
|
2024-02-08 00:34:43 -05:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-11 20:35:41 -05:00
|
|
|
// Display Date In Select World Screen
|
|
|
|
static std::string AppPlatform_linux_getDateString_injection(__attribute__((unused)) AppPlatform_linux *app_platform, int time) {
|
|
|
|
// From https://github.com/ReMinecraftPE/mcpe/blob/56e51027b1c2e67fe5a0e8a091cefe51d4d11926/platforms/sdl/base/AppPlatform_sdl_base.cpp#L68-L84
|
|
|
|
time_t tt = time;
|
2024-04-02 19:22:01 -04:00
|
|
|
tm t = {};
|
2024-02-11 20:35:41 -05:00
|
|
|
gmtime_r(&tt, &t);
|
|
|
|
char buf[2048];
|
|
|
|
strftime(buf, sizeof buf, "%b %d %Y %H:%M:%S", &t);
|
|
|
|
return std::string(buf);
|
|
|
|
}
|
|
|
|
|
2021-06-21 21:50:26 -04:00
|
|
|
// Init
|
2024-06-15 08:52:15 -04:00
|
|
|
template <typename... Args>
|
|
|
|
static void nop(__attribute__((unused)) Args... args) {
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
void init_misc() {
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Classic HUD
|
|
|
|
if (feature_has("Classic HUD", server_disabled)) {
|
|
|
|
use_classic_hud = 1;
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Food overlay
|
|
|
|
if (feature_has("Food Overlay", server_disabled)) {
|
2024-04-03 03:19:12 -04:00
|
|
|
overwrite_calls(Gui_renderHearts, Gui_renderHearts_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
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);
|
2024-04-03 03:19:12 -04:00
|
|
|
overwrite_calls(Gui_renderChatMessages, Gui_renderChatMessages_injection);
|
|
|
|
overwrite_calls(Gui_tick, Gui_tick_injection);
|
|
|
|
overwrite_calls(Inventory_selectSlot, Inventory_selectSlot_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Translucent Toolbar
|
|
|
|
if (feature_has("Translucent Toolbar", server_disabled)) {
|
2024-04-03 03:19:12 -04:00
|
|
|
overwrite_calls(Gui_renderToolBar, Gui_renderToolBar_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
overwrite_call((void *) 0x26c5c, (void *) Gui_renderToolBar_glColor4f_injection);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fix Screen Rendering When GUI is Hidden
|
2024-05-24 04:44:53 -04:00
|
|
|
overwrite_calls(Screen_render, Screen_render_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Sanitize Username
|
2024-05-24 04:44:53 -04:00
|
|
|
overwrite_calls(LoginPacket_read, LoginPacket_read_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Fix RakNet::RakString Security Bug
|
2024-04-03 03:19:12 -04:00
|
|
|
overwrite_calls_manual((void *) RakNet_RakString_constructor, (void *) RakNet_RakString_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Print Error Message If RakNet Startup Fails
|
|
|
|
overwrite_call((void *) 0x73778, (void *) RakNetInstance_host_RakNet_RakPeer_Startup_injection);
|
|
|
|
|
|
|
|
// Fix Bug Where RakNetInstance Starts Pinging Potential Servers Before The "Join Game" Screen Is Opened
|
2024-04-03 03:19:12 -04:00
|
|
|
overwrite_calls(RakNetInstance_constructor, RakNetInstance_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Close Current Screen On Death To Prevent Bugs
|
|
|
|
if (feature_has("Close Current Screen On Death", server_disabled)) {
|
2024-05-24 04:44:53 -04:00
|
|
|
overwrite_calls(LocalPlayer_die, LocalPlayer_die_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fix Furnace Not Checking Item Auxiliary When Inserting New Item
|
|
|
|
if (feature_has("Fix Furnace Not Checking Item Auxiliary", server_disabled)) {
|
2024-04-03 03:19:12 -04:00
|
|
|
overwrite_calls(FurnaceScreen_handleAddItem, FurnaceScreen_handleAddItem_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
2024-04-03 03:19:12 -04:00
|
|
|
overwrite_calls(GameRenderer_render, GameRenderer_render_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove Forced GUI Lag
|
|
|
|
if (feature_has("Remove Forced GUI Lag (Can Break Joining Servers)", server_enabled)) {
|
2024-06-15 08:52:15 -04:00
|
|
|
overwrite_calls(Common_sleepMs, nop<Common_sleepMs_t, int>);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Properly Generate Buffers
|
2024-04-03 03:19:12 -04:00
|
|
|
overwrite(Common_anGenBuffers, anGenBuffers_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Fix Graphics Bug When Switching To First-Person While Sneaking
|
2024-05-04 20:46:15 -04:00
|
|
|
patch_vtable(PlayerRenderer_render, PlayerRenderer_render_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Disable Speed Bridging
|
|
|
|
if (feature_has("Disable Speed Bridging", server_disabled)) {
|
|
|
|
unsigned char disable_speed_bridging_patch[4] = {0x03, 0x00, 0x53, 0xe1}; // "cmp r3, r3"
|
|
|
|
patch((void *) 0x494b4, disable_speed_bridging_patch);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disable Creative Mode Mining Delay
|
|
|
|
if (feature_has("Disable Creative Mode Mining Delay", server_disabled)) {
|
|
|
|
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
|
|
|
|
patch((void *) 0x19fa0, nop_patch);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Change Grass Color
|
|
|
|
if (feature_has("Add Biome Colors To Grass", server_disabled)) {
|
2024-05-04 20:46:15 -04:00
|
|
|
patch_vtable(GrassTile_getColor, GrassTile_getColor_injection);
|
2024-05-24 04:44:53 -04:00
|
|
|
overwrite_calls(TallGrass_getColor, TallGrass_getColor_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Generate Caves
|
|
|
|
if (feature_has("Generate Caves", server_auto)) {
|
2024-04-03 03:19:12 -04:00
|
|
|
overwrite_calls(RandomLevelSource_buildSurface, RandomLevelSource_buildSurface_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Disable Block Tinting
|
|
|
|
if (feature_has("Disable Block Tinting", server_disabled)) {
|
2024-05-24 04:44:53 -04:00
|
|
|
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>);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Custom GUI Scale
|
|
|
|
const char *gui_scale_str = getenv("MCPI_GUI_SCALE");
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disable Hostile AI In Creative Mode
|
|
|
|
if (feature_has("Disable Hostile AI In Creative Mode", server_enabled)) {
|
|
|
|
overwrite_call((void *) 0x83b8c, (void *) PathfinderMob_findAttackTarget_injection);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 3D Chests
|
|
|
|
if (feature_has("3D Chest Model", server_disabled)) {
|
|
|
|
overwrite_call((void *) 0x5e830, (void *) Tile_getRenderShape_injection);
|
2024-04-03 03:19:12 -04:00
|
|
|
overwrite_calls(ChestTileEntity_constructor, ChestTileEntity_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
overwrite_call((void *) 0x6655c, (void *) ModelPart_render_injection);
|
|
|
|
overwrite_call((void *) 0x66568, (void *) ModelPart_render_injection);
|
|
|
|
overwrite_call((void *) 0x66574, (void *) ModelPart_render_injection);
|
2024-04-03 03:19:12 -04:00
|
|
|
overwrite_calls(Tesselator_vertexUV, Tesselator_vertexUV_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
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
|
2024-04-03 03:19:12 -04:00
|
|
|
overwrite_calls(ContainerMenu_constructor, ContainerMenu_injection);
|
2024-05-24 04:44:53 -04:00
|
|
|
overwrite_calls(ContainerMenu_destructor_complete, ContainerMenu_destructor_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
2024-06-12 02:33:29 -04:00
|
|
|
overwrite_calls(ChestTileEntity_shouldSave, ChestTileEntity_shouldSave_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Replace Block Highlight With Outline
|
|
|
|
if (feature_has("Replace Block Highlight With Outline", server_disabled)) {
|
2024-05-04 20:46:15 -04:00
|
|
|
overwrite(LevelRenderer_renderHitSelect, LevelRenderer_renderHitOutline);
|
2024-04-02 19:22:01 -04:00
|
|
|
unsigned char fix_outline_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
|
|
|
|
patch((void *) 0x4d830, fix_outline_patch);
|
2024-06-15 08:52:15 -04:00
|
|
|
overwrite_call((void *) 0x4d764, (void *) LevelRenderer_render_AABB_glColor4f_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fix Furnace Visual Bug
|
2024-04-03 03:19:12 -04:00
|
|
|
overwrite_calls(FurnaceTileEntity_getLitProgress, FurnaceTileEntity_getLitProgress_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Send the full level, not only changed chunks
|
|
|
|
if (feature_has("Send Full Level When Hosting Game", server_enabled)) {
|
|
|
|
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
|
|
|
|
patch((void *) 0x717c4, nop_patch);
|
|
|
|
unsigned char mov_r3_ff[4] = {0xff, 0x30, 0xa0, 0xe3}; // "mov r3, #0xff"
|
|
|
|
patch((void *) 0x7178c, mov_r3_ff);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Java Light Ramp
|
|
|
|
if (feature_has("Use Java Beta 1.3 Light Ramp", server_disabled)) {
|
2024-05-24 04:44:53 -04:00
|
|
|
overwrite_calls(Dimension_updateLightRamp, Dimension_updateLightRamp_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fix used items transferring durability
|
2024-04-03 03:19:12 -04:00
|
|
|
overwrite_calls(Player_startUsingItem, Player_startUsingItem_injection);
|
|
|
|
overwrite_calls(Player_stopUsingItem, Player_stopUsingItem_injection);
|
2024-04-02 19:22:01 -04:00
|
|
|
|
|
|
|
// Fix invalid ItemInHandRenderer texture cache
|
2024-05-16 04:07:02 -04:00
|
|
|
if (feature_has("Fix Held Item Caching", server_disabled)) {
|
2024-04-02 19:22:01 -04:00
|
|
|
// This works by forcing MCPI to always use the branch that enables using the
|
|
|
|
// cache, but then patches that as well 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);
|
|
|
|
}
|
|
|
|
|
2020-12-02 18:18:49 -05:00
|
|
|
// Implement AppPlatform::readAssetFile So Translations Work
|
2022-04-09 20:01:16 -04:00
|
|
|
if (feature_has("Load Language Files", server_enabled)) {
|
2024-05-24 04:44:53 -04:00
|
|
|
overwrite_calls(AppPlatform_readAssetFile, AppPlatform_readAssetFile_injection);
|
2021-07-04 19:02:45 -04:00
|
|
|
}
|
2020-12-02 18:18:49 -05:00
|
|
|
|
2022-04-11 22:52:38 -04:00
|
|
|
// Fix Pause Menu
|
|
|
|
if (feature_has("Fix Pause Menu", server_disabled)) {
|
|
|
|
// Add Missing Buttons To Pause Menu
|
2024-05-24 04:44:53 -04:00
|
|
|
overwrite_calls(PauseScreen_init, PauseScreen_init_injection);
|
2022-04-11 22:52:38 -04:00
|
|
|
}
|
2024-02-07 06:47:46 +00:00
|
|
|
|
2024-02-11 20:35:41 -05:00
|
|
|
// Implement Crafting Remainders
|
2024-02-07 06:47:46 +00:00
|
|
|
overwrite_call((void *) 0x2e230, (void *) PaneCraftingScreen_craftSelectedItem_PaneCraftingScreen_recheckRecipes_injection);
|
2024-05-24 04:44:53 -04:00
|
|
|
overwrite_calls(Item_getCraftingRemainingItem, Item_getCraftingRemainingItem_injection);
|
2024-02-08 00:34:43 -05:00
|
|
|
|
|
|
|
// Replace 2011 std::sort With Optimized(TM) Code
|
2024-02-11 20:35:41 -05:00
|
|
|
if (feature_has("Optimized Chunk Sorting", server_enabled)) {
|
2024-05-04 20:46:15 -04:00
|
|
|
overwrite_manual((void *) 0x51fac, (void *) sort_chunks);
|
2024-02-11 20:35:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Display Date In Select World Screen
|
|
|
|
if (feature_has("Display Date In Select World Screen", server_disabled)) {
|
2024-05-04 20:46:15 -04:00
|
|
|
patch_vtable(AppPlatform_linux_getDateString, AppPlatform_linux_getDateString_injection);
|
2024-02-11 20:35:41 -05:00
|
|
|
}
|
2024-04-02 19:22:01 -04:00
|
|
|
|
2024-05-19 00:19:01 -04:00
|
|
|
// Don't Wrap Text On '\r' Or '\t' Because THey Are Actual Characters In MCPI
|
|
|
|
patch_address(&Strings::text_wrapping_delimiter, (void *) " \n");
|
|
|
|
|
2024-04-02 19:22:01 -04:00
|
|
|
// Init Logging
|
|
|
|
_init_misc_logging();
|
|
|
|
_init_misc_api();
|
2024-06-15 08:52:15 -04:00
|
|
|
|
|
|
|
// 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 *, Config *>);
|
|
|
|
overwrite_calls(LevelRenderer_generateSky, nop<LevelRenderer_generateSky_t, LevelRenderer *>);
|
|
|
|
}
|
2021-06-21 21:50:26 -04:00
|
|
|
}
|