Fix Mouse Cursor Bugs

This commit is contained in:
TheBrokenRail 2021-06-19 19:07:09 -04:00
parent 0f6c3c2e43
commit 747d2032e6
13 changed files with 170 additions and 58 deletions

View File

@ -1 +1 @@
2.0.1
2.0.2

View File

@ -1,5 +1,8 @@
# Changelog
**2.0.2**
* Fix Mouse Cursor Bugs
**2.0.1**
* Fix Blank Screen On Twister OS

View File

@ -12,6 +12,9 @@ typedef uint32_t bool;
// Globals
typedef void (*renderCursor_t)(float x, float y, unsigned char *minecraft);
static renderCursor_t renderCursor = (renderCursor_t) 0x480c4;
static char **default_path = (char **) 0xe264; // /.minecraft/
static char **default_username = (char **) 0x18fd4; // StevePi
@ -120,6 +123,20 @@ static uint32_t Minecraft_command_server_property_offset = 0xcc0; // CommandServ
static uint32_t Minecraft_screen_property_offset = 0xc10; // Screen *
static uint32_t Minecraft_gui_property_offset = 0x198; // Gui
// GameRenderer
typedef void (*GameRenderer_render_t)(unsigned char *game_renderer, float param_1);
static GameRenderer_render_t GameRenderer_render = (GameRenderer_render_t) 0x4a338;
static uint32_t GameRenderer_minecraft_property_offset = 0x4; // Minecraft *
// Mouse
typedef int (*Mouse_get_t)();
static Mouse_get_t Mouse_getX = (Mouse_get_t) 0x1385c;
static Mouse_get_t Mouse_getY = (Mouse_get_t) 0x1386c;
// CommandServer
static uint32_t CommandServer_minecraft_property_offset = 0x18; // Minecraft *

View File

