2.2.8
This commit is contained in:
parent
a79a601c59
commit
472f5d67a5
@ -1,5 +1,15 @@
|
||||
# Changelog
|
||||
|
||||
**2.2.8**
|
||||
* Add "Hide Chat Messages" Optional Feature Flag
|
||||
* Add "Remove Creative Restrictions" Optional Feature Flag
|
||||
* Improve GLFW->SDL Mouse Motion Event Conversion
|
||||
* Performance Optimizations
|
||||
* Make Majority Of Server-Specific Logging Code Also Apply To The Client
|
||||
* Simple Benchmark Mode
|
||||
* Fix Typo When Audio Source File Doesn't Exist
|
||||
* Improve Build System
|
||||
|
||||
**2.2.7**
|
||||
* Fix Crash When OpenAL Is Unavailable
|
||||
* Fix Command Input In Server
|
||||
|
@ -9,3 +9,8 @@ FALSE This Flag Is Off By Default
|
||||
|
||||
## ``--only-generate`` (Server Mode Only)
|
||||
If you run MCPI-Reborn with ``--only-generate``, it will immediately exit once world generation has completed. This is mainly used for automatically testing MCPI-Reborn.
|
||||
|
||||
## ``--benchmark`` (Client Mode Only)
|
||||
If you run MCPI-Reborn with ``--benchmark``, it will enter a simple benchmark mode. This means automatically loading a newly generated world, then rotating the camera for a period of time. When it has finished, it will then exit and print the average FPS while the world was loaded. In this mode, all user input is blocked. However you can still modify rendering settings by changing feature flags.
|
||||
|
||||
The world used will always be re-created on start and uses a hard-coded seed.
|
||||
|
BIN
images/start.png
BIN
images/start.png
Binary file not shown.
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
@ -8,6 +8,7 @@ TRUE Display Nametags By Default
|
||||
TRUE Fix Sign Placement
|
||||
TRUE Show Block Outlines
|
||||
FALSE Expand Creative Inventory
|
||||
FALSE Remove Creative Restrictions
|
||||
FALSE Peaceful Mode
|
||||
TRUE Animated Water
|
||||
TRUE Remove Invalid Item Background
|
||||
@ -16,6 +17,7 @@ TRUE Smooth Lighting
|
||||
FALSE 3D Anaglyph
|
||||
TRUE Fix Camera Rendering
|
||||
TRUE Implement Chat
|
||||
FALSE Hide Chat Messages
|
||||
TRUE Implement Death Messages
|
||||
TRUE Implement Game-Mode Switching
|
||||
TRUE Allow Joining Survival Servers
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
#include <media-layer/internal.h>
|
||||
#include <media-layer/core.h>
|
||||
|
||||
// SDL Is Replaced With GLFW
|
||||
|
||||
@ -41,3 +42,7 @@ int SDL_PushEvent(SDL_Event *event) {
|
||||
pthread_mutex_unlock(&queue_mutex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void media_ensure_loaded() {
|
||||
// NOP
|
||||
}
|
||||
|
@ -16,6 +16,14 @@
|
||||
#include "audio/engine.h"
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
|
||||
// Allow Disabling Interaction
|
||||
static void update_cursor();
|
||||
static int is_interactable = 1;
|
||||
void media_set_interactable(int toggle) {
|
||||
is_interactable = toggle;
|
||||
update_cursor();
|
||||
}
|
||||
|
||||
// GLFW Code Not Needed In Headless Mode
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
|
||||
@ -139,63 +147,75 @@ static SDLMod glfw_modifier_to_sdl_modifier(int mods) {
|
||||
|
||||
// Pass Key Presses To SDL
|
||||
static void glfw_key(__attribute__((unused)) GLFWwindow *window, int key, int scancode, int action, __attribute__((unused)) int mods) {
|
||||
SDL_Event event;
|
||||
int up = action == GLFW_RELEASE;
|
||||
event.type = up ? SDL_KEYUP : SDL_KEYDOWN;
|
||||
event.key.state = up ? SDL_RELEASED : SDL_PRESSED;
|
||||
event.key.keysym.scancode = scancode;
|
||||
event.key.keysym.mod = glfw_modifier_to_sdl_modifier(mods);
|
||||
event.key.keysym.sym = glfw_key_to_sdl_key(key);
|
||||
SDL_PushEvent(&event);
|
||||
if (key == GLFW_KEY_BACKSPACE && !up) {
|
||||
character_event((char) '\b');
|
||||
if (is_interactable) {
|
||||
SDL_Event event;
|
||||
int up = action == GLFW_RELEASE;
|
||||
event.type = up ? SDL_KEYUP : SDL_KEYDOWN;
|
||||
event.key.state = up ? SDL_RELEASED : SDL_PRESSED;
|
||||
event.key.keysym.scancode = scancode;
|
||||
event.key.keysym.mod = glfw_modifier_to_sdl_modifier(mods);
|
||||
event.key.keysym.sym = glfw_key_to_sdl_key(key);
|
||||
SDL_PushEvent(&event);
|
||||
if (key == GLFW_KEY_BACKSPACE && !up) {
|
||||
character_event((char) '\b');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pass Text To Minecraft
|
||||
static void glfw_char(__attribute__((unused)) GLFWwindow *window, unsigned int codepoint) {
|
||||
character_event((char) codepoint);
|
||||
if (is_interactable) {
|
||||
character_event((char) codepoint);
|
||||
}
|
||||
}
|
||||
|
||||
// Last Mouse Location
|
||||
static double last_mouse_x = 0;
|
||||
static double last_mouse_y = 0;
|
||||
static int ignore_relative_mouse = 1;
|
||||
// Ignore Relative Cursor Motion
|
||||
static int ignore_relative_motion = 0;
|
||||
|
||||
// Pass Mouse Movement To SDL
|
||||
static void glfw_motion(__attribute__((unused)) GLFWwindow *window, double xpos, double ypos) {
|
||||
SDL_Event event;
|
||||
event.type = SDL_MOUSEMOTION;
|
||||
event.motion.x = xpos;
|
||||
event.motion.y = ypos;
|
||||
event.motion.xrel = !ignore_relative_mouse ? (xpos - last_mouse_x) : 0;
|
||||
event.motion.yrel = !ignore_relative_mouse ? (ypos - last_mouse_y) : 0;
|
||||
ignore_relative_mouse = 0;
|
||||
if (is_interactable) {
|
||||
SDL_Event event;
|
||||
event.type = SDL_MOUSEMOTION;
|
||||
event.motion.x = xpos;
|
||||
event.motion.y = ypos;
|
||||
event.motion.xrel = !ignore_relative_motion ? (xpos - last_mouse_x) : 0;
|
||||
event.motion.yrel = !ignore_relative_motion ? (ypos - last_mouse_y) : 0;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
ignore_relative_motion = 0;
|
||||
last_mouse_x = xpos;
|
||||
last_mouse_y = ypos;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
|
||||
// Create And Push SDL Mouse Click Event
|
||||
static void click_event(int button, int up) {
|
||||
SDL_Event event;
|
||||
event.type = up ? SDL_MOUSEBUTTONUP : SDL_MOUSEBUTTONDOWN;
|
||||
event.button.x = last_mouse_x;
|
||||
event.button.y = last_mouse_y;
|
||||
event.button.state = up ? SDL_RELEASED : SDL_PRESSED;
|
||||
event.button.button = button;
|
||||
SDL_PushEvent(&event);
|
||||
if (is_interactable) {
|
||||
SDL_Event event;
|
||||
event.type = up ? SDL_MOUSEBUTTONUP : SDL_MOUSEBUTTONDOWN;
|
||||
event.button.x = last_mouse_x;
|
||||
event.button.y = last_mouse_y;
|
||||
event.button.state = up ? SDL_RELEASED : SDL_PRESSED;
|
||||
event.button.button = button;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
}
|
||||
|
||||
// Pass Mouse Click To SDL
|
||||
static void glfw_click(__attribute__((unused)) GLFWwindow *window, int button, int action, __attribute__((unused)) int mods) {
|
||||
int up = action == GLFW_RELEASE;
|
||||
int sdl_button = button == GLFW_MOUSE_BUTTON_RIGHT ? SDL_BUTTON_RIGHT : (button == GLFW_MOUSE_BUTTON_LEFT ? SDL_BUTTON_LEFT : SDL_BUTTON_MIDDLE);
|
||||
click_event(sdl_button, up);
|
||||
if (is_interactable) {
|
||||
int up = action == GLFW_RELEASE;
|
||||
int sdl_button = button == GLFW_MOUSE_BUTTON_RIGHT ? SDL_BUTTON_RIGHT : (button == GLFW_MOUSE_BUTTON_LEFT ? SDL_BUTTON_LEFT : SDL_BUTTON_MIDDLE);
|
||||
click_event(sdl_button, up);
|
||||
}
|
||||
}
|
||||
|
||||
// Pass Mouse Scroll To SDL
|
||||
static void glfw_scroll(__attribute__((unused)) GLFWwindow *window, __attribute__((unused)) double xoffset, double yoffset) {
|
||||
if (yoffset != 0) {
|
||||
if (is_interactable && yoffset != 0) {
|
||||
int sdl_button = yoffset > 0 ? SDL_BUTTON_WHEELUP : SDL_BUTTON_WHEELDOWN;
|
||||
click_event(sdl_button, 0);
|
||||
click_event(sdl_button, 1);
|
||||
@ -207,6 +227,17 @@ static void glfw_scroll(__attribute__((unused)) GLFWwindow *window, __attribute_
|
||||
// Track Media Layer State
|
||||
static int is_running = 0;
|
||||
|
||||
// Disable V-Sync
|
||||
static int disable_vsync = 0;
|
||||
void media_disable_vsync() {
|
||||
disable_vsync = 1;
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
if (is_running) {
|
||||
glfwSwapInterval(0);
|
||||
}
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
}
|
||||
|
||||
// Init Media Layer
|
||||
void SDL_WM_SetCaption(const char *title, __attribute__((unused)) const char *icon) {
|
||||
// Don't Enable GLFW In Headless Mode
|
||||
@ -250,6 +281,12 @@ void SDL_WM_SetCaption(const char *title, __attribute__((unused)) const char *ic
|
||||
|
||||
// Set State
|
||||
is_running = 1;
|
||||
|
||||
// Update State
|
||||
update_cursor();
|
||||
if (disable_vsync) {
|
||||
media_disable_vsync();
|
||||
}
|
||||
}
|
||||
|
||||
void media_swap_buffers() {
|
||||
@ -341,37 +378,53 @@ static int cursor_grabbed = 0;
|
||||
static int cursor_visible = 1;
|
||||
|
||||
// Update GLFW Cursor State (Client Only)
|
||||
static void update_cursor() {
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
static void update_glfw_cursor() {
|
||||
// Store Old Mode
|
||||
int old_mode = glfwGetInputMode(glfw_window, GLFW_CURSOR);
|
||||
if (is_running) {
|
||||
// Get New State
|
||||
int new_cursor_visible = is_interactable ? cursor_visible : 1;
|
||||
int new_cursor_grabbed = is_interactable ? cursor_grabbed : 0;
|
||||
|
||||
// Handle Cursor Visibility
|
||||
int new_mode;
|
||||
if (!cursor_visible) {
|
||||
if (cursor_grabbed) {
|
||||
new_mode = GLFW_CURSOR_DISABLED;
|
||||
// Store Old Mode
|
||||
int old_mode = glfwGetInputMode(glfw_window, GLFW_CURSOR);
|
||||
|
||||
// Handle Cursor Visibility
|
||||
int new_mode;
|
||||
if (!new_cursor_visible) {
|
||||
if (new_cursor_grabbed) {
|
||||
new_mode = GLFW_CURSOR_DISABLED;
|
||||
} else {
|
||||
new_mode = GLFW_CURSOR_HIDDEN;
|
||||
}
|
||||
} else {
|
||||
new_mode = GLFW_CURSOR_HIDDEN;
|
||||
new_mode = GLFW_CURSOR_NORMAL;
|
||||
}
|
||||
} else {
|
||||
new_mode = GLFW_CURSOR_NORMAL;
|
||||
}
|
||||
if (new_mode != old_mode) {
|
||||
// Set New Mode
|
||||
glfwSetInputMode(glfw_window, GLFW_CURSOR, new_mode);
|
||||
if (new_mode != old_mode) {
|
||||
// Ignore Relative Cursor Motion When Locking
|
||||
if (new_mode == GLFW_CURSOR_DISABLED && old_mode != GLFW_CURSOR_DISABLED) {
|
||||
ignore_relative_motion = 1;
|
||||
}
|
||||
|
||||
// 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
|
||||
glfwSetInputMode(glfw_window, GLFW_RAW_MOUSE_MOTION, new_mode == GLFW_CURSOR_DISABLED ? GLFW_TRUE : GLFW_FALSE);
|
||||
// Set New Mode
|
||||
glfwSetInputMode(glfw_window, GLFW_CURSOR, new_mode);
|
||||
|
||||
// Reset Last Mouse Position
|
||||
ignore_relative_mouse = 1;
|
||||
// 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
|
||||
glfwSetInputMode(glfw_window, GLFW_RAW_MOUSE_MOTION, new_mode == GLFW_CURSOR_DISABLED ? GLFW_TRUE : GLFW_FALSE);
|
||||
}
|
||||
|
||||
// Reset Mouse Position When Unlocking
|
||||
if (new_mode != GLFW_CURSOR_DISABLED && old_mode == GLFW_CURSOR_DISABLED) {
|
||||
double cursor_x;
|
||||
double cursor_y;
|
||||
glfwGetCursorPos(glfw_window, &cursor_x, &cursor_y);
|
||||
glfw_motion(glfw_window, cursor_x, cursor_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
}
|
||||
#endif
|
||||
|
||||
// Fix SDL Cursor Visibility/Grabbing
|
||||
SDL_GrabMode SDL_WM_GrabInput(SDL_GrabMode mode) {
|
||||
@ -386,9 +439,7 @@ SDL_GrabMode SDL_WM_GrabInput(SDL_GrabMode mode) {
|
||||
cursor_grabbed = 0;
|
||||
}
|
||||
// Update Cursor GLFW State (Client Only)
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
update_glfw_cursor();
|
||||
#endif
|
||||
update_cursor();
|
||||
// Return
|
||||
return mode;
|
||||
}
|
||||
@ -406,9 +457,7 @@ int SDL_ShowCursor(int toggle) {
|
||||
cursor_visible = 0;
|
||||
}
|
||||
// Update Cursor GLFW State (Client Only)
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
update_glfw_cursor();
|
||||
#endif
|
||||
update_cursor();
|
||||
// Return
|
||||
return toggle;
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ extern "C" {
|
||||
#define GL_DEPTH_TEST 0xb71
|
||||
#define GL_PACK_ALIGNMENT 0xd05
|
||||
#define GL_UNPACK_ALIGNMENT 0xcf5
|
||||
#define GL_SRC_ALPHA 0x302
|
||||
#define GL_ONE_MINUS_SRC_ALPHA 0x303
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
@ -8,11 +8,15 @@ extern "C" {
|
||||
#define DEFAULT_WIDTH 840
|
||||
#define DEFAULT_HEIGHT 480
|
||||
|
||||
void media_ensure_loaded();
|
||||
|
||||
void media_take_screenshot(char *home);
|
||||
void media_toggle_fullscreen();
|
||||
void media_swap_buffers();
|
||||
void media_cleanup();
|
||||
void media_get_framebuffer_size(int *width, int *height);
|
||||
void media_set_interactable(int is_interactable);
|
||||
void media_disable_vsync();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -307,3 +307,32 @@ CALL(60, media_audio_play, void, (const char *source, const char *name, float x,
|
||||
free(name);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(62, media_set_interactable, void, (int is_interactable)) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
|
||||
// Arguments
|
||||
write_int(is_interactable);
|
||||
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
#else
|
||||
int is_interactable = read_int();
|
||||
// Run
|
||||
media_set_interactable(is_interactable);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(63, media_disable_vsync, void, ()) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
#else
|
||||
// Run
|
||||
media_disable_vsync();
|
||||
#endif
|
||||
}
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include <unordered_map>
|
||||
#include <fstream>
|
||||
|
||||
#include <media-layer/core.h>
|
||||
|
||||
#include "../common/common.h"
|
||||
|
||||
// Track Client State
|
||||
@ -85,58 +87,36 @@ static void start_media_layer_proxy_client(int read, int write) {
|
||||
update_client_state(1, 0);
|
||||
}
|
||||
|
||||
// Maximize Pipe Buffer Size
|
||||
static void maximize_pipe_fd_size(int fd) {
|
||||
// Read Maximum Pipe Size
|
||||
std::ifstream max_size_file("/proc/sys/fs/pipe-max-size");
|
||||
if (!max_size_file.good()) {
|
||||
PROXY_ERR("%s", "Unable To Open Maximum Pipe Size File");
|
||||
}
|
||||
// Read One Line
|
||||
int max_size;
|
||||
std::string line;
|
||||
if (std::getline(max_size_file, line) && line.size() > 0) {
|
||||
max_size = std::stoi(line);
|
||||
} else {
|
||||
PROXY_ERR("%s", "Unable To Read Maximum Pipe Size File");
|
||||
}
|
||||
// Set Maximum Pipe Size
|
||||
errno = 0;
|
||||
if (fcntl(fd, F_SETPIPE_SZ, max_size) < max_size) {
|
||||
PROXY_ERR("Unable To Set Maximum Pipe Size: %s", errno != 0 ? strerror(errno) : "Unknown Error");
|
||||
}
|
||||
}
|
||||
static void maximize_pipe_size(int pipe[2]) {
|
||||
maximize_pipe_fd_size(pipe[0]);
|
||||
maximize_pipe_fd_size(pipe[1]);
|
||||
}
|
||||
|
||||
// Start Server
|
||||
__attribute__((constructor)) static void init_media_layer_proxy_server() {
|
||||
PROXY_INFO("%s", "Starting...");
|
||||
static int loaded = 0;
|
||||
__attribute__((constructor)) void media_ensure_loaded() {
|
||||
if (!loaded) {
|
||||
loaded = 1;
|
||||
|
||||
// Create Connection
|
||||
int server_to_client_pipe[2];
|
||||
safe_pipe2(server_to_client_pipe, 0);
|
||||
maximize_pipe_size(server_to_client_pipe);
|
||||
int client_to_server_pipe[2];
|
||||
safe_pipe2(client_to_server_pipe, 0);
|
||||
maximize_pipe_size(client_to_server_pipe);
|
||||
// Set Connection
|
||||
set_connection(client_to_server_pipe[0], server_to_client_pipe[1]);
|
||||
// Log
|
||||
PROXY_INFO("%s", "Starting...");
|
||||
|
||||
// Start Client
|
||||
start_media_layer_proxy_client(server_to_client_pipe[0], client_to_server_pipe[1]);
|
||||
// Create Connection
|
||||
int server_to_client_pipe[2];
|
||||
safe_pipe2(server_to_client_pipe, 0);
|
||||
int client_to_server_pipe[2];
|
||||
safe_pipe2(client_to_server_pipe, 0);
|
||||
// Set Connection
|
||||
set_connection(client_to_server_pipe[0], server_to_client_pipe[1]);
|
||||
|
||||
// Wait For Connection Message
|
||||
char *str = read_string();
|
||||
if (strcmp(str, CONNECTED_MSG) == 0) {
|
||||
PROXY_INFO("%s", "Connected");
|
||||
} else {
|
||||
PROXY_ERR("%s", "Unable To Connect");
|
||||
// Start Client
|
||||
start_media_layer_proxy_client(server_to_client_pipe[0], client_to_server_pipe[1]);
|
||||
|
||||
// Wait For Connection Message
|
||||
char *str = read_string();
|
||||
if (strcmp(str, CONNECTED_MSG) == 0) {
|
||||
PROXY_INFO("%s", "Connected");
|
||||
} else {
|
||||
PROXY_ERR("%s", "Unable To Connect");
|
||||
}
|
||||
// Free
|
||||
free(str);
|
||||
}
|
||||
// Free
|
||||
free(str);
|
||||
}
|
||||
|
||||
// Assign Unique ID To Function
|
||||
|
@ -23,7 +23,7 @@ target_link_libraries(chat reborn symbols feature pthread)
|
||||
|
||||
if(MCPI_SERVER_MODE)
|
||||
add_library(server SHARED src/server/server.cpp src/server/server_properties.cpp)
|
||||
target_link_libraries(server reborn symbols feature home compat version dl media-layer-core pthread)
|
||||
target_link_libraries(server reborn symbols feature home misc compat dl media-layer-core pthread)
|
||||
else()
|
||||
target_link_libraries(compat input sign chat home dl)
|
||||
|
||||
@ -39,7 +39,7 @@ else()
|
||||
target_link_libraries(camera reborn symbols media-layer-core feature home)
|
||||
|
||||
add_library(input SHARED src/input/input.cpp src/input/bow.c src/input/attack.c src/input/toggle.c src/input/misc.c src/input/drop.cpp)
|
||||
target_link_libraries(input reborn symbols feature media-layer-core)
|
||||
target_link_libraries(input reborn symbols creative feature media-layer-core)
|
||||
|
||||
add_library(sign SHARED src/sign/sign.cpp)
|
||||
target_link_libraries(sign reborn symbols feature input)
|
||||
@ -58,6 +58,11 @@ else()
|
||||
|
||||
add_library(atlas SHARED src/atlas/atlas.cpp)
|
||||
target_link_libraries(atlas reborn symbols feature GLESv1_CM)
|
||||
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
add_library(benchmark SHARED src/benchmark/benchmark.cpp)
|
||||
target_link_libraries(benchmark reborn symbols compat misc media-layer-core)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(game-mode SHARED src/game-mode/game-mode.c src/game-mode/game-mode.cpp)
|
||||
@ -66,8 +71,8 @@ target_link_libraries(game-mode reborn symbols feature)
|
||||
add_library(death SHARED src/death/death.cpp)
|
||||
target_link_libraries(death reborn symbols feature)
|
||||
|
||||
add_library(misc SHARED src/misc/misc.c src/misc/misc.cpp)
|
||||
target_link_libraries(misc reborn symbols feature)
|
||||
add_library(misc SHARED src/misc/misc.c src/misc/misc.cpp src/misc/logging.cpp)
|
||||
target_link_libraries(misc reborn symbols feature GLESv1_CM)
|
||||
|
||||
add_library(options SHARED src/options/options.c)
|
||||
target_link_libraries(options reborn symbols feature)
|
||||
@ -79,11 +84,14 @@ 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 misc death options chat home version test)
|
||||
target_link_libraries(init compat game-mode misc death options chat home version test media-layer-core)
|
||||
if(MCPI_SERVER_MODE)
|
||||
target_link_libraries(init server)
|
||||
else()
|
||||
target_link_libraries(init multiplayer sound camera input sign creative touch textures atlas)
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
target_link_libraries(init benchmark)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
## Install Mods
|
||||
@ -92,4 +100,7 @@ if(MCPI_SERVER_MODE)
|
||||
install(TARGETS server DESTINATION "${MCPI_INSTALL_DIR}/mods")
|
||||
else()
|
||||
install(TARGETS multiplayer sound override camera input sign creative touch textures atlas DESTINATION "${MCPI_INSTALL_DIR}/mods")
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
install(TARGETS benchmark DESTINATION "${MCPI_INSTALL_DIR}/mods")
|
||||
endif()
|
||||
endif()
|
||||
|
2
mods/src/benchmark/README.md
Normal file
2
mods/src/benchmark/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
# ``benchmark`` Mod
|
||||
This mod contain a simple game benchmark.
|
147
mods/src/benchmark/benchmark.cpp
Normal file
147
mods/src/benchmark/benchmark.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
#include <ctime>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <symbols/minecraft.h>
|
||||
|
||||
#include <media-layer/core.h>
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
#include "../init/init.h"
|
||||
#include "../compat/compat.h"
|
||||
#include "../misc/misc.h"
|
||||
|
||||
// --benchmark: Activate Benchmark
|
||||
static bool active = false;
|
||||
__attribute__((constructor)) static void _init_active(int argc, char *argv[]) {
|
||||
// Iterate Arguments
|
||||
for (int i = 1; i < argc; i++) {
|
||||
// Check Argument
|
||||
if (strcmp(argv[i], "--benchmark") == 0) {
|
||||
// Enabled
|
||||
active = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Constants
|
||||
#define NANOSECONDS_IN_SECOND 1000000000ll
|
||||
|
||||
// Config
|
||||
#define BENCHMARK_GAME_MODE 1 // Creative Mode
|
||||
#define BENCHMARK_SEED 2048 // Random Number
|
||||
#define BENCHMARK_WORLD_NAME "_Benchmark" // Random Number
|
||||
#define BENCHMARK_LENGTH (180ll * NANOSECONDS_IN_SECOND) // 3 Minutes
|
||||
#define BENCHMARK_ROTATION_INTERVAL ((long long int) (0.02f * NANOSECONDS_IN_SECOND))
|
||||
#define BENCHMARK_ROTATION_AMOUNT 10
|
||||
|
||||
// Create/Start World
|
||||
static void start_world(unsigned char *minecraft) {
|
||||
// Log
|
||||
INFO("%s", "Loading Benchmark");
|
||||
|
||||
// Specify Level Settings
|
||||
LevelSettings settings;
|
||||
settings.game_type = BENCHMARK_GAME_MODE;
|
||||
settings.seed = BENCHMARK_SEED;
|
||||
|
||||
// Delete World If It Already Exists
|
||||
unsigned char *level_source = (*Minecraft_getLevelSource)(minecraft);
|
||||
unsigned char *level_source_vtable = *(unsigned char **) level_source;
|
||||
ExternalFileLevelStorageSource_deleteLevel_t ExternalFileLevelStorageSource_deleteLevel = *(ExternalFileLevelStorageSource_deleteLevel_t *) (level_source_vtable + ExternalFileLevelStorageSource_deleteLevel_vtable_offset);
|
||||
(*ExternalFileLevelStorageSource_deleteLevel)(level_source, BENCHMARK_WORLD_NAME);
|
||||
|
||||
// Select Level
|
||||
(*Minecraft_selectLevel)(minecraft, BENCHMARK_WORLD_NAME, BENCHMARK_WORLD_NAME, settings);
|
||||
|
||||
// Open ProgressScreen
|
||||
void *screen = ::operator new(PROGRESS_SCREEN_SIZE);
|
||||
ALLOC_CHECK(screen);
|
||||
screen = (*ProgressScreen)((unsigned char *) screen);
|
||||
(*Minecraft_setScreen)(minecraft, (unsigned char *) screen);
|
||||
}
|
||||
|
||||
// Track Frames
|
||||
static unsigned long long int frames = 0;
|
||||
HOOK(media_swap_buffers, void, ()) {
|
||||
ensure_media_swap_buffers();
|
||||
(*real_media_swap_buffers)();
|
||||
frames++;
|
||||
}
|
||||
|
||||
// Get Time
|
||||
static long long int get_time() {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||||
long long int a = (long long int) ts.tv_nsec;
|
||||
long long int b = ((long long int) ts.tv_sec) * NANOSECONDS_IN_SECOND;
|
||||
return a + b;
|
||||
}
|
||||
|
||||
// Store Time When World Loaded
|
||||
static int world_loaded = 0;
|
||||
static long long int world_loaded_time;
|
||||
static unsigned long long int world_loaded_frames;
|
||||
|
||||
// Runs Every Tick
|
||||
static bool loaded = false;
|
||||
static bool exit_requested = false;
|
||||
static void Minecraft_update_injection(unsigned char *minecraft) {
|
||||
// Create/Start World
|
||||
if (!loaded) {
|
||||
start_world(minecraft);
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
// Detect World Loaded
|
||||
if (!world_loaded && (*Minecraft_isLevelGenerated)(minecraft)) {
|
||||
world_loaded = 1;
|
||||
world_loaded_time = get_time();
|
||||
world_loaded_frames = frames;
|
||||
}
|
||||
|
||||
// Run Benchmark
|
||||
if (!exit_requested && world_loaded) {
|
||||
// Get Time
|
||||
long long int current_time = get_time() - world_loaded_time;
|
||||
unsigned long long int current_frames = frames - world_loaded_frames;
|
||||
|
||||
// Rotate Player
|
||||
static long long int rotate_point = BENCHMARK_ROTATION_INTERVAL;
|
||||
if (current_time >= rotate_point) {
|
||||
SDL_Event event;
|
||||
event.type = SDL_MOUSEMOTION;
|
||||
event.motion.x = 0;
|
||||
event.motion.y = 0;
|
||||
event.motion.xrel = BENCHMARK_ROTATION_AMOUNT;
|
||||
event.motion.yrel = 0;
|
||||
SDL_PushEvent(&event);
|
||||
// Reset Rotation Timer
|
||||
rotate_point += BENCHMARK_ROTATION_INTERVAL;
|
||||
}
|
||||
|
||||
// Check If Benchmark Is Over
|
||||
if (current_time >= BENCHMARK_LENGTH) {
|
||||
// Request Exit
|
||||
compat_request_exit();
|
||||
// Disable Special Behavior After Requesting Exit
|
||||
exit_requested = true;
|
||||
|
||||
// Calculate FPS
|
||||
static double frames_per_nanosecond = ((double) current_frames) / ((double) current_time);
|
||||
static double frames_per_second = frames_per_nanosecond * NANOSECONDS_IN_SECOND;
|
||||
INFO("Benchmark Completed After %llu Frames In %lld Nanoseconds, Average FPS: %f", current_frames, current_time, frames_per_second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Init Benchmark
|
||||
void init_benchmark() {
|
||||
if (active) {
|
||||
misc_run_on_update(Minecraft_update_injection);
|
||||
// Disable Interaction
|
||||
media_set_interactable(0);
|
||||
// Disable V-Sync
|
||||
media_disable_vsync();
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "../init/init.h"
|
||||
#include "../feature/feature.h"
|
||||
#include "creative.h"
|
||||
|
||||
// Add Item To Inventory
|
||||
static void inventory_add_item(unsigned char *inventory, unsigned char *item, bool is_tile) {
|
||||
@ -51,10 +52,43 @@ static int32_t Inventory_setupDefault_FillingContainer_addItem_call_injection(un
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Check Restriction Status
|
||||
static int is_restricted = 1;
|
||||
int creative_is_restricted() {
|
||||
return is_restricted;
|
||||
}
|
||||
|
||||
// Init
|
||||
void init_creative() {
|
||||
// Add Extra Items To Creative Inventory (Only Replace Specific Function Call)
|
||||
if (feature_has("Expand Creative Inventory", 0)) {
|
||||
overwrite_call((void *) 0x8e0fc, (void *) Inventory_setupDefault_FillingContainer_addItem_call_injection);
|
||||
}
|
||||
|
||||
// Remove Creative Restrictions (Opening Chests, Crafting, Etc)
|
||||
if (feature_has("Remove Creative Restrictions", 0)) {
|
||||
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
|
||||
patch((void *) 0x1e3f4, nop_patch);
|
||||
unsigned char slot_count_patch[4] = {0x18, 0x00, 0x00, 0xea}; // "b 0x27110"
|
||||
patch((void *) 0x270a8, slot_count_patch);
|
||||
patch((void *) 0x341c0, nop_patch);
|
||||
patch((void *) 0x3adb4, nop_patch);
|
||||
patch((void *) 0x3b374, nop_patch);
|
||||
patch((void *) 0x43ee8, nop_patch);
|
||||
patch((void *) 0x43f3c, nop_patch);
|
||||
patch((void *) 0x43fd0, nop_patch);
|
||||
patch((void *) 0x43fd8, nop_patch);
|
||||
patch((void *) 0x8d080, nop_patch);
|
||||
patch((void *) 0x8d090, nop_patch);
|
||||
patch((void *) 0x91d48, nop_patch);
|
||||
patch((void *) 0x92098, nop_patch);
|
||||
unsigned char FillingContainer_removeResource_creative_check_patch[4] = {0x03, 0x00, 0x53, 0xe1}; // "cmp r3, r3"
|
||||
patch((void *) 0x923c0, FillingContainer_removeResource_creative_check_patch);
|
||||
patch((void *) 0x92828, nop_patch);
|
||||
// Maximize Creative Inventory Stack Size
|
||||
unsigned char maximize_stack_patch[4] = {0xff, 0xc0, 0xa0, 0xe3}; // "mov r12, 0xff"
|
||||
patch((void *) 0x8e104, maximize_stack_patch);
|
||||
// Disable Other Restrictions
|
||||
is_restricted = 0;
|
||||
}
|
||||
}
|
||||
|
11
mods/src/creative/creative.h
Normal file
11
mods/src/creative/creative.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int creative_is_restricted();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,7 +1,11 @@
|
||||
#include "init.h"
|
||||
|
||||
#include <media-layer/core.h>
|
||||
|
||||
__attribute__((constructor)) static void init() {
|
||||
media_ensure_loaded();
|
||||
run_tests();
|
||||
init_version();
|
||||
init_compat();
|
||||
#ifdef MCPI_SERVER_MODE
|
||||
init_server();
|
||||
@ -22,5 +26,7 @@ __attribute__((constructor)) static void init() {
|
||||
init_options();
|
||||
init_chat();
|
||||
init_home();
|
||||
init_version();
|
||||
#if !defined(MCPI_SERVER_MODE) && !defined(MCPI_HEADLESS_MODE)
|
||||
init_benchmark();
|
||||
#endif
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
void run_tests();
|
||||
void init_version();
|
||||
void init_compat();
|
||||
#ifdef MCPI_SERVER_MODE
|
||||
void init_server();
|
||||
@ -25,7 +26,9 @@ void init_death();
|
||||
void init_options();
|
||||
void init_chat();
|
||||
void init_home();
|
||||
void init_version();
|
||||
#if !defined(MCPI_SERVER_MODE) && !defined(MCPI_HEADLESS_MODE)
|
||||
void init_benchmark();
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "input.h"
|
||||
#include "../feature/feature.h"
|
||||
#include "../creative/creative.h"
|
||||
|
||||
// Enable Item Dropping
|
||||
static int enable_drop = 0;
|
||||
@ -22,7 +23,7 @@ void input_drop(int drop_slot) {
|
||||
|
||||
// Handle Drop Item Presses
|
||||
static void _handle_drop(unsigned char *minecraft) {
|
||||
if (!(*Minecraft_isCreativeMode)(minecraft) && (drop_item_presses > 0 || drop_slot_pressed)) {
|
||||
if ((!creative_is_restricted() || !(*Minecraft_isCreativeMode)(minecraft)) && (drop_item_presses > 0 || drop_slot_pressed)) {
|
||||
// Get Player
|
||||
unsigned char *player = *(unsigned char **) (minecraft + Minecraft_player_property_offset);
|
||||
if (player != NULL) {
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "input.h"
|
||||
#include "../feature/feature.h"
|
||||
#include "../creative/creative.h"
|
||||
|
||||
// Enable Miscellaneous Input Fixes
|
||||
static int enable_misc = 0;
|
||||
@ -59,9 +60,9 @@ static void _handle_mouse_grab(unsigned char *minecraft) {
|
||||
|
||||
// Block UI Interaction When Mouse Is Locked
|
||||
static bool Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection(unsigned char *minecraft) {
|
||||
if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF) {
|
||||
if (!enable_misc || SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF) {
|
||||
// Call Original Method
|
||||
return (*Minecraft_isCreativeMode)(minecraft);
|
||||
return creative_is_restricted() && (*Minecraft_isCreativeMode)(minecraft);
|
||||
} else {
|
||||
// Disable Item Drop Ticking
|
||||
return 1;
|
||||
@ -82,12 +83,12 @@ void _init_misc() {
|
||||
if (enable_misc) {
|
||||
// Fix OptionsScreen Ignoring The Back Button
|
||||
patch_address(OptionsScreen_handleBackEvent_vtable_addr, (void *) OptionsScreen_handleBackEvent_injection);
|
||||
|
||||
// Disable Item Dropping Using The Cursor When Cursor Is Hidden
|
||||
overwrite_call((void *) 0x27800, (void *) Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection);
|
||||
// Disable Opening Inventory Using The Cursor When Cursor Is Hidden
|
||||
overwrite_calls((void *) Gui_handleClick, (void *) Gui_handleClick_injection);
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
|
108
mods/src/misc/logging.cpp
Normal file
108
mods/src/misc/logging.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
#include <string>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <symbols/minecraft.h>
|
||||
|
||||
#include "misc.h"
|
||||
|
||||
// Print Chat To Log
|
||||
static bool Gui_addMessage_recursing = false;
|
||||
static void Gui_addMessage_injection(unsigned char *gui, std::string const& text) {
|
||||
// Sanitize Message
|
||||
char *new_message = strdup(text.c_str());
|
||||
ALLOC_CHECK(new_message);
|
||||
sanitize_string(&new_message, -1, 1);
|
||||
|
||||
// Process Message
|
||||
if (!Gui_addMessage_recursing) {
|
||||
// Start Recursing
|
||||
Gui_addMessage_recursing = true;
|
||||
|
||||
// Print Log Message
|
||||
fprintf(stderr, "[CHAT]: %s\n", new_message);
|
||||
|
||||
// Call Original Method
|
||||
(*Gui_addMessage)(gui, std::string(new_message));
|
||||
|
||||
// End Recursing
|
||||
Gui_addMessage_recursing = false;
|
||||
} else {
|
||||
// Call Original Method
|
||||
(*Gui_addMessage)(gui, std::string(new_message));
|
||||
}
|
||||
|
||||
// Free
|
||||
free(new_message);
|
||||
}
|
||||
|
||||
// Check If Two Percentages Are Different Enough To Be Logged
|
||||
#define SIGNIFICANT_PROGRESS 5
|
||||
static bool is_progress_difference_significant(int32_t new_val, int32_t old_val) {
|
||||
if (new_val != old_val) {
|
||||
if (new_val == -1 || old_val == -1) {
|
||||
return true;
|
||||
} else if (new_val == 0 || new_val == 100) {
|
||||
return true;
|
||||
} else {
|
||||
return new_val - old_val >= SIGNIFICANT_PROGRESS;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Print Progress Reports
|
||||
static int last_progress = -1;
|
||||
static const char *last_message = NULL;
|
||||
static void print_progress(unsigned char *minecraft) {
|
||||
const char *message = (*Minecraft_getProgressMessage)(minecraft);
|
||||
int32_t progress = *(int32_t *) (minecraft + Minecraft_progress_property_offset);
|
||||
if ((*Minecraft_isLevelGenerated)(minecraft)) {
|
||||
message = "Ready";
|
||||
progress = -1;
|
||||
}
|
||||
if (message != NULL) {
|
||||
bool message_different = message != last_message;
|
||||
bool progress_significant = is_progress_difference_significant(progress, last_progress);
|
||||
if (message_different || progress_significant) {
|
||||
if (progress != -1) {
|
||||
INFO("Status: %s: %i%%", message, progress);
|
||||
} else {
|
||||
INFO("Status: %s", message);
|
||||
}
|
||||
if (message_different) {
|
||||
last_message = message;
|
||||
}
|
||||
if (progress_significant) {
|
||||
last_progress = progress;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Print Progress Reports Regularly
|
||||
static void Minecraft_update_injection(unsigned char *minecraft) {
|
||||
// Print Progress Reports
|
||||
print_progress(minecraft);
|
||||
}
|
||||
|
||||
// Log When Game Is Saved
|
||||
void Level_saveLevelData_injection(unsigned char *level) {
|
||||
// Print Log Message
|
||||
INFO("%s", "Saving Game");
|
||||
|
||||
// Call Original Method
|
||||
(*Level_saveLevelData)(level);
|
||||
}
|
||||
|
||||
// Init
|
||||
void _init_misc_logging() {
|
||||
// Print Chat To Log
|
||||
overwrite_calls((void *) Gui_addMessage, (void *) Gui_addMessage_injection);
|
||||
|
||||
// Print Progress Reports
|
||||
misc_run_on_update(Minecraft_update_injection);
|
||||
|
||||
// Print Log On Game Save
|
||||
overwrite_calls((void *) Level_saveLevelData, (void *) Level_saveLevelData_injection);
|
||||
}
|
@ -2,6 +2,8 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <GLES/gl.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <symbols/minecraft.h>
|
||||
|
||||
@ -12,36 +14,52 @@
|
||||
// Maximum Username Length
|
||||
#define MAX_USERNAME_LENGTH 16
|
||||
|
||||
// Render Selected Item Text
|
||||
static void Gui_renderChatMessages_injection(unsigned char *gui, int32_t param_1, uint32_t param_2, uint32_t param_3, unsigned char *font) {
|
||||
// Additional GUI Rendering
|
||||
static int hide_chat_messages = 0;
|
||||
static int render_selected_item_text = 0;
|
||||
static void Gui_renderChatMessages_injection(unsigned char *gui, int32_t y_offset, uint32_t max_messages, bool disable_fading, unsigned char *font) {
|
||||
// Call Original Method
|
||||
(*Gui_renderChatMessages)(gui, param_1, param_2, param_3, font);
|
||||
// Calculate Selected Item Text Scale
|
||||
unsigned char *minecraft = *(unsigned char **) (gui + Gui_minecraft_property_offset);
|
||||
int32_t screen_width = *(int32_t *) (minecraft + Minecraft_screen_width_property_offset);
|
||||
float scale = ((float) screen_width) * *InvGuiScale;
|
||||
if (!hide_chat_messages) {
|
||||
(*Gui_renderChatMessages)(gui, y_offset, max_messages, disable_fading, font);
|
||||
}
|
||||
|
||||
// Render Selected Item Text
|
||||
(*Gui_renderOnSelectItemNameText)(gui, (int32_t) scale, font, param_1 - 0x13);
|
||||
if (render_selected_item_text) {
|
||||
// Fix GL Mode
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
// Calculate Selected Item Text Scale
|
||||
unsigned char *minecraft = *(unsigned char **) (gui + Gui_minecraft_property_offset);
|
||||
int32_t screen_width = *(int32_t *) (minecraft + Minecraft_screen_width_property_offset);
|
||||
float scale = ((float) screen_width) * *InvGuiScale;
|
||||
// Render Selected Item Text
|
||||
(*Gui_renderOnSelectItemNameText)(gui, (int32_t) scale, font, y_offset - 0x13);
|
||||
}
|
||||
}
|
||||
// Reset Selected Item Text Timer On Slot Select
|
||||
static uint32_t reset_selected_item_text_timer = 0;
|
||||
static void Gui_tick_injection(unsigned char *gui) {
|
||||
// Call Original Method
|
||||
(*Gui_tick)(gui);
|
||||
|
||||
// Handle Reset
|
||||
float *selected_item_text_timer = (float *) (gui + Gui_selected_item_text_timer_property_offset);
|
||||
if (reset_selected_item_text_timer) {
|
||||
// Reset
|
||||
*selected_item_text_timer = 0;
|
||||
reset_selected_item_text_timer = 0;
|
||||
if (render_selected_item_text) {
|
||||
float *selected_item_text_timer = (float *) (gui + Gui_selected_item_text_timer_property_offset);
|
||||
if (reset_selected_item_text_timer) {
|
||||
// Reset
|
||||
*selected_item_text_timer = 0;
|
||||
reset_selected_item_text_timer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Trigger Reset Selected Item Text Timer On Slot Select
|
||||
static void Inventory_selectSlot_injection(unsigned char *inventory, int32_t slot) {
|
||||
// Call Original Method
|
||||
(*Inventory_selectSlot)(inventory, slot);
|
||||
|
||||
// Trigger Reset Selected Item Text Timer
|
||||
reset_selected_item_text_timer = 1;
|
||||
if (render_selected_item_text) {
|
||||
reset_selected_item_text_timer = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Sanitize Username
|
||||
@ -125,12 +143,12 @@ void init_misc() {
|
||||
patch((void *) 0x63c98, invalid_item_background_patch);
|
||||
}
|
||||
|
||||
// Fix Selected Item Text
|
||||
if (feature_has("Render Selected Item Text", 0)) {
|
||||
overwrite_calls((void *) Gui_renderChatMessages, (void *) Gui_renderChatMessages_injection);
|
||||
overwrite_calls((void *) Gui_tick, (void *) Gui_tick_injection);
|
||||
overwrite_calls((void *) Inventory_selectSlot, (void *) Inventory_selectSlot_injection);
|
||||
}
|
||||
// Render Selected Item Text + Hide Chat Messages
|
||||
hide_chat_messages = feature_has("Hide Chat Messages", 0);
|
||||
render_selected_item_text = feature_has("Render Selected Item Text", 0);
|
||||
overwrite_calls((void *) Gui_renderChatMessages, (void *) Gui_renderChatMessages_injection);
|
||||
overwrite_calls((void *) Gui_tick, (void *) Gui_tick_injection);
|
||||
overwrite_calls((void *) Inventory_selectSlot, (void *) Inventory_selectSlot_injection);
|
||||
|
||||
// Sanitize Username
|
||||
patch_address(LoginPacket_read_vtable_addr, (void *) LoginPacket_read_injection);
|
||||
@ -144,6 +162,7 @@ void init_misc() {
|
||||
// Fix Bug Where RakNetInstance Starts Pinging Potential Servers Before The "Join Game" Screen Is Opened
|
||||
overwrite_calls((void *) RakNetInstance, (void *) RakNetInstance_injection);
|
||||
|
||||
// Init C++
|
||||
// Init C++ And Logging
|
||||
_init_misc_cpp();
|
||||
_init_misc_logging();
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <streambuf>
|
||||
#include <vector>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
@ -24,34 +25,24 @@ static AppPlatform_readAssetFile_return_value AppPlatform_readAssetFile_injectio
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Print Chat To Log
|
||||
static bool Gui_addMessage_recursing = false;
|
||||
static void Gui_addMessage_injection(unsigned char *gui, std::string const& text) {
|
||||
// Sanitize Message
|
||||
char *new_message = strdup(text.c_str());
|
||||
ALLOC_CHECK(new_message);
|
||||
sanitize_string(&new_message, -1, 1);
|
||||
// Run Functions On Input Tick
|
||||
static std::vector<misc_update_function_t> &get_misc_update_functions() {
|
||||
static std::vector<misc_update_function_t> functions;
|
||||
return functions;
|
||||
}
|
||||
void misc_run_on_update(misc_update_function_t function) {
|
||||
get_misc_update_functions().push_back(function);
|
||||
}
|
||||
|
||||
// Process Message
|
||||
if (!Gui_addMessage_recursing) {
|
||||
// Start Recursing
|
||||
Gui_addMessage_recursing = true;
|
||||
// Handle Custom Update Behavior
|
||||
static void Minecraft_update_injection(unsigned char *minecraft) {
|
||||
// Call Original Method
|
||||
(*Minecraft_update)(minecraft);
|
||||
|
||||
// Print Log Message
|
||||
fprintf(stderr, "[CHAT]: %s\n", new_message);
|
||||
|
||||
// Call Original Method
|
||||
(*Gui_addMessage)(gui, std::string(new_message));
|
||||
|
||||
// End Recursing
|
||||
Gui_addMessage_recursing = false;
|
||||
} else {
|
||||
// Call Original Method
|
||||
(*Gui_addMessage)(gui, std::string(new_message));
|
||||
// Run Input Tick Functions
|
||||
for (misc_update_function_t function : get_misc_update_functions()) {
|
||||
(*function)(minecraft);
|
||||
}
|
||||
|
||||
// Free
|
||||
free(new_message);
|
||||
}
|
||||
|
||||
// Init
|
||||
@ -61,6 +52,6 @@ void _init_misc_cpp() {
|
||||
overwrite((void *) AppPlatform_readAssetFile, (void *) AppPlatform_readAssetFile_injection);
|
||||
}
|
||||
|
||||
// Print Chat To Log
|
||||
overwrite_calls((void *) Gui_addMessage, (void *) Gui_addMessage_injection);
|
||||
// Handle Custom Update Behavior
|
||||
overwrite_calls((void *) Minecraft_update, (void *) Minecraft_update_injection);
|
||||
}
|
||||
|
@ -4,7 +4,13 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*misc_update_function_t)(unsigned char *minecraft);
|
||||
void misc_run_on_update(misc_update_function_t function);
|
||||
|
||||
void Level_saveLevelData_injection(unsigned char *level);
|
||||
|
||||
__attribute__((visibility("internal"))) void _init_misc_cpp();
|
||||
__attribute__((visibility("internal"))) void _init_misc_logging();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <symbols/minecraft.h>
|
||||
|
||||
#include "server_properties.h"
|
||||
|
||||
@ -23,9 +24,7 @@
|
||||
#include "../init/init.h"
|
||||
#include "../home/home.h"
|
||||
#include "../compat/compat.h"
|
||||
#include "../version/version.h"
|
||||
|
||||
#include <symbols/minecraft.h>
|
||||
#include "../misc/misc.h"
|
||||
|
||||
// --only-generate: Ony Generate World And Then Exit
|
||||
static bool only_generate = false;
|
||||
@ -66,17 +65,20 @@ static std::string get_world_name() {
|
||||
|
||||
// Create/Start World
|
||||
static void start_world(unsigned char *minecraft) {
|
||||
INFO("Starting Minecraft: Pi Edition: Dedicated Server (%s)", version_get());
|
||||
// Get World Name
|
||||
std::string world_name = get_world_name();
|
||||
|
||||
// Log
|
||||
INFO("Loading World: %s", world_name.c_str());
|
||||
|
||||
// Specify Level Settings
|
||||
LevelSettings settings;
|
||||
settings.game_type = get_server_properties().get_int("game-mode", DEFAULT_GAME_MODE);;
|
||||
settings.game_type = get_server_properties().get_int("game-mode", DEFAULT_GAME_MODE);
|
||||
std::string seed_str = get_server_properties().get_string("seed", DEFAULT_SEED);
|
||||
int32_t seed = seed_str.length() > 0 ? std::stoi(seed_str) : time(NULL);
|
||||
settings.seed = seed;
|
||||
|
||||
// Select Level
|
||||
std::string world_name = get_world_name();
|
||||
(*Minecraft_selectLevel)(minecraft, world_name, world_name, settings);
|
||||
|
||||
// Don't Open Port When Using --only-generate
|
||||
@ -94,51 +96,6 @@ static void start_world(unsigned char *minecraft) {
|
||||
(*Minecraft_setScreen)(minecraft, (unsigned char *) screen);
|
||||
}
|
||||
|
||||
// Check If Two Percentages Are Different Enough To Be Logged
|
||||
#define SIGNIFICANT_PROGRESS 5
|
||||
static bool is_progress_difference_significant(int32_t new_val, int32_t old_val) {
|
||||
if (new_val != old_val) {
|
||||
if (new_val == -1 || old_val == -1) {
|
||||
return true;
|
||||
} else if (new_val == 0 || new_val == 100) {
|
||||
return true;
|
||||
} else {
|
||||
return new_val - old_val >= SIGNIFICANT_PROGRESS;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Print Progress Reports
|
||||
static int last_progress = -1;
|
||||
static const char *last_message = NULL;
|
||||
static void print_progress(unsigned char *minecraft) {
|
||||
const char *message = (*Minecraft_getProgressMessage)(minecraft);
|
||||
int32_t progress = *(int32_t *) (minecraft + Minecraft_progress_property_offset);
|
||||
if ((*Minecraft_isLevelGenerated)(minecraft)) {
|
||||
message = "Ready";
|
||||
progress = -1;
|
||||
}
|
||||
if (message != NULL) {
|
||||
bool message_different = message != last_message;
|
||||
bool progress_significant = is_progress_difference_significant(progress, last_progress);
|
||||
if (message_different || progress_significant) {
|
||||
if (progress != -1) {
|
||||
INFO("Status: %s: %i%%", message, progress);
|
||||
} else {
|
||||
INFO("Status: %s", message);
|
||||
}
|
||||
if (message_different) {
|
||||
last_message = message;
|
||||
}
|
||||
if (progress_significant) {
|
||||
last_progress = progress;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check If Running In Whitelist Mode
|
||||
static bool is_whitelist() {
|
||||
return get_server_properties().get_bool("whitelist", DEFAULT_WHITELIST);
|
||||
@ -244,15 +201,6 @@ static void list_callback(unsigned char *minecraft, std::string username, unsign
|
||||
INFO(" - %s (%s)", username.c_str(), get_player_ip(minecraft, player));
|
||||
}
|
||||
|
||||
// Log When Game Is Saved
|
||||
static void Level_saveLevelData_injection(unsigned char *level) {
|
||||
// Print Log Message
|
||||
INFO("%s", "Saving Game");
|
||||
|
||||
// Call Original Method
|
||||
(*Level_saveLevelData)(level);
|
||||
}
|
||||
|
||||
// Handle Server Stop
|
||||
static void handle_server_stop(unsigned char *minecraft) {
|
||||
if (compat_check_exit_requested()) {
|
||||
@ -384,12 +332,6 @@ static void Minecraft_update_injection(unsigned char *minecraft) {
|
||||
only_generate = false;
|
||||
}
|
||||
|
||||
// Print Progress Reports
|
||||
print_progress(minecraft);
|
||||
|
||||
// Call Original Method
|
||||
(*Minecraft_update)(minecraft);
|
||||
|
||||
// Handle Commands
|
||||
handle_commands(minecraft);
|
||||
|
||||
@ -494,9 +436,9 @@ static void server_init() {
|
||||
// Open Properties File
|
||||
std::string file(home_get());
|
||||
file.append("/server.properties");
|
||||
|
||||
std::ifstream properties_file(file);
|
||||
|
||||
// Check Properties File
|
||||
if (!properties_file.good()) {
|
||||
// Write Defaults
|
||||
std::ofstream properties_file_output(file);
|
||||
@ -551,9 +493,7 @@ static void server_init() {
|
||||
unsigned char player_patch[4] = {0x00, 0x20, 0xa0, 0xe3}; // "mov r2, #0x0"
|
||||
patch((void *) 0x1685c, player_patch);
|
||||
// Start World On Launch
|
||||
overwrite_calls((void *) Minecraft_update, (void *) Minecraft_update_injection);
|
||||
// Print Log On Game Save
|
||||
overwrite_calls((void *) Level_saveLevelData, (void *) Level_saveLevelData_injection);
|
||||
misc_run_on_update(Minecraft_update_injection);
|
||||
// Set Max Players
|
||||
unsigned char max_players_patch[4] = {get_max_players(), 0x30, 0xa0, 0xe3}; // "mov r3, #MAX_PLAYERS"
|
||||
patch((void *) 0x166d0, max_players_patch);
|
||||
|
@ -42,7 +42,7 @@ std::string _sound_get_source_file() {
|
||||
// Check If Sound Exists
|
||||
if (access(full_path, F_OK) == -1) {
|
||||
// Fail
|
||||
WARN("%s", "Audio Source File Doesn't Exists: " SOURCE_FILE_BASE);
|
||||
WARN("%s", "Audio Source File Doesn't Exist: " SOURCE_FILE_BASE);
|
||||
source.assign("");
|
||||
} else {
|
||||
// Set
|
||||
|
@ -31,4 +31,7 @@ void init_version() {
|
||||
overwrite((void *) Common_getGameVersionString, (void *) Common_getGameVersionString_injection);
|
||||
// Normal GUI
|
||||
patch_address((void *) minecraft_pi_version, version_get());
|
||||
|
||||
// Log
|
||||
INFO("Starting Minecraft: Pi Edition (%s)", version_get());
|
||||
}
|
||||
|
@ -160,6 +160,9 @@ static uint32_t Minecraft_handleBack_vtable_offset = 0x34;
|
||||
typedef unsigned char *(*Minecraft_getCreator_t)(unsigned char *minecraft);
|
||||
static Minecraft_getCreator_t Minecraft_getCreator = (Minecraft_getCreator_t) 0x17538;
|
||||
|
||||
typedef unsigned char *(*Minecraft_getLevelSource_t)(unsigned char *minecraft);
|
||||
static Minecraft_getLevelSource_t Minecraft_getLevelSource = (Minecraft_getLevelSource_t) 0x16e84;
|
||||
|
||||
static uint32_t Minecraft_screen_width_property_offset = 0x20; // int32_t
|
||||
static uint32_t Minecraft_network_handler_property_offset = 0x174; // NetEventCallback *
|
||||
static uint32_t Minecraft_rak_net_instance_property_offset = 0x170; // RakNetInstance *
|
||||
@ -327,7 +330,7 @@ static Gui_handleClick_t Gui_handleClick = (Gui_handleClick_t) 0x2599c;
|
||||
typedef void (*Gui_renderOnSelectItemNameText_t)(unsigned char *gui, int32_t param_1, unsigned char *font, int32_t param_2);
|
||||
static Gui_renderOnSelectItemNameText_t Gui_renderOnSelectItemNameText = (Gui_renderOnSelectItemNameText_t) 0x26aec;
|
||||
|
||||
typedef void (*Gui_renderChatMessages_t)(unsigned char *gui, int32_t param_1, uint32_t param_2, bool param_3, unsigned char *font);
|
||||
typedef void (*Gui_renderChatMessages_t)(unsigned char *gui, int32_t y_offset, uint32_t max_messages, bool disable_fading, unsigned char *font);
|
||||
static Gui_renderChatMessages_t Gui_renderChatMessages = (Gui_renderChatMessages_t) 0x273d8;
|
||||
|
||||
static uint32_t Gui_minecraft_property_offset = 0x9f4; // Minecraft *
|
||||
@ -631,6 +634,11 @@ static AppPlatform_readAssetFile_t AppPlatform_readAssetFile = (AppPlatform_read
|
||||
typedef void (*Minecraft_selectLevel_t)(unsigned char *minecraft, std::string const& level_dir, std::string const& level_name, LevelSettings const& vsettings);
|
||||
static Minecraft_selectLevel_t Minecraft_selectLevel = (Minecraft_selectLevel_t) 0x16f38;
|
||||
|
||||
// ExternalFileLevelStorageSource
|
||||
|
||||
typedef void (*ExternalFileLevelStorageSource_deleteLevel_t)(unsigned char *external_file_level_storage_source, std::string const& level_name);
|
||||
static uint32_t ExternalFileLevelStorageSource_deleteLevel_vtable_offset = 0x20;
|
||||
|
||||
// CommandServer
|
||||
|
||||
typedef std::string (*CommandServer_parse_t)(unsigned char *command_server, struct ConnectedClient &client, std::string const& command);
|
||||
|
Loading…
Reference in New Issue
Block a user