589 lines
22 KiB
C++
Raw Normal View History

2024-04-02 19:22:01 -04:00
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <cmath>
2020-12-02 18:18:49 -05:00
#include <string>
#include <fstream>
#include <streambuf>
2024-04-02 19:22:01 -04:00
#include <GLES/gl.h>
2024-08-25 17:06:12 -04:00
#include <SDL/SDL.h>
#include <media-layer/core.h>
2020-12-02 18:18:49 -05:00
2021-01-27 16:26:19 -05:00
#include <libreborn/libreborn.h>
2021-09-11 23:18:12 -04:00
#include <symbols/minecraft.h>
2020-12-02 18:18:49 -05:00
2024-04-02 19:22:01 -04:00
#include <mods/init/init.h>
2022-06-25 17:30:08 -04:00
#include <mods/feature/feature.h>
2024-06-21 01:19:37 -04:00
#include <mods/input/input.h>
2022-06-25 17:30:08 -04:00
#include <mods/misc/misc.h>
2020-12-02 18:18:49 -05:00
2024-06-21 01:19:37 -04:00
#include "misc-internal.h"
2024-04-02 19:22:01 -04:00
// Sanitize Username
#define MAX_USERNAME_LENGTH 16
2024-04-03 03:19:12 -04:00
static void LoginPacket_read_injection(LoginPacket_read_t original, LoginPacket *packet, RakNet_BitStream *bit_stream) {
2024-04-02 19:22:01 -04:00
// Call Original Method
2024-04-03 03:19:12 -04:00
original(packet, bit_stream);
2024-04-02 19:22:01 -04:00
// Prepare
RakNet_RakString *rak_string = &packet->username;
// Get Original Username
2024-08-25 17:06:12 -04:00
const RakNet_RakString_SharedString *shared_string = rak_string->sharedString;
const char *c_str = shared_string->c_str;
2024-04-02 19:22:01 -04:00
// Sanitize
char *new_username = strdup(c_str);
ALLOC_CHECK(new_username);
2024-06-16 00:47:36 -04:00
sanitize_string(new_username, MAX_USERNAME_LENGTH, 0);
2024-04-02 19:22:01 -04:00
// Set New Username
2024-05-15 05:02:19 -04:00
rak_string->Assign(new_username);
2024-04-02 19:22:01 -04:00
// Free
free(new_username);
}
// Fix RakNet::RakString Security Bug
//
// RakNet::RakString's format constructor is often given unsanitized user input and is never used for formatting,
// this is a massive security risk, allowing clients to run arbitrary format specifiers, this disables the
// formatting functionality.
2024-07-14 05:06:27 -04:00
RakNet_RakString_constructor_t RakNet_RakString_constructor = (RakNet_RakString_constructor_t) 0xea5cc;
2024-04-02 19:22:01 -04:00
static RakNet_RakString *RakNet_RakString_injection(RakNet_RakString *rak_string, const char *format, ...) {
// Call Original Method
2024-05-15 05:08:39 -04:00
return RakNet_RakString_constructor(rak_string, "%s", format);
2024-04-02 19:22:01 -04:00
}
// Print Error Message If RakNet Startup Fails
static const char *RAKNET_ERROR_NAMES[] = {
"Success",
"Already Started",
"Invalid Socket Descriptors",
"Invalid Max Connections",
"Socket Family Not Supported",
"Part Already In Use",
"Failed To Bind Port",
"Failed Test Send",
"Port Cannot Be 0",
"Failed To Create Network Thread",
"Unknown"
};
static RakNet_StartupResult RakNetInstance_host_RakNet_RakPeer_Startup_injection(RakNet_RakPeer *rak_peer, unsigned short maxConnections, unsigned char *socketDescriptors, uint32_t socketDescriptorCount, int32_t threadPriority) {
// Call Original Method
2024-08-25 17:06:12 -04:00
const RakNet_StartupResult result = rak_peer->Startup(maxConnections, socketDescriptors, socketDescriptorCount, threadPriority);
2024-04-02 19:22:01 -04:00
// Print Error
if (result != RAKNET_STARTED) {
2024-06-15 08:52:15 -04:00
CONDITIONAL_ERR(reborn_is_server(), "Failed To Start RakNet: %s", RAKNET_ERROR_NAMES[result]);
2024-04-02 19:22:01 -04:00
}
// Return
return result;
}
// Fix Furnace Not Checking Item Auxiliary When Inserting New Item
2024-07-15 03:05:05 -04:00
static int32_t FurnaceScreen_handleAddItem_injection(FurnaceScreen_handleAddItem_t original, FurnaceScreen *furnace_screen, int32_t slot, const ItemInstance *item) {
2024-04-02 19:22:01 -04:00
// Get Existing Item
FurnaceTileEntity *tile_entity = furnace_screen->tile_entity;
2024-08-25 17:06:12 -04:00
const ItemInstance *existing_item = tile_entity->getItem(slot);
2024-04-02 19:22:01 -04:00
// Check Item
int valid;
if (item->id == existing_item->id && item->auxiliary == existing_item->auxiliary) {
// Item Matches, Is Valid
valid = 1;
} else {
// Item Doesn't Match, Check If Existing Item Is Empty
if ((existing_item->id | existing_item->count | existing_item->auxiliary) == 0) {
// Existing Item Is Empty, Is Valid
valid = 1;
} else {
// Existing Item Isn't Empty, Isn't Valid
valid = 0;
}
}
// Call Original Method
if (valid) {
// Valid
2024-04-03 03:19:12 -04:00
return original(furnace_screen, slot, item);
2024-04-02 19:22:01 -04:00
} else {
// Invalid
return 0;
}
}
// Get Real Selected Slot
int32_t misc_get_real_selected_slot(Player *player) {
// Get Selected Slot
2024-08-25 17:06:12 -04:00
const Inventory *inventory = player->inventory;
2024-04-02 19:22:01 -04:00
int32_t selected_slot = inventory->selectedSlot;
// Linked Slots
2024-08-25 17:06:12 -04:00
const int32_t linked_slots_length = inventory->linked_slots_length;
2024-04-02 19:22:01 -04:00
if (selected_slot < linked_slots_length) {
2024-08-25 17:06:12 -04:00
const int32_t *linked_slots = inventory->linked_slots;
2024-04-02 19:22:01 -04:00
selected_slot = linked_slots[selected_slot];
}
// Return
return selected_slot;
}
// Custom API Port
HOOK(bind, int, (int sockfd, const struct sockaddr *addr, socklen_t addrlen)) {
const sockaddr *new_addr = addr;
sockaddr_in in_addr = {};
if (addr->sa_family == AF_INET) {
2024-08-25 17:06:12 -04:00
in_addr = *(const sockaddr_in *) new_addr;
2024-04-02 19:22:01 -04:00
if (in_addr.sin_port == ntohs(4711)) {
const char *new_port_str = getenv(MCPI_API_PORT_ENV);
2024-04-02 19:22:01 -04:00
long int new_port;
if (new_port_str != nullptr && (new_port = strtol(new_port_str, nullptr, 0)) != 0L) {
in_addr.sin_port = htons(new_port);
}
}
2024-08-25 17:06:12 -04:00
new_addr = (const sockaddr *) &in_addr;
2024-04-02 19:22:01 -04:00
}
ensure_bind();
return real_bind(sockfd, new_addr, addrlen);
}
// Generate Caves
2024-04-03 03:19:12 -04:00
static void RandomLevelSource_buildSurface_injection(RandomLevelSource_buildSurface_t original, RandomLevelSource *random_level_source, int32_t chunk_x, int32_t chunk_y, unsigned char *chunk_data, Biome **biomes) {
2024-04-02 19:22:01 -04:00
// Call Original Method
2024-04-03 03:19:12 -04:00
original(random_level_source, chunk_x, chunk_y, chunk_data, biomes);
2024-04-02 19:22:01 -04:00
// Get Level
Level *level = random_level_source->level;
// Get Cave Feature
LargeCaveFeature *cave_feature = &random_level_source->cave_feature;
// Generate
2024-05-15 05:02:19 -04:00
cave_feature->apply((ChunkSource *) random_level_source, level, chunk_x, chunk_y, chunk_data, 0);
2024-04-02 19:22:01 -04:00
}
// Disable Hostile AI In Creative Mode
static Entity *PathfinderMob_findAttackTarget_injection(PathfinderMob *mob) {
// Call Original Method
2024-05-15 05:02:19 -04:00
Entity *target = mob->findAttackTarget();
2024-04-02 19:22:01 -04:00
// Only modify the AI of monsters
2024-05-15 05:02:19 -04:00
if (mob->getCreatureBaseType() != 1) {
2024-04-02 19:22:01 -04:00
return target;
}
// Check If Creative Mode
2024-05-15 05:02:19 -04:00
if (target != nullptr && target->isPlayer()) {
2024-08-25 17:06:12 -04:00
const Player *player = (Player *) target;
const Inventory *inventory = player->inventory;
const bool is_creative = inventory->is_creative;
2024-04-02 19:22:01 -04:00
if (is_creative) {
target = nullptr;
}
}
// Return
return target;
}
// Fix used items transferring durability
static int selected_slot = -1;
2024-08-25 17:06:12 -04:00
static void Player_startUsingItem_injection(Player_startUsingItem_t original, Player *self, ItemInstance *item_instance, const int time) {
2024-04-02 19:22:01 -04:00
selected_slot = self->inventory->selectedSlot;
2024-04-03 03:19:12 -04:00
original(self, item_instance, time);
2024-04-02 19:22:01 -04:00
}
2024-04-03 03:19:12 -04:00
static void Player_stopUsingItem_injection(Player_stopUsingItem_t original, Player *self) {
2024-04-02 19:22:01 -04:00
if (selected_slot != self->inventory->selectedSlot) {
self->itemBeingUsed.id = 0;
}
2024-04-03 03:19:12 -04:00
original(self);
2024-04-02 19:22:01 -04:00
}
2020-12-02 18:18:49 -05:00
// Read Asset File
2024-07-15 03:05:05 -04:00
static AppPlatform_readAssetFile_return_value AppPlatform_readAssetFile_injection(__attribute__((unused)) AppPlatform_readAssetFile_t original, __attribute__((unused)) AppPlatform *app_platform, const std::string &path) {
2023-11-11 00:44:26 -05:00
// Open File
2024-07-15 03:05:05 -04:00
std::ifstream stream("data/" + path, std::ios_base::binary | std::ios_base::ate);
2023-11-11 00:44:26 -05:00
if (!stream) {
// Does Not Exist
AppPlatform_readAssetFile_return_value ret;
ret.length = -1;
2024-04-02 19:22:01 -04:00
ret.data = nullptr;
2023-11-11 00:44:26 -05:00
return ret;
}
// Read File
2024-04-02 19:22:01 -04:00
std::streamoff len = stream.tellg();
char *buf = new char[len];
2024-04-02 19:22:01 -04:00
ALLOC_CHECK(buf);
stream.seekg(0, std::ifstream::beg);
stream.read(buf, len);
2023-11-11 00:44:26 -05:00
stream.close();
2020-12-04 12:17:51 -05:00
// Return String
AppPlatform_readAssetFile_return_value ret;
2024-08-25 17:06:12 -04:00
ret.length = int(len);
ret.data = strdup(buf);
2020-12-04 12:17:51 -05:00
return ret;
2020-12-02 18:18:49 -05:00
}
// Implement crafting remainders
static void PaneCraftingScreen_craftSelectedItem_PaneCraftingScreen_recheckRecipes_injection(PaneCraftingScreen *self) {
// Check for crafting remainders
2024-08-25 17:06:12 -04:00
const CItem *item = self->item;
for (size_t i = 0; i < item->ingredients.size(); i++) {
ItemInstance requested_item_instance = item->ingredients[i].requested_item;
2024-05-17 02:52:55 -04:00
Item *requested_item = Item::items[requested_item_instance.id];
2024-05-15 05:02:19 -04:00
ItemInstance *craftingRemainingItem = requested_item->getCraftingRemainingItem(&requested_item_instance);
2024-04-02 19:22:01 -04:00
if (craftingRemainingItem != nullptr) {
// Add or drop remainder
LocalPlayer *player = self->minecraft->player;
2024-05-15 05:02:19 -04:00
if (!player->inventory->add(craftingRemainingItem)) {
// Drop
2024-05-15 05:02:19 -04:00
player->drop(craftingRemainingItem, false);
}
}
}
// Call Original Method
2024-05-15 05:02:19 -04:00
self->recheckRecipes();
}
2024-08-25 17:06:12 -04:00
static ItemInstance *Item_getCraftingRemainingItem_injection(__attribute__((unused)) Item_getCraftingRemainingItem_t original, const Item *self, const ItemInstance *item_instance) {
2024-04-02 19:22:01 -04:00
if (self->craftingRemainingItem != nullptr) {
2024-05-17 00:36:28 -04:00
ItemInstance *ret = new ItemInstance;
ret->id = self->craftingRemainingItem->id;
ret->count = item_instance->count;
ret->auxiliary = 0;
return ret;
}
2024-04-02 19:22:01 -04:00
return nullptr;
}
2024-02-11 20:35:41 -05:00
// Display Date In Select World Screen
2024-08-25 17:06:12 -04:00
static std::string AppPlatform_linux_getDateString_injection(__attribute__((unused)) AppPlatform_linux *app_platform, const int time) {
2024-02-11 20:35:41 -05:00
// From https://github.com/ReMinecraftPE/mcpe/blob/56e51027b1c2e67fe5a0e8a091cefe51d4d11926/platforms/sdl/base/AppPlatform_sdl_base.cpp#L68-L84
2024-07-10 23:15:58 -04:00
const time_t tt = time;
2024-04-02 19:22:01 -04:00
tm t = {};
2024-02-11 20:35:41 -05:00
gmtime_r(&tt, &t);
char buf[2048];
strftime(buf, sizeof buf, "%b %d %Y %H:%M:%S", &t);
return std::string(buf);
}
// Missing Strings
static void add_missing_string(const std::string &key, const std::string &value) {
if (!I18n::_strings.contains(key)) {
I18n::_strings[key] = value;
}
}
static void Language_injection() {
// Fix Language Strings
add_missing_string("tile.waterStill.name", "Still Water");
add_missing_string("tile.lavaStill.name", "Still Lava");
add_missing_string("tile.grassCarried.name", "Carried Grass");
add_missing_string("tile.leavesCarried.name", "Carried Leaves");
add_missing_string("tile.invBedrock.name", "Invisible Bedrock");
// Missing Language Strings
add_missing_string("item.camera.name", "Camera");
add_missing_string("item.seedsMelon.name", "Melon Seeds");
add_missing_string("tile.pumpkinStem.name", "Pumpkin Stem");
add_missing_string("tile.stoneSlab.name", "Double Stone Slab");
}
// Invisible Bedrock
static Tile *Tile_initTiles_Tile_init_invBedrock_injection(Tile *t) {
Tile *ret = t->init();
t->setDescriptionId("invBedrock");
return ret;
}
// Append "Still" Suffix To Liquid Description Keys
static std::string *Tile_initTiles_std_string_constructor(std::string *self, const char *from, const std::string::allocator_type &alloc) {
new (self) std::string(from, alloc);
self->append("Still");
return self;
}
// Fix Pigmen Burning In The Sun
2024-08-24 00:30:06 -04:00
static bool fix_pigmen_burning = false;
static float Zombie_aiStep_getBrightness_injection(Entity *self, float param_1) {
2024-08-24 00:30:06 -04:00
if (fix_pigmen_burning && self->getEntityTypeId() == 36) {
return 0;
} else {
return self->getBrightness(param_1);
}
}
2024-08-22 23:43:32 -04:00
// Fix Door Item Dropping
static void DoorTile_neighborChanged_Tile_spawnResources_injection(DoorTile *self, Level *level, int x, int y, int z, int data2, __attribute__((unused)) float chance) {
self->spawnResources(level, x, y, z, data2, 1);
}
2024-08-23 05:18:20 -04:00
// Fix Cobweb Lighting
static Tile *Tile_initTiles_WebTile_setLightBlock_injection(Tile *self, __attribute__((unused)) int strength) {
return self;
}
2024-08-24 00:30:06 -04:00
// Fix Fire Immunity
static void Mob_baseTick_injection_fire_immunity(Mob_baseTick_t original, Mob *self) {
// Fix Fire Timer
if (self->fire_immune) {
self->fire_timer = 0;
}
// Call Original Method
original(self);
}
// Fix Fire Syncing
#define FLAG_ONFIRE 0
static void Mob_baseTick_injection_fire_syncing(Mob_baseTick_t original, Mob *self) {
// Fix Fire Timer
if (self->level->is_client_side) {
self->fire_timer = 0;
}
// Call Original Method
original(self);
// Sync Data
if (!self->level->is_client_side) {
self->setSharedFlag(FLAG_ONFIRE, self->fire_timer > 0);
}
}
static bool Entity_isOnFire_injection(Entity_isOnFire_t original, Entity *self) {
// Call Original Method
bool ret = original(self);
// Check Shared Data
bool shared_data = false;
if (self->isMob()) {
shared_data = ((Mob *) self)->getSharedFlag(FLAG_ONFIRE);
}
if (shared_data) {
ret = true;
}
// Return
return ret;
}
// Fix Sneaking Syncing
#define FLAG_SNEAKING 1
#define PLAYER_ACTION_STOP_SNEAKING 100
#define PLAYER_ACTION_START_SNEAKING 101
static void LocalPlayer_tick_injection(LocalPlayer_tick_t original, LocalPlayer *self) {
// Call Original Method
original(self);
// Sync Data
if (!self->level->is_client_side) {
self->setSharedFlag(FLAG_SNEAKING, self->isSneaking());
} else {
const bool real = self->isSneaking();
const bool synced = self->getSharedFlag(FLAG_SNEAKING);
if (real != synced) {
// Send To Server
PlayerActionPacket *packet = new PlayerActionPacket;
Packet_constructor->get(false)((Packet *) packet);
packet->vtable = PlayerActionPacket_vtable_base;
packet->entity_id = self->id;
packet->action = real ? PLAYER_ACTION_START_SNEAKING : PLAYER_ACTION_STOP_SNEAKING;
self->minecraft->rak_net_instance->send(*(Packet *) packet);
}
}
}
static void ServerSideNetworkHandler_handle_PlayerActionPacket_injection(ServerSideNetworkHandler_handle_PlayerActionPacket_t original, ServerSideNetworkHandler *self, const RakNet_RakNetGUID &rak_net_guid, PlayerActionPacket *packet) {
// Call Original Method
original(self, rak_net_guid, packet);
// Handle Sneaking
const bool is_sneaking = packet->action == PLAYER_ACTION_START_SNEAKING;
if (self->level != nullptr && (is_sneaking || packet->action == PLAYER_ACTION_STOP_SNEAKING)) {
Entity *entity = self->level->getEntity(packet->entity_id);
if (entity != nullptr && entity->isPlayer()) {
((Player *) entity)->setSharedFlag(FLAG_SNEAKING, is_sneaking);
}
}
}
// Make Mobs Actually Catch On Fire
static void set_on_fire(Mob *mob, const int seconds) {
const int value = seconds * 20;
if (value > mob->fire_timer) {
mob->fire_timer = value;
}
}
template <typename Self>
static void Monster_aiStep_injection(__attribute__((unused)) std::function<void(Self *)> original, Self *self) {
// Fire!
Level *level = self->level;
if (level->isDay() && !level->is_client_side) {
const float brightness = Zombie_aiStep_getBrightness_injection((Entity *) self, 1);
if (brightness > 0.5f) {
Random *random = &self->random;
if (level->canSeeSky(Mth::floor(self->x), Mth::floor(self->y), Mth::floor(self->z)) && random->nextFloat() * 3.5f < (brightness - 0.4f)) {
set_on_fire((Mob *) self, 8);
}
}
}
// Call Parent Method
Monster_aiStep->get(false)((Monster *) self);
}
// Clear Fire For Creative Players
static void Player_tick_injection(Player_tick_t original, Player *self) {
// Fix Value
if (self->inventory->is_creative && !self->level->is_client_side && self->isOnFire()) {
self->fire_timer = 0;
}
// Call Original Method
original(self);
}
// Init
2024-04-02 19:22:01 -04:00
void init_misc() {
// Sanitize Username
2024-08-25 17:06:12 -04:00
if (feature_has("Sanitize Usernames", server_enabled)) {
overwrite_calls(LoginPacket_read, LoginPacket_read_injection);
}
2024-04-02 19:22:01 -04:00
// Fix RakNet::RakString Security Bug
2024-08-25 17:06:12 -04:00
if (feature_has("Patch RakNet Security Bug", server_enabled)) {
overwrite_calls_manual((void *) RakNet_RakString_constructor, (void *) RakNet_RakString_injection);
}
2024-04-02 19:22:01 -04:00
// Print Error Message If RakNet Startup Fails
2024-08-25 17:06:12 -04:00
if (feature_has("Log RakNet Startup Errors", server_enabled)) {
overwrite_call((void *) 0x73778, (void *) RakNetInstance_host_RakNet_RakPeer_Startup_injection);
}
2024-04-02 19:22:01 -04:00
// Fix Furnace Not Checking Item Auxiliary When Inserting New Item
if (feature_has("Fix Furnace Not Checking Item Auxiliary", server_disabled)) {
2024-04-03 03:19:12 -04:00
overwrite_calls(FurnaceScreen_handleAddItem, FurnaceScreen_handleAddItem_injection);
2024-04-02 19:22:01 -04:00
}
// Disable Speed Bridging
if (feature_has("Disable Speed Bridging", server_disabled)) {
unsigned char disable_speed_bridging_patch[4] = {0x03, 0x00, 0x53, 0xe1}; // "cmp r3, r3"
patch((void *) 0x494b4, disable_speed_bridging_patch);
}
// Disable Creative Mode Mining Delay
if (feature_has("Disable Creative Mode Mining Delay", server_disabled)) {
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x19fa0, nop_patch);
}
// Generate Caves
if (feature_has("Generate Caves", server_auto)) {
2024-04-03 03:19:12 -04:00
overwrite_calls(RandomLevelSource_buildSurface, RandomLevelSource_buildSurface_injection);
2024-04-02 19:22:01 -04:00
}
// Disable Hostile AI In Creative Mode
if (feature_has("Disable Hostile AI In Creative Mode", server_enabled)) {
overwrite_call((void *) 0x83b8c, (void *) PathfinderMob_findAttackTarget_injection);
}
2024-08-25 17:06:12 -04:00
// Send The Full Level, Not Only Changed Chunks
2024-04-02 19:22:01 -04:00
if (feature_has("Send Full Level When Hosting Game", server_enabled)) {
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x717c4, nop_patch);
unsigned char mov_r3_ff[4] = {0xff, 0x30, 0xa0, 0xe3}; // "mov r3, #0xff"
patch((void *) 0x7178c, mov_r3_ff);
}
2024-08-25 17:06:12 -04:00
// Fix Used Items Transferring Durability
if (feature_has("Fix Transferring Durability When Using Items", server_disabled)) {
overwrite_calls(Player_startUsingItem, Player_startUsingItem_injection);
overwrite_calls(Player_stopUsingItem, Player_stopUsingItem_injection);
2024-04-02 19:22:01 -04:00
}
2020-12-02 18:18:49 -05:00
// Implement AppPlatform::readAssetFile So Translations Work
2022-04-09 20:01:16 -04:00
if (feature_has("Load Language Files", server_enabled)) {
2024-05-24 04:44:53 -04:00
overwrite_calls(AppPlatform_readAssetFile, AppPlatform_readAssetFile_injection);
2021-07-04 19:02:45 -04:00
}
2020-12-02 18:18:49 -05:00
2024-02-11 20:35:41 -05:00
// Implement Crafting Remainders
if (feature_has("Implement Crafting Remainders", server_enabled)) {
overwrite_call((void *) 0x2e230, (void *) PaneCraftingScreen_craftSelectedItem_PaneCraftingScreen_recheckRecipes_injection);
overwrite_calls(Item_getCraftingRemainingItem, Item_getCraftingRemainingItem_injection);
}
2024-02-08 00:34:43 -05:00
2024-02-11 20:35:41 -05:00
// Display Date In Select World Screen
if (feature_has("Display Date In Select World Screen", server_disabled)) {
2024-05-04 20:46:15 -04:00
patch_vtable(AppPlatform_linux_getDateString, AppPlatform_linux_getDateString_injection);
2024-02-11 20:35:41 -05:00
}
2024-04-02 19:22:01 -04:00
2024-06-21 01:19:37 -04:00
// Fullscreen
2024-08-25 17:06:12 -04:00
if (feature_has("Fullscreen Support", server_disabled)) {
misc_run_on_key_press([](__attribute__((unused)) Minecraft *mc, int key) {
if (key == MC_KEY_F11) {
media_toggle_fullscreen();
return true;
} else {
return false;
}
});
}
2024-06-21 01:19:37 -04:00
// Fix/Update Language Strings
if (feature_has("Add Missing Language Strings", server_disabled)) {
misc_run_on_language_setup(Language_injection);
// Water/Lava Language Strings
overwrite_call((void *) 0xc3b54, (void *) Tile_initTiles_std_string_constructor);
overwrite_call((void *) 0xc3c7c, (void *) Tile_initTiles_std_string_constructor);
// Carried Tile Language Strings
patch_address((void *) 0xc6674, (void *) "grassCarried");
patch_address((void *) 0xc6684, (void *) "leavesCarried");
// Invisible Bedrock Language String
overwrite_call((void *) 0xc5f04, (void *) Tile_initTiles_Tile_init_invBedrock_injection);
}
2024-08-25 17:06:12 -04:00
// Prevent Pigmen From Burning In The Sun
if (feature_has("Fix Pigmen Burning In The Sun", server_enabled)) {
2024-08-24 00:30:06 -04:00
fix_pigmen_burning = true;
overwrite_call((void *) 0x89a1c, (void *) Zombie_aiStep_getBrightness_injection);
}
2024-08-22 23:43:32 -04:00
// Fix Door Duplication
if (feature_has("Fix Door Duplication", server_enabled)) {
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0xbe230, nop_patch);
overwrite_call((void *) 0xbe110, (void *) DoorTile_neighborChanged_Tile_spawnResources_injection);
}
2024-08-23 05:18:20 -04:00
// Fix Cobweb Lighting
if (feature_has("Fix Cobweb Lighting", server_enabled)) {
overwrite_call((void *) 0xc444c, (void *) Tile_initTiles_WebTile_setLightBlock_injection);
}
2024-08-24 00:30:06 -04:00
// Fix Fire Immunity
if (feature_has("Fix Fire Immunity", server_enabled)) {
overwrite_calls(Mob_baseTick, Mob_baseTick_injection_fire_immunity);
}
// Fix Fire Syncing
if (feature_has("Fix Fire Syncing", server_enabled)) {
overwrite_calls(Mob_baseTick, Mob_baseTick_injection_fire_syncing);
overwrite_calls(Entity_isOnFire, Entity_isOnFire_injection);
}
// Fix Sneaking Syncing
if (feature_has("Fix Sneaking Syncing", server_enabled)) {
overwrite_calls(LocalPlayer_tick, LocalPlayer_tick_injection);
overwrite_calls(ServerSideNetworkHandler_handle_PlayerActionPacket, ServerSideNetworkHandler_handle_PlayerActionPacket_injection);
}
// Make Skeletons/Zombies Actually Catch On Fire
if (feature_has("Fix Sunlight Not Properly Setting Mobs On Fire", server_enabled)) {
overwrite_calls(Zombie_aiStep, Monster_aiStep_injection<Zombie>);
overwrite_calls(Skeleton_aiStep, Monster_aiStep_injection<Skeleton>);
}
// Clear Fire For Creative Players
if (feature_has("Stop Creative Players From Burning", server_enabled)) {
overwrite_calls(Player_tick, Player_tick_injection);
}
2024-08-25 17:06:12 -04:00
// Init Other Components
_init_misc_tinting();
_init_misc_ui();
2024-04-02 19:22:01 -04:00
_init_misc_logging();
_init_misc_api();
2024-08-25 17:06:12 -04:00
_init_misc_graphics();
}