@ -280,39 +280,82 @@ void media_cleanup() {
#endif // #ifndef MCPI_SERVER_MODE
}
#ifdef MCPI_SERVER_MODE
static SDL_GrabMode fake_grab_mode = SDL_GRAB_OFF;
#endif // #ifdef MCPI_SERVER_MODE
// Store Cursor State
static int cursor_grabbed = 0;
static int cursor_visible = 1;
// Fix SDL Cursor Visibility/Grabbing
SDL_GrabMode SDL_WM_GrabInput(SDL_GrabMode mode) {
#ifdef MCPI_SERVER_MODE
// Don't Grab Input In Server Mode
if (mode != SDL_GRAB_QUERY) {
fake_grab_mode = mode;
// Update GLFW Cursor State (Client Only)
#ifndef MCPI_SERVER_MODE
static void update_glfw_cursor() {
// Store Old Mode
int old_mode = glfwGetInputMode(glfw_window, GLFW_CURSOR);
// Handle Cursor Visibility
int new_mode;
if (!cursor_visible) {
if (cursor_grabbed) {
new_mode = GLFW_CURSOR_DISABLED;
} else {
new_mode = GLFW_CURSOR_HIDDEN;
}
return fake_grab_mode;
#else // #ifdef MCPI_SERVER_MODE
if (mode != SDL_GRAB_QUERY && mode != SDL_WM_GrabInput(SDL_GRAB_QUERY)) {
glfwSetInputMode(glfw_window, GLFW_CURSOR, mode == SDL_GRAB_OFF ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_DISABLED);
#if GLFW_VERSION_MAJOR > 3 || (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3)
glfwSetInputMode(glfw_window, GLFW_RAW_MOUSE_MOTION, mode == SDL_GRAB_OFF ? GLFW_FALSE : GLFW_TRUE);
#endif // #if GLFW_VERSION_MAJOR > 3 || (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3)
} else {
new_mode = GLFW_CURSOR_NORMAL;
}
if (new_mode != old_mode) {
// Set New Mode
glfwSetInputMode(glfw_window, GLFW_CURSOR, new_mode);
// Handle Cursor Lock/Unlock
if ((new_mode == GLFW_CURSOR_DISABLED && old_mode != GLFW_CURSOR_DISABLED) || (new_mode != GLFW_CURSOR_DISABLED && old_mode == GLFW_CURSOR_DISABLED)) {
// Use Raw Mouse Motion (GLFW 3.3+ Only)
#ifdef GLFW_RAW_MOUSE_MOTION
glfwSetInputMode(glfw_window, GLFW_RAW_MOUSE_MOTION, new_mode == GLFW_CURSOR_DISABLED ? GLFW_TRUE : GLFW_FALSE);
#endif
// Reset Last Mouse Position
ignore_relative_mouse = 1;
}
return mode == SDL_GRAB_QUERY ? (glfwGetInputMode(glfw_window, GLFW_CURSOR) == GLFW_CURSOR_NORMAL ? SDL_GRAB_OFF : SDL_GRAB_ON) : mode;
#endif // #ifdef MCPI_SERVER_MODE
}
}
#endif
// Fix SDL Cursor Visibility/Grabbing
SDL_GrabMode SDL_WM_GrabInput(SDL_GrabMode mode) {
if (mode == SDL_GRAB_QUERY) {
// Query
return cursor_grabbed ? SDL_GRAB_ON : SDL_GRAB_OFF;
} else if (mode == SDL_GRAB_ON) {
// Store State
cursor_grabbed = 1;
} else if (mode == SDL_GRAB_OFF) {
// Store State
cursor_grabbed = 0;
}
// Update Cursor GLFW State (Client Only)
#ifndef MCPI_SERVER_MODE
update_glfw_cursor();
#endif
// Return
return mode;
}
// Stub SDL Cursor Visibility
int SDL_ShowCursor(int toggle) {
#ifdef MCPI_SERVER_MODE
return toggle == SDL_QUERY ? (fake_grab_mode == SDL_GRAB_OFF ? SDL_ENABLE : SDL_DISABLE) : toggle;
#else // #ifdef MCPI_SERVER_MODE
return toggle == SDL_QUERY ? (glfwGetInputMode(glfw_window, GLFW_CURSOR) == GLFW_CURSOR_NORMAL ? SDL_ENABLE : SDL_DISABLE) : toggle;
#endif // #ifdef MCPI_SERVER_MODE
if (toggle == SDL_QUERY) {
// Query
return cursor_visible ? SDL_ENABLE : SDL_DISABLE;
} else if (toggle == SDL_ENABLE) {
// Store State
cursor_visible = 1;
} else if (toggle == SDL_DISABLE) {
// Store State
cursor_visible = 0;
}
// Update Cursor GLFW State (Client Only)
#ifndef MCPI_SERVER_MODE
update_glfw_cursor();
#endif
// Return
return toggle;
}
// Get Framebuffer Size

View File

@ -35,6 +35,9 @@ target_link_libraries(misc reborn feature util)
add_library(options SHARED src/options/options.c)
target_link_libraries(options reborn feature)
add_library(touch SHARED src/touch/touch.c)
target_link_libraries(touch reborn feature)
add_library(override SHARED src/override/override.c)
target_link_libraries(override reborn dl home)
@ -51,13 +54,13 @@ add_library(test SHARED src/test/test.c)
target_link_libraries(test reborn home)
add_library(init SHARED src/init/init.c)
target_link_libraries(init compat game_mode camera input misc options textures chat home test)
target_link_libraries(init compat game_mode camera input misc options touch textures chat home test)
if(MCPI_SERVER_MODE)
target_link_libraries(init server)
endif()
## Install Mods
install(TARGETS init compat readdir feature override game_mode camera input misc options textures chat home test DESTINATION "${MCPI_INSTALL_DIR}/mods")
install(TARGETS init compat readdir feature override game_mode camera input misc options touch textures chat home test DESTINATION "${MCPI_INSTALL_DIR}/mods")
if(MCPI_SERVER_MODE)
install(TARGETS server DESTINATION "${MCPI_INSTALL_DIR}/mods")
endif()

View File

@ -12,6 +12,13 @@
#include "../init/init.h"
#include "compat.h"
// Mouse Cursor Is Always Invisible In Vanilla MCPI
// Because In Vanilla MCPI, The GPU Overlay Covered The Normal Mouse Cursor
HOOK(SDL_ShowCursor, int, (int toggle)) {
ensure_SDL_ShowCursor();
return (*real_SDL_ShowCursor)(toggle == SDL_QUERY ? SDL_QUERY : SDL_DISABLE);
}
// Intercept SDL Events
HOOK(SDL_PollEvent, int, (SDL_Event *event)) {
// In Server Mode, Exit Requests Are Handled In src/server/server.cpp

View File

@ -4,17 +4,17 @@
#include <libreborn/media-layer/core.h>
// Functions That Have Their Return Values Used
static EGLSurface eglCreateWindowSurface_overwrite(__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLConfig config, __attribute__((unused)) NativeWindowType native_window, __attribute__((unused)) EGLint const *attrib_list) {
static EGLSurface eglCreateWindowSurface_injection(__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLConfig config, __attribute__((unused)) NativeWindowType native_window, __attribute__((unused)) EGLint const *attrib_list) {
return 0;
}
static EGLDisplay eglGetDisplay_overwrite(__attribute__((unused)) NativeDisplayType native_display) {
static EGLDisplay eglGetDisplay_injection(__attribute__((unused)) NativeDisplayType native_display) {
return 0;
}
static EGLContext eglCreateContext_overwrite(__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLConfig config, __attribute__((unused)) EGLContext share_context, __attribute__((unused)) EGLint const *attrib_list) {
static EGLContext eglCreateContext_injection(__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLConfig config, __attribute__((unused)) EGLContext share_context, __attribute__((unused)) EGLint const *attrib_list) {
return 0;
}
// Call media_swap_buffers()
static EGLBoolean eglSwapBuffers_overwrite(__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLSurface surface) {
static EGLBoolean eglSwapBuffers_injection(__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLSurface surface) {
media_swap_buffers();
return EGL_TRUE;
}
@ -25,15 +25,15 @@ __attribute__((constructor)) static void patch_egl_calls() {
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x1250c, nop_patch); // eglTerminate
patch((void *) 0x12580, nop_patch); // eglBindAPI
overwrite_call((void *) 0x12638, (void *) eglCreateWindowSurface_overwrite); // eglCreateWindowSurface
overwrite_call((void *) 0x12638, (void *) eglCreateWindowSurface_injection); // eglCreateWindowSurface
patch((void *) 0x12578, nop_patch); // eglChooseConfig
patch((void *) 0x1255c, nop_patch); // eglInitialize
patch((void *) 0x124f0, nop_patch); // eglMakeCurrent #1
patch((void *) 0x12654, nop_patch); // eglMakeCurrent #2
overwrite_call((void *) 0x124dc, (void *) eglSwapBuffers_overwrite); // eglSwapBuffers #1
overwrite_call((void *) 0x14b6c, (void *) eglSwapBuffers_overwrite); // eglSwapBuffers #2
overwrite_call((void *) 0x1254c, (void *) eglGetDisplay_overwrite); // eglGetDisplay
overwrite_call((void *) 0x124dc, (void *) eglSwapBuffers_injection); // eglSwapBuffers #1
overwrite_call((void *) 0x14b6c, (void *) eglSwapBuffers_injection); // eglSwapBuffers #2
overwrite_call((void *) 0x1254c, (void *) eglGetDisplay_injection); // eglGetDisplay
patch((void *) 0x124fc, nop_patch); // eglDestroySurface #1
patch((void *) 0x12504, nop_patch); // eglDestroySurface #2
overwrite_call((void *) 0x12594, (void *) eglCreateContext_overwrite); // eglCreateContext
overwrite_call((void *) 0x12594, (void *) eglCreateContext_injection); // eglCreateContext
}

View File

@ -11,6 +11,7 @@ __attribute__((constructor)) static void init() {
init_misc();
init_camera();
init_options();
init_touch();
init_textures();
init_chat();
init_home();

View File

@ -14,6 +14,7 @@ void init_input();
void init_misc();
void init_camera();
void init_options();
void init_touch();
void init_textures();
void init_chat();
void init_home();

View File

@ -3,7 +3,6 @@ This mod allows various options to be configured, including:
- Mob Spawning
- The Render Distance
- The Username
- Touch GUI
- Peaceful Mode
- 3D Anaglyph
- Autojump

View File

@ -68,21 +68,8 @@ static void Minecraft_init_injection(unsigned char *this) {
*(int32_t *) (options + Options_render_distance_property_offset) = render_distance;
}
// Enable Touch GUI
static int32_t Minecraft_isTouchscreen_injection(__attribute__((unused)) unsigned char *minecraft) {
return 1;
}
// Init
void init_options() {
int touch_gui = feature_has("Touch GUI");
if (touch_gui) {
// Main UI
overwrite((void *) Minecraft_isTouchscreen, Minecraft_isTouchscreen_injection);
// Force Correct Toolbar Size
unsigned char toolbar_patch[4] = {0x01, 0x00, 0x50, 0xe3}; // "cmp r0, #0x1"
patch((void *) 0x257b0, toolbar_patch);
}
mob_spawning = feature_has("Mob Spawning");
// Set Mob Spawning
overwrite((void *) LevelData_getSpawnMobs, LevelData_getSpawnMobs_injection);
@ -125,11 +112,6 @@ void init_options() {
patch((void *) 0xa6628, display_nametags_patch);
}
// Show Block Outlines
int block_outlines = feature_has("Show Block Outlines");
unsigned char outline_patch[4] = {block_outlines ? !touch_gui : touch_gui, 0x00, 0x50, 0xe3}; // "cmp r0, #0x1" or "cmp r0, #0x0"
patch((void *) 0x4a210, outline_patch);
smooth_lighting = feature_has("Smooth Lighting");
if (smooth_lighting) {
// Enable Smooth Lighting

2
mods/src/touch/README.md Normal file
View File

@ -0,0 +1,2 @@
# ``touch`` Mod
This mod allows the hidden touch GUI to be activated.

54
mods/src/touch/touch.c Normal file
View File

@ -0,0 +1,54 @@
#include <libreborn/libreborn.h>
#include "../feature/feature.h"
#include "../init/init.h"
#include <libreborn/minecraft.h>
// Enable Touch GUI
static int32_t Minecraft_isTouchscreen_injection(__attribute__((unused)) unsigned char *minecraft) {
return 1;
}
// Custom Cursor Rendering
// The Default Behavior For Touch GUI Is To Only Render The Cursor When The Mouse Is Clicking, This Fixes That
static void GameRenderer_render_injection(unsigned char *game_renderer, float param_1) {
// Call Real Method
(*GameRenderer_render)(game_renderer, param_1);
// Render Cursor
unsigned char *minecraft = *(unsigned char **) (game_renderer + GameRenderer_minecraft_property_offset);
unsigned char *current_screen = *(unsigned char **) (minecraft + Minecraft_screen_property_offset);
// Check If Cursor Should Render
if (current_screen != NULL) {
// Get X And Y
float x = (*Mouse_getX)() * (*InvGuiScale);
float y = (*Mouse_getY)() * (*InvGuiScale);
// Render
(*renderCursor)(x, y, minecraft);
}
}
// Init
void init_touch() {
int touch_gui = feature_has("Touch GUI");
if (touch_gui) {
// Main UI
overwrite((void *) Minecraft_isTouchscreen, Minecraft_isTouchscreen_injection);
// Disable Normal Cursor Rendering
unsigned char disable_cursor_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x4a6c0, disable_cursor_patch);
// Add Custom Cursor Rendering
overwrite_calls((void *) GameRenderer_render, (void *) GameRenderer_render_injection);
}
// Force Correct Toolbar Size
unsigned char toolbar_patch[4] = {0x01, 0x00, 0x50, 0xe3}; // "cmp r0, #0x1"
patch((void *) 0x257b0, toolbar_patch);
// Show Block Outlines
int block_outlines = feature_has("Show Block Outlines");
unsigned char outline_patch[4] = {block_outlines ? !touch_gui : touch_gui, 0x00, 0x50, 0xe3}; // "cmp r0, #0x1" or "cmp r0, #0x0"
patch((void *) 0x4a210, outline_patch);
}