From 7498c1e93257f72cff42b61671d757ae42597281 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Tue, 28 Sep 2021 14:04:05 -0400 Subject: [PATCH 01/28] Scale Animated Textures --- VERSION | 2 +- docs/CHANGELOG.md | 6 ++ images/start.png | Bin 31455 -> 31458 bytes media-layer/include/GLES/gl.h | 1 + media-layer/proxy/src/GLESv1_CM.c | 1 + mods/CMakeLists.txt | 2 +- mods/src/chat/chat.cpp | 2 +- mods/src/creative/creative.cpp | 3 + mods/src/feature/feature.c | 2 +- mods/src/server/server.cpp | 72 +++++++++---- mods/src/textures/textures.cpp | 150 ++++++++++++++++++++++++++++ symbols/include/symbols/minecraft.h | 14 ++- 12 files changed, 231 insertions(+), 24 deletions(-) diff --git a/VERSION b/VERSION index 530cdd91..21bb5e15 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2.4 +2.2.5 diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 86bafaee..a81d699d 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +**2.2.5** +* Scale Animated Textures +* Add More Blocks To Expanded Creative Inventory +* Reduce Unnecessary Logging +* Log IPs In Server Mode + **2.2.4** * Instead Of Crashing, Disable Polling Block Hits In Survival Mode Using The API diff --git a/images/start.png b/images/start.png index c56ab7047957f1a8b9113d028be3dc9a65342f8d..6566e27c4c5d62c1f24a0bd6d45dfc0bb4efaf92 100644 GIT binary patch delta 26740 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%0A+=XI&9!H;?j;gxB^Hq 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 delta 26688 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 diff --git a/media-layer/include/GLES/gl.h b/media-layer/include/GLES/gl.h index ba1d9fde..935917b2 100644 --- a/media-layer/include/GLES/gl.h +++ b/media-layer/include/GLES/gl.h @@ -7,6 +7,7 @@ extern "C" { #define GL_FALSE 0 #define GL_FOG_COLOR 0xb66 #define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_TEXTURE_BINDING_2D 0x8069 #define GL_UNSIGNED_BYTE 0x1401 #define GL_RGB 0x1907 #define GL_RGBA 0x1908 diff --git a/media-layer/proxy/src/GLESv1_CM.c b/media-layer/proxy/src/GLESv1_CM.c index 2eb0c6ca..8d7d0956 100644 --- a/media-layer/proxy/src/GLESv1_CM.c +++ b/media-layer/proxy/src/GLESv1_CM.c @@ -1099,6 +1099,7 @@ CALL(58, glIsEnabled, GLboolean, (GLenum cap)) { static int get_glGetIntegerv_params_size(GLenum pname) { switch (pname) { + case GL_TEXTURE_BINDING_2D: case GL_UNPACK_ALIGNMENT: { return 1; } diff --git a/mods/CMakeLists.txt b/mods/CMakeLists.txt index 7b3e4f26..d6e16b06 100644 --- a/mods/CMakeLists.txt +++ b/mods/CMakeLists.txt @@ -54,7 +54,7 @@ else() target_link_libraries(override reborn symbols dl home) add_library(textures SHARED src/textures/textures.cpp) - target_link_libraries(textures reborn symbols feature) + target_link_libraries(textures reborn symbols media-layer-core feature) add_library(atlas SHARED src/atlas/atlas.cpp) target_link_libraries(atlas reborn symbols feature GLESv1_CM) diff --git a/mods/src/chat/chat.cpp b/mods/src/chat/chat.cpp index ed17e872..f086b7e4 100644 --- a/mods/src/chat/chat.cpp +++ b/mods/src/chat/chat.cpp @@ -71,7 +71,7 @@ static void CommandServer_parse_CommandServer_dispatchPacket_injection(unsigned } // Handle ChatPacket Server-Side -static void ServerSideNetworkHandler_handle_ChatPacket_injection(unsigned char *server_side_network_handler, unsigned char *rak_net_guid, unsigned char *chat_packet) { +static void ServerSideNetworkHandler_handle_ChatPacket_injection(unsigned char *server_side_network_handler, RakNet_RakNetGUID *rak_net_guid, unsigned char *chat_packet) { unsigned char *player = (*ServerSideNetworkHandler_getPlayer)(server_side_network_handler, rak_net_guid); if (player != NULL) { char *username = *(char **) (player + Player_username_property_offset); diff --git a/mods/src/creative/creative.cpp b/mods/src/creative/creative.cpp index 8f869ae3..998e592b 100644 --- a/mods/src/creative/creative.cpp +++ b/mods/src/creative/creative.cpp @@ -44,6 +44,9 @@ static int32_t Inventory_setupDefault_FillingContainer_addItem_call_injection(un inventory_add_item(filling_container, *Tile_topSnow, true); inventory_add_item(filling_container, *Tile_ice, true); inventory_add_item(filling_container, *Tile_invisible_bedrock, true); + inventory_add_item(filling_container, *Tile_bedrock, true); + inventory_add_item(filling_container, *Tile_info_updateGame1, true); + inventory_add_item(filling_container, *Tile_info_updateGame2, true); return ret; } diff --git a/mods/src/feature/feature.c b/mods/src/feature/feature.c index 476af7da..fda15dbe 100644 --- a/mods/src/feature/feature.c +++ b/mods/src/feature/feature.c @@ -29,7 +29,7 @@ int feature_has(const char *name, int server_default) { tok = strtok(NULL, "|"); } free(features); -#ifndef MCPI_SERVER_MODE +#ifdef DEBUG INFO("Feature: %s: %s", name, ret ? "Enabled" : "Disabled"); #endif return ret; diff --git a/mods/src/server/server.cpp b/mods/src/server/server.cpp index a748c575..9b4468c6 100644 --- a/mods/src/server/server.cpp +++ b/mods/src/server/server.cpp @@ -198,16 +198,20 @@ static unsigned char *get_rak_peer(unsigned char *minecraft) { unsigned char *rak_net_instance = *(unsigned char **) (minecraft + Minecraft_rak_net_instance_property_offset); return *(unsigned char **) (rak_net_instance + RakNetInstance_peer_property_offset); } - -// Get IP From Player -static char *get_player_ip(unsigned char *minecraft, unsigned char *player) { - RakNet_RakNetGUID guid = get_rak_net_guid(player); - unsigned char *rak_peer = get_rak_peer(minecraft); +static char *get_rak_net_guid_ip(unsigned char *rak_peer, RakNet_RakNetGUID guid) { RakNet_SystemAddress address = get_system_address(rak_peer, guid); // Get IP return (*RakNet_SystemAddress_ToString)(&address, false, '|'); } +// Get IP From Player +static char *get_player_ip(unsigned char *minecraft, unsigned char *player) { + unsigned char *rak_peer = get_rak_peer(minecraft); + RakNet_RakNetGUID guid = get_rak_net_guid(player); + // Return + return get_rak_net_guid_ip(rak_peer,guid); +} + // Ban Player static void ban_callback(unsigned char *minecraft, std::string username, unsigned char *player) { // Get IP @@ -275,25 +279,34 @@ static unsigned char *get_server_side_network_handler(unsigned char *minecraft) static volatile bool stdin_buffer_complete = false; static volatile char *stdin_buffer = NULL; static void *read_stdin_thread(__attribute__((unused)) void *data) { - while (1) { - if (!stdin_buffer_complete) { - int x = getchar(); - if (x != EOF) { - if (x == '\n') { - if (stdin_buffer == NULL) { - stdin_buffer = strdup(""); + // Check If STDIN Is A TTY + if (isatty(fileno(stdin))) { + // Loop + while (1) { + if (!stdin_buffer_complete) { + // Read Data + int x = fgetc(stdin); + if (x != EOF) { + if (x == '\n') { + if (stdin_buffer == NULL) { + stdin_buffer = strdup(""); + } + stdin_buffer_complete = true; + break; + } else { + string_append((char **) &stdin_buffer, "%c", (char) x); } - stdin_buffer_complete = true; - } else { - string_append((char **) &stdin_buffer, "%c", (char) x); } } } } + return NULL; } __attribute__((destructor)) static void _free_stdin_buffer() { - free((void *) stdin_buffer); - stdin_buffer = NULL; + if (stdin_buffer != NULL) { + free((void *) stdin_buffer); + stdin_buffer = NULL; + } } // Handle Commands @@ -385,6 +398,7 @@ static void Minecraft_update_injection(unsigned char *minecraft) { handle_server_stop(minecraft); } +// Ban Players static bool RakNet_RakPeer_IsBanned_injection(__attribute__((unused)) unsigned char *rakpeer, const char *ip) { // Check banned-ips.txt std::string blacklist_file_path = get_blacklist_file(); @@ -420,6 +434,27 @@ static bool RakNet_RakPeer_IsBanned_injection(__attribute__((unused)) unsigned c } } +// Log IPs +static unsigned char *ServerSideNetworkHandler_onReady_ClientGeneration_ServerSideNetworkHandler_popPendingPlayer_injection(unsigned char *server_side_network_handler, RakNet_RakNetGUID *guid) { + // Call Original Method + unsigned char *player = (*ServerSideNetworkHandler_popPendingPlayer)(server_side_network_handler, guid); + + // Check If Player Is Null + if (player != NULL) { + // Get Data + char *username = (char *) *(unsigned char **) (player + Player_username_property_offset); + unsigned char *minecraft = *(unsigned char **) (server_side_network_handler + ServerSideNetworkHandler_minecraft_property_offset); + unsigned char *rak_peer = get_rak_peer(minecraft); + char *ip = get_rak_net_guid_ip(rak_peer, *guid); + + // Log + INFO("%s Has Joined (IP: %s)", username, ip); + } + + // Return + return player; +} + // Get MOTD static std::string get_motd() { std::string motd(get_server_properties().get_string("motd", DEFAULT_MOTD)); @@ -532,6 +567,9 @@ static void server_init() { patch((void *) 0x737e4, minecon_badge_patch); } + // Log IPs + overwrite_call((void *) 0x75e54, (void *) ServerSideNetworkHandler_onReady_ClientGeneration_ServerSideNetworkHandler_popPendingPlayer_injection); + // Start Reading STDIN pthread_t read_stdin_thread_obj; pthread_create(&read_stdin_thread_obj, NULL, read_stdin_thread, NULL); diff --git a/mods/src/textures/textures.cpp b/mods/src/textures/textures.cpp index 450e2e90..4b54f916 100644 --- a/mods/src/textures/textures.cpp +++ b/mods/src/textures/textures.cpp @@ -1,3 +1,9 @@ +#include +#include +#include + +#include + #include #include @@ -16,10 +22,154 @@ static void Minecraft_tick_injection(unsigned char *minecraft, int32_t param_1, } } +// Store Texture Sizes +struct texture_data { + GLint id; + GLsizei width; + GLsizei height; +}; +static std::vector &get_texture_data() { + static std::vector data; + return data; +} +HOOK(glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels)) { + // Store + texture_data data; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &data.id); + data.width = width; + data.height = height; + get_texture_data().push_back(data); + + // Call Original Method + ensure_glTexImage2D(); + (*real_glTexImage2D)(target, level, internalformat, width, height, border, format, type, pixels); +} +HOOK(glDeleteTextures, void, (GLsizei n, const GLuint *textures)) { + // Remove Old Data + for (int i = 0; i < n; i++) { + GLint id = textures[n]; + std::vector::iterator it = get_texture_data().begin(); + while (it != get_texture_data().end()) { + texture_data data = *it; + if (data.id == id) { + it = get_texture_data().erase(it); + } else { + ++it; + } + } + } + + // Call Original Method + ensure_glDeleteTextures(); + (*real_glDeleteTextures)(n, textures); +} +static void get_texture_size(GLint id, GLsizei *width, GLsizei *height) { + // Iterate + std::vector::iterator it = get_texture_data().begin(); + while (it != get_texture_data().end()) { + texture_data data = *it; + if (data.id == id) { + // Found + *width = data.width; + *height = data.height; + return; + } + ++it; + } + // Not Found + ERR("Unable To Find Size Of Texture: %i", id); +} + +// Scale Texture (Remember To Free) +#define PIXEL_SIZE 4 +static int get_line_size(int width) { + int line_size = width * PIXEL_SIZE; + { + // Handle Alignment + int alignment; + glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment); + // Round + int diff = line_size % alignment; + if (diff > 0) { + line_size = line_size + (alignment - diff); + } + } + return line_size; +} +static void *scale_texture(const unsigned char *src, GLsizei old_width, GLsizei old_height, GLsizei new_width, GLsizei new_height) { + int old_line_size = get_line_size(old_width); + int new_line_size = get_line_size(new_width); + + // Allocate + unsigned char *dst = (unsigned char *) malloc(new_height * new_line_size); + ALLOC_CHECK(dst); + + // Scale + for (int new_x = 0; new_x < new_width; new_x++) { + int old_x = (int) (((float) new_x / (float) new_width) * (float) old_width); + for (int new_y = 0; new_y < new_height; new_y++) { + int old_y = (int) (((float) new_y / (float) new_height) * (float) old_height); + + // Find Position + int new_position = (new_y * new_line_size) + (new_x * PIXEL_SIZE); + int old_position = (old_y * old_line_size) + (old_x * PIXEL_SIZE); + + // Copy + static_assert(sizeof (int32_t) == PIXEL_SIZE, "Pixel Size Doesn't Match 32-Bit Integer Size"); + *(int32_t *) &dst[new_position] = *(int32_t *) &src[old_position]; + } + } + + // Return + return dst; +} + +// Scale Animated Textures +static void Textures_tick_glTexSubImage2D_injection(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) { + // Get Current Texture Size + GLint current_texture; + glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); + GLsizei texture_width; + GLsizei texture_height; + get_texture_size(current_texture, &texture_width, &texture_height); + + // Calculate Factor + float width_factor = ((float) texture_width) / 256.0f; + float height_factor = ((float) texture_height) / 256.0f; + + // Only Scale If Needed + if (width_factor == 1.0f && height_factor == 1.0f) { + // No Scaling + glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); + } else { + // Check + if (format != GL_RGBA || type != GL_UNSIGNED_BYTE) { + // Pixels Must Be 4 Bytes + ERR("%s", "Unsupported Texture Format For Scaling"); + } + + // Scale + GLsizei new_width = width * width_factor; + GLsizei new_height = height * height_factor; + void *new_pixels = scale_texture((const unsigned char *) pixels, width, height, new_width, new_height); + + // Call Original Method + GLint new_xoffset = xoffset * width_factor; + GLint new_yoffset = yoffset * height_factor; + glTexSubImage2D(target, level, new_xoffset, new_yoffset, new_width, new_height, format, type, new_pixels); + + // Free + free(new_pixels); + } +} + // Init void init_textures() { // Tick Dynamic Textures (Animated Water) if (feature_has("Animated Water", 0)) { overwrite_calls((void *) Minecraft_tick, (void *) Minecraft_tick_injection); } + + // Scale Animated Textures + overwrite_call((void *) 0x53274, (void *) Textures_tick_glTexSubImage2D_injection); } diff --git a/symbols/include/symbols/minecraft.h b/symbols/include/symbols/minecraft.h index 2c897298..70ad00dc 100644 --- a/symbols/include/symbols/minecraft.h +++ b/symbols/include/symbols/minecraft.h @@ -36,6 +36,9 @@ static unsigned char **Tile_topSnow = (unsigned char **) 0x181b30; static unsigned char **Tile_ice = (unsigned char **) 0x181d80; static unsigned char **Tile_invisible_bedrock = (unsigned char **) 0x181d94; static unsigned char **Tile_netherReactor = (unsigned char **) 0x181dd0; +static unsigned char **Tile_info_updateGame1 = (unsigned char **) 0x181c68; +static unsigned char **Tile_info_updateGame2 = (unsigned char **) 0x181c6c; +static unsigned char **Tile_bedrock = (unsigned char **) 0x181cc4; static unsigned char **Tile_leaves = (unsigned char **) 0x18120c; static unsigned char **Tile_leaves_carried = (unsigned char **) 0x181dd8; @@ -456,17 +459,22 @@ static RakNet_SystemAddress_ToString_t RakNet_SystemAddress_ToString = (RakNet_S // ServerSideNetworkHandler -typedef void (*ServerSideNetworkHandler_onDisconnect_t)(unsigned char *server_side_network_handler, unsigned char *guid); +typedef void (*ServerSideNetworkHandler_onDisconnect_t)(unsigned char *server_side_network_handler, struct RakNet_RakNetGUID *guid); static ServerSideNetworkHandler_onDisconnect_t ServerSideNetworkHandler_onDisconnect = (ServerSideNetworkHandler_onDisconnect_t) 0x75164; static void *ServerSideNetworkHandler_onDisconnect_vtable_addr = (void *) 0x109bb0; -typedef unsigned char *(*ServerSideNetworkHandler_getPlayer_t)(unsigned char *server_side_network_handler, unsigned char *guid); +typedef unsigned char *(*ServerSideNetworkHandler_getPlayer_t)(unsigned char *server_side_network_handler, struct RakNet_RakNetGUID *guid); static ServerSideNetworkHandler_getPlayer_t ServerSideNetworkHandler_getPlayer = (ServerSideNetworkHandler_getPlayer_t) 0x75464; -typedef void (*ServerSideNetworkHandler_handle_t)(unsigned char *server_side_network_handler, unsigned char *rak_net_guid, unsigned char *packet); +typedef unsigned char *(*ServerSideNetworkHandler_popPendingPlayer_t)(unsigned char *server_side_network_handler, struct RakNet_RakNetGUID *guid); +static ServerSideNetworkHandler_popPendingPlayer_t ServerSideNetworkHandler_popPendingPlayer = (ServerSideNetworkHandler_popPendingPlayer_t) 0x75db4; + +typedef void (*ServerSideNetworkHandler_handle_t)(unsigned char *server_side_network_handler, struct RakNet_RakNetGUID *rak_net_guid, unsigned char *packet); static void *ServerSideNetworkHandler_handle_ChatPacket_vtable_addr = (void *) 0x109c60; +static uint32_t ServerSideNetworkHandler_minecraft_property_offset = 0x8; // Minecraft * + // Inventory typedef void (*Inventory_selectSlot_t)(unsigned char *inventory, int32_t slot); From c45211ad2296c55180e54345a39c1ca4cd795181 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Tue, 28 Sep 2021 16:03:56 -0400 Subject: [PATCH 02/28] Improve Changelog Formatting --- docs/CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index a81d699d..56474a80 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -17,7 +17,7 @@ * Make Missing Sound Event Cause Warning Rather Than Crash **2.2.1** -* Prevent `random.burp` Sound From Crashing Game +* Prevent ``random.burp`` Sound From Crashing Game * Always Cleanup Media Layer, Even On Crash * Resolve All Sounds On Startup @@ -25,7 +25,7 @@ * Sound Support * Split Off "Allow Joining Survival Servers" From Game-Mode Mod * Separate Headless Code From Server Code -* Fix Bug Where `RakNetInstance` Starts Pinging Potential Servers Before The "Join Game" Screen Is Opened +* Fix Bug Where ``RakNetInstance`` Starts Pinging Potential Servers Before The "Join Game" Screen Is Opened * Clean-Up Code * Remove Support For Debian Buster @@ -42,7 +42,7 @@ * Print Error Message If RakNet Fails To Start **2.1.4** -* Fix RakNet::RakString Security Bug +* Fix ``RakNet::RakString`` Security Bug **2.1.3** * Workaround Broken Library Search Path On Some ARM 32-Bit Systems @@ -80,7 +80,7 @@ * Optimize Media Layer Proxy **2.0.3** -* Make "kill" Admin Command Print Death Message +* Make ``kill`` Admin Command Print Death Message **2.0.2** * Fix Mouse Cursor Bugs From 6a9a22ac2571c18d54182718d38f12debea982e6 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Thu, 30 Sep 2021 19:37:24 -0400 Subject: [PATCH 03/28] Fix Bug In Texture Scaling Code --- VERSION | 2 +- docs/CHANGELOG.md | 3 +++ mods/src/textures/textures.cpp | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 21bb5e15..bda8fbec 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2.5 +2.2.6 diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 56474a80..5c74e0ac 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +**2.2.5** +* Fix Bug In Texture Scaling Code + **2.2.5** * Scale Animated Textures * Add More Blocks To Expanded Creative Inventory diff --git a/mods/src/textures/textures.cpp b/mods/src/textures/textures.cpp index 4b54f916..641d4cec 100644 --- a/mods/src/textures/textures.cpp +++ b/mods/src/textures/textures.cpp @@ -47,7 +47,7 @@ HOOK(glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLsi HOOK(glDeleteTextures, void, (GLsizei n, const GLuint *textures)) { // Remove Old Data for (int i = 0; i < n; i++) { - GLint id = textures[n]; + GLint id = textures[i]; std::vector::iterator it = get_texture_data().begin(); while (it != get_texture_data().end()) { texture_data data = *it; From 8c356dd65c1bca3cc36fc1f48766c5b3b9f852ea Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Thu, 30 Sep 2021 20:28:37 -0400 Subject: [PATCH 04/28] Update README Image --- images/start.png | Bin 31458 -> 31456 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/images/start.png b/images/start.png index 6566e27c4c5d62c1f24a0bd6d45dfc0bb4efaf92..7df95f121c7267069d6dce26b3bebceb881a91b4 100644 GIT binary patch delta 27524 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 Date: Mon, 4 Oct 2021 19:42:55 -0400 Subject: [PATCH 05/28] Clean Up --- mods/src/input/bow.c | 3 ++- mods/src/input/drop.cpp | 3 ++- mods/src/input/input.cpp | 15 --------------- mods/src/input/input.h | 5 ----- mods/src/input/misc.c | 6 ++++-- mods/src/input/toggle.c | 3 ++- mods/src/options/options.c | 6 +++--- symbols/include/symbols/minecraft.h | 27 +++++++++++++++++++++++++++ 8 files changed, 40 insertions(+), 28 deletions(-) diff --git a/mods/src/input/bow.c b/mods/src/input/bow.c index 80a8f2eb..9313a47b 100644 --- a/mods/src/input/bow.c +++ b/mods/src/input/bow.c @@ -14,7 +14,7 @@ void input_set_is_right_click(int val) { static int fix_bow = 0; // Handle Bow & Arrow -void _handle_bow(unsigned char *minecraft) { +static void _handle_bow(unsigned char *minecraft) { if (fix_bow && !is_right_click) { // GameMode Is Offset From minecraft By 0x160 // Player Is Offset From minecraft By 0x18c @@ -32,4 +32,5 @@ void _handle_bow(unsigned char *minecraft) { void _init_bow() { // Enable Bow & Arrow Fix fix_bow = feature_has("Fix Bow & Arrow", 0); + input_run_on_tick(_handle_bow); } diff --git a/mods/src/input/drop.cpp b/mods/src/input/drop.cpp index 68037228..ef051b34 100644 --- a/mods/src/input/drop.cpp +++ b/mods/src/input/drop.cpp @@ -21,7 +21,7 @@ void input_drop(int drop_slot) { } // Handle Drop Item Presses -void _handle_drop(unsigned char *minecraft) { +static void _handle_drop(unsigned char *minecraft) { if (!(*Minecraft_isCreativeMode)(minecraft) && (drop_item_presses > 0 || drop_slot_pressed)) { // Get Player unsigned char *player = *(unsigned char **) (minecraft + Minecraft_player_property_offset); @@ -85,4 +85,5 @@ void _handle_drop(unsigned char *minecraft) { // Init void _init_drop() { enable_drop = feature_has("Bind \"Q\" Key To Item Dropping", 0); + input_run_on_tick(_handle_drop); } diff --git a/mods/src/input/input.cpp b/mods/src/input/input.cpp index d83b4ca0..7e2e6973 100644 --- a/mods/src/input/input.cpp +++ b/mods/src/input/input.cpp @@ -21,21 +21,6 @@ static void Minecraft_tickInput_injection(unsigned char *minecraft) { // Call Original Method (*Minecraft_tickInput)(minecraft); - // Handle Bow - _handle_bow(minecraft); - - // Handle Toggle Options - _handle_toggle_options(minecraft); - - // Set Mouse Grab State - _handle_mouse_grab(minecraft); - - // Handle Back Button - _handle_back(minecraft); - - // Handle Item Drops - _handle_drop(minecraft); - // Run Input Tick Functions for (input_tick_function_t function : get_input_tick_functions()) { (*function)(minecraft); diff --git a/mods/src/input/input.h b/mods/src/input/input.h index b18b374c..83fe1102 100644 --- a/mods/src/input/input.h +++ b/mods/src/input/input.h @@ -19,14 +19,9 @@ void input_set_mouse_grab_state(int state); __attribute__((visibility("internal"))) void _init_attack(); __attribute__((visibility("internal"))) void _init_bow(); -__attribute__((visibility("internal"))) void _handle_bow(unsigned char *minecraft); -__attribute__((visibility("internal"))) void _handle_toggle_options(unsigned char *minecraft); __attribute__((visibility("internal"))) void _init_misc(); __attribute__((visibility("internal"))) void _init_toggle(); -__attribute__((visibility("internal"))) void _handle_mouse_grab(unsigned char *minecraft); -__attribute__((visibility("internal"))) void _handle_back(unsigned char *minecraft); __attribute__((visibility("internal"))) void _init_drop(); -__attribute__((visibility("internal"))) void _handle_drop(unsigned char *minecraft); #ifdef __cplusplus } diff --git a/mods/src/input/misc.c b/mods/src/input/misc.c index da0a18df..18cfa9c2 100644 --- a/mods/src/input/misc.c +++ b/mods/src/input/misc.c @@ -19,7 +19,7 @@ int input_back() { } // Handle Back Button Presses -void _handle_back(unsigned char *minecraft) { +static void _handle_back(unsigned char *minecraft) { unsigned char *minecraft_vtable = *(unsigned char **) minecraft; Minecraft_handleBack_t Minecraft_handleBack = *(Minecraft_handleBack_t *) (minecraft_vtable + Minecraft_handleBack_vtable_offset); for (int i = 0; i < back_button_presses; i++) { @@ -44,7 +44,7 @@ void input_set_mouse_grab_state(int state) { } // Grab/Un-Grab Mouse -void _handle_mouse_grab(unsigned char *minecraft) { +static void _handle_mouse_grab(unsigned char *minecraft) { if (mouse_grab_state == -1) { // Grab (*Minecraft_grabMouse)(minecraft); @@ -88,4 +88,6 @@ void _init_misc() { // Disable Opening Inventory Using The Cursor When Cursor Is Hidden overwrite_calls((void *) Gui_handleClick, (void *) Gui_handleClick_injection); } + input_run_on_tick(_handle_back); + input_run_on_tick(_handle_mouse_grab); } diff --git a/mods/src/input/toggle.c b/mods/src/input/toggle.c index 2b8f7e69..1b68e9a9 100644 --- a/mods/src/input/toggle.c +++ b/mods/src/input/toggle.c @@ -18,7 +18,7 @@ void input_third_person() { } // Handle Toggle Options -void _handle_toggle_options(unsigned char *minecraft) { +static void _handle_toggle_options(unsigned char *minecraft) { if (enable_toggles) { // Handle Functions unsigned char *options = minecraft + Minecraft_options_property_offset; @@ -38,4 +38,5 @@ void _handle_toggle_options(unsigned char *minecraft) { // Init void _init_toggle() { enable_toggles = feature_has("Bind Common Toggleable Options To Function Keys", 0); + input_run_on_tick(_handle_toggle_options); } diff --git a/mods/src/options/options.c b/mods/src/options/options.c index 6c108e36..ab2d9875 100644 --- a/mods/src/options/options.c +++ b/mods/src/options/options.c @@ -100,20 +100,20 @@ void init_options() { } patch_address((void *) default_username, (void *) username); + // Disable Autojump By Default if (feature_has("Disable Autojump By Default", 0)) { - // Disable Autojump By Default unsigned char autojump_patch[4] = {0x00, 0x30, 0xa0, 0xe3}; // "mov r3, #0x0" patch((void *) 0x44b90, autojump_patch); } + // Display Nametags By Default if (feature_has("Display Nametags By Default", 0)) { - // Display Nametags By Default unsigned char display_nametags_patch[4] = {0x1d, 0x60, 0xc0, 0xe5}; // "strb r6, [r0, #0x1d]" patch((void *) 0xa6628, display_nametags_patch); } + // Enable Smooth Lighting smooth_lighting = feature_has("Smooth Lighting", 0); if (smooth_lighting) { - // Enable Smooth Lighting unsigned char smooth_lighting_patch[4] = {0x01, 0x00, 0x53, 0xe3}; // "cmp r3, #0x1" patch((void *) 0x59ea4, smooth_lighting_patch); } diff --git a/symbols/include/symbols/minecraft.h b/symbols/include/symbols/minecraft.h index 70ad00dc..07ae5813 100644 --- a/symbols/include/symbols/minecraft.h +++ b/symbols/include/symbols/minecraft.h @@ -53,6 +53,15 @@ static uint32_t Tile_id_property_offset = 0x8; // Structures +struct AABB { + float x1; + float y1; + float z1; + float x2; + float y2; + float z2; +}; + struct LevelSettings { unsigned long seed; int32_t game_type; @@ -133,6 +142,8 @@ static uint32_t Minecraft_progress_property_offset = 0xc60; // int32_t static uint32_t Minecraft_command_server_property_offset = 0xcc0; // CommandServer * static uint32_t Minecraft_screen_property_offset = 0xc10; // Screen * static uint32_t Minecraft_gui_property_offset = 0x198; // Gui +static uint32_t Minecraft_pov_property_offset = 0x150; // Mob * +static uint32_t Minecraft_perf_renderer_property_offset = 0xcbc; // PerfRenderer * // GameRenderer @@ -197,6 +208,7 @@ static uint32_t Options_hide_gui_property_offset = 0xec; // unsigned char / bool static uint32_t Options_third_person_property_offset = 0xed; // unsigned char / bool static uint32_t Options_render_distance_property_offset = 0x10; // int32_t static uint32_t Options_sound_property_offset = 0x4; // int32_t +static uint32_t Options_debug_property_offset = 0xee; // unsigned char / bool // MouseBuildInput @@ -314,6 +326,21 @@ static Level_saveLevelData_t Level_saveLevelData = (Level_saveLevelData_t) 0xa2e static uint32_t Level_players_property_offset = 0x60; // std::vector +// LevelRenderer + +typedef void (*LevelRenderer_render_t)(unsigned char *level_renderer, unsigned char *mob, int param_1, float delta); +static LevelRenderer_render_t LevelRenderer_render = (LevelRenderer_render_t) 0x4f710; + +typedef void (*LevelRenderer_renderDebug_t)(unsigned char *level_renderer, struct AABB *aabb, float delta); +static LevelRenderer_renderDebug_t LevelRenderer_renderDebug = (LevelRenderer_renderDebug_t) 0x4d310; + +static uint32_t LevelRenderer_minecraft_property_offset = 0x4; // Minecraft * + +// PerfRenderer + +typedef void (*PerfRenderer_debugFpsMeterKeyPress_t)(unsigned char *perf_renderer, int key); +static PerfRenderer_debugFpsMeterKeyPress_t PerfRenderer_debugFpsMeterKeyPress = (PerfRenderer_debugFpsMeterKeyPress_t) 0x79118; + // TextEditScreen #define TEXT_EDIT_SCREEN_SIZE 0xd0 From f3eaa57041035aefc6c907044bddf3b4c9e626da Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Mon, 4 Oct 2021 19:46:22 -0400 Subject: [PATCH 06/28] Fix Symbol Name --- symbols/include/symbols/minecraft.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/symbols/include/symbols/minecraft.h b/symbols/include/symbols/minecraft.h index 07ae5813..deb78cf8 100644 --- a/symbols/include/symbols/minecraft.h +++ b/symbols/include/symbols/minecraft.h @@ -264,7 +264,7 @@ static Player_isUsingItem_t Player_isUsingItem = (Player_isUsingItem_t) 0x8f15c; typedef void (*Player_drop_t)(unsigned char *player, ItemInstance *item_instance, bool is_death); static uint32_t Player_drop_vtable_offset = 0x208; -static Mob_getWalkingSpeedModifier_t Player_getWalkingSpeed = (Mob_getWalkingSpeedModifier_t) 0x8ea0c; +static Mob_getWalkingSpeedModifier_t Player_getWalkingSpeedModifier = (Mob_getWalkingSpeedModifier_t) 0x8ea0c; static uint32_t Player_username_property_offset = 0xbf4; // char * static uint32_t Player_inventory_property_offset = 0xbe0; // Inventory * From 74d14ecaa62149ed2c614122408d3be7a81abe34 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Thu, 7 Oct 2021 16:54:47 -0400 Subject: [PATCH 07/28] Small Optimization --- media-layer/include/SDL/SDL_events.h | 12 +-- media-layer/proxy/src/media-layer-core.c | 119 +---------------------- 2 files changed, 11 insertions(+), 120 deletions(-) diff --git a/media-layer/include/SDL/SDL_events.h b/media-layer/include/SDL/SDL_events.h index 758de852..23946068 100644 --- a/media-layer/include/SDL/SDL_events.h +++ b/media-layer/include/SDL/SDL_events.h @@ -114,8 +114,8 @@ typedef struct SDL_JoyButtonEvent { typedef struct SDL_ResizeEvent { uint8_t type; - int w; - int h; + int32_t w; + int32_t h; } SDL_ResizeEvent; typedef struct SDL_ExposeEvent { @@ -128,14 +128,14 @@ typedef struct SDL_QuitEvent { typedef struct SDL_UserEvent { uint8_t type; - int code; - void *data1; - void *data2; + int32_t code; + uint32_t data1; + uint32_t data2; } SDL_UserEvent; typedef struct SDL_SysWMEvent { uint8_t type; - void *msg; + uint32_t msg; } SDL_SysWMEvent; typedef union SDL_Event { diff --git a/media-layer/proxy/src/media-layer-core.c b/media-layer/proxy/src/media-layer-core.c index 850466d2..a7fffae0 100644 --- a/media-layer/proxy/src/media-layer-core.c +++ b/media-layer/proxy/src/media-layer-core.c @@ -9,116 +9,6 @@ #include "common/common.h" -// Read/Write SDL Events -static void write_SDL_Event(SDL_Event event) { - // Write EVent Type - write_int(event.type); - // Write Event Details - switch (event.type) { - // Focus Event - case SDL_ACTIVEEVENT: { - write_int(event.active.gain); - write_int(event.active.state); - break; - } - // Key Press Events - case SDL_KEYDOWN: - case SDL_KEYUP: { - write_int(event.key.state); - write_int(event.key.keysym.scancode); - write_int(event.key.keysym.sym); - write_int(event.key.keysym.mod); - write_int(event.key.keysym.unicode); - break; - } - // Mouse Motion Event - case SDL_MOUSEMOTION: { - write_int(event.motion.state); - write_int(event.motion.x); - write_int(event.motion.y); - write_int(event.motion.xrel); - write_int(event.motion.yrel); - break; - } - // Mouse Press Events - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: { - write_int(event.button.button); - write_int(event.button.state); - write_int(event.button.x); - write_int(event.button.y); - break; - } - // User-Specified Event (Repurposed As Unicode Character Event) - case SDL_USEREVENT: { - write_int(event.user.code); - break; - } - } -} -static SDL_Event read_SDL_Event() { - // Create Event - SDL_Event event; - event.type = read_int(); - // Read Event Details - switch (event.type) { - // Focus Event - case SDL_ACTIVEEVENT: { - event.active.gain = read_int(); - event.active.state = read_int(); - break; - } - // Key Press Events - case SDL_KEYDOWN: - case SDL_KEYUP: { - event.key.state = read_int(); - event.key.keysym.scancode = read_int(); - event.key.keysym.sym = read_int(); - event.key.keysym.mod = read_int(); - event.key.keysym.unicode = read_int(); - break; - } - // Mouse Motion Event - case SDL_MOUSEMOTION: { - event.motion.state = read_int(); - event.motion.x = read_int(); - event.motion.y = read_int(); - event.motion.xrel = read_int(); - event.motion.yrel = read_int(); - break; - } - // Mouse Press Events - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: { - event.button.button = read_int(); - event.button.state = read_int(); - event.button.x = read_int(); - event.button.y = read_int(); - break; - } - // Quit Event - case SDL_QUIT: { - break; - } - // User-Specified Event (Repurposed As Unicode Character Event) - case SDL_USEREVENT: { - event.user.code = read_int(); - break; - } - // Unsupported Event - default: { - INFO("Unsupported SDL Event: %u", event.type); - } - } - // Return -#pragma GCC diagnostic push -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -#endif - return event; -#pragma GCC diagnostic pop -} - // SDL Functions CALL(0, SDL_Init, int, (uint32_t flags)) { @@ -156,7 +46,7 @@ CALL(1, SDL_PollEvent, int, (SDL_Event *event)) { // Get Return Value int32_t ret = (int32_t) read_int(); if (ret) { - *event = read_SDL_Event(); + safe_read((void *) event, sizeof (SDL_Event)); } // Release Proxy @@ -171,7 +61,7 @@ CALL(1, SDL_PollEvent, int, (SDL_Event *event)) { // Return Values write_int(ret); if (ret) { - write_SDL_Event(event); + safe_write((void *) &event, sizeof (SDL_Event)); } #endif } @@ -182,7 +72,7 @@ CALL(2, SDL_PushEvent, int, (SDL_Event *event)) { start_proxy_call(); // Arguments - write_SDL_Event(*event); + safe_write((void *) event, sizeof (SDL_Event)); // Get Return Value int32_t ret = (int32_t) read_int(); @@ -193,7 +83,8 @@ CALL(2, SDL_PushEvent, int, (SDL_Event *event)) { // Return Value return ret; #else - SDL_Event event = read_SDL_Event(); + SDL_Event event; + safe_read((void *) &event, sizeof (SDL_Event)); // Run int ret = SDL_PushEvent(&event); // Return Value From 637f1c11321994185445af2db742bf17a9b191a9 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Tue, 12 Oct 2021 16:01:07 -0400 Subject: [PATCH 08/28] 2.2.7 --- VERSION | 2 +- docs/CHANGELOG.md | 4 + images/start.png | Bin 31456 -> 31460 bytes media-layer/core/src/audio/api.cpp | 148 +++++++++++++++-------------- mods/src/server/server.cpp | 1 - 5 files changed, 82 insertions(+), 73 deletions(-) diff --git a/VERSION b/VERSION index bda8fbec..5bc1cc43 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2.6 +2.2.7 diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 5c74e0ac..f43fb192 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +**2.2.7** +* Fix Crash When OpenAL Is Unavailable +* Fix Command Input In Server + **2.2.5** * Fix Bug In Texture Scaling Code diff --git a/images/start.png b/images/start.png index 7df95f121c7267069d6dce26b3bebceb881a91b4..7201171320d188cdba2a0d91fe15e42877d2444e 100644 GIT binary patch delta 1408 zcmZva`#aMM0LE44^wbE=4x#3_hLn)SoOmjlnWbEg`#~98JTC(C3mV+$uT&CDvyWyb0B>*@0syzl#Y|5@4bab?HzaRe|@xgE#wQI^DK zv4FJ=Fatvtf^^6{Ejls*Q ztJ1VL_3mUyZ;h1Qc+}E6D1&>OR<*%+60;OwnDb=8bW2pCn5KgMWOv6SU z6V7tTDlj@YX9q@Bzsy(|e`+~6(1A0p&rtF9>f{LRm=cCylb1m5Cj7ncM|o7u-Y%1d z@|Hm^D1YY^?4s6ayj7WH#D3BIqV2IV+8u22>K-wPe*fUDwk_>Fl3z!M;$DIo%txhy z5H+pAZWIT8nvD`*(m!4n;!8|mudKDax%7yKhHn|; zObgMv^8%WF&Lw_C>WeqMCMAXh@n(%)wIwDjyKzpB3_WK&C;&z=nkvQdU&!1x21z^@ zz4QkeJ6S+8aVuZ0O^lrn^~w`p_nTVeQcwyW*I*q1YAAI~C4CN6_(^^lE$f0Lkpszn zc=fM`bBbTyKAC@;n2I#sY2ibxLfY<>!H6TslK{6191h_Hs2=5be(ODLKHH@?VaM3q=_4M**0hF8|6nL6AEe6=ZaH?6a}Tdjgf^; zD{>xqJJTLa-tzAm*@7$RxeW?RY%G}cS+`yl_qe1u$K!B%3eFyPpu{^51MEf-&@vm6 ztYt5Lh}~ij3mS0p3>4MMsC5(Ajk#!|wud=O=vOqF`Yaz~T7gNgwE&Pq`Br90HBh1X zp@xJ*+n#bZb4Dm})2HFqH!h#xX8_j~8lAxmz^+~qm+=2u+5R8`xDH?F`oY*U1+eCQ zHX;>3&2|L_6>+e0eYV}C{_HkbY+uv*(_~mRm9x_NCuYi+`_ud8wvpgWI6np1H-H z%#F(s-a2BMe|6)FuwtAWH62cXWC#QFc)$f8o~*2uLGKZ6QdYmVB6H%ZeD>} zjH{LO0JmVX;9;QsqQz z%@Jy%rgCSWhf zwUpj;vEPcy^o4Ja4YP!;BLntu-ctVXRk*0Kra`zFpR_5S+rGj{#>t#wzD^r)C@L_C z5Vwh%9XlXmGU;mQ6*XXSyCoGrkVu{ld*xedQ7fA?K{hz&kC0ARQHmOs46Mxcp{xo iduJ*uDbX`S-E<(c$*A9S=j3Bb-$1&YcWyirn)xqnci@x& delta 1367 zcmV-d1*rPu^#S1Z0kGLe7I7W_Qu(#e{x*30hp#VT`-hjGbo&RBaZVF|q`L7jA{sJM zNZaJYUSnKe3e&P7g{F*~cDVm~|BjcO%G60=Jo>)u+VVoh#1+6nl`UBQmCqa zjCH-RrsDFiz4qG3b@b!V^*iFKVd6~xb#EPgjw6xux$DQC&H57k+^dI@>c>Den0ul5*wn$M z9M|)(zTKrum-?@z^N$o(Eq(4b;lcW`+AFLtg(>Dbw>p&%A^cCuVk-SEjOO289j|{X z+pdJ|?}j5>L_|bHL_`UbjY$v!%u$n{Ni_nNLX*}>H-9$g`J^*&5>Ygca1jv^5fKq3 zgdHv-A|fIpqJ&t76iQh^di!(6iXt zw!dejw7*n0*LJW8Pm<`Fd0e-v(?5&2+Fz%C7IC$|l#NYd6Fwx>K@YW(vheAo&rUB# z52KRGaa+w`DY2Q{*{1z%!r{s@szo0guIC@At#nfRSJQ4f{d2U*j3BpGs#KC&|#C7~j?Qiot;u_Ma|6Yu?-(Oz;gm0JaA5Ln2Tayt}6Mtcr zLZXD}VI)#`iIknpH9W~Cq({oY7MG+m-MMnj@Mbe%t__=VY(8t9&F8CgJ+9)~cZoCs zcP+CC*>Yu*Rc|QS)Tb6cFPlt~HpjfpI(imaX+m=;%cadZN6KDklburH8ai8R$01QY z;|LcK5fKp)Q9{_^A|fIpA|gtNb$>{ql)Yp}r#btFl#N8J$hdZMIr}?|%U!dqNTlp5 zayf2UTwJrYNXyy&{+6A}skQc(LSHVv_+tOHlpW4>Qe&HmW%X^@gp*0@NTGvqm9OuM z&Zhn2nhe?|Y)NMmie{4uP&aMjxX5*MQrN01*W+Ibk<#~9|BT`~|43ZhO-euBTr*qR zOnfYn!p~gm;~J{!+Wr#Pc9z(j|MfPp2@#Y+BIC+JDP_5oCOdX5Uq2p__$|=Y>+i3G z*FWLQ+5Y~PjZ1g#ebs7vlTlX}f9SX)rmi;qVMphF;~QK<)5FV(ca z>pt2{P^*WH=^=$u``aA<`e$TQj!hVqYx_&vwP}Bwu*oFOKh?CG&G*GdI5o$-{$A<) zV^bfS<5oZC=v>b~QoHG-bB?Z>^S{mUub=;`IoIh~0j2DJNt{bvC(G99pAmn5J+l){ z^$&k;L+o|<|Lxu3vs`C+81R)P3#q-g$dW002ovPDHLkV1o2?%FX}) diff --git a/media-layer/core/src/audio/api.cpp b/media-layer/core/src/audio/api.cpp index 1aceb04a..44fe4fdf 100644 --- a/media-layer/core/src/audio/api.cpp +++ b/media-layer/core/src/audio/api.cpp @@ -25,90 +25,96 @@ static std::vector &get_sources() { // Update Listener void media_audio_update(float volume, float x, float y, float z, float yaw) { - // Update Listener Volume - alListenerf(AL_GAIN, volume); - AL_ERROR_CHECK(); + // Check + if (_media_audio_is_loaded()) { + // Update Listener Volume + alListenerf(AL_GAIN, volume); + AL_ERROR_CHECK(); - // Update Listener Position - alListener3f(AL_POSITION, x, y, z); - AL_ERROR_CHECK(); + // Update Listener Position + alListener3f(AL_POSITION, x, y, z); + AL_ERROR_CHECK(); - // Update Listener Orientation - float radian_yaw = yaw * (M_PI / 180); - ALfloat orientation[] = {-sinf(radian_yaw), 0.0f, cosf(radian_yaw), 0.0f, 1.0f, 0.0f}; - alListenerfv(AL_ORIENTATION, orientation); - AL_ERROR_CHECK(); + // Update Listener Orientation + float radian_yaw = yaw * (M_PI / 180); + ALfloat orientation[] = {-sinf(radian_yaw), 0.0f, cosf(radian_yaw), 0.0f, 1.0f, 0.0f}; + alListenerfv(AL_ORIENTATION, orientation); + AL_ERROR_CHECK(); - // Clear Finished Sources - std::vector::iterator it = get_sources().begin(); - while (it != get_sources().end()) { - ALuint source = *it; - bool remove = false; - // Check - if (source && alIsSource(source)) { - // Is Valid Source - ALint source_state; - alGetSourcei(source, AL_SOURCE_STATE, &source_state); - AL_ERROR_CHECK(); - if (source_state != AL_PLAYING) { - // Finished Playing - remove = true; - alDeleteSources(1, &source); + // Clear Finished Sources + std::vector::iterator it = get_sources().begin(); + while (it != get_sources().end()) { + ALuint source = *it; + bool remove = false; + // Check + if (source && alIsSource(source)) { + // Is Valid Source + ALint source_state; + alGetSourcei(source, AL_SOURCE_STATE, &source_state); AL_ERROR_CHECK(); + if (source_state != AL_PLAYING) { + // Finished Playing + remove = true; + alDeleteSources(1, &source); + AL_ERROR_CHECK(); + } + } else { + // Not A Source + remove = true; + } + // Remove If Needed + if (remove) { + it = get_sources().erase(it); + } else { + ++it; } - } else { - // Not A Source - remove = true; - } - // Remove If Needed - if (remove) { - it = get_sources().erase(it); - } else { - ++it; } } } void media_audio_play(const char *source, const char *name, float x, float y, float z, float pitch, float volume, int is_ui) { - // Load Sound - ALuint buffer = _media_audio_get_buffer(source, name); - if (volume > 0.0f && buffer) { - // Create Source - ALuint al_source; - alGenSources(1, &al_source); - AL_ERROR_CHECK(); + // Check + if (_media_audio_is_loaded()) { + // Load Sound + ALuint buffer = _media_audio_get_buffer(source, name); + if (volume > 0.0f && buffer) { + // Create Source + ALuint al_source; + alGenSources(1, &al_source); + AL_ERROR_CHECK(); - // Set Properties - alSourcef(al_source, AL_PITCH, pitch); - AL_ERROR_CHECK(); - alSourcef(al_source, AL_GAIN, volume); - AL_ERROR_CHECK(); - alSource3f(al_source, AL_POSITION, x, y, z); - AL_ERROR_CHECK(); - alSource3f(al_source, AL_VELOCITY, 0, 0, 0); - AL_ERROR_CHECK(); - alSourcei(al_source, AL_LOOPING, AL_FALSE); - AL_ERROR_CHECK(); - alSourcei(al_source, AL_SOURCE_RELATIVE, is_ui ? AL_TRUE : AL_FALSE); - AL_ERROR_CHECK(); + // Set Properties + alSourcef(al_source, AL_PITCH, pitch); + AL_ERROR_CHECK(); + alSourcef(al_source, AL_GAIN, volume); + AL_ERROR_CHECK(); + alSource3f(al_source, AL_POSITION, x, y, z); + AL_ERROR_CHECK(); + alSource3f(al_source, AL_VELOCITY, 0, 0, 0); + AL_ERROR_CHECK(); + alSourcei(al_source, AL_LOOPING, AL_FALSE); + AL_ERROR_CHECK(); + alSourcei(al_source, AL_SOURCE_RELATIVE, is_ui ? AL_TRUE : AL_FALSE); + AL_ERROR_CHECK(); - // Set Attenuation - alSourcei(al_source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE); - AL_ERROR_CHECK(); - alSourcef(al_source, AL_MAX_DISTANCE, 16.0f); - AL_ERROR_CHECK(); - alSourcef(al_source, AL_ROLLOFF_FACTOR, 1.0f); - AL_ERROR_CHECK(); - alSourcef(al_source, AL_REFERENCE_DISTANCE, 0.0f); - AL_ERROR_CHECK(); + // Set Attenuation + alSourcei(al_source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE); + AL_ERROR_CHECK(); + alSourcef(al_source, AL_MAX_DISTANCE, 16.0f); + AL_ERROR_CHECK(); + alSourcef(al_source, AL_ROLLOFF_FACTOR, 1.0f); + AL_ERROR_CHECK(); + alSourcef(al_source, AL_REFERENCE_DISTANCE, 0.0f); + AL_ERROR_CHECK(); - // Set Buffer - alSourcei(al_source, AL_BUFFER, buffer); - AL_ERROR_CHECK(); + // Set Buffer + alSourcei(al_source, AL_BUFFER, buffer); + AL_ERROR_CHECK(); - // Play - alSourcePlay(al_source); - AL_ERROR_CHECK(); - get_sources().push_back(al_source); + // Play + alSourcePlay(al_source); + AL_ERROR_CHECK(); + get_sources().push_back(al_source); + } } } diff --git a/mods/src/server/server.cpp b/mods/src/server/server.cpp index 9b4468c6..ba898f95 100644 --- a/mods/src/server/server.cpp +++ b/mods/src/server/server.cpp @@ -292,7 +292,6 @@ static void *read_stdin_thread(__attribute__((unused)) void *data) { stdin_buffer = strdup(""); } stdin_buffer_complete = true; - break; } else { string_append((char **) &stdin_buffer, "%c", (char) x); } From 28424aa86ad0ac6af3b163c723c9106440dc39f4 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Tue, 12 Oct 2021 16:13:11 -0400 Subject: [PATCH 09/28] Faster Build --- dependencies/libpng/CMakeLists.txt | 2 +- dependencies/zlib/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies/libpng/CMakeLists.txt b/dependencies/libpng/CMakeLists.txt index b6560a0d..0ba4b3e9 100644 --- a/dependencies/libpng/CMakeLists.txt +++ b/dependencies/libpng/CMakeLists.txt @@ -18,7 +18,7 @@ FetchContent_Populate(libpng) set(ZLIB_LIBRARY zlib) set(ZLIB_INCLUDE_DIR "${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}") set(CMAKE_POLICY_DEFAULT_CMP0054 OLD) # Silence Warning -add_subdirectory("${libpng_SOURCE_DIR}" "${libpng_BINARY_DIR}") +add_subdirectory("${libpng_SOURCE_DIR}" "${libpng_BINARY_DIR}" EXCLUDE_FROM_ALL) set(CMAKE_POLICY_DEFAULT_CMP0054 NEW) # Re-Enable New Behavior set_target_properties(png12 PROPERTIES LINK_FLAGS "-Wl,--version-script='${CMAKE_CURRENT_SOURCE_DIR}/libpng.vers'") # Use Symbol Versioning set_target_properties(png12 PROPERTIES DEBUG_POSTFIX "") # Fix LibPNG Suffix In Debug Mode diff --git a/dependencies/zlib/CMakeLists.txt b/dependencies/zlib/CMakeLists.txt index 04cfd399..f5fdf842 100644 --- a/dependencies/zlib/CMakeLists.txt +++ b/dependencies/zlib/CMakeLists.txt @@ -16,7 +16,7 @@ FetchContent_Declare( ) FetchContent_Populate(zlib) include_directories("${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}") # Fix ZLib Build -add_subdirectory("${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}") +add_subdirectory("${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}" EXCLUDE_FROM_ALL) # Install install(TARGETS zlib DESTINATION "${MCPI_LIB_DIR}") From f2bd893241d575f89a7a375fec969b51f96808f4 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Fri, 22 Oct 2021 17:28:26 -0400 Subject: [PATCH 10/28] Fix Build (Finally) --- dependencies/libpng/CMakeLists.txt | 3 ++- dependencies/zlib/CMakeLists.txt | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dependencies/libpng/CMakeLists.txt b/dependencies/libpng/CMakeLists.txt index 0ba4b3e9..234db5e6 100644 --- a/dependencies/libpng/CMakeLists.txt +++ b/dependencies/libpng/CMakeLists.txt @@ -8,7 +8,6 @@ add_compile_options(-w) ## LibPNG # Download -set(SKIP_INSTALL_ALL TRUE) # Skip Default LibPNG Installation FetchContent_Declare( libpng GIT_REPOSITORY "https://github.com/glennrp/libpng.git" @@ -23,6 +22,8 @@ set(CMAKE_POLICY_DEFAULT_CMP0054 NEW) # Re-Enable New Behavior set_target_properties(png12 PROPERTIES LINK_FLAGS "-Wl,--version-script='${CMAKE_CURRENT_SOURCE_DIR}/libpng.vers'") # Use Symbol Versioning set_target_properties(png12 PROPERTIES DEBUG_POSTFIX "") # Fix LibPNG Suffix In Debug Mode +# Ensure Build +set_target_properties(png12 PROPERTIES EXCLUDE_FROM_ALL FALSE) # Install install(TARGETS png12 DESTINATION "${MCPI_LIB_DIR}") diff --git a/dependencies/zlib/CMakeLists.txt b/dependencies/zlib/CMakeLists.txt index f5fdf842..09c0c364 100644 --- a/dependencies/zlib/CMakeLists.txt +++ b/dependencies/zlib/CMakeLists.txt @@ -8,7 +8,6 @@ add_compile_options(-w) ## zlib # Download -set(SKIP_INSTALL_ALL TRUE) # Skip Default ZLib Installation FetchContent_Declare( zlib GIT_REPOSITORY "https://github.com/madler/zlib.git" @@ -18,6 +17,8 @@ FetchContent_Populate(zlib) include_directories("${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}") # Fix ZLib Build add_subdirectory("${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}" EXCLUDE_FROM_ALL) +# Ensure Build +set_target_properties(zlib PROPERTIES EXCLUDE_FROM_ALL FALSE) # Install install(TARGETS zlib DESTINATION "${MCPI_LIB_DIR}") From 28a6d59c2d80d7a93aea654a9431c73bb0e4f1c2 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Fri, 22 Oct 2021 18:36:09 -0400 Subject: [PATCH 11/28] Fix Build Better --- dependencies/libpng/CMakeLists.txt | 2 +- dependencies/zlib/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies/libpng/CMakeLists.txt b/dependencies/libpng/CMakeLists.txt index 234db5e6..ce78ef14 100644 --- a/dependencies/libpng/CMakeLists.txt +++ b/dependencies/libpng/CMakeLists.txt @@ -23,7 +23,7 @@ set_target_properties(png12 PROPERTIES LINK_FLAGS "-Wl,--version-script='${CMAKE set_target_properties(png12 PROPERTIES DEBUG_POSTFIX "") # Fix LibPNG Suffix In Debug Mode # Ensure Build -set_target_properties(png12 PROPERTIES EXCLUDE_FROM_ALL FALSE) +add_custom_target(png12-build ALL DEPENDS png12) # Install install(TARGETS png12 DESTINATION "${MCPI_LIB_DIR}") diff --git a/dependencies/zlib/CMakeLists.txt b/dependencies/zlib/CMakeLists.txt index 09c0c364..d3500a5f 100644 --- a/dependencies/zlib/CMakeLists.txt +++ b/dependencies/zlib/CMakeLists.txt @@ -18,7 +18,7 @@ include_directories("${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}") # Fix ZLib Build add_subdirectory("${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}" EXCLUDE_FROM_ALL) # Ensure Build -set_target_properties(zlib PROPERTIES EXCLUDE_FROM_ALL FALSE) +add_custom_target(zlib-build ALL DEPENDS zlib) # Install install(TARGETS zlib DESTINATION "${MCPI_LIB_DIR}") From 1daede7dba20c702e8d3c1700c3539977cdb004a Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Fri, 22 Oct 2021 22:39:26 -0400 Subject: [PATCH 12/28] Fix ARM Toolchain On Some Devices --- cmake/arm-toolchain.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/arm-toolchain.cmake b/cmake/arm-toolchain.cmake index 9ffecead..f233f4e2 100644 --- a/cmake/arm-toolchain.cmake +++ b/cmake/arm-toolchain.cmake @@ -2,7 +2,7 @@ if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "aarch64_be" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "armv8b" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "armv8l") # Force 32-Bit Compile add_compile_options("-m32") -elseif(NOT CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm") +elseif((NOT CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm") AND (NOT CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "armv7l")) # Use ARM Cross-Compiler include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake") setup_toolchain("arm-linux-gnueabihf") From 12de038f37133a7902750c4436740018a9ab7f37 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Wed, 27 Oct 2021 18:14:30 -0400 Subject: [PATCH 13/28] Improve Patch Comment --- media-layer/core/src/media.c | 4 ++++ mods/src/options/options.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/media-layer/core/src/media.c b/media-layer/core/src/media.c index d2143784..d09fa32b 100644 --- a/media-layer/core/src/media.c +++ b/media-layer/core/src/media.c @@ -76,6 +76,10 @@ static SDLKey glfw_key_to_sdl_key(int key) { return SDLK_7; case GLFW_KEY_8: return SDLK_8; + case GLFW_KEY_9: + return SDLK_9; + case GLFW_KEY_0: + return SDLK_0; // UI Control case GLFW_KEY_ESCAPE: return SDLK_ESCAPE; diff --git a/mods/src/options/options.c b/mods/src/options/options.c index ab2d9875..e6cddabc 100644 --- a/mods/src/options/options.c +++ b/mods/src/options/options.c @@ -107,6 +107,8 @@ void init_options() { } // Display Nametags By Default if (feature_has("Display Nametags By Default", 0)) { + // r6 = 0x1 + // r5 = 0x0 unsigned char display_nametags_patch[4] = {0x1d, 0x60, 0xc0, 0xe5}; // "strb r6, [r0, #0x1d]" patch((void *) 0xa6628, display_nametags_patch); } From 9ad6cc3906aa3760a74f5b9df0d8724b114c633a Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Thu, 28 Oct 2021 19:21:07 -0400 Subject: [PATCH 14/28] Add Tile Symbols --- symbols/include/symbols/minecraft.h | 90 ++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 27 deletions(-) diff --git a/symbols/include/symbols/minecraft.h b/symbols/include/symbols/minecraft.h index deb78cf8..598bee28 100644 --- a/symbols/include/symbols/minecraft.h +++ b/symbols/include/symbols/minecraft.h @@ -19,38 +19,38 @@ 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; -static unsigned char **Item_shears = (unsigned char **) 0x17bbf0; -static unsigned char **Item_egg = (unsigned char **) 0x17bbd0; -static unsigned char **Item_dye_powder = (unsigned char **) 0x17bbe0; -static unsigned char **Item_camera = (unsigned char **) 0x17bc14; +static unsigned char **Material_stone = (unsigned char **) 0x180a9c; // Material -static unsigned char **Tile_water = (unsigned char **) 0x181b3c; -static unsigned char **Tile_lava = (unsigned char **) 0x181cc8; -static unsigned char **Tile_calmWater = (unsigned char **) 0x181b40; -static unsigned char **Tile_calmLava = (unsigned char **) 0x181ccc; -static unsigned char **Tile_glowingObsidian = (unsigned char **) 0x181dcc; -static unsigned char **Tile_web = (unsigned char **) 0x181d08; -static unsigned char **Tile_topSnow = (unsigned char **) 0x181b30; -static unsigned char **Tile_ice = (unsigned char **) 0x181d80; -static unsigned char **Tile_invisible_bedrock = (unsigned char **) 0x181d94; -static unsigned char **Tile_netherReactor = (unsigned char **) 0x181dd0; -static unsigned char **Tile_info_updateGame1 = (unsigned char **) 0x181c68; -static unsigned char **Tile_info_updateGame2 = (unsigned char **) 0x181c6c; -static unsigned char **Tile_bedrock = (unsigned char **) 0x181cc4; +static unsigned char *SOUND_STONE = (unsigned char *) 0x181c80; // Tile::SoundType -static unsigned char **Tile_leaves = (unsigned char **) 0x18120c; -static unsigned char **Tile_leaves_carried = (unsigned char **) 0x181dd8; -static unsigned char **Tile_grass = (unsigned char **) 0x181b14; -static unsigned char **Tile_grass_carried = (unsigned char **) 0x181dd4; +static unsigned char **Item_flintAndSteel = (unsigned char **) 0x17ba70; // Item +static unsigned char **Item_snowball = (unsigned char **) 0x17bbb0; // Item +static unsigned char **Item_shears = (unsigned char **) 0x17bbf0; // Item +static unsigned char **Item_egg = (unsigned char **) 0x17bbd0; // Item +static unsigned char **Item_dye_powder = (unsigned char **) 0x17bbe0; // Item +static unsigned char **Item_camera = (unsigned char **) 0x17bc14; // Item + +static unsigned char **Tile_water = (unsigned char **) 0x181b3c; // Tile +static unsigned char **Tile_lava = (unsigned char **) 0x181cc8; // Tile +static unsigned char **Tile_calmWater = (unsigned char **) 0x181b40; // Tile +static unsigned char **Tile_calmLava = (unsigned char **) 0x181ccc; // Tile +static unsigned char **Tile_glowingObsidian = (unsigned char **) 0x181dcc; // Tile +static unsigned char **Tile_web = (unsigned char **) 0x181d08; // Tile +static unsigned char **Tile_topSnow = (unsigned char **) 0x181b30; // Tile +static unsigned char **Tile_ice = (unsigned char **) 0x181d80; // Tile +static unsigned char **Tile_invisible_bedrock = (unsigned char **) 0x181d94; // Tile +static unsigned char **Tile_netherReactor = (unsigned char **) 0x181dd0; // Tile +static unsigned char **Tile_info_updateGame1 = (unsigned char **) 0x181c68; // Tile +static unsigned char **Tile_info_updateGame2 = (unsigned char **) 0x181c6c; // Tile +static unsigned char **Tile_bedrock = (unsigned char **) 0x181cc4; // Tile + +static unsigned char **Tile_leaves = (unsigned char **) 0x18120c; // Tile +static unsigned char **Tile_leaves_carried = (unsigned char **) 0x181dd8; // Tile +static unsigned char **Tile_grass = (unsigned char **) 0x181b14; // Tile +static unsigned char **Tile_grass_carried = (unsigned char **) 0x181dd4; // Tile static float *InvGuiScale = (float *) 0x135d98; -// Tile - -static uint32_t Tile_id_property_offset = 0x8; - // Structures struct AABB { @@ -74,6 +74,37 @@ struct RakNet_SystemAddress { unsigned char data[20]; }; +// Tile + +typedef void (*Tile_initTiles_t)(); +static Tile_initTiles_t Tile_initTiles = (Tile_initTiles_t) 0xc358c; + +#define TILE_SIZE 0x5c +#define TILE_VTABLE_SIZE 0x104 + +static unsigned char *Tile_vtable = (unsigned char *) 0x115670; + +typedef unsigned char *(*Tile_t)(unsigned char *tile, int32_t id, int32_t texture, const void *material); +static Tile_t Tile = (Tile_t) 0xc33a0; + +typedef unsigned char *(*Tile_init_t)(unsigned char *tile); +static Tile_init_t Tile_init = (Tile_init_t) 0xc34dc; + +typedef unsigned char *(*Tile_setDestroyTime_t)(unsigned char *tile, float destroy_time); +static uint32_t Tile_setDestroyTime_vtable_offset = 0xf8; + +typedef unsigned char *(*Tile_setExplodeable_t)(unsigned char *tile, float explodeable); +static uint32_t Tile_setExplodeable_vtable_offset = 0xf4; + +typedef unsigned char *(*Tile_setSoundType_t)(unsigned char *tile, unsigned char *sound_type); +static uint32_t Tile_setSoundType_vtable_offset = 0xe8; + +typedef int32_t (*Tile_use_t)(unsigned char *tile, unsigned char *level, int32_t x, int32_t y, int32_t z, unsigned char *player); +static uint32_t Tile_use_vtable_offset = 0x98; + +static uint32_t Tile_id_property_offset = 0x8; // int32_t +static uint32_t Tile_category_property_offset = 0x3c; // int32_t + // GameMode typedef void (*GameMode_releaseUsingItem_t)(unsigned char *game_mode, unsigned char *player); @@ -579,6 +610,11 @@ struct ConnectedClient { long time; }; +// Tile + +typedef unsigned char *(*Tile_setDescriptionId_t)(unsigned char *tile, std::string const& description_id); +static uint32_t Tile_setDescriptionId_vtable_offset = 0xe0; + // AppPlatform typedef void (*AppPlatform_saveScreenshot_t)(unsigned char *app_platform, std::string const& path, int32_t width, int32_t height); From 05587efc0429c8944228afb084fc16379a0d03d0 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Thu, 28 Oct 2021 22:57:47 -0400 Subject: [PATCH 15/28] Fix CMake --- cmake/arm-toolchain.cmake | 6 +++--- cmake/arm64-toolchain.cmake | 4 ++-- cmake/base-toolchain.cmake | 4 ++++ cmake/x86_64-toolchain.cmake | 4 ++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/cmake/arm-toolchain.cmake b/cmake/arm-toolchain.cmake index f233f4e2..42a495f8 100644 --- a/cmake/arm-toolchain.cmake +++ b/cmake/arm-toolchain.cmake @@ -1,10 +1,10 @@ # Compile For ARM -if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "aarch64_be" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "armv8b" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "armv8l") +include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake") +if(HOST_ARCHITECTURE STREQUAL "aarch64_be" OR HOST_ARCHITECTURE STREQUAL "aarch64" OR HOST_ARCHITECTURE STREQUAL "armv8b" OR HOST_ARCHITECTURE STREQUAL "armv8l") # Force 32-Bit Compile add_compile_options("-m32") -elseif((NOT CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm") AND (NOT CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "armv7l")) +elseif((NOT HOST_ARCHITECTURE STREQUAL "arm") AND (NOT HOST_ARCHITECTURE STREQUAL "armv7l")) # Use ARM Cross-Compiler - include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake") setup_toolchain("arm-linux-gnueabihf") endif() set(CMAKE_SYSTEM_NAME "Linux") diff --git a/cmake/arm64-toolchain.cmake b/cmake/arm64-toolchain.cmake index 45cee3cd..c6d5fd2f 100644 --- a/cmake/arm64-toolchain.cmake +++ b/cmake/arm64-toolchain.cmake @@ -1,7 +1,7 @@ # Compile For ARM64 -if(NOT (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "aarch64_be" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "armv8b" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "armv8l")) +include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake") +if(NOT (HOST_ARCHITECTURE STREQUAL "aarch64_be" OR HOST_ARCHITECTURE STREQUAL "aarch64" OR HOST_ARCHITECTURE STREQUAL "armv8b" OR HOST_ARCHITECTURE STREQUAL "armv8l")) # Use ARM64 Cross-Compiler - include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake") setup_toolchain("aarch64-linux-gnu") endif() set(CMAKE_SYSTEM_NAME "Linux") diff --git a/cmake/base-toolchain.cmake b/cmake/base-toolchain.cmake index b5c8347e..94fdbc8c 100644 --- a/cmake/base-toolchain.cmake +++ b/cmake/base-toolchain.cmake @@ -1,3 +1,7 @@ +# Get Host Architecture +find_program(UNAME uname /bin /usr/bin /usr/local/bin REQUIRED) +execute_process(COMMAND "${UNAME}" "-m" OUTPUT_VARIABLE HOST_ARCHITECTURE ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + # Pick GCC Version macro(pick_gcc_version gcc_root gcc_version) file(GLOB children RELATIVE "${gcc_root}" "${gcc_root}/*") diff --git a/cmake/x86_64-toolchain.cmake b/cmake/x86_64-toolchain.cmake index 3ec02864..36ac8964 100644 --- a/cmake/x86_64-toolchain.cmake +++ b/cmake/x86_64-toolchain.cmake @@ -1,7 +1,7 @@ # Compile For x86_64 -if(NOT CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64") +include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake") +if(NOT HOST_ARCHITECTURE STREQUAL "x86_64") # Use x86_64 Cross-Compiler - include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake") setup_toolchain("x86_64-linux-gnu") endif() set(CMAKE_SYSTEM_NAME "Linux") From 16ebea9ed6a53174fe0b27946c3088a8b63689a0 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Tue, 2 Nov 2021 17:50:26 -0400 Subject: [PATCH 16/28] Even More Symbols --- CMakeLists.txt | 10 +++++----- symbols/include/symbols/minecraft.h | 3 +++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ef87af9d..05f1a3f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,11 @@ if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "/" CACHE PATH "" FORCE) endif() +# Use LLD When Using Clang +if(CMAKE_C_COMPILER_ID STREQUAL "Clang") + add_link_options("-fuse-ld=lld") +endif() + # Buld LibPNG + ZLib + Download Minecraft: Pi Edition if(BUILD_ARM_COMPONENTS) add_subdirectory(dependencies) @@ -84,11 +89,6 @@ add_definitions(-D_GNU_SOURCE) set(CMAKE_C_STANDARD 99) set(CMAKE_CXX_STANDARD 11) -# Use LLD When Using Clang -if(CMAKE_C_COMPILER_ID STREQUAL "Clang") - add_link_options("-fuse-ld=lld") -endif() - # Specify Constants if(MCPI_SERVER_MODE) add_definitions(-DMCPI_SERVER_MODE) diff --git a/symbols/include/symbols/minecraft.h b/symbols/include/symbols/minecraft.h index 598bee28..59856fa0 100644 --- a/symbols/include/symbols/minecraft.h +++ b/symbols/include/symbols/minecraft.h @@ -355,6 +355,9 @@ static LevelData_getSpawnMobs_t LevelData_getSpawnMobs = (LevelData_getSpawnMobs typedef void (*Level_saveLevelData_t)(unsigned char *level); static Level_saveLevelData_t Level_saveLevelData = (Level_saveLevelData_t) 0xa2e94; +typedef void (*Level_setTileAndData_t)(unsigned char *level, int32_t x, int32_t y, int32_t z, int32_t id, int32_t data); +static Level_setTileAndData_t Level_setTileAndData = (Level_setTileAndData_t) 0xa38b4; + static uint32_t Level_players_property_offset = 0x60; // std::vector // LevelRenderer From 51d7974ded5cffdde54e577a493f8d25afc4547f Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Sat, 6 Nov 2021 22:40:11 -0400 Subject: [PATCH 17/28] Fix Typo --- mods/src/atlas/atlas.cpp | 4 ++-- symbols/include/symbols/minecraft.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mods/src/atlas/atlas.cpp b/mods/src/atlas/atlas.cpp index a9ffd3de..ab5afd74 100644 --- a/mods/src/atlas/atlas.cpp +++ b/mods/src/atlas/atlas.cpp @@ -15,10 +15,10 @@ static float ItemRenderer_renderGuiItemCorrect_injection(unsigned char *font, un bool use_carried = false; if (item_instance != NULL) { if (item_instance->id == leaves_id) { - (*ItemInstance_constructor_tile_extra)(&carried_item_instance, *Tile_leaves_carried, item_instance->count, item_instance->auxilary); + (*ItemInstance_constructor_tile_extra)(&carried_item_instance, *Tile_leaves_carried, item_instance->count, item_instance->auxiliary); use_carried = true; } else if (item_instance->id == grass_id) { - (*ItemInstance_constructor_tile_extra)(&carried_item_instance, *Tile_grass_carried, item_instance->count, item_instance->auxilary); + (*ItemInstance_constructor_tile_extra)(&carried_item_instance, *Tile_grass_carried, item_instance->count, item_instance->auxiliary); use_carried = true; } } diff --git a/symbols/include/symbols/minecraft.h b/symbols/include/symbols/minecraft.h index 59856fa0..8673ffb5 100644 --- a/symbols/include/symbols/minecraft.h +++ b/symbols/include/symbols/minecraft.h @@ -252,14 +252,14 @@ static void *MouseBuildInput_tickBuild_vtable_addr = (void *) 0x102564; typedef struct { int32_t count; int32_t id; - int32_t auxilary; + int32_t auxiliary; } ItemInstance; typedef ItemInstance *(*ItemInstance_constructor_t)(ItemInstance *item_instance, unsigned char *item); static ItemInstance_constructor_t ItemInstance_constructor_item = (ItemInstance_constructor_t) 0x9992c; static ItemInstance_constructor_t ItemInstance_constructor_tile = (ItemInstance_constructor_t) 0x998e4; -typedef ItemInstance *(*ItemInstance_constructor_extra_t)(ItemInstance *item_instance, unsigned char *item, int32_t count, int32_t auxilary); +typedef ItemInstance *(*ItemInstance_constructor_extra_t)(ItemInstance *item_instance, unsigned char *item, int32_t count, int32_t auxiliary); static ItemInstance_constructor_extra_t ItemInstance_constructor_tile_extra = (ItemInstance_constructor_extra_t) 0x99918; static ItemInstance_constructor_extra_t ItemInstance_constructor_item_extra = (ItemInstance_constructor_extra_t) 0x99960; From 5cf4d7f91541a6f136153f4537f7abc9a336c45b Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Tue, 9 Nov 2021 16:26:02 -0500 Subject: [PATCH 18/28] Small Cleanup --- mods/src/home/home.c | 5 +---- mods/src/input/attack.c | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/mods/src/home/home.c b/mods/src/home/home.c index 5edbafb5..f5023095 100644 --- a/mods/src/home/home.c +++ b/mods/src/home/home.c @@ -13,16 +13,13 @@ #define NEW_PATH "" // Store Launch Directory -static char *get_launch_directory() { +__attribute__((constructor)) static char *get_launch_directory() { static char *launch_directory = NULL; if (launch_directory == NULL) { launch_directory = getcwd(NULL, 0); } return launch_directory; } -__attribute__((constructor)) static void init_launch_directory() { - get_launch_directory(); -} __attribute__((destructor)) static void free_launch_directory() { free(get_launch_directory()); } diff --git a/mods/src/input/attack.c b/mods/src/input/attack.c index c23c538e..38d4e911 100644 --- a/mods/src/input/attack.c +++ b/mods/src/input/attack.c @@ -33,6 +33,7 @@ static int32_t MouseBuildInput_tickBuild_injection(unsigned char *mouse_build_in is_left_click = 2; } + // Return return ret; } From e5fc2a61aaf66e25e9718651ee822633473ab5e3 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Wed, 10 Nov 2021 22:17:04 -0500 Subject: [PATCH 19/28] Revamp Packaging --- .gitignore | 10 +- CMakeLists.txt | 5 +- ...-toolchain.cmake => amd64-toolchain.cmake} | 7 +- cmake/arm-toolchain.cmake | 11 -- cmake/arm64-toolchain.cmake | 7 +- cmake/armhf-toolchain.cmake | 7 + cmake/base-toolchain.cmake | 121 +++++++++++++++--- cmake/i386-toolchain.cmake | 7 + debian/.gitignore | 6 + debian/client-arm | 7 - debian/client-arm64 | 7 - debian/client-x86_64 | 7 - debian/control | 21 +++ debian/copyright | 21 +++ debian/server-arm | 7 - debian/server-arm64 | 7 - debian/server-x86_64 | 7 - scripts/build-all.sh | 14 -- scripts/build.sh | 6 +- scripts/ci/run.sh | 11 +- scripts/install-dependencies.sh | 5 + scripts/package.sh | 41 ++---- scripts/test.sh | 2 +- 23 files changed, 204 insertions(+), 140 deletions(-) rename cmake/{x86_64-toolchain.cmake => amd64-toolchain.cmake} (54%) delete mode 100644 cmake/arm-toolchain.cmake create mode 100644 cmake/armhf-toolchain.cmake create mode 100644 cmake/i386-toolchain.cmake create mode 100644 debian/.gitignore delete mode 100644 debian/client-arm delete mode 100644 debian/client-arm64 delete mode 100644 debian/client-x86_64 create mode 100644 debian/control create mode 100644 debian/copyright delete mode 100644 debian/server-arm delete mode 100644 debian/server-arm64 delete mode 100644 debian/server-x86_64 delete mode 100755 scripts/build-all.sh diff --git a/.gitignore b/.gitignore index 95c2f476..58bbd335 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ -/out -/debian/tmp -/.vscode -/build -/CMakeLists.txt.user +out +debian/tmp +.vscode +build +CMakeLists.txt.user *.autosave diff --git a/CMakeLists.txt b/CMakeLists.txt index 05f1a3f5..10923182 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ endif() # Setup ARM Cross Compilation if(USE_ARM32_TOOLCHAIN) - include(cmake/arm-toolchain.cmake) + include(cmake/armhf-toolchain.cmake) endif() # Utility Functions @@ -77,6 +77,9 @@ if(CMAKE_C_COMPILER_ID STREQUAL "Clang") add_link_options("-fuse-ld=lld") endif() +# PIC +set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) + # Buld LibPNG + ZLib + Download Minecraft: Pi Edition if(BUILD_ARM_COMPONENTS) add_subdirectory(dependencies) diff --git a/cmake/x86_64-toolchain.cmake b/cmake/amd64-toolchain.cmake similarity index 54% rename from cmake/x86_64-toolchain.cmake rename to cmake/amd64-toolchain.cmake index 36ac8964..145f4911 100644 --- a/cmake/x86_64-toolchain.cmake +++ b/cmake/amd64-toolchain.cmake @@ -1,8 +1,7 @@ # Compile For x86_64 include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake") -if(NOT HOST_ARCHITECTURE STREQUAL "x86_64") - # Use x86_64 Cross-Compiler - setup_toolchain("x86_64-linux-gnu") -endif() +# Use x86_64 Cross-Compiler +setup_toolchain("x86_64-linux-gnu") +# Details set(CMAKE_SYSTEM_NAME "Linux") set(CMAKE_SYSTEM_PROCESSOR "x86_64") diff --git a/cmake/arm-toolchain.cmake b/cmake/arm-toolchain.cmake deleted file mode 100644 index 42a495f8..00000000 --- a/cmake/arm-toolchain.cmake +++ /dev/null @@ -1,11 +0,0 @@ -# Compile For ARM -include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake") -if(HOST_ARCHITECTURE STREQUAL "aarch64_be" OR HOST_ARCHITECTURE STREQUAL "aarch64" OR HOST_ARCHITECTURE STREQUAL "armv8b" OR HOST_ARCHITECTURE STREQUAL "armv8l") - # Force 32-Bit Compile - add_compile_options("-m32") -elseif((NOT HOST_ARCHITECTURE STREQUAL "arm") AND (NOT HOST_ARCHITECTURE STREQUAL "armv7l")) - # Use ARM Cross-Compiler - setup_toolchain("arm-linux-gnueabihf") -endif() -set(CMAKE_SYSTEM_NAME "Linux") -set(CMAKE_SYSTEM_PROCESSOR "arm") diff --git a/cmake/arm64-toolchain.cmake b/cmake/arm64-toolchain.cmake index c6d5fd2f..9671e40a 100644 --- a/cmake/arm64-toolchain.cmake +++ b/cmake/arm64-toolchain.cmake @@ -1,8 +1,7 @@ # Compile For ARM64 include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake") -if(NOT (HOST_ARCHITECTURE STREQUAL "aarch64_be" OR HOST_ARCHITECTURE STREQUAL "aarch64" OR HOST_ARCHITECTURE STREQUAL "armv8b" OR HOST_ARCHITECTURE STREQUAL "armv8l")) - # Use ARM64 Cross-Compiler - setup_toolchain("aarch64-linux-gnu") -endif() +# Use ARM64 Cross-Compiler +setup_toolchain("aarch64-linux-gnu") +# Details set(CMAKE_SYSTEM_NAME "Linux") set(CMAKE_SYSTEM_PROCESSOR "aarch64") diff --git a/cmake/armhf-toolchain.cmake b/cmake/armhf-toolchain.cmake new file mode 100644 index 00000000..efcd9ddf --- /dev/null +++ b/cmake/armhf-toolchain.cmake @@ -0,0 +1,7 @@ +# Compile For ARM +include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake") +# Use ARM Cross-Compiler +setup_toolchain("arm-linux-gnueabihf") +# Details +set(CMAKE_SYSTEM_NAME "Linux") +set(CMAKE_SYSTEM_PROCESSOR "arm") diff --git a/cmake/base-toolchain.cmake b/cmake/base-toolchain.cmake index 94fdbc8c..fd5825b1 100644 --- a/cmake/base-toolchain.cmake +++ b/cmake/base-toolchain.cmake @@ -2,19 +2,103 @@ find_program(UNAME uname /bin /usr/bin /usr/local/bin REQUIRED) execute_process(COMMAND "${UNAME}" "-m" OUTPUT_VARIABLE HOST_ARCHITECTURE ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) -# Pick GCC Version -macro(pick_gcc_version gcc_root gcc_version) - file(GLOB children RELATIVE "${gcc_root}" "${gcc_root}/*") - set("${gcc_version}" "") - foreach(child IN LISTS children) - if(IS_DIRECTORY "${gcc_root}/${child}" AND ("${${gcc_version}}" STREQUAL "" OR "${child}" GREATER_EQUAL "${${gcc_version}}")) - set("${gcc_version}" "${child}") +# Get Include Directories +function(get_include_dirs target compiler result) + # Get Tool Name + set(tool "cc1") + if(compiler MATCHES "^.*g\\+\\+$") + set(tool "cc1plus") + endif() + + # Get Tool Path + execute_process( + COMMAND "${compiler}" "-print-prog-name=${tool}" + ERROR_QUIET + OUTPUT_VARIABLE tool + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + # Run Tool To Get Include Path + set(tool_output "") + execute_process( + COMMAND "${tool}" "-quiet" "-v" "-imultiarch" "${target}" + OUTPUT_QUIET + ERROR_VARIABLE tool_output + ERROR_STRIP_TRAILING_WHITESPACE + INPUT_FILE "/dev/null" + ) + string(REPLACE "\n" ";" tool_output "${tool_output}") + + # Loop + set(parsing_include_section FALSE) + foreach(line IN LISTS tool_output) + # Check Include Section Status + if(parsing_include_section) + # Check If Include Section Is Over + if(line MATCHES "^End of search list.$") + # Starting Include Section + set(parsing_include_section FALSE) + break() + else() + # Parsing Include Section + if(line MATCHES "^ .*$") + # Strip Line + string(STRIP "${line}" line) + # Add To List + list(APPEND "${result}" "${line}") + endif() + endif() + else() + # Check If Include Section Is Starting + if(line MATCHES "^#include <\\.\\.\\.> search starts here:$") + # Starting Include Section + set(parsing_include_section TRUE) + endif() endif() endforeach() - if("${${gcc_version}}" STREQUAL "") - message(FATAL_ERROR "Unable To Pick GCC Version") + + # Return + set("${result}" "${${result}}" PARENT_SCOPE) +endfunction() + +# Get GCC Prefix +function(get_gcc_prefix target result) + # Get Default Target + set("${result}" "" PARENT_SCOPE) + set(output "") + execute_process( + COMMAND "gcc" "-dumpmachine" + ERROR_QUIET + OUTPUT_VARIABLE output + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + # Check + if(NOT output STREQUAL target) + set("${result}" "${target}-" PARENT_SCOPE) endif() -endmacro() +endfunction() + +# Setup Include Directories +function(setup_include_dirs compiler target result) + # Get Full Compiler + set(prefix "") + get_gcc_prefix("${target}" prefix) + set(full_compiler "${prefix}${compiler}") + + # Get Include Directories + set(include_dirs "") + get_include_dirs("${target}" "${full_compiler}" include_dirs) + + # Loop + set(flags "") + foreach(include_dir IN LISTS include_dirs) + set(flags "${flags} -isystem ${include_dir}") + endforeach() + + # Return + set("${result}" "${${result}} ${flags}" PARENT_SCOPE) +endfunction() # Setup Toolchain macro(setup_toolchain target) @@ -24,20 +108,17 @@ macro(setup_toolchain target) set(CMAKE_CXX_COMPILER "clang++") set(CMAKE_CXX_COMPILER_TARGET "${target}") set(CMAKE_FIND_ROOT_PATH "/usr/${target}" "/usr/lib/${target}") - # Include Directories - pick_gcc_version("/usr/lib/gcc-cross/${target}" GCC_VERSION) + # Flags string(CONCAT NEW_FLAGS - "-nostdinc -nostdinc++ -Wno-unused-command-line-argument " - "-isystem /usr/${target}/include/c++/${GCC_VERSION} " - "-isystem /usr/${target}/include/c++/${GCC_VERSION}/${target} " - "-isystem /usr/${target}/include/c++/${GCC_VERSION}/backward " - "-isystem /usr/lib/gcc-cross/${target}/${GCC_VERSION}/include " - "-isystem /usr/lib/gcc-cross/${target}/${GCC_VERSION}/include-fixed " - "-isystem /usr/${target}/include " - "-isystem /usr/include" + "-nostdinc " + "-nostdinc++ " + "-Wno-unused-command-line-argument" ) set(CMAKE_C_FLAGS_INIT "${CMAKE_C_FLAGS_INIT} ${NEW_FLAGS}") set(CMAKE_CXX_FLAGS_INIT "${CMAKE_CXX_FLAGS_INIT} ${NEW_FLAGS}") + # Include Directories + setup_include_dirs("gcc" "${target}" CMAKE_C_FLAGS_INIT) + setup_include_dirs("g++" "${target}" CMAKE_CXX_FLAGS_INIT) # Extra set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) endmacro() diff --git a/cmake/i386-toolchain.cmake b/cmake/i386-toolchain.cmake new file mode 100644 index 00000000..5ae20546 --- /dev/null +++ b/cmake/i386-toolchain.cmake @@ -0,0 +1,7 @@ +# Compile For i386 +include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake") +# Use i386 Cross-Compiler +setup_toolchain("i386-linux-gnu") +# Details +set(CMAKE_SYSTEM_NAME "Linux") +set(CMAKE_SYSTEM_PROCESSOR "i386") diff --git a/debian/.gitignore b/debian/.gitignore new file mode 100644 index 00000000..07a6ac7b --- /dev/null +++ b/debian/.gitignore @@ -0,0 +1,6 @@ +* +!control +!copyright +!rukes +!source +!.gitignore diff --git a/debian/client-arm b/debian/client-arm deleted file mode 100644 index 7d98f969..00000000 --- a/debian/client-arm +++ /dev/null @@ -1,7 +0,0 @@ -Package: minecraft-pi-reborn-client -Version: ${VERSION} -Maintainer: TheBrokenRail -Description: Fun with Blocks -Homepage: https://www.minecraft.net/en-us/edition/pi -Architecture: armhf -Depends: libc6, libstdc++6, zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3, libopenal1 diff --git a/debian/client-arm64 b/debian/client-arm64 deleted file mode 100644 index d89a362a..00000000 --- a/debian/client-arm64 +++ /dev/null @@ -1,7 +0,0 @@ -Package: minecraft-pi-reborn-client -Version: ${VERSION} -Maintainer: TheBrokenRail -Description: Fun with Blocks -Homepage: https://www.minecraft.net/en-us/edition/pi -Architecture: arm64 -Depends: libc6, libstdc++6, libc6:armhf, libstdc++6:armhf, zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3, libopenal1 diff --git a/debian/client-x86_64 b/debian/client-x86_64 deleted file mode 100644 index 59d8eafc..00000000 --- a/debian/client-x86_64 +++ /dev/null @@ -1,7 +0,0 @@ -Package: minecraft-pi-reborn-client -Version: ${VERSION} -Maintainer: TheBrokenRail -Description: Fun with Blocks -Homepage: https://www.minecraft.net/en-us/edition/pi -Architecture: amd64 -Depends: libc6, libstdc++6, libc6-armhf-cross, libstdc++6-armhf-cross, zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3, libopenal1, qemu-user-static diff --git a/debian/control b/debian/control new file mode 100644 index 00000000..bbee0322 --- /dev/null +++ b/debian/control @@ -0,0 +1,21 @@ +Source: minecraft-pi-reborn +Section: games +Priority: optional +Maintainer: TheBrokenRail +Build-Depends: debhelper-compat (= 12), clang:native, lld:native, cmake, make:native, libglfw3, libglfw3-dev, libfreeimage3, libfreeimage-dev:native, libopenal1, libopenal-dev, crossbuild-essential-armhf +Standards-Version: 4.4.1 +Homepage: https://www.minecraft.net/en-us/edition/pi +Vcs-Browser: https://gitea.thebrokenrail.com/TheBrokenRail/minecraft-pi-reborn +Vcs-Git: https://gitea.thebrokenrail.com/TheBrokenRail/minecraft-pi-reborn.git + +Package: minecraft-pi-reborn-client +Architecture: amd64 i386 arm64 armhf +Multi-Arch: foreign +Depends: libc6, libstdc++6, libc6-armhf-cross [!arm64 !armhf], libstdc++6-armhf-cross [!arm64 !armhf], zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3, libopenal1, qemu-user-static [!arm64 !armhf] +Description: Fun with Blocks + +Package: minecraft-pi-reborn-server +Architecture: amd64 i386 arm64 armhf +Multi-Arch: foreign +Depends: libc6, libstdc++6, libc6-armhf-cross [!arm64 !armhf], libstdc++6-armhf-cross [!arm64 !armhf], qemu-user-static [!arm64 !armhf] +Description: Fun with Blocks (Dedicated Server) diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 00000000..2bad0ca1 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 TheBrokenRail + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/debian/server-arm b/debian/server-arm deleted file mode 100644 index 697b4ec3..00000000 --- a/debian/server-arm +++ /dev/null @@ -1,7 +0,0 @@ -Package: minecraft-pi-reborn-server -Version: ${VERSION} -Maintainer: TheBrokenRail -Description: Fun with Blocks -Homepage: https://www.minecraft.net/en-us/edition/pi -Architecture: armhf -Depends: libc6, libstdc++6 diff --git a/debian/server-arm64 b/debian/server-arm64 deleted file mode 100644 index 5bd4d13f..00000000 --- a/debian/server-arm64 +++ /dev/null @@ -1,7 +0,0 @@ -Package: minecraft-pi-reborn-server -Version: ${VERSION} -Maintainer: TheBrokenRail -Description: Fun with Blocks -Homepage: https://www.minecraft.net/en-us/edition/pi -Architecture: arm64 -Depends: libc6, libstdc++6, libc6:armhf, libstdc++6:armhf diff --git a/debian/server-x86_64 b/debian/server-x86_64 deleted file mode 100644 index 5c9e71b2..00000000 --- a/debian/server-x86_64 +++ /dev/null @@ -1,7 +0,0 @@ -Package: minecraft-pi-reborn-server -Version: ${VERSION} -Maintainer: TheBrokenRail -Description: Fun with Blocks -Homepage: https://www.minecraft.net/en-us/edition/pi -Architecture: amd64 -Depends: libc6, libstdc++6, libc6-armhf-cross, libstdc++6-armhf-cross, qemu-user-static diff --git a/scripts/build-all.sh b/scripts/build-all.sh deleted file mode 100755 index aa60a372..00000000 --- a/scripts/build-all.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -set -e - -# Clean Prefix -rm -rf out - -# Build -./scripts/build.sh client x86_64 -./scripts/build.sh server x86_64 -./scripts/build.sh client arm64 -./scripts/build.sh server arm64 -./scripts/build.sh client arm -./scripts/build.sh server arm diff --git a/scripts/build.sh b/scripts/build.sh index 031baca9..a682567c 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -48,7 +48,7 @@ build() { } # Build For ARM -arm_build() { +armhf_build() { # Create Build Dir rm -rf "build/$1-arm" mkdir -p "build/$1-arm" @@ -81,8 +81,8 @@ if [ "$1" != "client" ] && [ "$1" != "server" ]; then fi # Build -if [ "$2" = "arm" ]; then - arm_build "$1" +if [ "$2" = "armhf" ]; then + armhf_build "$1" else build "$1" "$2" fi diff --git a/scripts/ci/run.sh b/scripts/ci/run.sh index 937904f5..61017d4e 100755 --- a/scripts/ci/run.sh +++ b/scripts/ci/run.sh @@ -14,13 +14,12 @@ echo '==== Installing Dependencies ====' ./scripts/install-dependencies.sh # Build -echo '==== Building ====' -./scripts/build-all.sh +echo '==== Building & Packaging ====' +rm -rf out build +./scripts/package.sh amd64 +./scripts/package.sh arm64 +./scripts/package.sh armhf # Test echo '==== Testing ====' ./scripts/test.sh - -# Package -echo '==== Packaging ====' -./scripts/package.sh diff --git a/scripts/install-dependencies.sh b/scripts/install-dependencies.sh index 003b86f4..4577bb1e 100755 --- a/scripts/install-dependencies.sh +++ b/scripts/install-dependencies.sh @@ -20,6 +20,7 @@ sudo apt-get dist-upgrade -y # Install sudo apt-get install --no-install-recommends -y \ + build-essential \ ca-certificates \ lsb-release \ git \ @@ -27,6 +28,10 @@ sudo apt-get install --no-install-recommends -y \ lld \ cmake \ make \ + dpkg-dev \ + debhelper \ + devscripts \ + libdistro-info-perl \ libglfw3 libglfw3-dev \ libfreeimage3 libfreeimage-dev \ crossbuild-essential-armhf \ diff --git a/scripts/package.sh b/scripts/package.sh index a99cf141..fd3fe1e3 100755 --- a/scripts/package.sh +++ b/scripts/package.sh @@ -3,35 +3,18 @@ set -e # Prepare +rm -f debian/changelog +PACKAGE='minecraft-pi-reborn' VERSION="$(cat VERSION)" +DISTRO="$(lsb_release -cs)" +EDITOR='true' NAME='TheBrokenRail' EMAIL='connor24nolan@live.com' dch -u low -v "${VERSION}" --create --distribution "${DISTRO}" --package "${PACKAGE}" "Release ${VERSION}" -# Common -package() { - local dir="out/$1" - - # Create DEBIAN Dir - rm -rf "${dir}/DEBIAN" - mkdir -p "${dir}/DEBIAN" - cp "debian/$1" "${dir}/DEBIAN/control" - - # Format DEBIAN/control - sed -i "s/\${VERSION}/${VERSION}/g" "${dir}/DEBIAN/control" - - # Fix Permissions On Jenkins - chmod -R g-s "${dir}" - - # Package - dpkg-deb --root-owner-group --build "${dir}" out -} +# Custom Architecture +ARCH="$(dpkg-architecture -qDEB_BUILD_ARCH)" +if [ -z "$1" ]; then + ARCH="$1" +fi -# Find And Package -for dir in out/*; do - # Check If Directory Exists - if [ -d "${dir}" ]; then - # Check If Debian Package Exists - pkg="$(basename ${dir})" - if [ -f "debian/${pkg}" ]; then - package "${pkg}" - fi - fi -done +# Build +export DEB_CUSTOM_OUTPUT_DIR='out' +debuild --no-lintian -a"${ARCH}" -us -uc --buildinfo-option=-u"${DEB_CUSTOM_OUTPUT_DIR}" --changes-option=-u"${DEB_CUSTOM_OUTPUT_DIR}" -b diff --git a/scripts/test.sh b/scripts/test.sh index d5c7cbe9..c57235f9 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -3,7 +3,7 @@ set -e # Add minecraft-pi-reborn-server To PATH -export PATH="$(pwd)/out/server-x86_64/usr/bin:${PATH}" +export PATH="$(pwd)/out/server-$(dpkg-architecture -qDEB_HOST_ARCH)/usr/bin:${PATH}" # Create Test Directory rm -rf build/test From 320e0c652a4fbe124057a9ce0a5616c07b10a41d Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Wed, 10 Nov 2021 22:37:29 -0500 Subject: [PATCH 20/28] Add Missing File --- debian/.gitignore | 2 +- debian/rules | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100755 debian/rules diff --git a/debian/.gitignore b/debian/.gitignore index 07a6ac7b..3d8b8cac 100644 --- a/debian/.gitignore +++ b/debian/.gitignore @@ -1,6 +1,6 @@ * !control !copyright -!rukes +!rules !source !.gitignore diff --git a/debian/rules b/debian/rules new file mode 100755 index 00000000..1bd4e261 --- /dev/null +++ b/debian/rules @@ -0,0 +1,24 @@ +#!/usr/bin/make -f + +DEB_CUSTOM_OUTPUT_DIR ?= .. +include /usr/share/dpkg/architecture.mk + +%: + dh $@ + +override_dh_auto_configure: +override_dh_strip: +override_dh_dwz: +override_dh_makeshlibs: +override_dh_shlibdeps: + +override_dh_auto_build: + ./scripts/build.sh client $(DEB_HOST_ARCH) + ./scripts/build.sh server $(DEB_HOST_ARCH) + +override_dh_auto_install: + cp -ar out/client-$(DEB_HOST_ARCH)/. debian/minecraft-pi-reborn-client + cp -ar out/server-$(DEB_HOST_ARCH)/. debian/minecraft-pi-reborn-server + +override_dh_builddeb: + dh_builddeb --destdir=${DEB_CUSTOM_OUTPUT_DIR} From 7e3cfaa1a8cb8c431edf83133a0373da29e83f61 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Wed, 10 Nov 2021 22:48:41 -0500 Subject: [PATCH 21/28] Update Build Dependencies --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index bbee0322..aba76df7 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: minecraft-pi-reborn Section: games Priority: optional Maintainer: TheBrokenRail -Build-Depends: debhelper-compat (= 12), clang:native, lld:native, cmake, make:native, libglfw3, libglfw3-dev, libfreeimage3, libfreeimage-dev:native, libopenal1, libopenal-dev, crossbuild-essential-armhf +Build-Depends: debhelper-compat (= 12), clang:native, lld:native, cmake, git:native, make:native, libglfw3, libglfw3-dev, libfreeimage3, libfreeimage-dev:native, libopenal1, libopenal-dev, crossbuild-essential-armhf Standards-Version: 4.4.1 Homepage: https://www.minecraft.net/en-us/edition/pi Vcs-Browser: https://gitea.thebrokenrail.com/TheBrokenRail/minecraft-pi-reborn From 43d27e8e11139458b3b2fe1cfec0e50653d2556e Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Wed, 10 Nov 2021 22:52:33 -0500 Subject: [PATCH 22/28] Fix Build Dependencies --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index aba76df7..6e266710 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: minecraft-pi-reborn Section: games Priority: optional Maintainer: TheBrokenRail -Build-Depends: debhelper-compat (= 12), clang:native, lld:native, cmake, git:native, make:native, libglfw3, libglfw3-dev, libfreeimage3, libfreeimage-dev:native, libopenal1, libopenal-dev, crossbuild-essential-armhf +Build-Depends: debhelper-compat (= 12), clang:native, lld:native, cmake, git, make:native, libglfw3, libglfw3-dev, libfreeimage3, libfreeimage-dev:native, libopenal1, libopenal-dev, crossbuild-essential-armhf Standards-Version: 4.4.1 Homepage: https://www.minecraft.net/en-us/edition/pi Vcs-Browser: https://gitea.thebrokenrail.com/TheBrokenRail/minecraft-pi-reborn From 941572063e951ee6962b1602a92dd9cc0cc38b1f Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Thu, 11 Nov 2021 20:12:16 -0500 Subject: [PATCH 23/28] Revert To Binary Packaging --- .gitmodules | 8 +++++ cmake/i386-toolchain.cmake | 7 ---- cmake/i686-toolchain.cmake | 9 ++++++ debian/.gitignore | 6 ---- debian/client-amd64 | 7 ++++ debian/client-arm64 | 7 ++++ debian/client-armhf | 7 ++++ debian/control | 21 ------------ debian/copyright | 21 ------------ debian/rules | 24 -------------- debian/server-amd64 | 7 ++++ debian/server-arm64 | 7 ++++ debian/server-armhf | 7 ++++ dependencies/libpng/CMakeLists.txt | 17 +++------- dependencies/libpng/src | 1 + dependencies/minecraft-pi/CMakeLists.txt | 1 - dependencies/zlib/CMakeLists.txt | 16 ++------- dependencies/zlib/src | 1 + scripts/build-all.sh | 14 ++++++++ scripts/ci/run.sh | 11 ++++--- scripts/install-dependencies.sh | 5 --- scripts/package.sh | 41 +++++++++++++++++------- scripts/test.sh | 2 +- 23 files changed, 117 insertions(+), 130 deletions(-) create mode 100644 .gitmodules delete mode 100644 cmake/i386-toolchain.cmake create mode 100644 cmake/i686-toolchain.cmake delete mode 100644 debian/.gitignore create mode 100644 debian/client-amd64 create mode 100644 debian/client-arm64 create mode 100644 debian/client-armhf delete mode 100644 debian/control delete mode 100644 debian/copyright delete mode 100755 debian/rules create mode 100644 debian/server-amd64 create mode 100644 debian/server-arm64 create mode 100644 debian/server-armhf create mode 160000 dependencies/libpng/src create mode 160000 dependencies/zlib/src create mode 100755 scripts/build-all.sh diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..82965c68 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,8 @@ +[submodule "dependencies/libpng/src"] + path = dependencies/libpng/src + url = https://github.com/glennrp/libpng.git + shallow = true +[submodule "dependencies/zlib/src"] + path = dependencies/zlib/src + url = https://github.com/madler/zlib.git + shallow = true diff --git a/cmake/i386-toolchain.cmake b/cmake/i386-toolchain.cmake deleted file mode 100644 index 5ae20546..00000000 --- a/cmake/i386-toolchain.cmake +++ /dev/null @@ -1,7 +0,0 @@ -# Compile For i386 -include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake") -# Use i386 Cross-Compiler -setup_toolchain("i386-linux-gnu") -# Details -set(CMAKE_SYSTEM_NAME "Linux") -set(CMAKE_SYSTEM_PROCESSOR "i386") diff --git a/cmake/i686-toolchain.cmake b/cmake/i686-toolchain.cmake new file mode 100644 index 00000000..a8f0f945 --- /dev/null +++ b/cmake/i686-toolchain.cmake @@ -0,0 +1,9 @@ +# Warning +message(WARNING "i686 Builds Are Unsupported, Proceed At Your Own Risk") +# Compile For i686 +include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake") +# Use i686 Cross-Compiler +setup_toolchain("i686-linux-gnu") +# Details +set(CMAKE_SYSTEM_NAME "Linux") +set(CMAKE_SYSTEM_PROCESSOR "i686") diff --git a/debian/.gitignore b/debian/.gitignore deleted file mode 100644 index 3d8b8cac..00000000 --- a/debian/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -* -!control -!copyright -!rules -!source -!.gitignore diff --git a/debian/client-amd64 b/debian/client-amd64 new file mode 100644 index 00000000..59d8eafc --- /dev/null +++ b/debian/client-amd64 @@ -0,0 +1,7 @@ +Package: minecraft-pi-reborn-client +Version: ${VERSION} +Maintainer: TheBrokenRail +Description: Fun with Blocks +Homepage: https://www.minecraft.net/en-us/edition/pi +Architecture: amd64 +Depends: libc6, libstdc++6, libc6-armhf-cross, libstdc++6-armhf-cross, zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3, libopenal1, qemu-user-static diff --git a/debian/client-arm64 b/debian/client-arm64 new file mode 100644 index 00000000..d89a362a --- /dev/null +++ b/debian/client-arm64 @@ -0,0 +1,7 @@ +Package: minecraft-pi-reborn-client +Version: ${VERSION} +Maintainer: TheBrokenRail +Description: Fun with Blocks +Homepage: https://www.minecraft.net/en-us/edition/pi +Architecture: arm64 +Depends: libc6, libstdc++6, libc6:armhf, libstdc++6:armhf, zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3, libopenal1 diff --git a/debian/client-armhf b/debian/client-armhf new file mode 100644 index 00000000..7d98f969 --- /dev/null +++ b/debian/client-armhf @@ -0,0 +1,7 @@ +Package: minecraft-pi-reborn-client +Version: ${VERSION} +Maintainer: TheBrokenRail +Description: Fun with Blocks +Homepage: https://www.minecraft.net/en-us/edition/pi +Architecture: armhf +Depends: libc6, libstdc++6, zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3, libopenal1 diff --git a/debian/control b/debian/control deleted file mode 100644 index 6e266710..00000000 --- a/debian/control +++ /dev/null @@ -1,21 +0,0 @@ -Source: minecraft-pi-reborn -Section: games -Priority: optional -Maintainer: TheBrokenRail -Build-Depends: debhelper-compat (= 12), clang:native, lld:native, cmake, git, make:native, libglfw3, libglfw3-dev, libfreeimage3, libfreeimage-dev:native, libopenal1, libopenal-dev, crossbuild-essential-armhf -Standards-Version: 4.4.1 -Homepage: https://www.minecraft.net/en-us/edition/pi -Vcs-Browser: https://gitea.thebrokenrail.com/TheBrokenRail/minecraft-pi-reborn -Vcs-Git: https://gitea.thebrokenrail.com/TheBrokenRail/minecraft-pi-reborn.git - -Package: minecraft-pi-reborn-client -Architecture: amd64 i386 arm64 armhf -Multi-Arch: foreign -Depends: libc6, libstdc++6, libc6-armhf-cross [!arm64 !armhf], libstdc++6-armhf-cross [!arm64 !armhf], zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3, libopenal1, qemu-user-static [!arm64 !armhf] -Description: Fun with Blocks - -Package: minecraft-pi-reborn-server -Architecture: amd64 i386 arm64 armhf -Multi-Arch: foreign -Depends: libc6, libstdc++6, libc6-armhf-cross [!arm64 !armhf], libstdc++6-armhf-cross [!arm64 !armhf], qemu-user-static [!arm64 !armhf] -Description: Fun with Blocks (Dedicated Server) diff --git a/debian/copyright b/debian/copyright deleted file mode 100644 index 2bad0ca1..00000000 --- a/debian/copyright +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 TheBrokenRail - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/debian/rules b/debian/rules deleted file mode 100755 index 1bd4e261..00000000 --- a/debian/rules +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/make -f - -DEB_CUSTOM_OUTPUT_DIR ?= .. -include /usr/share/dpkg/architecture.mk - -%: - dh $@ - -override_dh_auto_configure: -override_dh_strip: -override_dh_dwz: -override_dh_makeshlibs: -override_dh_shlibdeps: - -override_dh_auto_build: - ./scripts/build.sh client $(DEB_HOST_ARCH) - ./scripts/build.sh server $(DEB_HOST_ARCH) - -override_dh_auto_install: - cp -ar out/client-$(DEB_HOST_ARCH)/. debian/minecraft-pi-reborn-client - cp -ar out/server-$(DEB_HOST_ARCH)/. debian/minecraft-pi-reborn-server - -override_dh_builddeb: - dh_builddeb --destdir=${DEB_CUSTOM_OUTPUT_DIR} diff --git a/debian/server-amd64 b/debian/server-amd64 new file mode 100644 index 00000000..5c9e71b2 --- /dev/null +++ b/debian/server-amd64 @@ -0,0 +1,7 @@ +Package: minecraft-pi-reborn-server +Version: ${VERSION} +Maintainer: TheBrokenRail +Description: Fun with Blocks +Homepage: https://www.minecraft.net/en-us/edition/pi +Architecture: amd64 +Depends: libc6, libstdc++6, libc6-armhf-cross, libstdc++6-armhf-cross, qemu-user-static diff --git a/debian/server-arm64 b/debian/server-arm64 new file mode 100644 index 00000000..5bd4d13f --- /dev/null +++ b/debian/server-arm64 @@ -0,0 +1,7 @@ +Package: minecraft-pi-reborn-server +Version: ${VERSION} +Maintainer: TheBrokenRail +Description: Fun with Blocks +Homepage: https://www.minecraft.net/en-us/edition/pi +Architecture: arm64 +Depends: libc6, libstdc++6, libc6:armhf, libstdc++6:armhf diff --git a/debian/server-armhf b/debian/server-armhf new file mode 100644 index 00000000..697b4ec3 --- /dev/null +++ b/debian/server-armhf @@ -0,0 +1,7 @@ +Package: minecraft-pi-reborn-server +Version: ${VERSION} +Maintainer: TheBrokenRail +Description: Fun with Blocks +Homepage: https://www.minecraft.net/en-us/edition/pi +Architecture: armhf +Depends: libc6, libstdc++6 diff --git a/dependencies/libpng/CMakeLists.txt b/dependencies/libpng/CMakeLists.txt index ce78ef14..ddc8934f 100644 --- a/dependencies/libpng/CMakeLists.txt +++ b/dependencies/libpng/CMakeLists.txt @@ -1,29 +1,20 @@ project(libpng) -include(FetchContent) - # Silence Warnings add_compile_options(-w) ## LibPNG # Download -FetchContent_Declare( - libpng - GIT_REPOSITORY "https://github.com/glennrp/libpng.git" - GIT_TAG "v1.2.59" -) -FetchContent_Populate(libpng) -set(ZLIB_LIBRARY zlib) -set(ZLIB_INCLUDE_DIR "${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}") +set(ZLIB_LIBRARY zlibstatic) +set(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../zlib" "${CMAKE_CURRENT_BINARY_DIR}/../zlib") set(CMAKE_POLICY_DEFAULT_CMP0054 OLD) # Silence Warning -add_subdirectory("${libpng_SOURCE_DIR}" "${libpng_BINARY_DIR}" EXCLUDE_FROM_ALL) +add_subdirectory(src EXCLUDE_FROM_ALL) set(CMAKE_POLICY_DEFAULT_CMP0054 NEW) # Re-Enable New Behavior -set_target_properties(png12 PROPERTIES LINK_FLAGS "-Wl,--version-script='${CMAKE_CURRENT_SOURCE_DIR}/libpng.vers'") # Use Symbol Versioning +set_target_properties(png12 PROPERTIES LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libpng.vers") # Use Symbol Versioning set_target_properties(png12 PROPERTIES DEBUG_POSTFIX "") # Fix LibPNG Suffix In Debug Mode # Ensure Build add_custom_target(png12-build ALL DEPENDS png12) # Install install(TARGETS png12 DESTINATION "${MCPI_LIB_DIR}") - diff --git a/dependencies/libpng/src b/dependencies/libpng/src new file mode 160000 index 00000000..5bb5bf34 --- /dev/null +++ b/dependencies/libpng/src @@ -0,0 +1 @@ +Subproject commit 5bb5bf345aef1e62adcfe30791f4364730a2aede diff --git a/dependencies/minecraft-pi/CMakeLists.txt b/dependencies/minecraft-pi/CMakeLists.txt index 9deea304..647410df 100644 --- a/dependencies/minecraft-pi/CMakeLists.txt +++ b/dependencies/minecraft-pi/CMakeLists.txt @@ -13,4 +13,3 @@ FetchContent_Populate(minecraft-pi) # Install install(DIRECTORY "${minecraft-pi_SOURCE_DIR}/" DESTINATION "${MCPI_INSTALL_DIR}" USE_SOURCE_PERMISSIONS) - diff --git a/dependencies/zlib/CMakeLists.txt b/dependencies/zlib/CMakeLists.txt index d3500a5f..591ed9ab 100644 --- a/dependencies/zlib/CMakeLists.txt +++ b/dependencies/zlib/CMakeLists.txt @@ -1,24 +1,12 @@ project(zlib) -include(FetchContent) - # Silence Warnings add_compile_options(-w) ## zlib # Download -FetchContent_Declare( - zlib - GIT_REPOSITORY "https://github.com/madler/zlib.git" - GIT_TAG "v1.2.11" -) -FetchContent_Populate(zlib) -include_directories("${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}") # Fix ZLib Build -add_subdirectory("${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}" EXCLUDE_FROM_ALL) +add_subdirectory(src EXCLUDE_FROM_ALL) # Ensure Build -add_custom_target(zlib-build ALL DEPENDS zlib) -# Install -install(TARGETS zlib DESTINATION "${MCPI_LIB_DIR}") - +add_custom_target(zlib-build ALL DEPENDS zlibstatic) diff --git a/dependencies/zlib/src b/dependencies/zlib/src new file mode 160000 index 00000000..cacf7f1d --- /dev/null +++ b/dependencies/zlib/src @@ -0,0 +1 @@ +Subproject commit cacf7f1d4e3d44d871b605da3b647f07d718623f diff --git a/scripts/build-all.sh b/scripts/build-all.sh new file mode 100755 index 00000000..674d780e --- /dev/null +++ b/scripts/build-all.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +set -e + +# Clean Prefix +rm -rf out + +# Build +./scripts/build.sh client amd64 +./scripts/build.sh server amd64 +./scripts/build.sh client arm64 +./scripts/build.sh server arm64 +./scripts/build.sh client armhf +./scripts/build.sh server armhf diff --git a/scripts/ci/run.sh b/scripts/ci/run.sh index 61017d4e..937904f5 100755 --- a/scripts/ci/run.sh +++ b/scripts/ci/run.sh @@ -14,12 +14,13 @@ echo '==== Installing Dependencies ====' ./scripts/install-dependencies.sh # Build -echo '==== Building & Packaging ====' -rm -rf out build -./scripts/package.sh amd64 -./scripts/package.sh arm64 -./scripts/package.sh armhf +echo '==== Building ====' +./scripts/build-all.sh # Test echo '==== Testing ====' ./scripts/test.sh + +# Package +echo '==== Packaging ====' +./scripts/package.sh diff --git a/scripts/install-dependencies.sh b/scripts/install-dependencies.sh index 4577bb1e..003b86f4 100755 --- a/scripts/install-dependencies.sh +++ b/scripts/install-dependencies.sh @@ -20,7 +20,6 @@ sudo apt-get dist-upgrade -y # Install sudo apt-get install --no-install-recommends -y \ - build-essential \ ca-certificates \ lsb-release \ git \ @@ -28,10 +27,6 @@ sudo apt-get install --no-install-recommends -y \ lld \ cmake \ make \ - dpkg-dev \ - debhelper \ - devscripts \ - libdistro-info-perl \ libglfw3 libglfw3-dev \ libfreeimage3 libfreeimage-dev \ crossbuild-essential-armhf \ diff --git a/scripts/package.sh b/scripts/package.sh index fd3fe1e3..a99cf141 100755 --- a/scripts/package.sh +++ b/scripts/package.sh @@ -3,18 +3,35 @@ set -e # Prepare -rm -f debian/changelog -PACKAGE='minecraft-pi-reborn' VERSION="$(cat VERSION)" -DISTRO="$(lsb_release -cs)" -EDITOR='true' NAME='TheBrokenRail' EMAIL='connor24nolan@live.com' dch -u low -v "${VERSION}" --create --distribution "${DISTRO}" --package "${PACKAGE}" "Release ${VERSION}" -# Custom Architecture -ARCH="$(dpkg-architecture -qDEB_BUILD_ARCH)" -if [ -z "$1" ]; then - ARCH="$1" -fi +# Common +package() { + local dir="out/$1" + + # Create DEBIAN Dir + rm -rf "${dir}/DEBIAN" + mkdir -p "${dir}/DEBIAN" + cp "debian/$1" "${dir}/DEBIAN/control" + + # Format DEBIAN/control + sed -i "s/\${VERSION}/${VERSION}/g" "${dir}/DEBIAN/control" + + # Fix Permissions On Jenkins + chmod -R g-s "${dir}" + + # Package + dpkg-deb --root-owner-group --build "${dir}" out +} -# Build -export DEB_CUSTOM_OUTPUT_DIR='out' -debuild --no-lintian -a"${ARCH}" -us -uc --buildinfo-option=-u"${DEB_CUSTOM_OUTPUT_DIR}" --changes-option=-u"${DEB_CUSTOM_OUTPUT_DIR}" -b +# Find And Package +for dir in out/*; do + # Check If Directory Exists + if [ -d "${dir}" ]; then + # Check If Debian Package Exists + pkg="$(basename ${dir})" + if [ -f "debian/${pkg}" ]; then + package "${pkg}" + fi + fi +done diff --git a/scripts/test.sh b/scripts/test.sh index c57235f9..d5c7cbe9 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -3,7 +3,7 @@ set -e # Add minecraft-pi-reborn-server To PATH -export PATH="$(pwd)/out/server-$(dpkg-architecture -qDEB_HOST_ARCH)/usr/bin:${PATH}" +export PATH="$(pwd)/out/server-x86_64/usr/bin:${PATH}" # Create Test Directory rm -rf build/test From 2e9ee42d755cb2f732cec77e9df9feb2fb4e7e00 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Thu, 11 Nov 2021 20:37:43 -0500 Subject: [PATCH 24/28] Fix ZLib Includes --- dependencies/libpng/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/libpng/CMakeLists.txt b/dependencies/libpng/CMakeLists.txt index ddc8934f..478460ed 100644 --- a/dependencies/libpng/CMakeLists.txt +++ b/dependencies/libpng/CMakeLists.txt @@ -7,7 +7,7 @@ add_compile_options(-w) # Download set(ZLIB_LIBRARY zlibstatic) -set(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../zlib" "${CMAKE_CURRENT_BINARY_DIR}/../zlib") +set(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/src" "${CMAKE_CURRENT_BINARY_DIR}/../zlib/src") set(CMAKE_POLICY_DEFAULT_CMP0054 OLD) # Silence Warning add_subdirectory(src EXCLUDE_FROM_ALL) set(CMAKE_POLICY_DEFAULT_CMP0054 NEW) # Re-Enable New Behavior From 6a7d881258a3977bdbd166d4f63c1fb405ee91b2 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Thu, 11 Nov 2021 21:37:29 -0500 Subject: [PATCH 25/28] Fix CI --- cmake/base-toolchain.cmake | 42 ++++++++++++++++----------------- scripts/install-dependencies.sh | 1 + 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/cmake/base-toolchain.cmake b/cmake/base-toolchain.cmake index fd5825b1..08a50724 100644 --- a/cmake/base-toolchain.cmake +++ b/cmake/base-toolchain.cmake @@ -1,6 +1,20 @@ +# Sanity Check Return +function(sanity_check_return ret) + if(NOT ret EQUAL "0") + message(FATAL_ERROR "Process Failed") + endif() +endfunction() + # Get Host Architecture find_program(UNAME uname /bin /usr/bin /usr/local/bin REQUIRED) -execute_process(COMMAND "${UNAME}" "-m" OUTPUT_VARIABLE HOST_ARCHITECTURE ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) +execute_process( + COMMAND "${UNAME}" "-m" + OUTPUT_VARIABLE HOST_ARCHITECTURE + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE ret +) +sanity_check_return("${ret}") # Get Include Directories function(get_include_dirs target compiler result) @@ -16,7 +30,9 @@ function(get_include_dirs target compiler result) ERROR_QUIET OUTPUT_VARIABLE tool OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE ret ) + sanity_check_return("${ret}") # Run Tool To Get Include Path set(tool_output "") @@ -26,7 +42,9 @@ function(get_include_dirs target compiler result) ERROR_VARIABLE tool_output ERROR_STRIP_TRAILING_WHITESPACE INPUT_FILE "/dev/null" + RESULT_VARIABLE ret ) + sanity_check_return("${ret}") string(REPLACE "\n" ";" tool_output "${tool_output}") # Loop @@ -61,30 +79,10 @@ function(get_include_dirs target compiler result) set("${result}" "${${result}}" PARENT_SCOPE) endfunction() -# Get GCC Prefix -function(get_gcc_prefix target result) - # Get Default Target - set("${result}" "" PARENT_SCOPE) - set(output "") - execute_process( - COMMAND "gcc" "-dumpmachine" - ERROR_QUIET - OUTPUT_VARIABLE output - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - # Check - if(NOT output STREQUAL target) - set("${result}" "${target}-" PARENT_SCOPE) - endif() -endfunction() - # Setup Include Directories function(setup_include_dirs compiler target result) # Get Full Compiler - set(prefix "") - get_gcc_prefix("${target}" prefix) - set(full_compiler "${prefix}${compiler}") + set(full_compiler "${target}-${compiler}") # Get Include Directories set(include_dirs "") diff --git a/scripts/install-dependencies.sh b/scripts/install-dependencies.sh index 003b86f4..53a44bba 100755 --- a/scripts/install-dependencies.sh +++ b/scripts/install-dependencies.sh @@ -31,6 +31,7 @@ sudo apt-get install --no-install-recommends -y \ libfreeimage3 libfreeimage-dev \ crossbuild-essential-armhf \ crossbuild-essential-arm64 \ + gcc \ libopenal-dev \ qemu-user-static From f8b7af137014f9d9c6d926e69066b95310d16834 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Thu, 11 Nov 2021 22:27:10 -0500 Subject: [PATCH 26/28] Fix CI Again --- scripts/install-dependencies.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/install-dependencies.sh b/scripts/install-dependencies.sh index 53a44bba..b62df998 100755 --- a/scripts/install-dependencies.sh +++ b/scripts/install-dependencies.sh @@ -30,8 +30,7 @@ sudo apt-get install --no-install-recommends -y \ libglfw3 libglfw3-dev \ libfreeimage3 libfreeimage-dev \ crossbuild-essential-armhf \ - crossbuild-essential-arm64 \ - gcc \ + gcc g++ \ libopenal-dev \ qemu-user-static @@ -43,6 +42,7 @@ if [ ! -z "${ARM_PACKAGES_SUPPORTED}" ]; then libopenal-dev:armhf \ libglfw3:arm64 libglfw3-dev:arm64 \ libfreeimage3:arm64 \ - libopenal-dev:arm64 + libopenal-dev:arm64 \ + crossbuild-essential-arm64 fi From da0aef568decaf46fd7d9043fc8d6af0e5864883 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Thu, 11 Nov 2021 22:52:47 -0500 Subject: [PATCH 27/28] Fix CI Test --- scripts/install-dependencies.sh | 1 + scripts/test.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/install-dependencies.sh b/scripts/install-dependencies.sh index b62df998..9f2f8c5d 100755 --- a/scripts/install-dependencies.sh +++ b/scripts/install-dependencies.sh @@ -22,6 +22,7 @@ sudo apt-get dist-upgrade -y sudo apt-get install --no-install-recommends -y \ ca-certificates \ lsb-release \ + dpkg-dev \ git \ clang \ lld \ diff --git a/scripts/test.sh b/scripts/test.sh index d5c7cbe9..75407580 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -3,7 +3,7 @@ set -e # Add minecraft-pi-reborn-server To PATH -export PATH="$(pwd)/out/server-x86_64/usr/bin:${PATH}" +export PATH="$(pwd)/out/server-$(dpkg-architecture -qDEB_BUILD_ARCH)/usr/bin:${PATH}" # Create Test Directory rm -rf build/test From e85231bf69181369f28022ef6d204efbd05101d2 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Fri, 12 Nov 2021 05:04:11 +0000 Subject: [PATCH 28/28] Fix ARMHF Output Path --- scripts/build.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/build.sh b/scripts/build.sh index a682567c..d74155b5 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -50,12 +50,12 @@ build() { # Build For ARM armhf_build() { # Create Build Dir - rm -rf "build/$1-arm" - mkdir -p "build/$1-arm" - cd "build/$1-arm" + rm -rf "build/$1-armhf" + mkdir -p "build/$1-armhf" + cd "build/$1-armhf" # Create Prefix - local prefix="$(cd ../../; pwd)/out/$1-arm" + local prefix="$(cd ../../; pwd)/out/$1-armhf" rm -rf "${prefix}" mkdir -p "${prefix}"