Some Modernization

This commit is contained in:
TheBrokenRail 2024-06-21 01:19:37 -04:00
parent cecd61ed72
commit 5e229fb6a8
36 changed files with 338 additions and 406 deletions

View File

@ -241,7 +241,7 @@ void setup_crash_report() {
// Print Exit Code Log Line
safe_write(STDERR_FILENO, exit_code_line.c_str(), strlen(exit_code_line.c_str()));
// Write Exit Code Log Line
safe_write(reborn_get_debug_fd(), exit_code_line.c_str(), strlen(exit_code_line.c_str()));
safe_write(reborn_get_log_fd(), exit_code_line.c_str(), strlen(exit_code_line.c_str()));
}
// Close Log File

View File

@ -4,7 +4,7 @@
extern "C" {
#endif
#define ENV(name, ...) extern const char *name##_ENV;
#define ENV(name, ...) extern const char *const name##_ENV;
#include "env-list.h"
#undef ENV

View File

@ -1,38 +1,11 @@
#pragma once
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "util.h"
// Set obj To NULL On asprintf() Failure
#define safe_asprintf(obj, ...) \
{ \
if (asprintf(obj, __VA_ARGS__) == -1) { \
*obj = NULL; \
} \
ALLOC_CHECK(*obj); \
}
// Dynamic String Append Macro
#define string_append(str, format, ...) \
{ \
char *old = *str; \
safe_asprintf(str, "%s" format, *str == NULL ? "" : *str, ##__VA_ARGS__); \
ALLOC_CHECK(*str); \
if (old != NULL && old != *str) { \
free(old); \
} \
}
#ifdef __cplusplus
extern "C" {
#endif
// Sanitize String
void sanitize_string(char *str, int max_length, unsigned int allow_newlines);
void sanitize_string(char *str, int max_length, int allow_newlines);
// CP437
char *to_cp437(const char *input);

View File

@ -2,7 +2,7 @@
#include <libreborn/exec.h>
// Define Constants
#define ENV(name, ...) const char *name##_ENV = #name;
#define ENV(name, ...) const char *const name##_ENV = #name;
#include <libreborn/env-list.h>
#undef ENV

View File

@ -127,10 +127,19 @@ char *run_command(const char *const command[], int *exit_status, size_t *output_
}
}
// Set obj To NULL On asprintf() Failure
#define safe_asprintf(obj, ...) \
{ \
if (asprintf(obj, __VA_ARGS__) == -1) { \
*obj = NULL; \
} \
ALLOC_CHECK(*obj); \
}
// Get Exit Status String
void get_exit_status_string(int status, char **out) {
void get_exit_status_string(const int status, char **out) {
if (out != NULL) {
*out =NULL;
*out = NULL;
if (WIFEXITED(status)) {
safe_asprintf(out, ": Exit Code: %i", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {

View File

@ -1,7 +1,9 @@
#include <libreborn/string.h>
#include <string.h>
// Sanitize String
void sanitize_string(char *str, int max_length, unsigned int allow_newlines) {
void sanitize_string(char *str, const int max_length, const int allow_newlines) {
// Store Message Length
size_t length = strlen(str);
// Truncate Message

View File

@ -58,6 +58,7 @@ set(SRC
src/input/toggle.cpp
src/input/misc.cpp
src/input/drop.cpp
src/input/keys.cpp
# sign
src/sign/sign.cpp
# atlas

View File

@ -27,4 +27,5 @@ void init_bucket();
void init_cake();
void init_home();
void init_override();
void init_screenshot();
}

View File

@ -1,16 +1,12 @@
#pragma once
#include <symbols/minecraft.h>
extern "C" {
typedef void (*input_tick_function_t)(Minecraft *minecraft);
void input_run_on_tick(input_tick_function_t function);
void input_set_is_right_click(int val);
int input_back();
void input_drop(int drop_slot);
void input_set_is_ctrl(bool val);
void input_set_is_left_click(int val);
void input_set_mouse_grab_state(int state);
enum {
#define KEY(name, value) MC_KEY_##name = (value),
#include "key-list.h"
#undef KEY
};
}

View File

@ -0,0 +1,13 @@
// MCPI Seems To Use https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
KEY(BACKSPACE, 0x8)
KEY(DELETE, 0x2e)
KEY(LEFT, 0x25)
KEY(RIGHT, 0x27)
KEY(F1, 0x70)
KEY(F2, 0x71)
KEY(F5, 0x74)
KEY(F11, 0x7a)
KEY(RETURN, 0xd)
KEY(t, 0x54)
KEY(q, 0x51)
KEY(ESCAPE, 0x1b)

View File

@ -23,3 +23,4 @@ void misc_run_on_tiles_setup(const std::function<void()> &func);
void misc_run_on_items_setup(const std::function<void()> &func);
void misc_run_on_language_setup(const std::function<void()> &func);
void misc_run_on_game_key_press(const std::function<bool(Minecraft *, int)> &func);
void misc_run_on_key_press(const std::function<bool(Minecraft *, int)> &func);

View File

@ -1,5 +1,7 @@
#pragma once
struct Gui;
extern "C" {
void screenshot_take(const char *home);
void screenshot_take(Gui *gui);
}

View File

@ -3,12 +3,11 @@
#include <mods/feature/feature.h>
#include <mods/screenshot/screenshot.h>
#include <mods/home/home.h>
#include <mods/init/init.h>
// Take Screenshot Using TripodCamera
static void AppPlatform_saveScreenshot_injection(__attribute__((unused)) AppPlatform_saveScreenshot_t original, __attribute__((unused)) AppPlatform *app_platform, __attribute__((unused)) std::string *path, __attribute__((unused)) int32_t width, __attribute__((unused)) int32_t height) {
screenshot_take(home_get());
screenshot_take(nullptr);
}
// Enable TripodCameraRenderer

View File

@ -1,9 +1,13 @@
#include "chat-internal.h"
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <mods/chat/chat.h>
#include <mods/text-input-box/TextInputScreen.h>
#include <mods/misc/misc.h>
#include <mods/touch/touch.h>
#include <mods/input/input.h>
static std::vector<std::string> &get_history() {
static std::vector<std::string> history = {};
@ -143,7 +147,7 @@ static Screen *create_chat_screen() {
// Init
void _init_chat_ui() {
misc_run_on_game_key_press([](Minecraft *minecraft, int key) {
if (key == 0x54) {
if (key == MC_KEY_t) {
if (minecraft->isLevelGenerated() && minecraft->screen == nullptr) {
minecraft->setScreen(create_chat_screen());
}

View File

@ -14,8 +14,6 @@
#include <mods/input/input.h>
#include <mods/sign/sign.h>
#include <mods/chat/chat.h>
#include <mods/home/home.h>
// Custom Title
HOOK(SDL_WM_SetCaption, void, (__attribute__((unused)) const char *title, const char *icon)) {
@ -47,24 +45,16 @@ HOOK(SDL_PollEvent, int, (SDL_Event *event)) {
// Handle Events
if (ret == 1 && event != nullptr) {
int handled = 0;
bool handled = false;
switch (event->type) {
case SDL_KEYDOWN: {
// Handle Key Presses
if (event->key.keysym.sym == SDLK_F11) {
media_toggle_fullscreen();
handled = 1;
} else if (event->key.keysym.sym == SDLK_F2) {
screenshot_take(home_get());
handled = 1;
} else if (event->key.keysym.sym == SDLK_ESCAPE) {
// Treat Escape As Back Button Press (This Fixes Issues With Signs)
handled = input_back();
} else if (event->key.keysym.sym == SDLK_q) {
// Drop Item
input_drop((event->key.keysym.mod & KMOD_CTRL) != 0);
handled = 1;
case SDL_KEYDOWN:
case SDL_KEYUP: {
// Track Control Key
bool is_ctrl = (event->key.keysym.mod & KMOD_CTRL) != 0;
if (event->type == SDL_KEYUP) {
is_ctrl = false;
}
input_set_is_ctrl(is_ctrl);
break;
}
case SDL_MOUSEBUTTONDOWN:
@ -72,8 +62,6 @@ HOOK(SDL_PollEvent, int, (SDL_Event *event)) {
// Track Right-Click State
if (event->button.button == SDL_BUTTON_RIGHT) {
input_set_is_right_click(event->button.state != SDL_RELEASED);
} else if (event->button.button == SDL_BUTTON_LEFT) {
input_set_is_left_click(event->button.state != SDL_RELEASED);
}
break;
}
@ -81,7 +69,7 @@ HOOK(SDL_PollEvent, int, (SDL_Event *event)) {
// SDL_UserEvent Is Never Used In MCPI, So It Is Repurposed For Character Events
if (event->user.code == USER_EVENT_CHARACTER) {
sign_key_press((char) event->user.data1);
handled = 1;
handled = true;
}
break;
}

View File

@ -13,13 +13,17 @@ __attribute__((constructor)) static void init() {
} else {
init_multiplayer();
}
init_sound();
if (!reborn_is_headless()) {
init_sound();
}
init_input();
init_sign();
init_camera();
init_atlas();
init_title_screen();
init_skin();
if (!reborn_is_headless()) {
init_skin();
}
init_fps();
init_touch();
init_textures();
@ -36,4 +40,7 @@ __attribute__((constructor)) static void init() {
if (!reborn_is_server()) {
init_benchmark();
}
if (!reborn_is_headless()) {
init_screenshot();
}
}

View File

@ -3,53 +3,28 @@
#include <mods/feature/feature.h>
#include "input-internal.h"
#include <mods/input/input.h>
// Store Left Click (0 = Not Pressed, 1 = Pressed)
static int is_left_click = 0;
void input_set_is_left_click(int val) {
if ((is_left_click == 0 && val == 1) || (is_left_click != 0 && val == 0)) {
is_left_click = val;
}
}
// Add Attacking To MouseBuildInput
static int32_t MouseBuildInput_tickBuild_injection(MouseBuildInput_tickBuild_t original, MouseBuildInput *mouse_build_input, Player *local_player, uint32_t *build_action_intention_return) {
#define REMOVE_ATTACK_BAI 0xa
#define ATTACK_BAI 0x8
static bool MouseBuildInput_tickBuild_injection(MouseBuildInput_tickBuild_t original, MouseBuildInput *mouse_build_input, Player *local_player, uint32_t *build_action_intention_return) {
// Call Original Method
int32_t ret = original(mouse_build_input, local_player, build_action_intention_return);
// Use Attack/Place BuildActionIntention If No Other Valid BuildActionIntention Was Selected And This Was Not A Repeated Left Click
if (ret != 0 && is_left_click == 1 && *build_action_intention_return == 0xa) {
// Get Target HitResult
const bool ret = original(mouse_build_input, local_player, build_action_intention_return);
// Convert Remove/Attack Into Attack If A Tile Is Not Selected
if (ret && *build_action_intention_return == REMOVE_ATTACK_BAI) {
Minecraft *minecraft = ((LocalPlayer *) local_player)->minecraft;
HitResult *hit_result = &minecraft->hit_result;
int32_t hit_result_type = hit_result->type;
// Check if The Target Is An Entity Using HitResult
if (hit_result_type == 1) {
// Change BuildActionIntention To Attack/Place Mode (Place Will Not Happen Because The HitResult Is An Entity)
*build_action_intention_return = 0x8;
if (minecraft->hit_result.type != 0) {
*build_action_intention_return = ATTACK_BAI;
}
}
// Return
return ret;
}
// Fix Holding Attack
static bool last_player_attack_successful = false;
static bool Player_attack_Entity_hurt_injection(Entity *entity, Entity *attacker, int32_t damage) {
// Call Original Method
last_player_attack_successful = entity->hurt(attacker, damage);
return last_player_attack_successful;
}
static ItemInstance *Player_attack_Inventory_getSelected_injection(Inventory *inventory) {
// Check If Attack Was Successful
if (!last_player_attack_successful) {
return nullptr;
static void Minecraft_handleBuildAction_injection(Minecraft_handleBuildAction_t original, Minecraft *self, uint *bai) {
if (*bai == ATTACK_BAI) {
*bai = REMOVE_ATTACK_BAI;
}
// Call Original Method
return inventory->getSelected();
original(self, bai);
}
// Init
@ -57,9 +32,6 @@ void _init_attack() {
// Allow Attacking Mobs
if (feature_has("Fix Attacking", server_disabled)) {
overwrite_calls(MouseBuildInput_tickBuild, MouseBuildInput_tickBuild_injection);
// Fix Holding Attack
overwrite_call((void *) 0x8fc1c, (void *) Player_attack_Entity_hurt_injection);
overwrite_call((void *) 0x8fc24, (void *) Player_attack_Inventory_getSelected_injection);
overwrite_calls(Minecraft_handleBuildAction, Minecraft_handleBuildAction_injection);
}
}

View File

@ -11,23 +11,23 @@ void input_set_is_right_click(int val) {
is_right_click = val;
}
// Enable Bow & Arrow Fix
static int fix_bow = 0;
// Handle Bow & Arrow
static void _handle_bow(Minecraft *minecraft) {
if (fix_bow && !is_right_click) {
static void _handle_bow(Minecraft_tickInput_t original, Minecraft *minecraft) {
if (!is_right_click) {
GameMode *game_mode = minecraft->game_mode;
LocalPlayer *player = minecraft->player;
if (player != nullptr && game_mode != nullptr && player->isUsingItem()) {
game_mode->releaseUsingItem((Player *) player);
}
}
// Call Original Method
original(minecraft);
}
// Init
void _init_bow() {
// Enable Bow & Arrow Fix
fix_bow = feature_has("Fix Bow & Arrow", server_disabled);
input_run_on_tick(_handle_bow);
if (feature_has("Fix Bow & Arrow", server_disabled)) {
overwrite_calls(Minecraft_tickInput, _handle_bow);
}
}

View File

@ -7,25 +7,15 @@
#include <mods/creative/creative.h>
#include <mods/misc/misc.h>
// Enable Item Dropping
static int enable_drop = 0;
// Store Drop Item Presses
static int drop_item_presses = 0;
static bool drop_slot_pressed = false;
void input_drop(int drop_slot) {
if (enable_drop) {
if (drop_slot) {
drop_slot_pressed = true;
} else {
drop_item_presses++;
}
}
// Track Control Key
static bool drop_slot = false;
void input_set_is_ctrl(const bool val) {
drop_slot = val;
}
// Handle Drop Item Presses
static void _handle_drop(Minecraft *minecraft) {
if ((minecraft->screen == nullptr) && (!creative_is_restricted() || !Minecraft_isCreativeMode(minecraft)) && (drop_item_presses > 0 || drop_slot_pressed)) {
if (!creative_is_restricted() || !Minecraft_isCreativeMode(minecraft)) {
// Get Player
LocalPlayer *player = minecraft->player;
if (player != nullptr) {
@ -43,16 +33,12 @@ static void _handle_drop(Minecraft *minecraft) {
*dropped_item = *inventory_item;
// Update Inventory
if (drop_slot_pressed) {
// Drop Slot
// Empty Slot
if (drop_slot) {
// Drop Entire Slot
inventory_item->count = 0;
} else {
// Drop Item
// Set Item Drop Count
int drop_count = drop_item_presses < inventory_item->count ? drop_item_presses : inventory_item->count;
const int drop_count = 1;
dropped_item->count = drop_count;
inventory_item->count -= drop_count;
}
@ -68,13 +54,18 @@ static void _handle_drop(Minecraft *minecraft) {
}
}
}
// Reset
drop_item_presses = 0;
drop_slot_pressed = false;
}
// Init
void _init_drop() {
enable_drop = feature_has("Bind \"Q\" Key To Item Dropping", server_disabled);
input_run_on_tick(_handle_drop);
if (feature_has("Bind \"Q\" Key To Item Dropping", server_disabled)) {
misc_run_on_game_key_press([](Minecraft *mc, int key) {
if (key == MC_KEY_q) {
_handle_drop(mc);
return true;
} else {
return false;
}
});
}
}

View File

@ -4,4 +4,5 @@ __attribute__((visibility("internal"))) void _init_attack();
__attribute__((visibility("internal"))) void _init_bow();
__attribute__((visibility("internal"))) void _init_misc();
__attribute__((visibility("internal"))) void _init_toggle();
__attribute__((visibility("internal"))) void _init_drop();
__attribute__((visibility("internal"))) void _init_drop();
__attribute__((visibility("internal"))) void _init_keys();

View File

@ -1,7 +1,3 @@
#include <vector>
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <media-layer/core.h>
#include <mods/feature/feature.h>
@ -9,26 +5,6 @@
#include "input-internal.h"
#include <mods/input/input.h>
// Run Functions On Input Tick
static std::vector<input_tick_function_t> &get_input_tick_functions() {
static std::vector<input_tick_function_t> functions;
return functions;
}
void input_run_on_tick(input_tick_function_t function) {
get_input_tick_functions().push_back(function);
}
// Handle Input Fixes
static void Minecraft_tickInput_injection(Minecraft_tickInput_t original, Minecraft *minecraft) {
// Call Original Method
original(minecraft);
// Run Input Tick Functions
for (input_tick_function_t function : get_input_tick_functions()) {
function(minecraft);
}
}
// Init
void init_input() {
// Miscellaneous
@ -43,9 +19,6 @@ void init_input() {
// Enable Bow & Arrow Fix
_init_bow();
// Loop
overwrite_calls(Minecraft_tickInput, Minecraft_tickInput_injection);
// Allow Attacking Mobs
_init_attack();
@ -53,4 +26,7 @@ void init_input() {
if (feature_has("Disable Raw Mouse Motion (Not Recommended)", server_disabled)) {
media_set_raw_mouse_motion_enabled(0);
}
// Extra Key Codes
_init_keys();
}

24
mods/src/input/keys.cpp Normal file
View File

@ -0,0 +1,24 @@
#include <mods/input/input.h>
#include <symbols/minecraft.h>
#include <libreborn/libreborn.h>
#include <SDL/SDL.h>
#include "input-internal.h"
// Translator
static int32_t sdl_key_to_minecraft_key_injection(Common_sdl_key_to_minecraft_key_t original, int32_t sdl_key) {
switch (sdl_key) {
#define KEY(name, value) case SDLK_##name: return MC_KEY_##name;
#include <mods/input/key-list.h>
#undef KEY
default: {
// Call Original Method
return original(sdl_key);
}
}
}
// Init
void _init_keys() {
overwrite_calls(Common_sdl_key_to_minecraft_key, sdl_key_to_minecraft_key_injection);
}

View File

@ -1,25 +1,16 @@
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <SDL/SDL.h>
#include "input-internal.h"
#include <mods/input/input.h>
#include <mods/feature/feature.h>
#include <mods/creative/creative.h>
#include <mods/misc/misc.h>
// Enable Miscellaneous Input Fixes
static int enable_misc = 0;
// Store Back Button Presses
static int back_button_presses = 0;
int input_back() {
if (enable_misc) {
back_button_presses++;
return 1; // Handled
} else {
return 0; // Not Handled
}
}
// Handle Back Button Presses
static void _handle_back(Minecraft *minecraft) {
// If Minecraft's Level property is initialized, but Minecraft's Player property is nullptr, then Minecraft::handleBack may crash.
@ -28,10 +19,7 @@ static void _handle_back(Minecraft *minecraft) {
return;
}
// Send Event
for (int i = 0; i < back_button_presses; i++) {
minecraft->handleBack(0);
}
back_button_presses = 0;
minecraft->handleBack(false);
}
// Fix OptionsScreen Ignoring The Back Button
@ -52,32 +40,12 @@ static bool InBedScreen_handleBackEvent_injection(InBedScreen *screen, bool do_n
// Stop Sleeping
LocalPlayer *player = minecraft->player;
if (player != nullptr) {
player->stopSleepInBed(1, 1, 1);
player->stopSleepInBed(true, true, true);
}
}
return true;
}
// Set Mouse Grab State
static int mouse_grab_state = 0;
void input_set_mouse_grab_state(int state) {
mouse_grab_state = state;
}
// Grab/Un-Grab Mouse
static void _handle_mouse_grab(Minecraft *minecraft) {
if (mouse_grab_state == -1) {
// Grab
minecraft->grabMouse();
} else if (mouse_grab_state == 1) {
// Un-Grab
minecraft->releaseMouse();
}
mouse_grab_state = 0;
}
#include <SDL/SDL.h>
// Block UI Interaction When Mouse Is Locked
static bool Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection(Minecraft *minecraft) {
bool is_in_game = minecraft->screen == nullptr || minecraft->screen->vtable == (Screen_vtable *) Touch_IngameBlockSelectionScreen_vtable_base;
@ -86,7 +54,7 @@ static bool Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection(Minecraft *
return creative_is_restricted() && minecraft->isCreativeMode();
} else {
// Disable Item Drop Ticking
return 1;
return true;
}
}
@ -108,10 +76,16 @@ void _init_misc() {
patch_vtable(InBedScreen_handleBackEvent, InBedScreen_handleBackEvent_injection);
// Disable Opening Inventory Using The Cursor When Cursor Is Hidden
overwrite_calls(Gui_handleClick, Gui_handleClick_injection);
// Proper Back Button Handling
misc_run_on_key_press([](Minecraft *mc, const int key) {
if (key == MC_KEY_ESCAPE) {
_handle_back(mc);
return true;
} else {
return false;
}
});
}
// Disable Item Dropping Using The Cursor When Cursor Is Hidden
overwrite_call((void *) 0x27800, (void *) Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection);
input_run_on_tick(_handle_back);
input_run_on_tick(_handle_mouse_grab);
}

View File

@ -9,11 +9,11 @@
// Handle Toggle Options
static bool _handle_toggle_options(Minecraft *minecraft, int key) {
Options *options = &minecraft->options;
if (key == 0x70) {
if (key == MC_KEY_F1) {
// Toggle Hide GUI
options->hide_gui = options->hide_gui ^ 1;
return true;
} else if (key == 0x74) {
} else if (key == MC_KEY_F5) {
// Toggle Third Person
options->third_person = (options->third_person + 1) % 3;
return true;

View File

@ -89,6 +89,15 @@ void misc_run_on_game_key_press(const std::function<bool(Minecraft *, int)> &fun
original(self, key);
});
}
void misc_run_on_key_press(const std::function<bool(Minecraft *, int)> &func) {
misc_run_on_game_key_press(func);
overwrite_calls(Screen_keyPressed, [func](Screen_keyPressed_t original, Screen *self, int key) {
if (func(self->minecraft, key)) {
return;
}
original(self, key);
});
}
// Render Fancy Background
void misc_render_background(int color, Minecraft *minecraft, int x, int y, int width, int height) {

View File

@ -19,9 +19,11 @@
#include <mods/init/init.h>
#include <mods/feature/feature.h>
#include "misc-internal.h"
#include <mods/input/input.h>
#include <mods/misc/misc.h>
#include "misc-internal.h"
// Classic HUD
#define DEFAULT_HUD_PADDING 2
#define NEW_HUD_PADDING 1
@ -134,12 +136,12 @@ static void Gui_renderChatMessages_injection(Gui_renderChatMessages_t original,
}
// Call Original Method
if (!hide_chat_messages && !is_in_chat) {
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) {
if (render_selected_item_text && !disable_fading) {
// Fix GL Mode
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Calculate Selected Item Text Scale
@ -361,7 +363,7 @@ int32_t misc_get_real_selected_slot(Player *player) {
}
// Properly Generate Buffers
static void anGenBuffers_injection(int32_t count, uint32_t *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);
}
@ -829,7 +831,7 @@ void init_misc() {
}
// Properly Generate Buffers
overwrite(Common_anGenBuffers, anGenBuffers_injection);
overwrite_calls(Common_anGenBuffers, anGenBuffers_injection);
// Fix Graphics Bug When Switching To First-Person While Sneaking
patch_vtable(PlayerRenderer_render, PlayerRenderer_render_injection);
@ -904,7 +906,9 @@ void init_misc() {
// Replace Block Highlight With Outline
if (feature_has("Replace Block Highlight With Outline", server_disabled)) {
overwrite(LevelRenderer_renderHitSelect, LevelRenderer_renderHitOutline);
overwrite_calls(LevelRenderer_renderHitSelect, [](__attribute__((unused)) LevelRenderer_renderHitSelect_t original, LevelRenderer *self, Player *player, 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);
@ -968,6 +972,16 @@ void init_misc() {
// Don't Wrap Text On '\r' Or '\t' Because THey Are Actual Characters In MCPI
patch_address(&Strings::text_wrapping_delimiter, (void *) " \n");
// Fullscreen
misc_run_on_key_press([](__attribute__((unused)) Minecraft *mc, int key) {
if (key == MC_KEY_F11) {
media_toggle_fullscreen();
return true;
} else {
return false;
}
});
// Init Logging
_init_misc_logging();
_init_misc_api();

View File

@ -13,7 +13,7 @@
#include "options-internal.h"
// Force Mob Spawning
static bool LevelData_getSpawnMobs_injection(__attribute__((unused)) LevelData *level_data) {
static bool LevelData_getSpawnMobs_injection(__attribute__((unused)) LevelData_getSpawnMobs_t original, __attribute__((unused)) LevelData *level_data) {
return true;
}
@ -101,7 +101,7 @@ static void Options_save_Options_addOptionToSaveOutput_injection(Options *option
}
// MCPI's OptionsFile::getOptionStrings is broken, this is the version in v0.7.0
static std::vector<std::string> OptionsFile_getOptionStrings_injection(OptionsFile *options_file) {
static std::vector<std::string> OptionsFile_getOptionStrings_injection(__attribute__((unused)) OptionsFile_getOptionStrings_t original, OptionsFile *options_file) {
// Get options.txt Path
std::string path = options_file->options_txt_path;
// Parse
@ -145,7 +145,7 @@ static const char *get_new_options_txt_path() {
void init_options() {
// Force Mob Spawning
if (feature_has("Force Mob Spawning", server_auto)) {
overwrite(LevelData_getSpawnMobs, LevelData_getSpawnMobs_injection);
overwrite_calls(LevelData_getSpawnMobs, LevelData_getSpawnMobs_injection);
}
// Render Distance
@ -191,7 +191,7 @@ void init_options() {
// When Loading, options.txt Should Be Opened In Read Mode
patch_address((void *) &Strings::options_txt_fopen_mode_when_loading, (void *) "r");
// Fix OptionsFile::getOptionStrings
overwrite(OptionsFile_getOptionStrings, OptionsFile_getOptionStrings_injection);
overwrite_calls(OptionsFile_getOptionStrings, OptionsFile_getOptionStrings_injection);
// Sensitivity Loading/Saving Is Broken, Disable It
patch((void *) 0x1931c, nop_patch);

View File

@ -11,12 +11,22 @@
#include <libreborn/libreborn.h>
#include <GLES/gl.h>
#include <symbols/minecraft.h>
#include <mods/screenshot/screenshot.h>
#include <mods/home/home.h>
#include <mods/misc/misc.h>
#include <mods/input/input.h>
#include <mods/init/init.h>
// Ensure Screenshots Folder Exists
static void ensure_screenshots_folder(const char *screenshots) {
// Check Screenshots Folder
ensure_directory(screenshots);
static std::string get_screenshot_dir() {
std::string dir = std::string(home_get()) + "/screenshots";
ensure_directory(dir.c_str());
return dir;
}
static std::string get_screenshot(const std::string &filename) {
return get_screenshot_dir() + '/' + filename;
}
// Take Screenshot
@ -27,15 +37,12 @@ static int save_png(const char *filename, unsigned char *pixels, int line_size,
// Write Image
return !stbi_write_png(filename, width, height, 4, pixels, line_size);
}
void screenshot_take(const char *home) {
void screenshot_take(Gui *gui) {
// Check
if (reborn_is_headless()) {
IMPOSSIBLE();
}
// Get Directory
const std::string screenshots = std::string(home) + "/screenshots";
// Get Timestamp
time_t raw_time;
time(&raw_time);
@ -43,16 +50,18 @@ void screenshot_take(const char *home) {
char time[512];
strftime(time, 512, "%Y-%m-%d_%H.%M.%S", time_info);
// Ensure Screenshots Folder Exists
ensure_screenshots_folder(screenshots.c_str());
// Prevent Overwriting Screenshots
int num = 1;
std::string file = screenshots + '/' + time + ".png";
while (access(file.c_str(), F_OK) != -1) {
file = screenshots + '/' + time + '-' + std::to_string(num) + ".png";
int num = 0;
std::string filename;
do {
filename = std::string(time);
if (num > 0) {
filename += '-' + std::to_string(num);
}
filename += ".png";
num++;
}
} while (access(get_screenshot(filename).c_str(), F_OK) != -1);
const std::string file = get_screenshot(filename);
// Get Image Size
GLint viewport[4];
@ -85,9 +94,29 @@ void screenshot_take(const char *home) {
if (save_png(file.c_str(), pixels, line_size, width, height)) {
WARN("Screenshot Failed: %s", file.c_str());
} else {
INFO("Screenshot Saved: %s", file.c_str());
std::string msg = "Screenshot Saved: ";
INFO("%s%s", msg.c_str(), file.c_str());
if (gui) {
msg += filename;
gui->addMessage(&msg);
}
}
// Free
free(pixels);
}
// Init
void init_screenshot() {
// Create Directory
get_screenshot_dir();
// Take Screenshot On F2
misc_run_on_key_press([](Minecraft *mc, int key) {
if (key == MC_KEY_F2) {
screenshot_take(&mc->gui);
return true;
} else {
return false;
}
});
}

View File

@ -16,7 +16,6 @@
#include <symbols/minecraft.h>
#include <mods/server/server.h>
#include <mods/feature/feature.h>
#include <mods/init/init.h>
#include <mods/home/home.h>
#include <mods/compat/compat.h>
@ -202,23 +201,6 @@ static void list_callback(Minecraft *minecraft, const std::string &username, Pla
INFO(" - %s (%s)", username.c_str(), get_player_ip(minecraft, player));
}
// Handle Server Stop
static void handle_server_stop(Minecraft *minecraft) {
if (compat_check_exit_requested()) {
INFO("Stopping Server");
// Save And Exit
Level *level = get_level(minecraft);
if (level != nullptr) {
level->saveLevelData();
}
minecraft->leaveGame(false);
// Stop Game
SDL_Event event;
event.type = SDL_QUIT;
SDL_PushEvent(&event);
}
}
// Track TPS
#define NANOSECONDS_IN_SECOND 1000000000ll
static long long int get_time() {
@ -248,112 +230,109 @@ static ServerSideNetworkHandler *get_server_side_network_handler(Minecraft *mine
}
// Read STDIN Thread
static volatile bool stdin_buffer_complete = false;
static volatile char *stdin_buffer = nullptr;
static pthread_t read_stdin_thread_obj;
static volatile bool stdin_line_ready = false;
static std::string stdin_line;
static void *read_stdin_thread(__attribute__((unused)) void *data) {
// Loop
while (true) {
int bytes_available;
if (ioctl(fileno(stdin), FIONREAD, &bytes_available) == -1) {
bytes_available = 0;
}
char buffer[bytes_available];
bytes_available = read(fileno(stdin), (void *) buffer, bytes_available);
for (int i = 0; i < bytes_available; i++) {
if (!stdin_buffer_complete) {
// Read Data
char x = buffer[i];
if (x == '\n') {
if (stdin_buffer == nullptr) {
stdin_buffer = (volatile char *) malloc(1);
stdin_buffer[0] = '\0';
}
stdin_buffer_complete = true;
} else {
string_append((char **) &stdin_buffer, "%c", (char) x);
}
}
}
char *line = nullptr;
size_t len = 0;
while (getline(&line, &len, stdin) != -1) {
stdin_line = line;
stdin_line_ready = true;
// Wait For Line To Be Read
while (stdin_line_ready) {}
}
free(line);
return nullptr;
}
__attribute__((destructor)) static void _free_stdin_buffer() {
if (stdin_buffer != nullptr) {
free((void *) stdin_buffer);
stdin_buffer = nullptr;
// Handle Server Stop
static void handle_server_stop(Minecraft *minecraft) {
if (compat_check_exit_requested()) {
INFO("Stopping Server");
// Save And Exit
Level *level = get_level(minecraft);
if (level != nullptr) {
level->saveLevelData();
}
minecraft->leaveGame(false);
// Kill Reader Thread
pthread_cancel(read_stdin_thread_obj);
pthread_join(read_stdin_thread_obj, nullptr);
stdin_line_ready = false;
// Stop Game
SDL_Event event;
event.type = SDL_QUIT;
SDL_PushEvent(&event);
}
}
// Handle Commands
static void handle_commands(Minecraft *minecraft) {
// Check If Level Is Generated
if (minecraft->isLevelGenerated() && stdin_buffer_complete) {
if (minecraft->isLevelGenerated() && stdin_line_ready) {
// Read Line
std::string data = std::move(stdin_line);
data.pop_back(); // Remove Newline
stdin_line_ready = false;
// Command Ready; Run It
if (stdin_buffer != nullptr) {
ServerSideNetworkHandler *server_side_network_handler = get_server_side_network_handler(minecraft);
if (server_side_network_handler != nullptr) {
std::string data((char *) stdin_buffer);
static std::string ban_command("ban ");
static std::string say_command("say ");
static std::string kill_command("kill ");
static std::string list_command("list");
static std::string reload_command("reload");
static std::string tps_command("tps");
static std::string stop_command("stop");
static std::string help_command("help");
if (!is_whitelist() && data.rfind(ban_command, 0) == 0) {
// IP-Ban Target Username
std::string ban_username = data.substr(ban_command.length());
find_players(minecraft, ban_username, ban_callback, false);
} else if (data == reload_command) {
INFO("Reloading %s", is_whitelist() ? "Whitelist" : "Blacklist");
is_ip_in_blacklist(nullptr);
} else if (data.rfind(kill_command, 0) == 0) {
// Kill Target Username
std::string kill_username = data.substr(kill_command.length());
find_players(minecraft, kill_username, kill_callback, false);
} else if (data.rfind(say_command, 0) == 0) {
// Format Message
std::string message = "[Server] " + data.substr(say_command.length());
char *safe_message = to_cp437(message.c_str());
std::string cpp_string = safe_message;
// Post Message To Chat
server_side_network_handler->displayGameMessage(&cpp_string);
// Free
free(safe_message);
} else if (data == list_command) {
// List Players
INFO("All Players:");
find_players(minecraft, "", list_callback, true);
} else if (data == tps_command) {
// Print TPS
INFO("TPS: %f", tps);
} else if (data == stop_command) {
// Stop Server
compat_request_exit();
} else if (data == help_command) {
INFO("All Commands:");
if (!is_whitelist()) {
INFO(" ban <Username> - IP-Ban All Players With Specifed Username");
}
INFO(" reload - Reload The %s", is_whitelist() ? "Whitelist" : "Blacklist");
INFO(" kill <Username> - Kill All Players With Specifed Username");
INFO(" say <Message> - Print Specified Message To Chat");
INFO(" list - List All Players");
INFO(" tps - Print TPS");
INFO(" stop - Stop Server");
INFO(" help - Print This Message");
} else {
INFO("Invalid Command: %s", data.c_str());
ServerSideNetworkHandler *server_side_network_handler = get_server_side_network_handler(minecraft);
if (server_side_network_handler != nullptr) {
static std::string ban_command("ban ");
static std::string say_command("say ");
static std::string kill_command("kill ");
static std::string list_command("list");
static std::string reload_command("reload");
static std::string tps_command("tps");
static std::string stop_command("stop");
static std::string help_command("help");
if (!is_whitelist() && data.rfind(ban_command, 0) == 0) {
// IP-Ban Target Username
std::string ban_username = data.substr(ban_command.length());
find_players(minecraft, ban_username, ban_callback, false);
} else if (data == reload_command) {
INFO("Reloading %s", is_whitelist() ? "Whitelist" : "Blacklist");
is_ip_in_blacklist(nullptr);
} else if (data.rfind(kill_command, 0) == 0) {
// Kill Target Username
std::string kill_username = data.substr(kill_command.length());
find_players(minecraft, kill_username, kill_callback, false);
} else if (data.rfind(say_command, 0) == 0) {
// Format Message
std::string message = "[Server] " + data.substr(say_command.length());
char *safe_message = to_cp437(message.c_str());
std::string cpp_string = safe_message;
// Post Message To Chat
server_side_network_handler->displayGameMessage(&cpp_string);
// Free
free(safe_message);
} else if (data == list_command) {
// List Players
INFO("All Players:");
find_players(minecraft, "", list_callback, true);
} else if (data == tps_command) {
// Print TPS
INFO("TPS: %f", tps);
} else if (data == stop_command) {
// Stop Server
compat_request_exit();
} else if (data == help_command) {
INFO("All Commands:");
if (!is_whitelist()) {
INFO(" ban <Username> - IP-Ban All Players With Specifed Username");
}
INFO(" reload - Reload The %s", is_whitelist() ? "Whitelist" : "Blacklist");
INFO(" kill <Username> - Kill All Players With Specifed Username");
INFO(" say <Message> - Print Specified Message To Chat");
INFO(" list - List All Players");
INFO(" tps - Print TPS");
INFO(" stop - Stop Server");
INFO(" help - Print This Message");
} else {
INFO("Invalid Command: %s", data.c_str());
}
// Free
free((void *) stdin_buffer);
stdin_buffer = nullptr;
}
stdin_buffer_complete = false;
}
}
@ -577,7 +556,6 @@ static void server_init() {
misc_run_on_tick(Minecraft_tick_injection);
// Start Reading STDIN
pthread_t read_stdin_thread_obj;
pthread_create(&read_stdin_thread_obj, nullptr, read_stdin_thread, nullptr);
}

View File

@ -1,34 +1,12 @@
#include <vector>
#include <SDL/SDL.h>
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <mods/init/init.h>
#include <mods/feature/feature.h>
#include <mods/input/input.h>
#include <mods/sign/sign.h>
// Handle Backspace
static int32_t sdl_key_to_minecraft_key_injection(Common_sdl_key_to_minecraft_key_t original, int32_t sdl_key) {
if (sdl_key == SDLK_BACKSPACE) {
return 0x8;
} else if (sdl_key == SDLK_DELETE) {
return 0x2e;
} else if (sdl_key == SDLK_LEFT) {
return 0x25;
} else if (sdl_key == SDLK_RIGHT) {
return 0x27;
} else if (sdl_key == SDLK_F1) {
return 0x70;
} else if (sdl_key == SDLK_F5) {
return 0x74;
} else {
// Call Original Method
return original(sdl_key);
}
}
// Open Sign Screen
static void LocalPlayer_openTextEdit_injection(LocalPlayer *local_player, TileEntity *sign) {
if (sign->type == 4) {
@ -41,7 +19,7 @@ static void LocalPlayer_openTextEdit_injection(LocalPlayer *local_player, TileEn
}
// Store Text Input
void sign_key_press(char key) {
void sign_key_press(const char key) {
Keyboard::_inputText.push_back(key);
}
@ -51,7 +29,4 @@ void init_sign() {
// Fix Signs
patch_vtable(LocalPlayer_openTextEdit, LocalPlayer_openTextEdit_injection);
}
// Handle Backspace
overwrite_calls(Common_sdl_key_to_minecraft_key, sdl_key_to_minecraft_key_injection);
}

View File

@ -79,10 +79,6 @@ static int32_t Textures_loadAndBindTexture_injection(Textures *textures, __attri
// Init
void init_skin() {
// Not Needed On Headless Mode
if (reborn_is_headless()) {
return;
}
// Check Feature Flag
if (feature_has("Load Custom Skins", server_disabled)) {
// LocalPlayer

View File

@ -69,15 +69,15 @@ static void play(std::string name, float x, float y, float z, float volume, floa
media_audio_play(source.c_str(), resolved_name.c_str(), x, y, z, pitch, volume, is_ui);
}
}
static void SoundEngine_playUI_injection(__attribute__((unused)) SoundEngine *sound_engine, std::string *name, float volume, float pitch) {
static void SoundEngine_playUI_injection(__attribute__((unused)) SoundEngine_playUI_t original, __attribute__((unused)) SoundEngine *sound_engine, std::string *name, float volume, float pitch) {
play(*name, 0, 0, 0, volume, pitch, true);
}
static void SoundEngine_play_injection(__attribute__((unused)) SoundEngine *sound_engine, std::string *name, float x, float y, float z, float volume, float pitch) {
static void SoundEngine_play_injection(__attribute__((unused)) SoundEngine_play_t original, __attribute__((unused)) SoundEngine *sound_engine, std::string *name, float x, float y, float z, float volume, float pitch) {
play(*name, x, y, z, volume, pitch, false);
}
// Refresh Data
static void SoundEngine_update_injection(SoundEngine *sound_engine, Mob *listener_mob, __attribute__((unused)) float listener_angle) {
static void SoundEngine_update_injection(__attribute__((unused)) SoundEngine_update_t original, SoundEngine *sound_engine, Mob *listener_mob, __attribute__((unused)) float listener_angle) {
// Variables
static float volume = 0;
static float x = 0;
@ -117,15 +117,11 @@ static void SoundEngine_init_injection(SoundEngine_init_t original, SoundEngine
// Init
void init_sound() {
// Not Needed On Headless Mode
if (reborn_is_headless()) {
return;
}
// Implement Sound Engine
if (feature_has("Implement Sound Engine", server_disabled)) {
overwrite(SoundEngine_playUI, SoundEngine_playUI_injection);
overwrite(SoundEngine_play, SoundEngine_play_injection);
overwrite(SoundEngine_update, SoundEngine_update_injection);
overwrite_calls(SoundEngine_playUI, SoundEngine_playUI_injection);
overwrite_calls(SoundEngine_play, SoundEngine_play_injection);
overwrite_calls(SoundEngine_update, SoundEngine_update_injection);
overwrite_calls(SoundEngine_init, SoundEngine_init_injection);
}
}

View File

@ -1,6 +1,7 @@
#include <libreborn/libreborn.h>
#include <mods/text-input-box/TextInputBox.h>
#include <mods/input/input.h>
TextInputBox *TextInputBox::create(const std::string &placeholder, const std::string &text) {
// Construct
@ -49,7 +50,7 @@ void TextInputBox::keyPressed(int key) {
}
switch (key) {
case 0x8: {
case MC_KEY_BACKSPACE: {
// Backspace
if (m_text.empty()) {
return;
@ -65,7 +66,7 @@ void TextInputBox::keyPressed(int key) {
recalculateScroll();
break;
}
case 0x2e: {
case MC_KEY_DELETE: {
// Delete
if (m_text.empty()) {
return;
@ -79,7 +80,7 @@ void TextInputBox::keyPressed(int key) {
m_text.erase(m_text.begin() + m_insertHead, m_text.begin() + m_insertHead + 1);
break;
}
case 0x25: {
case MC_KEY_LEFT: {
// Left
m_insertHead--;
if (m_insertHead < 0) {
@ -88,7 +89,7 @@ void TextInputBox::keyPressed(int key) {
recalculateScroll();
break;
}
case 0x27: {
case MC_KEY_RIGHT: {
// Right
m_insertHead++;
if (!m_text.empty()) {
@ -101,7 +102,7 @@ void TextInputBox::keyPressed(int key) {
recalculateScroll();
break;
}
case 0x0d: {
case MC_KEY_RETURN: {
// Enter
m_bFocused = false;
break;

View File

@ -7,8 +7,8 @@
#include <symbols/minecraft.h>
// Enable Touch GUI
static int32_t Minecraft_isTouchscreen_injection(__attribute__((unused)) Minecraft *minecraft) {
return 1;
static bool Minecraft_isTouchscreen_injection(__attribute__((unused)) Minecraft_isTouchscreen_t original, __attribute__((unused)) Minecraft *minecraft) {
return true;
}
// IngameBlockSelectionScreen Memory Allocation Override
@ -17,7 +17,7 @@ static unsigned char *operator_new_IngameBlockSelectionScreen_injection(__attrib
}
// Improved Button Hover Behavior
static int32_t Button_hovered_injection(__attribute__((unused)) Button *button, __attribute__((unused)) Minecraft *minecraft, __attribute__((unused)) int32_t click_x, __attribute__((unused)) int32_t click_y) {
static int32_t Button_hovered_injection(__attribute__((unused)) Button_hovered_t original, __attribute__((unused)) Button *button, __attribute__((unused)) Minecraft *minecraft, __attribute__((unused)) int32_t click_x, __attribute__((unused)) int32_t click_y) {
// Get Mouse Position
int32_t x = Mouse::getX() * Gui::InvGuiScale;
int32_t y = Mouse::getY() * Gui::InvGuiScale;
@ -33,7 +33,7 @@ static int32_t Button_hovered_injection(__attribute__((unused)) Button *button,
}
static void LargeImageButton_render_GuiComponent_drawCenteredString_injection(GuiComponent *component, Font *font, std::string *text, int32_t x, int32_t y, int32_t color) {
// Change Color On Hover
if (color == 0xe0e0e0 && Button_hovered_injection((Button *) component, nullptr, 0, 0)) {
if (color == 0xe0e0e0 && Button_hovered_injection(nullptr, (Button *) component, nullptr, 0, 0)) {
color = 0xffffa0;
}
@ -64,7 +64,7 @@ void init_touch() {
int touch_buttons = touch_gui;
if (touch_gui) {
// Main UI
overwrite(Minecraft_isTouchscreen, Minecraft_isTouchscreen_injection);
overwrite_calls(Minecraft_isTouchscreen, Minecraft_isTouchscreen_injection);
// Force Correct Toolbar Size
unsigned char toolbar_patch[4] = {0x01, 0x00, 0x50, 0xe3}; // "cmp r0, #0x1"
@ -97,7 +97,7 @@ void init_touch() {
// Improved Button Hover Behavior
if (touch_buttons && feature_has("Improved Button Hover Behavior", server_disabled)) {
overwrite(Button_hovered, Button_hovered_injection);
overwrite_calls(Button_hovered, Button_hovered_injection);
overwrite_call((void *) 0x1ebd4, (void *) LargeImageButton_render_GuiComponent_drawCenteredString_injection);
}

View File

@ -16,7 +16,7 @@ const char *version_get() {
}
// Injection For Touch GUI Version
static std::string Common_getGameVersionString_injection(__attribute__((unused)) std::string *version_suffix) {
static std::string Common_getGameVersionString_injection(__attribute__((unused)) Common_getGameVersionString_t original, __attribute__((unused)) std::string *version_suffix) {
// Set Version
return version_get();
}
@ -24,7 +24,7 @@ static std::string Common_getGameVersionString_injection(__attribute__((unused))
// Init
void init_version() {
// Touch GUI
overwrite(Common_getGameVersionString, Common_getGameVersionString_injection);
overwrite_calls(Common_getGameVersionString, Common_getGameVersionString_injection);
// Normal GUI
patch_address((void *) &Strings::minecraft_pi_version, (void *) version_get());

View File

@ -1,3 +1,3 @@
vtable 0x102540;
virtual-method int tickBuild(Player *player, uint *build_action_intention_return) = 0xc;
virtual-method bool tickBuild(Player *player, uint *build_action_intention_return) = 0xc;