Add Chat
This commit is contained in:
parent
b037ff6d98
commit
032490c7b2
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
/out
|
/out
|
||||||
/debian/tmp
|
/debian/tmp
|
||||||
|
/.vscode
|
@ -5,7 +5,7 @@ ENV DEBIAN_FRONTEND noninteractive
|
|||||||
RUN \
|
RUN \
|
||||||
# Install Runtime Dependencies
|
# Install Runtime Dependencies
|
||||||
apt-get update && \
|
apt-get update && \
|
||||||
apt-get install -y --no-install-recommends tini libgles1 libx11-6 libsdl1.2debian zlib1g libfreeimage3 libglfw3 xinput libxfixes3 gosu && \
|
apt-get install -y --no-install-recommends tini libgles1 libx11-6 libsdl1.2debian zlib1g libfreeimage3 libglfw3 xinput libxfixes3 gosu tk && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Compile Environment
|
# Compile Environment
|
||||||
|
@ -8,9 +8,16 @@ extern "C" {
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
// Logging
|
||||||
#define INFO(msg, ...) fprintf(stderr, "[INFO]: " msg "\n", __VA_ARGS__);
|
#define INFO(msg, ...) fprintf(stderr, "[INFO]: " msg "\n", __VA_ARGS__);
|
||||||
#define ERR(msg, ...) fprintf(stderr, "[ERR]: " msg "\n", __VA_ARGS__); exit(EXIT_FAILURE);
|
#define ERR(msg, ...) fprintf(stderr, "[ERR]: " msg "\n", __VA_ARGS__); exit(EXIT_FAILURE);
|
||||||
|
|
||||||
|
// Check Memory Allocation
|
||||||
|
#define ALLOC_CHECK(obj) if (obj == NULL) { ERR("(%s:%i) Memory Allocation Failed", __FILE__, __LINE__); }
|
||||||
|
|
||||||
|
// Set obj To NULL On asprintf() Failure
|
||||||
|
#define asprintf(obj, ...) if (asprintf(obj, __VA_ARGS__) == -1) { *obj = NULL; }
|
||||||
|
|
||||||
#define HOOK(name, return_type, args) \
|
#define HOOK(name, return_type, args) \
|
||||||
typedef return_type (*name##_t)args; \
|
typedef return_type (*name##_t)args; \
|
||||||
static name##_t real_##name = NULL; \
|
static name##_t real_##name = NULL; \
|
||||||
|
@ -102,6 +102,15 @@ static uint32_t Minecraft_player_property_offset = 0x18c; // LocalPlayer *
|
|||||||
static uint32_t Minecraft_options_property_offset = 0x3c; // Options
|
static uint32_t Minecraft_options_property_offset = 0x3c; // Options
|
||||||
static uint32_t Minecraft_hit_result_property_offset = 0xc38; // HitResult
|
static uint32_t Minecraft_hit_result_property_offset = 0xc38; // HitResult
|
||||||
static uint32_t Minecraft_progress_property_offset = 0xc60; // int32_t
|
static uint32_t Minecraft_progress_property_offset = 0xc60; // int32_t
|
||||||
|
static uint32_t Minecraft_command_server_property_offset = 0xcc0; // CommandServer *
|
||||||
|
|
||||||
|
// CommandServer
|
||||||
|
|
||||||
|
static uint32_t CommandServer_minecraft_property_offset = 0x18; // Minecraft *
|
||||||
|
|
||||||
|
// ChatPacket
|
||||||
|
|
||||||
|
static uint32_t ChatPacket_message_property_offset = 0xc; // char *
|
||||||
|
|
||||||
// HitResult
|
// HitResult
|
||||||
|
|
||||||
@ -245,6 +254,12 @@ static FillingContainer_addItem_t FillingContainer_addItem = (FillingContainer_a
|
|||||||
|
|
||||||
// RakNetInstance
|
// RakNetInstance
|
||||||
|
|
||||||
|
typedef void (*RakNetInstance_send_t)(unsigned char *rak_net_instance, unsigned char *packet);
|
||||||
|
static uint32_t RakNetInstance_send_vtable_offset = 0x38;
|
||||||
|
|
||||||
|
typedef uint32_t (*RakNetInstance_isServer_t)(unsigned char *rak_net_instance);
|
||||||
|
static uint32_t RakNetInstance_isServer_vtable_offset = 0x48;
|
||||||
|
|
||||||
static uint32_t RakNetInstance_peer_property_offset = 0x4;
|
static uint32_t RakNetInstance_peer_property_offset = 0x4;
|
||||||
|
|
||||||
// RakNet::RakPeer
|
// RakNet::RakPeer
|
||||||
@ -261,6 +276,8 @@ static void *ServerSideNetworkHandler_onDisconnect_vtable_addr = (void *) 0x109b
|
|||||||
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, unsigned char *guid);
|
||||||
static ServerSideNetworkHandler_getPlayer_t ServerSideNetworkHandler_getPlayer = (ServerSideNetworkHandler_getPlayer_t) 0x75464;
|
static ServerSideNetworkHandler_getPlayer_t ServerSideNetworkHandler_getPlayer = (ServerSideNetworkHandler_getPlayer_t) 0x75464;
|
||||||
|
|
||||||
|
static void *ServerSideNetworkHandler_handle_ChatPacket_vtable_addr = (void *) 0x109c60;
|
||||||
|
|
||||||
// Entity
|
// Entity
|
||||||
|
|
||||||
typedef void (*Entity_die_t)(unsigned char *entity, unsigned char *cause);
|
typedef void (*Entity_die_t)(unsigned char *entity, unsigned char *cause);
|
||||||
@ -300,6 +317,14 @@ static ItemRenderer_renderGuiItemCorrect_t ItemRenderer_renderGuiItemCorrect = (
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
// Structures
|
||||||
|
|
||||||
|
struct ConnectedClient {
|
||||||
|
uint32_t sock;
|
||||||
|
std::string str;
|
||||||
|
long time;
|
||||||
|
};
|
||||||
|
|
||||||
// AppPlatform
|
// AppPlatform
|
||||||
|
|
||||||
typedef void (*AppPlatform_saveScreenshot_t)(unsigned char *app_platform, std::string const& param1, std::string const& param_2);
|
typedef void (*AppPlatform_saveScreenshot_t)(unsigned char *app_platform, std::string const& param1, std::string const& param_2);
|
||||||
@ -320,6 +345,11 @@ static Minecraft_selectLevel_t Minecraft_selectLevel = (Minecraft_selectLevel_t)
|
|||||||
typedef void (*Minecraft_leaveGame_t)(unsigned char *minecraft, bool save_remote_level);
|
typedef void (*Minecraft_leaveGame_t)(unsigned char *minecraft, bool save_remote_level);
|
||||||
static Minecraft_leaveGame_t Minecraft_leaveGame = (Minecraft_leaveGame_t) 0x15ea0;
|
static Minecraft_leaveGame_t Minecraft_leaveGame = (Minecraft_leaveGame_t) 0x15ea0;
|
||||||
|
|
||||||
|
// CommandServer
|
||||||
|
|
||||||
|
typedef std::string (*CommandServer_parse_t)(unsigned char *command_server, struct ConnectedClient &client, std::string const& command);
|
||||||
|
static CommandServer_parse_t CommandServer_parse = (CommandServer_parse_t) 0x6aa8c;
|
||||||
|
|
||||||
// Level
|
// Level
|
||||||
|
|
||||||
typedef void (*Level_addParticle_t)(unsigned char *level, std::string const& particle, float x, float y, float z, float deltaX, float deltaY, float deltaZ, int count);
|
typedef void (*Level_addParticle_t)(unsigned char *level, std::string const& particle, float x, float y, float z, float deltaX, float deltaY, float deltaZ, int count);
|
||||||
@ -340,7 +370,7 @@ static Textures_tick_t Textures_tick = (Textures_tick_t) 0x531c4;
|
|||||||
|
|
||||||
// RakNet::RakPeer
|
// RakNet::RakPeer
|
||||||
|
|
||||||
typedef bool (*RakNet_RakPeer_IsBanned_t)(unsigned char *rakpeer, const char *ip);
|
typedef bool (*RakNet_RakPeer_IsBanned_t)(unsigned char *rak_peer, const char *ip);
|
||||||
static RakNet_RakPeer_IsBanned_t RakNet_RakPeer_IsBanned = (RakNet_RakPeer_IsBanned_t) 0xda3b4;
|
static RakNet_RakPeer_IsBanned_t RakNet_RakPeer_IsBanned = (RakNet_RakPeer_IsBanned_t) 0xda3b4;
|
||||||
|
|
||||||
// RakNet::SystemAddress
|
// RakNet::SystemAddress
|
||||||
|
@ -41,7 +41,7 @@ add_library(game_mode SHARED src/game_mode/game_mode.c src/game_mode/game_mode.c
|
|||||||
target_link_libraries(game_mode reborn)
|
target_link_libraries(game_mode reborn)
|
||||||
|
|
||||||
add_library(input SHARED src/input/input.c src/input/input.cpp)
|
add_library(input SHARED src/input/input.c src/input/input.cpp)
|
||||||
target_link_libraries(input reborn feature SDL)
|
target_link_libraries(input reborn feature SDL chat)
|
||||||
|
|
||||||
add_library(misc SHARED src/misc/misc.c src/misc/misc.cpp)
|
add_library(misc SHARED src/misc/misc.c src/misc/misc.cpp)
|
||||||
target_link_libraries(misc reborn feature util)
|
target_link_libraries(misc reborn feature util)
|
||||||
@ -55,11 +55,14 @@ target_link_libraries(override reborn dl)
|
|||||||
add_library(textures SHARED src/textures/textures.cpp)
|
add_library(textures SHARED src/textures/textures.cpp)
|
||||||
target_link_libraries(textures reborn feature GLESv1_CM)
|
target_link_libraries(textures reborn feature GLESv1_CM)
|
||||||
|
|
||||||
|
add_library(chat SHARED src/chat/chat.cpp src/chat/ui.c)
|
||||||
|
target_link_libraries(chat reborn pthread)
|
||||||
|
|
||||||
add_library(test SHARED src/test/test.c)
|
add_library(test SHARED src/test/test.c)
|
||||||
target_link_libraries(test reborn)
|
target_link_libraries(test reborn)
|
||||||
|
|
||||||
add_library(init SHARED src/init/init.c)
|
add_library(init SHARED src/init/init.c)
|
||||||
target_link_libraries(init compat server game_mode camera input misc options textures test)
|
target_link_libraries(init compat server game_mode camera input misc options textures chat test)
|
||||||
|
|
||||||
## Stubs
|
## Stubs
|
||||||
|
|
||||||
@ -76,4 +79,4 @@ target_link_libraries(GLESv2 GLESv1_CM)
|
|||||||
target_link_options(GLESv2 PRIVATE "-Wl,--no-as-needed")
|
target_link_options(GLESv2 PRIVATE "-Wl,--no-as-needed")
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
install(TARGETS init compat readdir feature screenshot override server game_mode camera input misc options textures test bcm_host EGL GLESv2 DESTINATION /mods)
|
install(TARGETS init compat readdir feature screenshot override server game_mode camera input misc options textures chat test bcm_host EGL GLESv2 DESTINATION /mods)
|
@ -17,6 +17,7 @@ static unsigned char *EntityRenderDispatcher_injection(unsigned char *dispatcher
|
|||||||
|
|
||||||
// Register TripodCameraRenderer
|
// Register TripodCameraRenderer
|
||||||
unsigned char *renderer = (unsigned char *) ::operator new(TRIPOD_CAMERA_RENDERER_SIZE);
|
unsigned char *renderer = (unsigned char *) ::operator new(TRIPOD_CAMERA_RENDERER_SIZE);
|
||||||
|
ALLOC_CHECK(renderer);
|
||||||
(*TripodCameraRenderer)(renderer);
|
(*TripodCameraRenderer)(renderer);
|
||||||
(*EntityRenderDispatcher_assign)(dispatcher, (unsigned char) 0x5, renderer);
|
(*EntityRenderDispatcher_assign)(dispatcher, (unsigned char) 0x5, renderer);
|
||||||
|
|
||||||
|
108
mods/src/chat/chat.cpp
Normal file
108
mods/src/chat/chat.cpp
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#include <string>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <vector>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include <libreborn/libreborn.h>
|
||||||
|
#include <libreborn/minecraft.h>
|
||||||
|
|
||||||
|
#include "../init/init.h"
|
||||||
|
|
||||||
|
#include "chat.h"
|
||||||
|
|
||||||
|
// Send API Command
|
||||||
|
static void send_api_command(unsigned char *minecraft, char *str) {
|
||||||
|
struct ConnectedClient client;
|
||||||
|
client.sock = -1;
|
||||||
|
client.str = "";
|
||||||
|
client.time = 0;
|
||||||
|
unsigned char *command_server = *(unsigned char **) (minecraft + Minecraft_command_server_property_offset);
|
||||||
|
if (command_server != NULL) {
|
||||||
|
(*CommandServer_parse)(command_server, client, str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Send API Chat Command
|
||||||
|
static void send_api_chat_command(unsigned char *minecraft, char *str) {
|
||||||
|
char *command = NULL;
|
||||||
|
asprintf(&command, "chat.post(%s)\n", str);
|
||||||
|
ALLOC_CHECK(command);
|
||||||
|
send_api_command(minecraft, command);
|
||||||
|
free(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send Message To Players
|
||||||
|
static void send_message(unsigned char *server_side_network_handler, char *username, char *message) {
|
||||||
|
char *full_message = NULL;
|
||||||
|
asprintf(&full_message, "<%s> %s", username, message);
|
||||||
|
ALLOC_CHECK(full_message);
|
||||||
|
(*ServerSideNetworkHandler_displayGameMessage)(server_side_network_handler, std::string(full_message));
|
||||||
|
free(full_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manually Send (And Loopback) ChatPacket
|
||||||
|
static void CommandServer_parse_CommandServer_dispatchPacket_injection(unsigned char *command_server, unsigned char *packet) {
|
||||||
|
unsigned char *minecraft = *(unsigned char **) (command_server + CommandServer_minecraft_property_offset);
|
||||||
|
if (minecraft != NULL) {
|
||||||
|
unsigned char *rak_net_instance = *(unsigned char **) (minecraft + Minecraft_rak_net_instance_property_offset);
|
||||||
|
unsigned char *rak_net_instance_vtable = *(unsigned char **) rak_net_instance;
|
||||||
|
RakNetInstance_isServer_t RakNetInstance_isServer = *(RakNetInstance_isServer_t *) (rak_net_instance_vtable + RakNetInstance_isServer_vtable_offset);
|
||||||
|
if ((*RakNetInstance_isServer)(rak_net_instance)) {
|
||||||
|
// Hosting Multiplayer
|
||||||
|
char *message = *(char **) (packet + ChatPacket_message_property_offset);
|
||||||
|
unsigned char *server_side_network_handler = *(unsigned char **) (minecraft + Minecraft_server_side_network_handler_property_offset);
|
||||||
|
send_message(server_side_network_handler, *default_username, message);
|
||||||
|
} else {
|
||||||
|
// Client
|
||||||
|
RakNetInstance_send_t RakNetInstance_send = *(RakNetInstance_send_t *) (rak_net_instance_vtable + RakNetInstance_send_vtable_offset);
|
||||||
|
(*RakNetInstance_send)(rak_net_instance, packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
unsigned char *player = (*ServerSideNetworkHandler_getPlayer)(server_side_network_handler, rak_net_guid);
|
||||||
|
if (player != NULL) {
|
||||||
|
char *username = *(char **) (player + Player_username_property_offset);
|
||||||
|
char *message = *(char **) (chat_packet + ChatPacket_message_property_offset);
|
||||||
|
send_message(server_side_network_handler, username, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message Queue
|
||||||
|
static pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
static std::vector<std::string> queue;
|
||||||
|
// Add To Queue
|
||||||
|
void chat_queue_message(char *message) {
|
||||||
|
// Lock
|
||||||
|
pthread_mutex_lock(&queue_mutex);
|
||||||
|
// Add
|
||||||
|
std::string str;
|
||||||
|
str.append(message);
|
||||||
|
queue.push_back(str);
|
||||||
|
// Unlock
|
||||||
|
pthread_mutex_unlock(&queue_mutex);
|
||||||
|
}
|
||||||
|
// Empty Queue
|
||||||
|
void chat_send_messages(unsigned char *minecraft) {
|
||||||
|
// Lock
|
||||||
|
pthread_mutex_lock(&queue_mutex);
|
||||||
|
// Loop
|
||||||
|
for (unsigned int i = 0; i < queue.size(); i++) {
|
||||||
|
send_api_chat_command(minecraft, (char *) queue[i].c_str());
|
||||||
|
}
|
||||||
|
queue.clear();
|
||||||
|
// Unlock
|
||||||
|
pthread_mutex_unlock(&queue_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init
|
||||||
|
void init_chat() {
|
||||||
|
// Disable Original ChatPacket Loopback
|
||||||
|
unsigned char disable_chat_packet_loopback_patch[4] = {0x00, 0xf0, 0x20, 0xe3};
|
||||||
|
patch((void *) 0x6b490, disable_chat_packet_loopback_patch);
|
||||||
|
// Manually Send (And Loopback) ChatPacket
|
||||||
|
overwrite_call((void *) 0x6b518, (void *) CommandServer_parse_CommandServer_dispatchPacket_injection);
|
||||||
|
// Re-Broadcast ChatPacket
|
||||||
|
patch_address(ServerSideNetworkHandler_handle_ChatPacket_vtable_addr, (void *) ServerSideNetworkHandler_handle_ChatPacket_injection);
|
||||||
|
}
|
13
mods/src/chat/chat.h
Normal file
13
mods/src/chat/chat.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void chat_open();
|
||||||
|
void chat_queue_message(char *message);
|
||||||
|
void chat_send_messages(unsigned char *minecraft);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
95
mods/src/chat/ui.c
Normal file
95
mods/src/chat/ui.c
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <libreborn/libreborn.h>
|
||||||
|
|
||||||
|
#include "chat.h"
|
||||||
|
|
||||||
|
#define CHAT_WINDOW_TCL \
|
||||||
|
"set message \"\"\n" \
|
||||||
|
"proc submit {} {\n" \
|
||||||
|
"global message\n" \
|
||||||
|
"puts \"$message\"\n" \
|
||||||
|
"exit\n" \
|
||||||
|
"}\n" \
|
||||||
|
\
|
||||||
|
"wm resizable . false false\n" \
|
||||||
|
"wm title . \"Chat\"\n" \
|
||||||
|
"wm attributes . -topmost true -type {dialog}\n" \
|
||||||
|
\
|
||||||
|
"ttk::label .label -text \"Enter Chat Message:\"\n" \
|
||||||
|
\
|
||||||
|
"ttk::entry .entry -textvariable message\n" \
|
||||||
|
"focus .entry\n" \
|
||||||
|
"bind .entry <Key-Return> submit\n" \
|
||||||
|
\
|
||||||
|
"ttk::frame .button\n" \
|
||||||
|
"ttk::button .button.submit -text \"Submit\" -command submit\n" \
|
||||||
|
"ttk::button .button.cancel -text \"Cancel\" -command exit\n" \
|
||||||
|
\
|
||||||
|
"grid .label -row 0 -padx 6 -pady 6\n" \
|
||||||
|
"grid .entry -row 1 -padx 6\n" \
|
||||||
|
"grid .button -row 2 -padx 3 -pady 6\n" \
|
||||||
|
"grid .button.cancel -row 0 -column 0 -padx 3\n" \
|
||||||
|
"grid .button.submit -row 0 -column 1 -padx 3\n"
|
||||||
|
|
||||||
|
// Run Command
|
||||||
|
static char *run_command(char *command, int *return_code) {
|
||||||
|
// Don't Contaminate Child Process
|
||||||
|
unsetenv("LD_LIBRARY_PATH");
|
||||||
|
unsetenv("LD_PRELOAD");
|
||||||
|
|
||||||
|
// Start
|
||||||
|
FILE *out = popen(command, "r");
|
||||||
|
if (!out) {
|
||||||
|
ERR("%s", "Failed To Run Command");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record
|
||||||
|
char *output = NULL;
|
||||||
|
int c;
|
||||||
|
while ((c = fgetc(out)) != EOF) {
|
||||||
|
asprintf(&output, "%s%c", output == NULL ? "" : output, (char) c);
|
||||||
|
ALLOC_CHECK(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return
|
||||||
|
*return_code = pclose(out);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chat Thread
|
||||||
|
static void *chat_thread(__attribute__((unused)) void *nop) {
|
||||||
|
// Prepare
|
||||||
|
setenv("CHAT_WINDOW_TCL", CHAT_WINDOW_TCL, 1);
|
||||||
|
// Open
|
||||||
|
int return_code;
|
||||||
|
char *output = run_command("echo \"${CHAT_WINDOW_TCL}\" | wish -name \"Minecraft - Pi edition\"", &return_code);
|
||||||
|
// Handle Message
|
||||||
|
if (output != NULL) {
|
||||||
|
if (return_code == 0) {
|
||||||
|
// Remove Ending Newline
|
||||||
|
int length = strlen(output);
|
||||||
|
if (output[length - 1] == '\n') {
|
||||||
|
output[length - 1] = '\0';
|
||||||
|
}
|
||||||
|
length = strlen(output);
|
||||||
|
// Submit
|
||||||
|
chat_queue_message(output);
|
||||||
|
}
|
||||||
|
// Free
|
||||||
|
free(output);
|
||||||
|
}
|
||||||
|
// Return
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Chat Thead
|
||||||
|
void chat_open() {
|
||||||
|
pthread_t thread;
|
||||||
|
pthread_create(&thread, NULL, chat_thread, NULL);
|
||||||
|
}
|
@ -19,6 +19,7 @@
|
|||||||
#include "../feature/feature.h"
|
#include "../feature/feature.h"
|
||||||
#include "../input/input.h"
|
#include "../input/input.h"
|
||||||
#include "../screenshot/screenshot.h"
|
#include "../screenshot/screenshot.h"
|
||||||
|
#include "../chat/chat.h"
|
||||||
#include "../init/init.h"
|
#include "../init/init.h"
|
||||||
|
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
@ -99,6 +100,9 @@ static SDLKey glfw_key_to_sdl_key(int key) {
|
|||||||
// Third Person
|
// Third Person
|
||||||
case GLFW_KEY_F5:
|
case GLFW_KEY_F5:
|
||||||
return SDLK_F5;
|
return SDLK_F5;
|
||||||
|
// Chat
|
||||||
|
case GLFW_KEY_T:
|
||||||
|
return SDLK_t;
|
||||||
// Unknown
|
// Unknown
|
||||||
default:
|
default:
|
||||||
return SDLK_UNKNOWN;
|
return SDLK_UNKNOWN;
|
||||||
@ -189,6 +193,8 @@ HOOK(SDL_WM_SetCaption, void, (const char *title, __attribute__((unused)) const
|
|||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 1);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 1);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
|
// Extra Settings
|
||||||
|
glfwWindowHint(GLFW_AUTO_ICONIFY, GLFW_FALSE);
|
||||||
|
|
||||||
glfw_window = glfwCreateWindow(DEFAULT_WIDTH, DEFAULT_HEIGHT, title, NULL, NULL);
|
glfw_window = glfwCreateWindow(DEFAULT_WIDTH, DEFAULT_HEIGHT, title, NULL, NULL);
|
||||||
if (!glfw_window) {
|
if (!glfw_window) {
|
||||||
@ -274,6 +280,15 @@ HOOK(SDL_PollEvent, int, (SDL_Event *event)) {
|
|||||||
} else if (event->key.keysym.sym == SDLK_F5) {
|
} else if (event->key.keysym.sym == SDLK_F5) {
|
||||||
input_third_person();
|
input_third_person();
|
||||||
handled = 1;
|
handled = 1;
|
||||||
|
} else if (event->key.keysym.sym == SDLK_t) {
|
||||||
|
// Release Mouse Immediately
|
||||||
|
SDL_WM_GrabInput(SDL_GRAB_OFF);
|
||||||
|
// Stop Tracking Mouse
|
||||||
|
glfw_key(glfw_window, GLFW_KEY_TAB, -1, GLFW_PRESS, -1);
|
||||||
|
glfw_key(glfw_window, GLFW_KEY_TAB, -1, GLFW_RELEASE, -1);
|
||||||
|
// Open Chat
|
||||||
|
chat_open();
|
||||||
|
handled = 1;
|
||||||
}
|
}
|
||||||
} else if (event->type == SDL_MOUSEBUTTONDOWN || event->type == SDL_MOUSEBUTTONUP) {
|
} else if (event->type == SDL_MOUSEBUTTONDOWN || event->type == SDL_MOUSEBUTTONUP) {
|
||||||
if (event->button.button == SDL_BUTTON_RIGHT) {
|
if (event->button.button == SDL_BUTTON_RIGHT) {
|
||||||
|
@ -18,6 +18,7 @@ static void SelectWorldScreen_tick_injection(unsigned char *screen) {
|
|||||||
std::string new_name = (*SelectWorldScreen_getUniqueLevelName)(screen, WORLD_NAME);
|
std::string new_name = (*SelectWorldScreen_getUniqueLevelName)(screen, WORLD_NAME);
|
||||||
// Create SimpleLevelChooseScreen
|
// Create SimpleLevelChooseScreen
|
||||||
unsigned char *new_screen = (unsigned char *) ::operator new(SIMPLE_LEVEL_CHOOSE_SCREEN_SIZE);
|
unsigned char *new_screen = (unsigned char *) ::operator new(SIMPLE_LEVEL_CHOOSE_SCREEN_SIZE);
|
||||||
|
ALLOC_CHECK(new_screen);
|
||||||
(*SimpleChooseLevelScreen)(new_screen, new_name);
|
(*SimpleChooseLevelScreen)(new_screen, new_name);
|
||||||
// Set Screen
|
// Set Screen
|
||||||
unsigned char *minecraft = get_minecraft_from_screen(screen);
|
unsigned char *minecraft = get_minecraft_from_screen(screen);
|
||||||
@ -35,6 +36,7 @@ static void Touch_SelectWorldScreen_tick_injection(unsigned char *screen) {
|
|||||||
std::string new_name = (*Touch_SelectWorldScreen_getUniqueLevelName)(screen, WORLD_NAME);
|
std::string new_name = (*Touch_SelectWorldScreen_getUniqueLevelName)(screen, WORLD_NAME);
|
||||||
// Create SimpleLevelChooseScreen
|
// Create SimpleLevelChooseScreen
|
||||||
unsigned char *new_screen = (unsigned char *) ::operator new(SIMPLE_LEVEL_CHOOSE_SCREEN_SIZE);
|
unsigned char *new_screen = (unsigned char *) ::operator new(SIMPLE_LEVEL_CHOOSE_SCREEN_SIZE);
|
||||||
|
ALLOC_CHECK(new_screen);
|
||||||
(*SimpleChooseLevelScreen)(new_screen, new_name);
|
(*SimpleChooseLevelScreen)(new_screen, new_name);
|
||||||
// Set Screen
|
// Set Screen
|
||||||
unsigned char *minecraft = get_minecraft_from_screen(screen);
|
unsigned char *minecraft = get_minecraft_from_screen(screen);
|
||||||
|
@ -10,4 +10,5 @@ __attribute__((constructor)) static void init() {
|
|||||||
init_camera();
|
init_camera();
|
||||||
init_options();
|
init_options();
|
||||||
init_textures();
|
init_textures();
|
||||||
|
init_chat();
|
||||||
}
|
}
|
@ -13,6 +13,7 @@ void init_misc();
|
|||||||
void init_camera();
|
void init_camera();
|
||||||
void init_options();
|
void init_options();
|
||||||
void init_textures();
|
void init_textures();
|
||||||
|
void init_chat();
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "../feature/feature.h"
|
#include "../feature/feature.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "../init/init.h"
|
#include "../init/init.h"
|
||||||
|
#include "../chat/chat.h"
|
||||||
|
|
||||||
#include <libreborn/minecraft.h>
|
#include <libreborn/minecraft.h>
|
||||||
|
|
||||||
@ -57,6 +58,9 @@ static void Minecraft_tickInput_injection(unsigned char *minecraft) {
|
|||||||
*(options + Options_third_person_property_offset) = *(options + Options_third_person_property_offset) ^ 1;
|
*(options + Options_third_person_property_offset) = *(options + Options_third_person_property_offset) ^ 1;
|
||||||
}
|
}
|
||||||
third_person_toggle = 0;
|
third_person_toggle = 0;
|
||||||
|
|
||||||
|
// Send Queued Chat Message
|
||||||
|
chat_send_messages(minecraft);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <SDL/SDL_events.h>
|
#include <SDL/SDL_events.h>
|
||||||
|
@ -12,6 +12,7 @@ static void LocalPlayer_openTextEdit_injection(unsigned char *local_player, unsi
|
|||||||
if (*(int32_t *) (sign + TileEntity_id_property_offset) == 4) {
|
if (*(int32_t *) (sign + TileEntity_id_property_offset) == 4) {
|
||||||
unsigned char *minecraft = *(unsigned char **) (local_player + LocalPlayer_minecraft_property_offset);
|
unsigned char *minecraft = *(unsigned char **) (local_player + LocalPlayer_minecraft_property_offset);
|
||||||
unsigned char *screen = (unsigned char *) ::operator new(TEXT_EDIT_SCREEN_SIZE);
|
unsigned char *screen = (unsigned char *) ::operator new(TEXT_EDIT_SCREEN_SIZE);
|
||||||
|
ALLOC_CHECK(screen);
|
||||||
screen = (*TextEditScreen)(screen, sign);
|
screen = (*TextEditScreen)(screen, sign);
|
||||||
(*Minecraft_setScreen)(minecraft, screen);
|
(*Minecraft_setScreen)(minecraft, screen);
|
||||||
}
|
}
|
||||||
|
@ -27,10 +27,12 @@ static AppPlatform_readAssetFile_return_value AppPlatform_readAssetFile_injectio
|
|||||||
|
|
||||||
static void inventory_add_item(unsigned char *inventory, unsigned char *item, bool is_tile) {
|
static void inventory_add_item(unsigned char *inventory, unsigned char *item, bool is_tile) {
|
||||||
unsigned char *item_instance = (unsigned char *) ::operator new(ITEM_INSTANCE_SIZE);
|
unsigned char *item_instance = (unsigned char *) ::operator new(ITEM_INSTANCE_SIZE);
|
||||||
|
ALLOC_CHECK(item_instance);
|
||||||
item_instance = (*(is_tile ? ItemInstance_constructor_tile : ItemInstance_constructor_item))(item_instance, item);
|
item_instance = (*(is_tile ? ItemInstance_constructor_tile : ItemInstance_constructor_item))(item_instance, item);
|
||||||
(*FillingContainer_addItem)(inventory, item_instance);
|
(*FillingContainer_addItem)(inventory, item_instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Expand Creative Inventory
|
||||||
static int32_t Inventory_setupDefault_FillingContainer_addItem_call_injection(unsigned char *filling_container, unsigned char *item_instance) {
|
static int32_t Inventory_setupDefault_FillingContainer_addItem_call_injection(unsigned char *filling_container, unsigned char *item_instance) {
|
||||||
// Call Original
|
// Call Original
|
||||||
int32_t ret = (*FillingContainer_addItem)(filling_container, item_instance);
|
int32_t ret = (*FillingContainer_addItem)(filling_container, item_instance);
|
||||||
@ -46,6 +48,7 @@ static int32_t Inventory_setupDefault_FillingContainer_addItem_call_injection(un
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
unsigned char *item_instance = (unsigned char *) ::operator new(ITEM_INSTANCE_SIZE);
|
unsigned char *item_instance = (unsigned char *) ::operator new(ITEM_INSTANCE_SIZE);
|
||||||
|
ALLOC_CHECK(item_instance);
|
||||||
item_instance = (*ItemInstance_constructor_item_extra)(item_instance, *Item_dye_powder, 1, i);
|
item_instance = (*ItemInstance_constructor_item_extra)(item_instance, *Item_dye_powder, 1, i);
|
||||||
(*FillingContainer_addItem)(filling_container, item_instance);
|
(*FillingContainer_addItem)(filling_container, item_instance);
|
||||||
}
|
}
|
||||||
@ -96,6 +99,15 @@ static void Inventory_selectSlot_injection(unsigned char *inventory, int32_t slo
|
|||||||
reset_selected_item_text_timer = true;
|
reset_selected_item_text_timer = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Print Chat To Log
|
||||||
|
static void Gui_addMessage_injection(unsigned char *gui, std::string const& text) {
|
||||||
|
// Print Log Message
|
||||||
|
fprintf(stderr, "[CHAT]: %s\n", text.c_str());
|
||||||
|
|
||||||
|
// Call Original Method
|
||||||
|
(*Gui_addMessage)(gui, text);
|
||||||
|
}
|
||||||
|
|
||||||
void init_misc_cpp() {
|
void init_misc_cpp() {
|
||||||
// Implement AppPlatform::readAssetFile So Translations Work
|
// Implement AppPlatform::readAssetFile So Translations Work
|
||||||
overwrite((void *) AppPlatform_readAssetFile, (void *) AppPlatform_readAssetFile_injection);
|
overwrite((void *) AppPlatform_readAssetFile, (void *) AppPlatform_readAssetFile_injection);
|
||||||
@ -109,4 +121,7 @@ void init_misc_cpp() {
|
|||||||
overwrite_calls((void *) Gui_renderChatMessages, (void *) Gui_renderChatMessages_injection);
|
overwrite_calls((void *) Gui_renderChatMessages, (void *) Gui_renderChatMessages_injection);
|
||||||
overwrite_calls((void *) Gui_tick, (void *) Gui_tick_injection);
|
overwrite_calls((void *) Gui_tick, (void *) Gui_tick_injection);
|
||||||
overwrite_calls((void *) Inventory_selectSlot, (void *) Inventory_selectSlot_injection);
|
overwrite_calls((void *) Inventory_selectSlot, (void *) Inventory_selectSlot_injection);
|
||||||
|
|
||||||
|
// Print Chat To Log
|
||||||
|
overwrite_calls((void *) Gui_addMessage, (void *) Gui_addMessage_injection);
|
||||||
}
|
}
|
@ -18,10 +18,12 @@ static char *get_override_path(const char *filename) {
|
|||||||
// Get Asset Override Path
|
// Get Asset Override Path
|
||||||
char *overrides = NULL;
|
char *overrides = NULL;
|
||||||
asprintf(&overrides, "%s/.minecraft-pi/overrides", getenv("HOME"));
|
asprintf(&overrides, "%s/.minecraft-pi/overrides", getenv("HOME"));
|
||||||
|
ALLOC_CHECK(overrides);
|
||||||
// Get data Path
|
// Get data Path
|
||||||
char *data = NULL;
|
char *data = NULL;
|
||||||
char *cwd = getcwd(NULL, 0);
|
char *cwd = getcwd(NULL, 0);
|
||||||
asprintf(&data, "%s/data", cwd);
|
asprintf(&data, "%s/data", cwd);
|
||||||
|
ALLOC_CHECK(data);
|
||||||
free(cwd);
|
free(cwd);
|
||||||
// Get Full Path
|
// Get Full Path
|
||||||
char *new_path = NULL;
|
char *new_path = NULL;
|
||||||
@ -29,6 +31,7 @@ static char *get_override_path(const char *filename) {
|
|||||||
if (full_path != NULL) {
|
if (full_path != NULL) {
|
||||||
if (starts_with(full_path, data)) {
|
if (starts_with(full_path, data)) {
|
||||||
asprintf(&new_path, "%s%s", overrides, &full_path[strlen(data)]);
|
asprintf(&new_path, "%s%s", overrides, &full_path[strlen(data)]);
|
||||||
|
ALLOC_CHECK(new_path);
|
||||||
if (access(new_path, F_OK) == -1) {
|
if (access(new_path, F_OK) == -1) {
|
||||||
free(new_path);
|
free(new_path);
|
||||||
new_path = NULL;
|
new_path = NULL;
|
||||||
|
@ -31,12 +31,15 @@ void take_screenshot() {
|
|||||||
|
|
||||||
char *screenshots = NULL;
|
char *screenshots = NULL;
|
||||||
asprintf(&screenshots, "%s/.minecraft-pi/screenshots", getenv("HOME"));
|
asprintf(&screenshots, "%s/.minecraft-pi/screenshots", getenv("HOME"));
|
||||||
|
ALLOC_CHECK(screenshots);
|
||||||
|
|
||||||
int num = 1;
|
int num = 1;
|
||||||
char *file = NULL;
|
char *file = NULL;
|
||||||
asprintf(&file, "%s/%s.png", screenshots, time);
|
asprintf(&file, "%s/%s.png", screenshots, time);
|
||||||
|
ALLOC_CHECK(file);
|
||||||
while (access(file, F_OK) != -1) {
|
while (access(file, F_OK) != -1) {
|
||||||
asprintf(&file, "%s/%s-%i.png", screenshots, time, num);
|
asprintf(&file, "%s/%s-%i.png", screenshots, time, num);
|
||||||
|
ALLOC_CHECK(file);
|
||||||
num++;
|
num++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,6 +87,7 @@ __attribute__((constructor)) static void init() {
|
|||||||
// Screenshots Folder
|
// Screenshots Folder
|
||||||
char *screenshots_folder = NULL;
|
char *screenshots_folder = NULL;
|
||||||
asprintf(&screenshots_folder, "%s/.minecraft-pi/screenshots", getenv("HOME"));
|
asprintf(&screenshots_folder, "%s/.minecraft-pi/screenshots", getenv("HOME"));
|
||||||
|
ALLOC_CHECK(screenshots_folder);
|
||||||
{
|
{
|
||||||
// Check Screenshots Folder
|
// Check Screenshots Folder
|
||||||
struct stat obj;
|
struct stat obj;
|
||||||
|
@ -53,11 +53,8 @@ static void *read_stdin_thread(__attribute__((unused)) void *data) {
|
|||||||
}
|
}
|
||||||
stdin_buffer_complete = true;
|
stdin_buffer_complete = true;
|
||||||
} else {
|
} else {
|
||||||
if (stdin_buffer == NULL) {
|
asprintf((char **) &stdin_buffer, "%s%c", stdin_buffer == NULL ? "" : stdin_buffer, (char) x);
|
||||||
asprintf((char **) &stdin_buffer, "%c", (char) x);
|
ALLOC_CHECK(stdin_buffer);
|
||||||
} else {
|
|
||||||
asprintf((char **) &stdin_buffer, "%s%c", stdin_buffer, (char) x);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,6 +84,7 @@ static void start_world(unsigned char *minecraft) {
|
|||||||
INFO("Listening On: %i", port);
|
INFO("Listening On: %i", port);
|
||||||
|
|
||||||
void *screen = ::operator new(PROGRESS_SCREEN_SIZE);
|
void *screen = ::operator new(PROGRESS_SCREEN_SIZE);
|
||||||
|
ALLOC_CHECK(screen);
|
||||||
screen = (*ProgressScreen)((unsigned char *) screen);
|
screen = (*ProgressScreen)((unsigned char *) screen);
|
||||||
(*Minecraft_setScreen)(minecraft, (unsigned char *) screen);
|
(*Minecraft_setScreen)(minecraft, (unsigned char *) screen);
|
||||||
}
|
}
|
||||||
@ -348,14 +346,6 @@ static void Minecraft_update_injection(unsigned char *minecraft) {
|
|||||||
handle_server_stop(minecraft);
|
handle_server_stop(minecraft);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Gui_addMessage_injection(unsigned char *gui, std::string const& text) {
|
|
||||||
// Print Log Message
|
|
||||||
fprintf(stderr, "[CHAT]: %s\n", text.c_str());
|
|
||||||
|
|
||||||
// Call Original Method
|
|
||||||
(*Gui_addMessage)(gui, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool RakNet_RakPeer_IsBanned_injection(__attribute__((unused)) unsigned char *rakpeer, const char *ip) {
|
static bool RakNet_RakPeer_IsBanned_injection(__attribute__((unused)) unsigned char *rakpeer, const char *ip) {
|
||||||
// Check banned-ips.txt
|
// Check banned-ips.txt
|
||||||
std::string banned_ips_file_path = get_banned_ips_file();
|
std::string banned_ips_file_path = get_banned_ips_file();
|
||||||
@ -483,8 +473,6 @@ static void server_init() {
|
|||||||
// Exit handler
|
// Exit handler
|
||||||
signal(SIGINT, exit_handler);
|
signal(SIGINT, exit_handler);
|
||||||
signal(SIGTERM, exit_handler);
|
signal(SIGTERM, exit_handler);
|
||||||
// Print Chat To Log
|
|
||||||
overwrite_calls((void *) Gui_addMessage, (void *) Gui_addMessage_injection);
|
|
||||||
// Set Max Players
|
// Set Max Players
|
||||||
unsigned char max_players_patch[4] = {get_max_players(), 0x30, 0xa0, 0xe3};
|
unsigned char max_players_patch[4] = {get_max_players(), 0x30, 0xa0, 0xe3};
|
||||||
patch((void *) 0x166d0, max_players_patch);
|
patch((void *) 0x166d0, max_players_patch);
|
||||||
|
@ -48,6 +48,7 @@ void run_tests() {
|
|||||||
{
|
{
|
||||||
char *path = NULL;
|
char *path = NULL;
|
||||||
asprintf(&path, "%s/.minecraft-pi", getenv("HOME"));
|
asprintf(&path, "%s/.minecraft-pi", getenv("HOME"));
|
||||||
|
ALLOC_CHECK(path);
|
||||||
int ret = access(path, R_OK | W_OK);
|
int ret = access(path, R_OK | W_OK);
|
||||||
free(path);
|
free(path);
|
||||||
|
|
||||||
|
@ -30,9 +30,11 @@ static float ItemRenderer_renderGuiItemCorrect_injection(unsigned char *font, un
|
|||||||
int32_t auxilary = *(int32_t *) (item_instance + ItemInstance_auxilary_property_offset);
|
int32_t auxilary = *(int32_t *) (item_instance + ItemInstance_auxilary_property_offset);
|
||||||
if (id == leaves_id) {
|
if (id == leaves_id) {
|
||||||
carried_item_instance = (unsigned char *) ::operator new(ITEM_INSTANCE_SIZE);
|
carried_item_instance = (unsigned char *) ::operator new(ITEM_INSTANCE_SIZE);
|
||||||
|
ALLOC_CHECK(carried_item_instance);
|
||||||
(*ItemInstance_constructor_tile_extra)(carried_item_instance, *Tile_leaves_carried, count, auxilary);
|
(*ItemInstance_constructor_tile_extra)(carried_item_instance, *Tile_leaves_carried, count, auxilary);
|
||||||
} else if (id == grass_id) {
|
} else if (id == grass_id) {
|
||||||
carried_item_instance = (unsigned char *) ::operator new(ITEM_INSTANCE_SIZE);
|
carried_item_instance = (unsigned char *) ::operator new(ITEM_INSTANCE_SIZE);
|
||||||
|
ALLOC_CHECK(carried_item_instance);
|
||||||
(*ItemInstance_constructor_tile_extra)(carried_item_instance, *Tile_grass_carried, count, auxilary);
|
(*ItemInstance_constructor_tile_extra)(carried_item_instance, *Tile_grass_carried, count, auxilary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,12 @@ mkdir -p out/deb
|
|||||||
rm -rf debian/tmp
|
rm -rf debian/tmp
|
||||||
mkdir debian/tmp
|
mkdir debian/tmp
|
||||||
|
|
||||||
|
# Version Time
|
||||||
|
DEB_VERSION_TIME="$(date --utc '+%Y%m%d.%H%M')"
|
||||||
|
|
||||||
# Prepare DEBIAN/control
|
# Prepare DEBIAN/control
|
||||||
prepare_control() {
|
prepare_control() {
|
||||||
sed -i 's/${VERSION}/'"${DEB_VERSION}.$(date --utc '+%Y%m%d.%H%M')"'/g' "$1/DEBIAN/control"
|
sed -i 's/${VERSION}/'"${DEB_VERSION}.${DEB_VERSION_TIME}"'/g' "$1/DEBIAN/control"
|
||||||
sed -i 's/${DEPENDENCIES}/'"${COMMON_DEPENDENCIES}$2"'/g' "$1/DEBIAN/control"
|
sed -i 's/${DEPENDENCIES}/'"${COMMON_DEPENDENCIES}$2"'/g' "$1/DEBIAN/control"
|
||||||
sed -i 's/${RECOMMENDED_DEPENDENCIES}/'"${RECOMMENDED_DEPENDENCIES}$2"'/g' "$1/DEBIAN/control"
|
sed -i 's/${RECOMMENDED_DEPENDENCIES}/'"${RECOMMENDED_DEPENDENCIES}$2"'/g' "$1/DEBIAN/control"
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user