Fancy Info Screen
This commit is contained in:
parent
09bae1cf3e
commit
d519142a8a
@ -61,3 +61,4 @@ TRUE Add Splashes
|
|||||||
TRUE Display Date In Select World Screen
|
TRUE Display Date In Select World Screen
|
||||||
TRUE Optimized Chunk Sorting
|
TRUE Optimized Chunk Sorting
|
||||||
TRUE Disable Buggy Held Item Caching
|
TRUE Disable Buggy Held Item Caching
|
||||||
|
TRUE Add Info Button To Options
|
@ -32,12 +32,18 @@ set(SRC
|
|||||||
# options
|
# options
|
||||||
src/options/options.cpp
|
src/options/options.cpp
|
||||||
src/options/ui.cpp
|
src/options/ui.cpp
|
||||||
|
src/options/info.cpp
|
||||||
# bucket
|
# bucket
|
||||||
src/bucket/bucket.cpp
|
src/bucket/bucket.cpp
|
||||||
# cake
|
# cake
|
||||||
src/cake/cake.cpp
|
src/cake/cake.cpp
|
||||||
# home
|
# home
|
||||||
src/home/home.cpp
|
src/home/home.cpp
|
||||||
|
# touch
|
||||||
|
src/touch/touch.cpp
|
||||||
|
# text-input-box
|
||||||
|
src/text-input-box/TextInputBox.cpp
|
||||||
|
src/text-input-box/TextInputScreen.cpp
|
||||||
# test
|
# test
|
||||||
src/test/test.cpp
|
src/test/test.cpp
|
||||||
# init
|
# init
|
||||||
@ -83,8 +89,6 @@ else()
|
|||||||
src/input/crafting.cpp
|
src/input/crafting.cpp
|
||||||
# sign
|
# sign
|
||||||
src/sign/sign.cpp
|
src/sign/sign.cpp
|
||||||
# touch
|
|
||||||
src/touch/touch.cpp
|
|
||||||
# atlas
|
# atlas
|
||||||
src/atlas/atlas.cpp
|
src/atlas/atlas.cpp
|
||||||
# title-screen
|
# title-screen
|
||||||
@ -98,9 +102,6 @@ else()
|
|||||||
# textures
|
# textures
|
||||||
src/textures/textures.cpp
|
src/textures/textures.cpp
|
||||||
src/textures/lava.cpp
|
src/textures/lava.cpp
|
||||||
# text-input-box
|
|
||||||
src/text-input-box/TextInputBox.cpp
|
|
||||||
src/text-input-box/TextInputScreen.cpp
|
|
||||||
# fps
|
# fps
|
||||||
src/fps/fps.cpp
|
src/fps/fps.cpp
|
||||||
)
|
)
|
||||||
|
@ -17,12 +17,12 @@ void init_sound();
|
|||||||
void init_input();
|
void init_input();
|
||||||
void init_sign();
|
void init_sign();
|
||||||
void init_camera();
|
void init_camera();
|
||||||
void init_touch();
|
|
||||||
void init_atlas();
|
void init_atlas();
|
||||||
void init_title_screen();
|
void init_title_screen();
|
||||||
void init_skin();
|
void init_skin();
|
||||||
void init_fps();
|
void init_fps();
|
||||||
#endif
|
#endif
|
||||||
|
void init_touch();
|
||||||
void init_textures();
|
void init_textures();
|
||||||
void init_creative();
|
void init_creative();
|
||||||
void init_game_mode();
|
void init_game_mode();
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <symbols/minecraft.h>
|
||||||
|
|
||||||
// Message Limitations
|
// Message Limitations
|
||||||
#define MAX_CHAT_MESSAGE_LENGTH 256
|
#define MAX_CHAT_MESSAGE_LENGTH 256
|
||||||
|
|
||||||
@ -9,11 +11,7 @@
|
|||||||
__attribute__((visibility("internal"))) std::string _chat_get_prefix(char *username);
|
__attribute__((visibility("internal"))) std::string _chat_get_prefix(char *username);
|
||||||
|
|
||||||
// Queue Message For Sending
|
// Queue Message For Sending
|
||||||
#ifndef MCPI_SERVER_MODE
|
__attribute__((visibility("internal"))) void _chat_send_message(Minecraft *minecraft, const char *message);
|
||||||
__attribute__((visibility("internal"))) void _chat_queue_message(const char *message);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Init Chat UI
|
// Init Chat UI
|
||||||
#ifndef MCPI_HEADLESS_MODE
|
__attribute__((visibility("internal"))) void _init_chat_ui();
|
||||||
__attribute__((visibility("internal"))) void _init_chat_ui();
|
|
||||||
#endif
|
|
@ -1,21 +1,13 @@
|
|||||||
// Config Needs To Load First
|
|
||||||
#include <libreborn/libreborn.h>
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <libreborn/libreborn.h>
|
||||||
#include <symbols/minecraft.h>
|
#include <symbols/minecraft.h>
|
||||||
#ifndef MCPI_HEADLESS_MODE
|
|
||||||
#include <media-layer/core.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <mods/init/init.h>
|
#include <mods/init/init.h>
|
||||||
#include <mods/feature/feature.h>
|
#include <mods/feature/feature.h>
|
||||||
#ifndef MCPI_HEADLESS_MODE
|
|
||||||
#include <mods/input/input.h>
|
|
||||||
#endif
|
|
||||||
#include "chat-internal.h"
|
#include "chat-internal.h"
|
||||||
#include <mods/chat/chat.h>
|
#include <mods/chat/chat.h>
|
||||||
|
|
||||||
@ -33,7 +25,6 @@ std::string chat_send_api_command(Minecraft *minecraft, std::string str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef MCPI_HEADLESS_MODE
|
|
||||||
// Send API Chat Command
|
// Send API Chat Command
|
||||||
static void send_api_chat_command(Minecraft *minecraft, char *str) {
|
static void send_api_chat_command(Minecraft *minecraft, char *str) {
|
||||||
char *command = nullptr;
|
char *command = nullptr;
|
||||||
@ -41,7 +32,6 @@ static void send_api_chat_command(Minecraft *minecraft, char *str) {
|
|||||||
chat_send_api_command(minecraft, command);
|
chat_send_api_command(minecraft, command);
|
||||||
free(command);
|
free(command);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// Send Message To Players
|
// Send Message To Players
|
||||||
std::string _chat_get_prefix(char *username) {
|
std::string _chat_get_prefix(char *username) {
|
||||||
@ -87,25 +77,10 @@ static void ServerSideNetworkHandler_handle_ChatPacket_injection(ServerSideNetwo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef MCPI_HEADLESS_MODE
|
// Send Message
|
||||||
// Message Queue
|
void _chat_send_message(Minecraft *minecraft, const char *message) {
|
||||||
static std::vector<std::string> queue;
|
send_api_chat_command(minecraft, (char *) message);
|
||||||
// Add To Queue
|
|
||||||
void _chat_queue_message(const char *message) {
|
|
||||||
// Add
|
|
||||||
std::string str = message;
|
|
||||||
queue.push_back(str);
|
|
||||||
}
|
}
|
||||||
// Empty Queue
|
|
||||||
unsigned int old_chat_counter = 0;
|
|
||||||
static void send_queued_messages(Minecraft *minecraft) {
|
|
||||||
// Loop
|
|
||||||
for (unsigned int i = 0; i < queue.size(); i++) {
|
|
||||||
send_api_chat_command(minecraft, (char *) queue[i].c_str());
|
|
||||||
}
|
|
||||||
queue.clear();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
void init_chat() {
|
void init_chat() {
|
||||||
@ -117,12 +92,8 @@ void init_chat() {
|
|||||||
overwrite_call((void *) 0x6b518, (void *) CommandServer_parse_CommandServer_dispatchPacket_injection);
|
overwrite_call((void *) 0x6b518, (void *) CommandServer_parse_CommandServer_dispatchPacket_injection);
|
||||||
// Re-Broadcast ChatPacket
|
// Re-Broadcast ChatPacket
|
||||||
patch_vtable(ServerSideNetworkHandler_handle_ChatPacket, ServerSideNetworkHandler_handle_ChatPacket_injection);
|
patch_vtable(ServerSideNetworkHandler_handle_ChatPacket, ServerSideNetworkHandler_handle_ChatPacket_injection);
|
||||||
#ifndef MCPI_HEADLESS_MODE
|
|
||||||
// Send Messages On Input Tick
|
|
||||||
input_run_on_tick(send_queued_messages);
|
|
||||||
// Init UI
|
// Init UI
|
||||||
_init_chat_ui();
|
_init_chat_ui();
|
||||||
#endif
|
|
||||||
// Disable Built-In Chat Message Limiting
|
// Disable Built-In Chat Message Limiting
|
||||||
unsigned char message_limit_patch[4] = {0x03, 0x00, 0x53, 0xe1}; // "cmp r4, r4"
|
unsigned char message_limit_patch[4] = {0x03, 0x00, 0x53, 0xe1}; // "cmp r4, r4"
|
||||||
patch((void *) 0x6b4c0, message_limit_patch);
|
patch((void *) 0x6b4c0, message_limit_patch);
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
// Config Needs To Load First
|
|
||||||
#include <libreborn/libreborn.h>
|
|
||||||
|
|
||||||
// Chat UI Code Is Useless In Headless Mode
|
|
||||||
#ifndef MCPI_HEADLESS_MODE
|
|
||||||
|
|
||||||
#include "chat-internal.h"
|
#include "chat-internal.h"
|
||||||
|
#include <libreborn/libreborn.h>
|
||||||
#include <mods/chat/chat.h>
|
#include <mods/chat/chat.h>
|
||||||
#include <mods/text-input-box/TextInputScreen.h>
|
#include <mods/text-input-box/TextInputScreen.h>
|
||||||
#include <mods/misc/misc.h>
|
#include <mods/misc/misc.h>
|
||||||
@ -94,7 +89,7 @@ CUSTOM_VTABLE(chat_screen, Screen) {
|
|||||||
if (get_history().size() == 0 || text != get_history().back()) {
|
if (get_history().size() == 0 || text != get_history().back()) {
|
||||||
get_history().push_back(text);
|
get_history().push_back(text);
|
||||||
}
|
}
|
||||||
_chat_queue_message(text.c_str());
|
_chat_send_message(super->minecraft, text.c_str());
|
||||||
}
|
}
|
||||||
Minecraft_setScreen(super->minecraft, nullptr);
|
Minecraft_setScreen(super->minecraft, nullptr);
|
||||||
} else if (key == 0x26) {
|
} else if (key == 0x26) {
|
||||||
@ -158,5 +153,3 @@ void _init_chat_ui() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@ -20,12 +20,12 @@ __attribute__((constructor)) static void init(int argc, char *argv[]) {
|
|||||||
init_input();
|
init_input();
|
||||||
init_sign();
|
init_sign();
|
||||||
init_camera();
|
init_camera();
|
||||||
init_touch();
|
|
||||||
init_atlas();
|
init_atlas();
|
||||||
init_title_screen();
|
init_title_screen();
|
||||||
init_skin();
|
init_skin();
|
||||||
init_fps();
|
init_fps();
|
||||||
#endif
|
#endif
|
||||||
|
init_touch();
|
||||||
init_textures();
|
init_textures();
|
||||||
init_creative();
|
init_creative();
|
||||||
init_game_mode();
|
init_game_mode();
|
||||||
|
278
mods/src/options/info.cpp
Normal file
278
mods/src/options/info.cpp
Normal file
@ -0,0 +1,278 @@
|
|||||||
|
#include <libreborn/libreborn.h>
|
||||||
|
#include <symbols/minecraft.h>
|
||||||
|
#include <GLES/gl.h>
|
||||||
|
|
||||||
|
#include <mods/touch/touch.h>
|
||||||
|
|
||||||
|
#include "options-internal.h"
|
||||||
|
|
||||||
|
// Button IDs
|
||||||
|
#define DISCORD_ID 0
|
||||||
|
#define BACK_ID 1
|
||||||
|
#define INFO_ID_START 2
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
static int line_button_width = 80;
|
||||||
|
static int line_button_height = 24;
|
||||||
|
static int padding = 4;
|
||||||
|
static int line_height = 8;
|
||||||
|
static int bottom_padding = padding;
|
||||||
|
static int inner_padding = padding;
|
||||||
|
static int title_padding = 8;
|
||||||
|
static int info_text_y_offset = (line_button_height - line_height) / 2;
|
||||||
|
static int content_y_offset_top = (title_padding * 2) + line_height;
|
||||||
|
static int content_y_offset_bottom = (bottom_padding * 2) + line_button_height;
|
||||||
|
|
||||||
|
// Extra Version Info
|
||||||
|
static std::string extra_version_info =
|
||||||
|
#ifdef MCPI_IS_APPIMAGE_BUILD
|
||||||
|
"AppImage"
|
||||||
|
#elif defined(MCPI_IS_FLATPAK_BUILD)
|
||||||
|
"Flatpak"
|
||||||
|
#else
|
||||||
|
""
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
static std::string extra_version_info_full = !extra_version_info.empty() ? (" (" + extra_version_info + ")") : "";
|
||||||
|
|
||||||
|
// Profile Directory
|
||||||
|
static std::string profile_directory_suffix =
|
||||||
|
#ifdef MCPI_IS_FLATPAK_BUILD
|
||||||
|
"/.var/app/" MCPI_APP_ID "/.minecraft-pi"
|
||||||
|
#else
|
||||||
|
"/.minecraft-pi"
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
static std::string get_profile_directory_url() {
|
||||||
|
const char *home = getenv("HOME");
|
||||||
|
if (home == nullptr) {
|
||||||
|
IMPOSSIBLE();
|
||||||
|
}
|
||||||
|
return std::string("file://") + home + profile_directory_suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info Data
|
||||||
|
#define MORE_INFO_TEXT "More Info"
|
||||||
|
struct info_line {
|
||||||
|
std::string (*get_text)();
|
||||||
|
std::string button_url;
|
||||||
|
std::string button_text;
|
||||||
|
};
|
||||||
|
std::string info_sound_data_state = "N/A";
|
||||||
|
static info_line info[] = {
|
||||||
|
{
|
||||||
|
.get_text = []() {
|
||||||
|
return std::string("Version: v") + reborn_get_version() + extra_version_info_full;
|
||||||
|
},
|
||||||
|
.button_url = "https://gitea.thebrokenrail.com/minecraft-pi-reborn/minecraft-pi-reborn/src/branch/master/docs/CHANGELOG.md",
|
||||||
|
.button_text = MORE_INFO_TEXT
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.get_text = []() {
|
||||||
|
return std::string("Profile Directory");
|
||||||
|
},
|
||||||
|
.button_url = get_profile_directory_url(),
|
||||||
|
.button_text = "Open"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.get_text = []() {
|
||||||
|
return std::string("Sound Data: ") + info_sound_data_state;
|
||||||
|
},
|
||||||
|
.button_url = "https://gitea.thebrokenrail.com/minecraft-pi-reborn/minecraft-pi-reborn/src/branch/master/docs/SOUND.md",
|
||||||
|
.button_text = MORE_INFO_TEXT
|
||||||
|
},
|
||||||
|
};
|
||||||
|
#define info_size int(sizeof(info) / sizeof(info_line))
|
||||||
|
|
||||||
|
// Positioned Info
|
||||||
|
struct info_pos {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
struct info_line_position {
|
||||||
|
info_pos text;
|
||||||
|
info_pos button;
|
||||||
|
};
|
||||||
|
static info_line_position positioned_info[info_size];
|
||||||
|
static int content_height = 0;
|
||||||
|
static void position_info(Font *font, int width, int height) {
|
||||||
|
// First Stage (Find Max Text Width)
|
||||||
|
int info_text_width = 0;
|
||||||
|
for (int i = 0; i < info_size; i++) {
|
||||||
|
std::string text = info[i].get_text();
|
||||||
|
int text_width = font->width(&text);
|
||||||
|
if (text_width > info_text_width) {
|
||||||
|
info_text_width = text_width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second Stage (Initial Positioning)
|
||||||
|
int y = 0;
|
||||||
|
for (int i = 0; i < info_size; i++) {
|
||||||
|
// Padding
|
||||||
|
if (i != 0) {
|
||||||
|
y += padding;
|
||||||
|
}
|
||||||
|
// Y
|
||||||
|
positioned_info[i].button.y = y;
|
||||||
|
positioned_info[i].text.y = y + info_text_y_offset;
|
||||||
|
// X
|
||||||
|
positioned_info[i].button.x = info_text_width + padding;
|
||||||
|
positioned_info[i].text.x = 0;
|
||||||
|
// Advance
|
||||||
|
y += line_button_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Third Stage (Centering)
|
||||||
|
int info_height = y;
|
||||||
|
int info_width = info_text_width + padding + line_button_width;
|
||||||
|
content_height = height - content_y_offset_top - content_y_offset_bottom;
|
||||||
|
int info_y_offset = ((content_height - info_height) / 2) + content_y_offset_top;
|
||||||
|
int info_x_offset = (width - info_width) / 2;
|
||||||
|
for (int i = 0; i < info_size; i++) {
|
||||||
|
positioned_info[i].button.x += info_x_offset;
|
||||||
|
positioned_info[i].button.y += info_y_offset;
|
||||||
|
positioned_info[i].text.x += info_x_offset;
|
||||||
|
positioned_info[i].text.y += info_y_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open URL
|
||||||
|
static void open_url(const std::string &url) {
|
||||||
|
int return_code;
|
||||||
|
const char *command[] = {"xdg-open", url.c_str(), nullptr};
|
||||||
|
char *output = run_command(command, &return_code, nullptr);
|
||||||
|
if (output != nullptr) {
|
||||||
|
free(output);
|
||||||
|
}
|
||||||
|
if (!is_exit_status_success(return_code)) {
|
||||||
|
WARN("Unable To Open URL: %s", url.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render Fancy Background
|
||||||
|
static void render_background(Minecraft *minecraft, int x, int y, int width, int height) {
|
||||||
|
// https://github.com/ReMinecraftPE/mcpe/blob/f0d65eaecec1b3fe9c2f2b251e114a890c54ab77/source/client/gui/components/RolledSelectionList.cpp#L169-L179
|
||||||
|
std::string texture = "gui/background.png";
|
||||||
|
minecraft->textures->loadAndBindTexture(&texture);
|
||||||
|
Tesselator *t = &Tesselator_instance;
|
||||||
|
t->begin(7);
|
||||||
|
t->color(32, 32, 32, 255);
|
||||||
|
float x1 = x;
|
||||||
|
float x2 = x + width;
|
||||||
|
float y1 = y;
|
||||||
|
float y2 = y + height;
|
||||||
|
t->vertexUV(x1, y2, 0.0f, x1 / 32.0f, y2 / 32.0f);
|
||||||
|
t->vertexUV(x2, y2, 0.0f, x2 / 32.0f, y2 / 32.0f);
|
||||||
|
t->vertexUV(x2, y1, 0.0f, x2 / 32.0f, y1 / 32.0f);
|
||||||
|
t->vertexUV(x1, y1, 0.0f, x1 / 32.0f, y1 / 32.0f);
|
||||||
|
t->draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create VTable
|
||||||
|
CUSTOM_VTABLE(info_screen, Screen) {
|
||||||
|
// Buttons
|
||||||
|
static Button *discord;
|
||||||
|
static Button *back;
|
||||||
|
static Button *info_buttons[info_size];
|
||||||
|
// Init
|
||||||
|
vtable->init = [](Screen *self) {
|
||||||
|
// Info
|
||||||
|
for (int i = 0; i < info_size; i++) {
|
||||||
|
Button *button = touch_create_button(INFO_ID_START + i, info[i].button_text);
|
||||||
|
self->rendered_buttons.push_back(button);
|
||||||
|
self->selectable_buttons.push_back(button);
|
||||||
|
info_buttons[i] = button;
|
||||||
|
}
|
||||||
|
// Discord Button
|
||||||
|
discord = touch_create_button(DISCORD_ID, "Discord");
|
||||||
|
self->rendered_buttons.push_back(discord);
|
||||||
|
self->selectable_buttons.push_back(discord);
|
||||||
|
// Back Button
|
||||||
|
back = touch_create_button(BACK_ID, "Back");
|
||||||
|
self->rendered_buttons.push_back(back);
|
||||||
|
self->selectable_buttons.push_back(back);
|
||||||
|
};
|
||||||
|
// Handle Back
|
||||||
|
vtable->handleBackEvent = [](Screen *self, bool do_nothing) {
|
||||||
|
if (!do_nothing) {
|
||||||
|
OptionsScreen *screen = alloc_OptionsScreen();
|
||||||
|
ALLOC_CHECK(screen);
|
||||||
|
screen->constructor();
|
||||||
|
self->minecraft->setScreen((Screen *) screen);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
// Rendering
|
||||||
|
static Screen_render_t original_render = vtable->render;
|
||||||
|
vtable->render = [](Screen *self, int x, int y, float param_1) {
|
||||||
|
// Background
|
||||||
|
self->vtable->renderBackground(self);
|
||||||
|
// Gradient
|
||||||
|
render_background(self->minecraft, 0, content_y_offset_top, self->width, content_height);
|
||||||
|
// Call Original Method
|
||||||
|
original_render(self, x, y, param_1);
|
||||||
|
// Title
|
||||||
|
std::string title = "Reborn Information";
|
||||||
|
self->drawCenteredString(self->font, &title, self->width / 2, title_padding, 0xffffffff);
|
||||||
|
// Info Text
|
||||||
|
for (int i = 0; i < info_size; i++) {
|
||||||
|
std::string text = info[i].get_text();
|
||||||
|
self->drawString(self->font, &text, positioned_info[i].text.x, positioned_info[i].text.y, 0xffffffff);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Positioning
|
||||||
|
vtable->setupPositions = [](Screen *self) {
|
||||||
|
// Height/Width
|
||||||
|
int width = 120;
|
||||||
|
discord->width = back->width = width;
|
||||||
|
discord->height = back->height = line_button_height;
|
||||||
|
// X/Y
|
||||||
|
discord->y = back->y = self->height - bottom_padding - line_button_height;
|
||||||
|
discord->x = (self->width / 2) - inner_padding - width;
|
||||||
|
back->x = (self->width / 2) + inner_padding;
|
||||||
|
// Info
|
||||||
|
position_info(self->font, self->width, self->height);
|
||||||
|
for (int i = 0; i < info_size; i++) {
|
||||||
|
Button *button = info_buttons[i];
|
||||||
|
button->width = line_button_width;
|
||||||
|
button->height = line_button_height;
|
||||||
|
button->x = positioned_info[i].button.x;
|
||||||
|
button->y = positioned_info[i].button.y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Cleanup
|
||||||
|
vtable->removed = [](Screen *self) {
|
||||||
|
for (Button *button : self->rendered_buttons) {
|
||||||
|
button->destructor_deleting();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Handle Button Click
|
||||||
|
vtable->buttonClicked = [](Screen *self, Button *button) {
|
||||||
|
if (button->id == BACK_ID) {
|
||||||
|
// Back
|
||||||
|
self->handleBackEvent(false);
|
||||||
|
} else if (button->id == DISCORD_ID) {
|
||||||
|
// Open Discord Invite
|
||||||
|
open_url("https://discord.gg/mcpi-revival-740287937727561779");
|
||||||
|
} else if (button->id >= INFO_ID_START) {
|
||||||
|
// Open Info URL
|
||||||
|
int i = button->id - INFO_ID_START;
|
||||||
|
open_url(info[i].button_url);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Screen
|
||||||
|
Screen *_create_options_info_screen() {
|
||||||
|
// Allocate
|
||||||
|
Screen *screen = alloc_Screen();
|
||||||
|
ALLOC_CHECK(screen);
|
||||||
|
screen->constructor();
|
||||||
|
|
||||||
|
// Set VTable
|
||||||
|
screen->vtable = get_info_screen_vtable();
|
||||||
|
|
||||||
|
// Return
|
||||||
|
return screen;
|
||||||
|
}
|
@ -1,4 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <symbols/minecraft.h>
|
||||||
|
|
||||||
__attribute__((visibility("internal"))) void _init_options_ui();
|
__attribute__((visibility("internal"))) void _init_options_ui();
|
||||||
__attribute__((visibility("internal"))) extern Options *stored_options;
|
__attribute__((visibility("internal"))) extern Options *stored_options;
|
||||||
|
__attribute__((visibility("internal"))) Screen *_create_options_info_screen();
|
@ -1,4 +1,5 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <libreborn/libreborn.h>
|
#include <libreborn/libreborn.h>
|
||||||
#include <symbols/minecraft.h>
|
#include <symbols/minecraft.h>
|
||||||
@ -89,6 +90,72 @@ static void OptionButton_toggle_Options_save_injection(Options *self) {
|
|||||||
Options_save(self);
|
Options_save(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add "Reborn" Info Button
|
||||||
|
#define INFO_BUTTON_ID 99
|
||||||
|
static void OptionsScreen_init_injection(OptionsScreen_init_t original, OptionsScreen *self) {
|
||||||
|
// Call Original Method
|
||||||
|
original(self);
|
||||||
|
|
||||||
|
// Add Button
|
||||||
|
Touch_TButton *button = alloc_Touch_TButton();
|
||||||
|
ALLOC_CHECK(button);
|
||||||
|
std::string name = "Reborn";
|
||||||
|
button->constructor(INFO_BUTTON_ID, &name);
|
||||||
|
self->rendered_buttons.push_back((Button *) button);
|
||||||
|
self->selectable_buttons.push_back((Button *) button);
|
||||||
|
}
|
||||||
|
static void OptionsScreen_setupPositions_injection(OptionsScreen_setupPositions_t original, OptionsScreen *self) {
|
||||||
|
// Call Original Method
|
||||||
|
original(self);
|
||||||
|
|
||||||
|
// Find Button
|
||||||
|
Button *prevButton = nullptr;
|
||||||
|
Button *button = nullptr;
|
||||||
|
for (Button *x : self->selectable_buttons) {
|
||||||
|
if (x->id == INFO_BUTTON_ID) {
|
||||||
|
button = x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prevButton = x;
|
||||||
|
}
|
||||||
|
if (button == nullptr || prevButton == nullptr) {
|
||||||
|
IMPOSSIBLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup Button
|
||||||
|
button->width = prevButton->width;
|
||||||
|
button->height = prevButton->height;
|
||||||
|
button->x = prevButton->x;
|
||||||
|
button->y = prevButton->y + prevButton->height;
|
||||||
|
}
|
||||||
|
static void OptionsScreen_buttonClicked_injection(OptionsScreen_buttonClicked_t original, OptionsScreen *self, Button *button) {
|
||||||
|
// Check ID
|
||||||
|
if (button->id == INFO_BUTTON_ID) {
|
||||||
|
// Show Screen
|
||||||
|
self->minecraft->setScreen(_create_options_info_screen());
|
||||||
|
} else {
|
||||||
|
// Call Original Method
|
||||||
|
original(self, button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void OptionsScreen_removed_injection(OptionsScreen_removed_t original, OptionsScreen *self) {
|
||||||
|
// Delete Button
|
||||||
|
Button *button = nullptr;
|
||||||
|
for (Button *x : self->selectable_buttons) {
|
||||||
|
if (x->id == INFO_BUTTON_ID) {
|
||||||
|
button = x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (button == nullptr) {
|
||||||
|
IMPOSSIBLE();
|
||||||
|
}
|
||||||
|
button->destructor_deleting();
|
||||||
|
|
||||||
|
// Call Original Method
|
||||||
|
original(self);
|
||||||
|
}
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
void _init_options_ui() {
|
void _init_options_ui() {
|
||||||
// Fix Options Screen
|
// Fix Options Screen
|
||||||
@ -115,4 +182,16 @@ void _init_options_ui() {
|
|||||||
// Fix Difficulty When Toggling
|
// Fix Difficulty When Toggling
|
||||||
overwrite_call((void *) 0x1cd00, (void *) OptionButton_toggle_Options_save_injection);
|
overwrite_call((void *) 0x1cd00, (void *) OptionButton_toggle_Options_save_injection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Info Button
|
||||||
|
if (feature_has("Add Info Button To Options", server_disabled)) {
|
||||||
|
// Add Button
|
||||||
|
overwrite_virtual_calls(OptionsScreen_init, OptionsScreen_init_injection);
|
||||||
|
// Position Button
|
||||||
|
overwrite_virtual_calls(OptionsScreen_setupPositions, OptionsScreen_setupPositions_injection);
|
||||||
|
// Handle Click
|
||||||
|
overwrite_virtual_calls(OptionsScreen_buttonClicked, OptionsScreen_buttonClicked_injection);
|
||||||
|
// Cleanup
|
||||||
|
overwrite_virtual_calls(OptionsScreen_removed, OptionsScreen_removed_injection);
|
||||||
|
}
|
||||||
}
|
}
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
// Resolve Source File Path
|
// Resolve Source File Path
|
||||||
#define SOURCE_FILE_BASE "data/libminecraftpe.so"
|
#define SOURCE_FILE_BASE "data/libminecraftpe.so"
|
||||||
|
extern std::string info_sound_data_state;
|
||||||
std::string _sound_get_source_file() {
|
std::string _sound_get_source_file() {
|
||||||
static bool source_loaded = false;
|
static bool source_loaded = false;
|
||||||
static std::string source;
|
static std::string source;
|
||||||
@ -38,9 +39,11 @@ std::string _sound_get_source_file() {
|
|||||||
// Fail
|
// Fail
|
||||||
WARN("Audio Source File Doesn't Exist: " SOURCE_FILE_BASE " (See: https://gitea.thebrokenrail.com/minecraft-pi-reborn/minecraft-pi-reborn/src/branch/master/docs/SOUND.md)");
|
WARN("Audio Source File Doesn't Exist: " SOURCE_FILE_BASE " (See: https://gitea.thebrokenrail.com/minecraft-pi-reborn/minecraft-pi-reborn/src/branch/master/docs/SOUND.md)");
|
||||||
source.assign("");
|
source.assign("");
|
||||||
|
info_sound_data_state = "Missing";
|
||||||
} else {
|
} else {
|
||||||
// Set
|
// Set
|
||||||
source.assign(path);
|
source.assign(path);
|
||||||
|
info_sound_data_state = "Loaded";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free
|
// Free
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
extends GuiComponent;
|
extends GuiComponent;
|
||||||
|
|
||||||
size 0x28;
|
size 0x28;
|
||||||
constructor (int param_1, std::string *text) = 0x1bc54;
|
constructor (int id, std::string *text) = 0x1bc54;
|
||||||
|
|
||||||
method int hovered(Minecraft *minecraft, int click_x, int click_y) = 0x1be2c;
|
method int hovered(Minecraft *minecraft, int click_x, int click_y) = 0x1be2c;
|
||||||
|
|
||||||
@ -10,3 +10,4 @@ property int height = 0x18;
|
|||||||
property int x = 0xc;
|
property int x = 0xc;
|
||||||
property int y = 0x10;
|
property int y = 0x10;
|
||||||
property std::string text = 0x1c;
|
property std::string text = 0x1c;
|
||||||
|
property int id = 0x20;
|
@ -4,7 +4,7 @@ constructor () = 0x28204;
|
|||||||
vtable 0x1039b0;
|
vtable 0x1039b0;
|
||||||
|
|
||||||
method void blit(int x_dest, int y_dest, int x_src, int y_src, int width_dest, int height_dest, int width_src, int height_src) = 0x282a4;
|
method void blit(int x_dest, int y_dest, int x_src, int y_src, int width_dest, int height_dest, int width_src, int height_src) = 0x282a4;
|
||||||
method void drawCenteredString(Font *font, std::string *text, int x, int y, int color) = 0x2821c;
|
method void drawCenteredString(Font *font, std::string *text, int x, int y, uint color) = 0x2821c;
|
||||||
method void drawString(Font *font, std::string *text, int x, int y, int color) = 0x28284;
|
method void drawString(Font *font, std::string *text, int x, int y, uint color) = 0x28284;
|
||||||
method void fill(int x1, int y1, int x2, int y2, uint color) = 0x285f0;
|
method void fill(int x1, int y1, int x2, int y2, uint color) = 0x285f0;
|
||||||
method void fillGradient(int x1, int y1, int x2, int y2, int color1, int color2) = 0x287c0;
|
method void fillGradient(int x1, int y1, int x2, int y2, int color1, int color2) = 0x287c0;
|
@ -1,4 +1,4 @@
|
|||||||
extends Button;
|
extends Button;
|
||||||
|
|
||||||
size 0x28;
|
size 0x28;
|
||||||
constructor (int param_1, std::string *text) = 0x1c168;
|
constructor (int id, std::string *text) = 0x1c168;
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
extends Screen;
|
extends Screen;
|
||||||
|
|
||||||
vtable 0x104978;
|
vtable 0x104978;
|
||||||
|
|
||||||
|
size 0x70;
|
||||||
|
constructor () = 0x35488;
|
Loading…
Reference in New Issue
Block a user