Compare commits

...

2 Commits

Author SHA1 Message Date
053bf4aa5f Show Reborn Version In Start Screen
All checks were successful
minecraft-pi-reborn/pipeline/head This commit looks good
2021-06-28 16:00:52 -04:00
2b0d1d55ff External Server Support 2021-06-27 22:16:37 -04:00
33 changed files with 321 additions and 133 deletions

View File

@ -94,6 +94,10 @@ if(MCPI_SERVER_MODE)
add_definitions(-DMCPI_SERVER_MODE)
endif()
# Version
file(STRINGS VERSION VERSION)
add_definitions(-DVERSION="${VERSION}")
# Build libreborn
add_subdirectory(libreborn)

View File

@ -1 +1 @@
2.0.4
2.0.5

View File

@ -72,7 +72,7 @@ This sub-component implements stubs for various redundant libraries used by MCPI
This is always compiled for ARM.
##### What To Stub And What To Patch?
Most libraries (like ``bcm_host``) can just be replaced with stubs, because they don't need to do anything and aren't used by anything else. However, some libraries (like EGL) might be used by some of MCPI-Reborn's dependencies (like GLFW) so instead of being replaced by a stub, each call is manually patched out from MCPI. A stub is still generated just in case that library isn't present on the system to silence linker errors, but it is only loaded if no other version is available.
Most libraries (like ``bcm_host``) can just be replaced with stubs, because they don't need to do anything and aren't used by anything else. However, some libraries (like EGL and X11) might be used by some of MCPI-Reborn's dependencies (like GLFW) so instead of being replaced by a stub, each call is manually patched out from MCPI. A stub is still generated just in case that library isn't present on the system to silence linker errors, but it is only loaded if no other version is available.
#### Headers
This sub-component includes headers for SDL, GLES, and EGL allowing easy (cross-)compilation.

View File

@ -1,5 +1,9 @@
# Changelog
**2.0.5**
* Show Reborn Version In Start Screen
* External Server Support
**2.0.4**
* Optimize Media Layer Proxy

14
docs/MULTIPLAYER.md Normal file
View File

@ -0,0 +1,14 @@
# Multiplayer
MCPI-Reborn supports two ways to play multiplayer.
## Local Network (LAN)
This is also supported by vanilla MCPI. Just load a world in MCPI and other devices on the network can join.
## External Servers
Unlike vanilla MCPI, MCPI-Reborn allows you to natively join a server outside of the local network. Just modify ``~/.minecraft-pi/servers.txt`` and it should show up in MCPI's server list.
### Example ``~/.minecraft-pi/servers.txt``
```
# Comment
example.com:19132
```

View File

@ -7,4 +7,5 @@
* [View Building](BUILDING.md)
* [View Architecture](ARCHITECTURE.md)
* [View Command Line Arguments](COMMAND_LINE.md)
* [View Multiplayer](MULTIPLAYER.md)
* [View Changelog](CHANGELOG.md)

View File

@ -3,7 +3,7 @@ Name=Minecraft: Pi Edition: Reborn
Comment=Fun with Blocks
Icon=/usr/share/pixmaps/minecraft-pi-reborn-client.png
StartupNotify=false
StartupWMClass=Minecraft - Pi edition
StartupWMClass=Minecraft: Pi Edition: Reborn
Exec=/usr/bin/minecraft-pi-reborn-client
Terminal=false
Type=Application

View File

@ -106,7 +106,7 @@ static void run_zenity_and_set_env(const char *env_name, std::vector<std::string
std::vector<std::string> full_command;
full_command.push_back("zenity");
full_command.push_back("--class");
full_command.push_back("Minecraft - Pi edition");
full_command.push_back("Minecraft: Pi Edition: Reborn");
full_command.insert(full_command.end(), command.begin(), command.end());
// Convert To C Array
const char *full_command_array[full_command.size() + 1];

View File

@ -17,6 +17,7 @@ static renderCursor_t renderCursor = (renderCursor_t) 0x480c4;
static char **default_path = (char **) 0xe264; // /.minecraft/
static char **default_username = (char **) 0x18fd4; // StevePi
static char **minecraft_pi_version = (char **) 0x39d94; // v0.1.1 alpha
static unsigned char **Item_flintAndSteel = (unsigned char **) 0x17ba70;
static unsigned char **Item_snowball = (unsigned char **) 0x17bbb0;
@ -345,6 +346,11 @@ static uint32_t RakNetInstance_send_vtable_offset = 0x38;
typedef uint32_t (*RakNetInstance_isServer_t)(unsigned char *rak_net_instance);
static uint32_t RakNetInstance_isServer_vtable_offset = 0x48;
typedef void (*RakNetInstance_pingForHosts_t)(unsigned char *rak_net_instance, int32_t base_port);
static RakNetInstance_pingForHosts_t RakNetInstance_pingForHosts = (RakNetInstance_pingForHosts_t) 0x73538;
static uint32_t RakNetInstance_pingForHosts_vtable_offset = 0x14;
static void *RakNetInstance_pingForHosts_vtable_addr = (void *) 0x109afc;
static uint32_t RakNetInstance_peer_property_offset = 0x4; // RakNet::RakPeer *
// RakNet::RakPeer
@ -355,6 +361,9 @@ static uint32_t RakNet_RakPeer_GetSystemAddressFromGuid_vtable_offset = 0xd0;
typedef bool (*RakNet_RakPeer_IsBanned_t)(unsigned char *rak_peer, const char *ip);
static RakNet_RakPeer_IsBanned_t RakNet_RakPeer_IsBanned = (RakNet_RakPeer_IsBanned_t) 0xda3b4;
typedef bool (*RakNet_RakPeer_Ping_t)(unsigned char *rak_peer, const char *host, unsigned short remotePort, bool onlyReplyOnAcceptingConnections, uint32_t connectionSocketIndex);
static RakNet_RakPeer_Ping_t RakNet_RakPeer_Ping = (RakNet_RakPeer_Ping_t) 0xd9c2c;
// RakNet::SystemAddress
typedef char *(*RakNet_SystemAddress_ToString_t)(struct RakNet_SystemAddress *system_address, bool print_delimiter, char delimiter);
@ -469,6 +478,11 @@ static SelectWorldScreen_getUniqueLevelName_t SelectWorldScreen_getUniqueLevelNa
static SelectWorldScreen_getUniqueLevelName_t Touch_SelectWorldScreen_getUniqueLevelName = (SelectWorldScreen_getUniqueLevelName_t) 0x3d82c;
// Common
typedef std::string (*Common_getGameVersionString_t)(std::string const& version_suffix);
static Common_getGameVersionString_t Common_getGameVersionString = (Common_getGameVersionString_t) 0x15068;
#endif
#pragma GCC diagnostic pop

View File

@ -30,11 +30,5 @@ add_subdirectory(extras)
# Add Symlinks So MCPI Can Locate Libraries
if(BUILD_ARM_COMPONENTS)
if(MCPI_SERVER_MODE OR MCPI_USE_MEDIA_LAYER_PROXY)
install_symlink("libmedia-layer-core.so" "${MCPI_LIB_DIR}/libX11.so.6")
else()
# When Loading In Client Mode On An ARM Host, Use Native X11 By Default
install_symlink("../lib/libmedia-layer-core.so" "${MCPI_FALLBACK_LIB_DIR}/libX11.so.6")
endif()
install_symlink("libmedia-layer-core.so" "${MCPI_LIB_DIR}/libSDL-1.2.so.0")
endif()

View File

@ -2,6 +2,5 @@ project(media-layer-extras)
if(BUILD_ARM_COMPONENTS)
# Add Source To Media Core
target_sources(media-layer-core PRIVATE src/SDL.c src/X11.cpp)
target_link_libraries(media-layer-core dl)
target_sources(media-layer-core PRIVATE src/SDL.c)
endif()

View File

@ -1,76 +0,0 @@
#include <elf.h>
#include <vector>
#include <X11/Xlib.h>
#include <libreborn/libreborn.h>
#include <libreborn/media-layer/core.h>
#ifndef MEDIA_LAYER_PROXY_SERVER
// Store Adresses That Are Part Of MCPI
struct text_section_data {
void *section;
Elf32_Word size;
};
static std::vector<text_section_data> &get_text_sections() {
static std::vector<text_section_data> sections;
return sections;
}
static void text_section_callback(void *section, Elf32_Word size, __attribute__((unused)) void *data) {
text_section_data section_data;
section_data.section = section;
section_data.size = size;
get_text_sections().push_back(section_data);
}
// Check If The Current Return Address Is Part Of MCPI Or An External Library
static inline int _is_returning_to_external_library(void *return_addr) {
// Load Text Sections If Not Loaded
if (get_text_sections().size() < 1) {
iterate_text_sections(text_section_callback, NULL);
}
// Iterate Text Sections
for (std::vector<text_section_data>::size_type i = 0; i < get_text_sections().size(); i++) {
text_section_data section_data = get_text_sections()[i];
// Check Text Section
if (return_addr >= section_data.section && return_addr < (((unsigned char *) section_data.section) + section_data.size)) {
// Part Of MCPI
return 0;
}
}
// Part Of An External Library
return 1;
}
#define is_returning_to_external_library() _is_returning_to_external_library(__builtin_extract_return_addr(__builtin_return_address(0)))
#else
// When Using The Media Layer Proxy, None Of These Functions Are Ever Called By An External Library
#define is_returning_to_external_library() 0
#endif
// Don't Directly Use XLib Unless Returning To An External library
HOOK(XTranslateCoordinates, int, (void *display, XID src_w, XID dest_w, int src_x, int src_y, int *dest_x_return, int *dest_y_return, XID *child_return)) {
if (is_returning_to_external_library()) {
// Use Real Function
ensure_XTranslateCoordinates();
return (*real_XTranslateCoordinates)(display, src_w, dest_w, src_x, src_y, dest_x_return, dest_y_return, child_return);
} else {
// Use MCPI Replacemnt Function
*dest_x_return = src_x;
*dest_y_return = src_y;
return 1;
}
}
HOOK(XGetWindowAttributes, int, (void *display, XID w, XWindowAttributes *window_attributes_return)) {
if (is_returning_to_external_library()) {
// Use Real Function
ensure_XGetWindowAttributes();
return (*real_XGetWindowAttributes)(display, w, window_attributes_return);
} else {
// Use MCPI Replacemnt Function
XWindowAttributes attributes;
attributes.x = 0;
attributes.y = 0;
media_get_framebuffer_size(&attributes.width, &attributes.height);
*window_attributes_return = attributes;
return 1;
}
}

View File

@ -5,15 +5,15 @@ extern "C" {
#endif
#define GL_FALSE 0
#define GL_FOG_COLOR 0x0B66
#define GL_FOG_COLOR 0xb66
#define GL_ARRAY_BUFFER_BINDING 0x8894
#define GL_UNSIGNED_BYTE 0x1401
#define GL_RGB 0x1907
#define GL_RGBA 0x1908
#define GL_MODELVIEW_MATRIX 0x0BA6
#define GL_PROJECTION_MATRIX 0x0BA7
#define GL_VIEWPORT 0x0BA2
#define GL_DEPTH_TEST 0x0B71
#define GL_MODELVIEW_MATRIX 0xba6
#define GL_PROJECTION_MATRIX 0xba7
#define GL_VIEWPORT 0xba2
#define GL_DEPTH_TEST 0xb71
#include <stdio.h>
#include <stdint.h>

View File

@ -14,11 +14,15 @@ if(BUILD_ARM_COMPONENTS)
# Stub EGL
add_library(EGL SHARED src/EGL.c)
target_link_libraries(EGL reborn-headers media-layer-headers)
# Stub X11
add_library(X11 SHARED src/X11.c)
target_link_libraries(X11 reborn-headers media-layer-headers)
set_target_properties(X11 PROPERTIES SOVERSION "6")
# Install
if(MCPI_SERVER_MODE OR MCPI_USE_MEDIA_LAYER_PROXY)
install(TARGETS EGL DESTINATION "${MCPI_LIB_DIR}")
install(TARGETS EGL X11 DESTINATION "${MCPI_LIB_DIR}")
else()
install(TARGETS EGL DESTINATION "${MCPI_FALLBACK_LIB_DIR}") # Place At The End Of LD_LIBRARY_PATH
install(TARGETS EGL X11 DESTINATION "${MCPI_FALLBACK_LIB_DIR}") # Place At The End Of LD_LIBRARY_PATH
endif()
# Install GLESv1_CM Stubs In Server Mode

View File

@ -1,15 +1,3 @@
/*
* This is only loaded when no other EGL library is present on the system to silence linker errors.
*
* All EGL calls are manually patched out in mods/src/compat/egl.c.
* Unlike with bcm_host, EGL can't just be always stubbed out with LD_PRELOAD, because in some situations GLFW has it as a dependency.
*
* So normally, MCPI just loads the real EGL and never uses it (because MCPI's EGL calls were patched out).
* However, since the real EGL is still loaded, GLFW can use it if it needs to.
*
* This stub library is just in case the system has no EGL library present.
*/
#include <EGL/egl.h>
#include <libreborn/libreborn.h>

View File

@ -0,0 +1,14 @@
#include <X11/Xlib.h>
#include <libreborn/libreborn.h>
#define IMPOSSIBLE() ERR("(%s:%i) This Should Never Be Called", __FILE__, __LINE__)
// Raw X11 Is Replaced With GLFW
int XTranslateCoordinates(__attribute__((unused)) void *display, __attribute__((unused)) XID src_w, __attribute__((unused)) XID dest_w, __attribute__((unused)) int src_x, __attribute__((unused)) int src_y, __attribute__((unused)) int *dest_x_return, __attribute__((unused)) int *dest_y_return, __attribute__((unused)) XID *child_return) {
IMPOSSIBLE();
}
int XGetWindowAttributes(__attribute__((unused)) void *display, __attribute__((unused)) XID w, __attribute__((unused)) XWindowAttributes *window_attributes_return) {
IMPOSSIBLE();
}

View File

@ -7,7 +7,7 @@ add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
## Mods
add_library(compat SHARED src/compat/compat.c src/compat/egl.c)
add_library(compat SHARED src/compat/compat.c src/compat/egl.c src/compat/x11.c)
target_link_libraries(compat feature input media-layer-core dl)
add_library(readdir SHARED src/readdir/readdir.c)
@ -15,9 +15,15 @@ add_library(readdir SHARED src/readdir/readdir.c)
add_library(feature SHARED src/feature/feature.c)
target_link_libraries(feature reborn)
add_library(version SHARED src/version/version.cpp)
target_link_libraries(version reborn)
if(MCPI_SERVER_MODE)
add_library(server SHARED src/server/server.cpp src/server/server_properties.cpp)
target_link_libraries(server reborn feature home compat dl media-layer-core pthread)
target_link_libraries(server reborn feature home compat version dl media-layer-core pthread)
else()
add_library(multiplayer SHARED src/multiplayer/multiplayer.cpp)
target_link_libraries(multiplayer reborn home)
endif()
add_library(camera SHARED src/camera/camera.cpp)
@ -57,13 +63,17 @@ 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 death options touch textures chat home test)
target_link_libraries(init compat game_mode camera input misc death options touch textures chat home version test)
if(MCPI_SERVER_MODE)
target_link_libraries(init server)
else()
target_link_libraries(init multiplayer)
endif()
## Install Mods
install(TARGETS init compat readdir feature override game_mode camera input misc death options touch textures chat home test DESTINATION "${MCPI_INSTALL_DIR}/mods")
install(TARGETS init compat readdir feature override game_mode camera input misc death options touch textures chat home version test DESTINATION "${MCPI_INSTALL_DIR}/mods")
if(MCPI_SERVER_MODE)
install(TARGETS server DESTINATION "${MCPI_INSTALL_DIR}/mods")
else()
install(TARGETS multiplayer DESTINATION "${MCPI_INSTALL_DIR}/mods")
endif()

View File

@ -42,7 +42,7 @@ unsigned int chat_get_counter() {
static void *chat_thread(__attribute__((unused)) void *nop) {
// Open
int return_code;
char *output = run_command("zenity --title \"Chat\" --class \"Minecraft - Pi edition\" --entry --text \"Enter Chat Message:\"", &return_code);
char *output = run_command("zenity --title 'Chat' --class 'Minecraft: Pi Edition: Reborn' --entry --text 'Enter Chat Message:'", &return_code);
// Handle Message
if (output != NULL) {
// Check Return Code

View File

@ -1,2 +1,2 @@
# ``compat`` Mod
This utility mod sends keyboard input to other mods. It also patches out all EGL calls.
This utility mod sends keyboard input to other mods. It also patches out all EGL and X11 calls.

View File

@ -12,6 +12,12 @@
#include "../init/init.h"
#include "compat.h"
// Custom Title
HOOK(SDL_WM_SetCaption, void, (__attribute__((unused)) const char *title, const char *icon)) {
ensure_SDL_WM_SetCaption();
(*real_SDL_WM_SetCaption)("Minecraft: Pi Edition: Reborn", icon);
}
// 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)) {

28
mods/src/compat/x11.c Normal file
View File

@ -0,0 +1,28 @@
#include <X11/Xlib.h>
#include <libreborn/libreborn.h>
#include <libreborn/media-layer/core.h>
// Functions That Have Their Return Values Used
static int XTranslateCoordinates_injection(__attribute__((unused)) void *display, __attribute__((unused)) XID src_w, __attribute__((unused)) XID dest_w, int src_x, int src_y, int *dest_x_return, int *dest_y_return, __attribute__((unused)) XID *child_return) {
// Use MCPI Replacemnt Function
*dest_x_return = src_x;
*dest_y_return = src_y;
return 1;
}
static int XGetWindowAttributes_injection(__attribute__((unused)) void *display, __attribute__((unused)) XID w, XWindowAttributes *window_attributes_return) {
// Use MCPI Replacemnt Function
XWindowAttributes attributes;
attributes.x = 0;
attributes.y = 0;
media_get_framebuffer_size(&attributes.width, &attributes.height);
*window_attributes_return = attributes;
return 1;
}
// Patch X11 Calls
__attribute__((constructor)) static void patch_x11_calls() {
// Disable X11 Calls
overwrite_call((void *) 0x132a4, (void *) XGetWindowAttributes_injection); // XGetWindowAttributes
overwrite_call((void *) 0x132d4, (void *) XTranslateCoordinates_injection); // XTranslateCoordinates
}

View File

@ -12,14 +12,13 @@
// Store Game Data In Launch Directory
#define NEW_PATH ""
// Store Launch Directory
static char *launch_directory = NULL;
__attribute__((constructor)) static void init_launch_directory() {
launch_directory = getcwd(NULL, 0);
}
char *home_get_launch_directory() {
return launch_directory;
}
// Pretend $HOME Is Launch Directory
HOOK(getenv, char *, (const char *name)) {
if (strcmp(name, "HOME") == 0) {
return launch_directory;
@ -32,10 +31,18 @@ HOOK(getenv, char *, (const char *name)) {
// Get MCPI Home Directory
char *home_get() {
char *dir = NULL;
safe_asprintf(&dir, "%s/" NEW_PATH, getenv("HOME"));
static char *dir = NULL;
// Load
if (dir == NULL) {
safe_asprintf(&dir, "%s/" NEW_PATH, getenv("HOME"));
}
// Return
return dir;
}
// Free
__attribute__((destructor)) static void _free_home() {
free(home_get());
}
// Init
void init_home() {

View File

@ -4,11 +4,7 @@
extern "C" {
#endif
#ifdef MCPI_SERVER_MODE
char *home_get_launch_directory();
#endif
char *home_get(); // Remember To free()
char *home_get();
#ifdef __cplusplus
}

View File

@ -5,6 +5,8 @@ __attribute__((constructor)) static void init() {
init_compat();
#ifdef MCPI_SERVER_MODE
init_server();
#else
init_multiplayer();
#endif
init_game_mode();
init_input();
@ -16,4 +18,5 @@ __attribute__((constructor)) static void init() {
init_textures();
init_chat();
init_home();
init_version();
}

View File

@ -8,6 +8,8 @@ void run_tests();
void init_compat();
#ifdef MCPI_SERVER_MODE
void init_server();
#else
void init_multiplayer();
#endif
void init_game_mode();
void init_input();
@ -19,6 +21,7 @@ void init_touch();
void init_textures();
void init_chat();
void init_home();
void init_version();
#ifdef __cplusplus
}

View File

@ -0,0 +1,4 @@
# ``multiplayer`` Mod
This mod implements connecting to external (non-LAN) servers. This mod is client mode only.
It is controlled by the ``~/.minecraft-pi/servers.txt`` file.

View File

@ -0,0 +1,126 @@
#ifdef MCPI_SERVER_MODE
#error "External Server Code Requires Client Mode"
#endif
#include <fstream>
#include <functional>
#include <string>
#include <vector>
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include "../home/home.h"
#include "../init/init.h"
// Load Server List
struct server_list_entry {
std::string address;
int port;
};
static std::vector<struct server_list_entry> server_list_entries;
static bool server_list_loaded = false;
static void load_servers() {
// Prepare
server_list_entries.clear();
// Open Servers File
std::string file(home_get());
file.append("/servers.txt");
// Create Stream
std::ifstream server_list_file(file);
if (!server_list_file.good()) {
// Write Defaults
std::ofstream server_list_file_output(file);
server_list_file_output << "# External Servers File\n";
server_list_file_output << "thebrokenrail.com:19132\n";
server_list_file_output.close();
// Re-Open Stream
server_list_file = std::ifstream(file);
}
// Check Servers File
if (!server_list_file.is_open()) {
ERR("Unable To Open %s", file.c_str());
}
// Iterate Lines
{
std::string line;
while (std::getline(server_list_file, line)) {
// Check Line
if (line.length() > 0) {
if (line[0] == '#') {
continue;
}
// Parse
std::string address;
std::string port_str;
// Loop
size_t last_colon = line.find_last_of(':');
if (last_colon != std::string::npos) {
for (std::string::size_type i = 0; i < line.length(); i++) {
if (i > last_colon) {
port_str.push_back(line[i]);
} else if (i < last_colon) {
address.push_back(line[i]);
}
}
}
// Check Line
if (address.length() < 1 || port_str.length() < 1 || port_str.find_first_not_of("0123456789") != std::string::npos) {
// Invalid Line
WARN("Invalid Server: %s", line.c_str());
continue;
}
// Parse Port
int port = std::stoi(port_str);
// Done
struct server_list_entry entry;
entry.address = address;
entry.port = port;
server_list_entries.push_back(entry);
}
}
}
// Close
server_list_file.close();
}
// Iterare Server List
static void iterate_servers(std::function<void(const char *address, int port)> callback) {
// Load
if (!server_list_loaded) {
load_servers();
server_list_loaded = true;
}
// Loop
for (std::vector<struct server_list_entry>::size_type i = 0; i < server_list_entries.size(); i++) {
struct server_list_entry entry = server_list_entries[i];
callback(entry.address.c_str(), entry.port);
}
}
static void RakNetInstance_pingForHosts_injection(unsigned char *rak_net_instance, int32_t base_port) {
// Call Original
(*RakNetInstance_pingForHosts)(rak_net_instance, base_port);
// Get RakNet::RakPeer
unsigned char *rak_peer = *(unsigned char **) (rak_net_instance + RakNetInstance_peer_property_offset);
// Add External Servers
iterate_servers([rak_peer](const char *address, int port) {
(*RakNet_RakPeer_Ping)(rak_peer, address, port, 1, 0);
});
}
// Init
void init_multiplayer() {
// Inject Code
patch_address(RakNetInstance_pingForHosts_vtable_addr, (void *) RakNetInstance_pingForHosts_injection);
}

View File

@ -20,8 +20,6 @@ static char *get_override_path(const char *filename) {
// Get Asset Override Path
char *overrides = NULL;
safe_asprintf(&overrides, "%s/overrides", home_path);
// Free Home Path
free(home_path);
// Get Data Path
char *data = NULL;
char *cwd = getcwd(NULL, 0);

View File

@ -23,6 +23,7 @@
#include "../init/init.h"
#include "../home/home.h"
#include "../compat/compat.h"
#include "../version/version.h"
#include <libreborn/minecraft.h>
@ -65,7 +66,7 @@ static std::string get_world_name() {
// Create/Start World
static void start_world(unsigned char *minecraft) {
INFO("%s", "Starting Minecraft: Pi Edition Dedicated Server");
INFO("Starting Minecraft: Pi Edition: Dedicated Server (%s)", version_get());
// Specify Level Settings
LevelSettings settings;
@ -144,7 +145,7 @@ static bool is_whitelist() {
}
// Get Path Of Blacklist (Or Whitelist) File
static std::string get_blacklist_file() {
std::string file(home_get_launch_directory());
std::string file(home_get());
file.append(is_whitelist() ? "/whitelist.txt" : "/blacklist.txt");
return file;
}
@ -457,12 +458,12 @@ static unsigned char get_max_players() {
static void server_init() {
// Open Properties File
std::string file(home_get_launch_directory());
std::string file(home_get());
file.append("/server.properties");
std::ifstream properties_file(file);
if (!properties_file || !properties_file.good()) {
if (!properties_file.good()) {
// Write Defaults
std::ofstream properties_file_output(file);
properties_file_output << "# Message Of The Day\n";
@ -490,9 +491,9 @@ static void server_init() {
properties_file = std::ifstream(file);
}
// Open Properties File
// Check Properties File
if (!properties_file.is_open()) {
ERR("%s", "Unable To Open server.properties");
ERR("Unable To Open %s", file.c_str());
}
// Load Properties
get_server_properties().load(properties_file);
@ -502,7 +503,7 @@ static void server_init() {
// Create Empty Blacklist/Whitelist File
std::string blacklist_file_path = get_blacklist_file();
std::ifstream blacklist_file(blacklist_file_path);
if (!blacklist_file || !blacklist_file.good()) {
if (!blacklist_file.good()) {
// Write Default
std::ofstream blacklist_output(blacklist_file_path);
blacklist_output << "# Blacklist/Whitelist; Each Line Is One IP Address\n";

View File

@ -13,7 +13,6 @@ void run_tests() {
char *path = home_get();
int exists = access(path, F_OK) == 0;
int can_write = exists ? access(path, R_OK | W_OK) == 0 : 1;
free(path);
if (!can_write) {
// Failure

View File

@ -0,0 +1,2 @@
# ``version`` Mod
This mod adds the MCPI-Reborn version to the start screen.

View File

@ -0,0 +1,34 @@
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include "version.h"
#include "../init/init.h"
// Get New Version
char *version_get() {
static char *version = NULL;
// Load
if (version == NULL) {
safe_asprintf(&version, "%s / Reborn v" VERSION, *minecraft_pi_version);
}
// Return
return version;
}
// Free
__attribute__((destructor)) static void _free_version() {
free(version_get());
}
// Injection For Touch GUI Version
static std::string Common_getGameVersionString_injection(__attribute__((unused)) std::string const& version_suffix) {
// Set Version
return version_get();
}
// Init
void init_version() {
// Touch GUI
overwrite((void *) Common_getGameVersionString, (void *) Common_getGameVersionString_injection);
// Normal GUI
patch_address((void *) minecraft_pi_version, version_get());
}

View File

@ -0,0 +1,11 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
char *version_get();
#ifdef __cplusplus
}
#endif