minecraft-pi-reborn/mods/src/server/server.cpp

624 lines
21 KiB
C++
Raw Normal View History

2020-10-10 23:02:13 +00:00
#include <string>
2024-06-15 12:52:15 +00:00
#include <cstdint>
2020-10-10 23:02:13 +00:00
#include <ctime>
#include <cstdio>
#include <fstream>
2020-11-03 22:39:55 +00:00
#include <vector>
#include <sys/ioctl.h>
#include <pthread.h>
2020-10-10 23:02:13 +00:00
#include <unistd.h>
2021-06-17 21:32:24 +00:00
#include <SDL/SDL.h>
2020-10-10 23:02:13 +00:00
2024-06-15 12:52:15 +00:00
#include <libreborn/libreborn.h>
2021-11-14 04:29:48 +00:00
#include <symbols/minecraft.h>
2020-10-10 23:02:13 +00:00
2024-01-24 01:51:36 +00:00
#include <mods/server/server.h>
2022-06-25 21:30:08 +00:00
#include <mods/init/init.h>
#include <mods/home/home.h>
#include <mods/compat/compat.h>
#include <mods/misc/misc.h>
2024-06-15 12:52:15 +00:00
#include <mods/game-mode/game-mode.h>
2021-06-17 21:32:24 +00:00
// --only-generate: Ony Generate World And Then Exit
static bool only_generate = false;
2024-05-12 07:19:01 +00:00
__attribute__((constructor)) static void _init_only_generate() {
only_generate = getenv(_MCPI_ONLY_GENERATE_ENV) != nullptr;
2021-06-17 21:32:24 +00:00
}
2020-10-10 23:02:13 +00:00
// Server Properties
2024-01-24 01:51:36 +00:00
ServerProperties &get_server_properties() {
2020-10-10 23:02:13 +00:00
static ServerProperties properties;
return properties;
}
// Default Server Properties
2024-09-21 05:46:52 +00:00
namespace ServerPropertyTypes {
static ServerProperty message_of_the_day("motd", "Minecraft Server", "Message Of The Day");
static ServerProperty show_minecon_badge("show-minecon-badge", "false", "Show The MineCon Badge Next To MOTD In Server List");
static ServerProperty game_mode("game-mode", "0", "Game Mode (0 = Survival, 1 = Creative)");
static ServerProperty port("port", "19132", "Port");
static ServerProperty seed("seed", "", "World Seed (Blank = Random Seed)");
static ServerProperty force_mob_spawning("force-mob-spawning", "false", "Force Mob Spawning (false = Disabled, true = Enabled)");
static ServerProperty peaceful_mode("peaceful-mode", "false", "Peaceful Mode (false = Disabled, true = Enabled)");
static ServerProperty world_name("world-name", "world", "World To Select");
static ServerProperty max_players("max-players", "4", "Maximum Player Count");
static ServerProperty enable_whitelist("whitelist", "false", "Enable Whitelist");
static ServerProperty enable_death_messages("death-messages", "true", "Enable Death Messages");
static ServerProperty enable_cave_generation("generate-caves", "true", "Generate Caves");
}
2020-10-10 23:02:13 +00:00
2020-11-06 04:05:37 +00:00
// Get World Name
2021-06-17 21:32:24 +00:00
static std::string get_world_name() {
2024-09-21 05:46:52 +00:00
const std::string name = get_server_properties().get_string(ServerPropertyTypes::world_name);
2022-07-20 06:58:14 +00:00
char *safe_name_c = to_cp437(name.c_str());
std::string safe_name = safe_name_c;
free(safe_name_c);
return safe_name;
2020-11-06 04:05:37 +00:00
}
2020-11-03 22:39:55 +00:00
// Create/Start World
2024-01-06 23:03:48 +00:00
static void start_world(Minecraft *minecraft) {
2021-11-14 04:29:48 +00:00
// Get World Name
std::string world_name = get_world_name();
// Log
INFO("Loading World: %s", world_name.c_str());
2022-05-11 22:24:03 +00:00
// Peaceful Mode
2024-01-06 23:03:48 +00:00
Options *options = &minecraft->options;
2024-09-21 05:46:52 +00:00
options->game_difficulty = get_server_properties().get_bool(ServerPropertyTypes::peaceful_mode) ? 0 : 2;
2022-05-11 22:24:03 +00:00
2021-06-17 21:32:24 +00:00
// Specify Level Settings
2020-11-03 22:39:55 +00:00
LevelSettings settings;
2024-09-21 05:46:52 +00:00
settings.game_type = get_server_properties().get_int(ServerPropertyTypes::game_mode);
const std::string seed_str = get_server_properties().get_string(ServerPropertyTypes::seed);
2024-06-15 12:52:15 +00:00
const int32_t seed = get_seed_from_string(seed_str);
2020-11-03 22:39:55 +00:00
settings.seed = seed;
2020-10-10 23:02:13 +00:00
2021-06-17 21:32:24 +00:00
// Select Level
2024-07-15 07:05:05 +00:00
minecraft->selectLevel(world_name, world_name, settings);
2020-10-10 23:02:13 +00:00
2021-06-17 21:32:24 +00:00
// Don't Open Port When Using --only-generate
if (!only_generate) {
// Open Port
2024-09-21 05:46:52 +00:00
const int port = get_server_properties().get_int(ServerPropertyTypes::port);
2021-06-17 21:32:24 +00:00
INFO("Listening On: %i", port);
2024-05-15 09:02:19 +00:00
minecraft->hostMultiplayer(port);
2021-06-17 21:32:24 +00:00
}
2020-10-10 23:02:13 +00:00
2021-06-17 21:32:24 +00:00
// Open ProgressScreen
2024-09-21 01:30:47 +00:00
ProgressScreen *screen = ProgressScreen::allocate();
2021-02-16 17:26:40 +00:00
ALLOC_CHECK(screen);
2024-05-15 09:02:19 +00:00
screen = screen->constructor();
minecraft->setScreen((Screen *) screen);
2020-11-03 22:39:55 +00:00
}
2020-10-10 23:02:13 +00:00
// Check If Running In Whitelist Mode
static bool is_whitelist() {
2024-09-21 05:46:52 +00:00
return get_server_properties().get_bool(ServerPropertyTypes::enable_whitelist);
}
// Get Path Of Blacklist (Or Whitelist) File
static std::string get_blacklist_file() {
2021-06-28 02:16:37 +00:00
std::string file(home_get());
2021-06-17 21:32:24 +00:00
file.append(is_whitelist() ? "/whitelist.txt" : "/blacklist.txt");
2020-11-03 22:39:55 +00:00
return file;
}
2020-11-06 04:05:37 +00:00
// Get Vector Of Players In Level
2024-01-06 23:03:48 +00:00
static std::vector<Player *> get_players_in_level(Level *level) {
return level->players;
2020-11-06 04:05:37 +00:00
}
// Get Player's Username
2024-01-06 23:03:48 +00:00
static std::string get_player_username(Player *player) {
2024-09-21 01:30:47 +00:00
const std::string *username = &player->username;
2022-07-20 06:58:14 +00:00
char *safe_username_c = from_cp437(username->c_str());
std::string safe_username = safe_username_c;
free(safe_username_c);
return safe_username;
2020-11-06 04:05:37 +00:00
}
// Get Level From Minecraft
2024-09-21 01:30:47 +00:00
static Level *get_level(const Minecraft *minecraft) {
2024-01-06 23:03:48 +00:00
return minecraft->level;
2020-11-06 04:05:37 +00:00
}
2020-11-03 22:39:55 +00:00
// Find Players With Username And Run Callback
2024-06-15 12:52:15 +00:00
typedef void (*player_callback_t)(Minecraft *minecraft, const std::string &username, Player *player);
2024-09-21 01:30:47 +00:00
static void find_players(Minecraft *minecraft, const std::string &target_username, const player_callback_t callback, const bool all_players) {
2024-01-06 23:03:48 +00:00
Level *level = get_level(minecraft);
2024-09-21 01:30:47 +00:00
const std::vector<Player *> players = get_players_in_level(level);
2020-11-03 22:39:55 +00:00
bool found_player = false;
for (std::size_t i = 0; i < players.size(); i++) {
// Iterate Players
2024-01-06 23:03:48 +00:00
Player *player = players[i];
2022-07-20 06:58:14 +00:00
std::string username = get_player_username(player);
2020-11-04 00:31:27 +00:00
if (all_players || username == target_username) {
2020-11-03 22:39:55 +00:00
// Run Callback
2024-01-07 08:23:43 +00:00
callback(minecraft, username, player);
2020-11-03 22:39:55 +00:00
found_player = true;
}
}
2020-11-04 00:31:27 +00:00
if (!all_players && !found_player) {
2020-11-03 22:39:55 +00:00
INFO("Invalid Player: %s", target_username.c_str());
}
}
2021-06-17 21:32:24 +00:00
// Get RakNet Objects
2024-01-06 23:03:48 +00:00
static RakNet_RakNetGUID get_rak_net_guid(Player *player) {
return ((ServerPlayer *) player)->guid;
2020-11-04 21:05:31 +00:00
}
2024-01-06 23:03:48 +00:00
static RakNet_SystemAddress get_system_address(RakNet_RakPeer *rak_peer, RakNet_RakNetGUID guid) {
2020-11-03 22:39:55 +00:00
// Get SystemAddress
2024-05-15 09:02:19 +00:00
return rak_peer->GetSystemAddressFromGuid(guid);
2020-11-04 21:05:31 +00:00
}
2024-09-21 01:30:47 +00:00
static RakNet_RakPeer *get_rak_peer(const Minecraft *minecraft) {
2024-01-06 23:03:48 +00:00
return minecraft->rak_net_instance->peer;
2020-11-04 21:05:31 +00:00
}
2024-09-21 01:30:47 +00:00
static char *get_rak_net_guid_ip(RakNet_RakPeer *rak_peer, const RakNet_RakNetGUID &guid) {
2021-09-28 18:04:05 +00:00
RakNet_SystemAddress address = get_system_address(rak_peer, guid);
// Get IP
2024-05-15 09:02:19 +00:00
return address.ToString(false, '|');
2021-09-28 18:04:05 +00:00
}
2020-11-04 21:05:31 +00:00
// Get IP From Player
2024-09-21 01:30:47 +00:00
static char *get_player_ip(const Minecraft *minecraft, Player *player) {
2024-01-06 23:03:48 +00:00
RakNet_RakPeer *rak_peer = get_rak_peer(minecraft);
2024-09-21 01:30:47 +00:00
const RakNet_RakNetGUID guid = get_rak_net_guid(player);
2021-09-28 18:04:05 +00:00
// Return
2024-01-06 23:03:48 +00:00
return get_rak_net_guid_ip(rak_peer, guid);
2020-11-03 22:39:55 +00:00
}
// Ban Player
2022-06-26 03:32:31 +00:00
static bool is_ip_in_blacklist(const char *ip);
2024-06-15 12:52:15 +00:00
static void ban_callback(Minecraft *minecraft, const std::string &username, Player *player) {
2020-11-03 22:39:55 +00:00
// Get IP
char *ip = get_player_ip(minecraft, player);
// Ban Player
INFO("Banned: %s (%s)", username.c_str(), ip);
// Write To File
std::ofstream blacklist_output(get_blacklist_file(), std::ios_base::app);
if (blacklist_output) {
if (blacklist_output.good()) {
blacklist_output << "# " << username << '\n' << ip << '\n';
2020-11-03 22:39:55 +00:00
}
if (blacklist_output.is_open()) {
blacklist_output.close();
}
}
2022-06-26 03:32:31 +00:00
// Reload
2024-04-02 23:22:01 +00:00
is_ip_in_blacklist(nullptr);
2020-10-10 23:02:13 +00:00
}
2020-11-03 22:39:55 +00:00
// Kill Player
2024-06-15 12:52:15 +00:00
static void kill_callback(__attribute__((unused)) Minecraft *minecraft, __attribute__((unused)) const std::string &username, Player *player) {
2024-05-15 09:02:19 +00:00
player->hurt(nullptr, INT32_MAX);
2020-11-03 22:39:55 +00:00
INFO("Killed: %s", username.c_str());
}
// List Player
2024-06-15 12:52:15 +00:00
static void list_callback(Minecraft *minecraft, const std::string &username, Player *player) {
2020-11-03 22:39:55 +00:00
INFO(" - %s (%s)", username.c_str(), get_player_ip(minecraft, player));
}
// Track TPS
#define NANOSECONDS_IN_SECOND 1000000000ll
static long long int get_time() {
2024-05-05 00:46:15 +00:00
timespec ts = {};
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
2024-09-21 01:30:47 +00:00
const long long int a = (long long int) ts.tv_nsec;
const long long int b = ((long long int) ts.tv_sec) * NANOSECONDS_IN_SECOND;
return a + b;
}
static bool is_last_tick_time_set = false;
static long long int last_tick_time;
static double tps = 0;
2024-09-21 01:30:47 +00:00
static void Minecraft_tick_injection(__attribute__((unused)) const Minecraft *minecraft) {
const long long int time = get_time();
if (is_last_tick_time_set) {
2024-09-21 01:30:47 +00:00
const long long int tick_time = time - last_tick_time;
tps = ((double) NANOSECONDS_IN_SECOND) / ((double) tick_time);
} else {
is_last_tick_time_set = true;
}
last_tick_time = time;
}
2020-11-04 21:05:31 +00:00
// Get ServerSideNetworkHandler From Minecraft
2024-09-21 01:30:47 +00:00
static ServerSideNetworkHandler *get_server_side_network_handler(const Minecraft *minecraft) {
2024-01-06 23:03:48 +00:00
return (ServerSideNetworkHandler *) minecraft->network_handler;
2020-11-03 22:39:55 +00:00
}
2021-06-17 21:32:24 +00:00
// Read STDIN Thread
2024-06-21 05:19:37 +00:00
static pthread_t read_stdin_thread_obj;
static volatile bool stdin_line_ready = false;
static std::string stdin_line;
2021-06-17 21:32:24 +00:00
static void *read_stdin_thread(__attribute__((unused)) void *data) {
// Loop
2024-06-21 05:19:37 +00:00
char *line = nullptr;
size_t len = 0;
while (getline(&line, &len, stdin) != -1) {
stdin_line = line;
stdin_line_ready = true;
// Wait For Line To Be Read
while (stdin_line_ready) {}
2021-06-17 21:32:24 +00:00
}
2024-06-21 05:19:37 +00:00
free(line);
2024-04-02 23:22:01 +00:00
return nullptr;
2021-06-17 21:32:24 +00:00
}
2024-06-21 05:19:37 +00:00
// Handle Server Stop
static void handle_server_stop(Minecraft *minecraft) {
if (compat_check_exit_requested()) {
INFO("Stopping Server");
// Save And Exit
Level *level = get_level(minecraft);
if (level != nullptr) {
level->saveLevelData();
}
minecraft->leaveGame(false);
// Kill Reader Thread
pthread_cancel(read_stdin_thread_obj);
pthread_join(read_stdin_thread_obj, nullptr);
stdin_line_ready = false;
// Stop Game
SDL_Event event;
event.type = SDL_QUIT;
SDL_PushEvent(&event);
2021-09-28 18:04:05 +00:00
}
2021-06-17 21:32:24 +00:00
}
2020-11-03 22:39:55 +00:00
// Handle Commands
2024-09-21 06:30:06 +00:00
bool ServerCommand::has_args() const {
return name[name.length() - 1] == ' ';
}
std::string ServerCommand::get_lhs_help() const {
std::string out;
out.append(4, ' ');
out += name;
if (has_args()) {
out += "<Arguments>";
2024-09-21 05:46:52 +00:00
}
2024-09-21 06:30:06 +00:00
return out;
}
std::string ServerCommand::get_full_help(const int max_lhs_length) const {
std::string out = get_lhs_help();
out.append(max_lhs_length - out.length(), ' ');
out += " - ";
out += comment;
return out;
}
std::vector<ServerCommand> *server_get_commands(Minecraft *minecraft, ServerSideNetworkHandler *server_side_network_handler) {
std::vector<ServerCommand> *commands = new std::vector<ServerCommand>;
// Ban Player
if (!is_whitelist()) {
commands->push_back({
.name = "ban ",
.comment = "IP-Ban All Players With Specified Username",
.callback = [minecraft](const std::string &cmd) {
find_players(minecraft, cmd, ban_callback, false);
}
});
2024-09-21 05:46:52 +00:00
}
2024-09-21 06:30:06 +00:00
// Reload White/Blacklist
commands->push_back({
.name = "reload",
.comment = std::string("Reload The ") + (is_whitelist() ? "Whitelist" : "Blacklist"),
.callback = [](__attribute__((unused)) const std::string &cmd) {
INFO("Reloading %s", is_whitelist() ? "Whitelist" : "Blacklist");
is_ip_in_blacklist(nullptr);
}
});
// Kill Player
commands->push_back({
.name = "kill ",
.comment = "Kill All Players With Specified Username",
.callback = [minecraft](const std::string &cmd) {
find_players(minecraft, cmd, kill_callback, false);
}
});
// Post Message
commands->push_back({
.name = "say ",
.comment = "Print Specified Message To Chat",
.callback = [server_side_network_handler](const std::string &cmd) {
// Format Message
const std::string message = "[Server] " + cmd;
char *safe_message = to_cp437(message.c_str());
std::string cpp_string = safe_message;
// Post Message To Chat
server_side_network_handler->displayGameMessage(cpp_string);
// Free
free(safe_message);
}
});
// List Players
commands->push_back({
.name = "list",
.comment = "List All Players",
.callback = [minecraft](__attribute__((unused)) const std::string &cmd) {
INFO("All Players:");
find_players(minecraft, "", list_callback, true);
}
});
// Ticks-Per-Second
commands->push_back({
.name = "tps",
.comment = "Print TPS",
.callback = [](__attribute__((unused)) const std::string &cmd) {
INFO("TPS: %f", tps);
}
});
// Stop
commands->push_back({
.name = "stop",
.comment = "Stop Server",
.callback = [](__attribute__((unused)) const std::string &cmd) {
compat_request_exit();
}
});
// Help Page
commands->push_back({
.name = "help",
.comment = "Print This Message",
.callback = [commands](__attribute__((unused)) const std::string &cmd) {
INFO("All Commands:");
int max_lhs_length = 0;
for (ServerCommand command : *commands) {
const int lhs_length = command.get_lhs_help().length();
if (lhs_length > max_lhs_length) {
max_lhs_length = lhs_length;
}
}
for (ServerCommand command : *commands) {
INFO("%s", command.get_full_help(max_lhs_length).c_str());
}
}
});
// Return
return commands;
}
2024-01-06 23:03:48 +00:00
static void handle_commands(Minecraft *minecraft) {
2021-06-17 21:32:24 +00:00
// Check If Level Is Generated
2024-06-21 05:19:37 +00:00
if (minecraft->isLevelGenerated() && stdin_line_ready) {
// Read Line
std::string data = std::move(stdin_line);
data.pop_back(); // Remove Newline
stdin_line_ready = false;
2021-06-17 21:32:24 +00:00
// Command Ready; Run It
2024-06-21 05:19:37 +00:00
ServerSideNetworkHandler *server_side_network_handler = get_server_side_network_handler(minecraft);
if (server_side_network_handler != nullptr) {
2024-09-21 05:46:52 +00:00
// Generate Command List
2024-09-21 06:30:06 +00:00
std::vector<ServerCommand> *commands = server_get_commands(minecraft, server_side_network_handler);
2024-09-21 05:46:52 +00:00
// Run
bool success = false;
2024-09-21 06:30:06 +00:00
for (ServerCommand command : *commands) {
2024-09-21 05:46:52 +00:00
const bool valid = command.has_args() ? data.rfind(command.name, 0) == 0 : data == command.name;
if (valid) {
command.callback(data.substr(command.name.length()));
success = true;
break;
}
}
if (!success) {
2024-06-21 05:19:37 +00:00
INFO("Invalid Command: %s", data.c_str());
2020-11-03 22:39:55 +00:00
}
2024-09-21 06:30:06 +00:00
// Free
delete commands;
2020-11-03 22:39:55 +00:00
}
}
}
// Runs Every Tick
static bool loaded = false;
2024-01-06 23:03:48 +00:00
static void Minecraft_update_injection(Minecraft *minecraft) {
2020-11-03 22:39:55 +00:00
// Create/Start World
if (!loaded) {
start_world(minecraft);
loaded = true;
}
2021-06-17 21:32:24 +00:00
// Handle --only-generate
2024-05-15 09:02:19 +00:00
if (only_generate && minecraft->isLevelGenerated()) {
2021-06-17 21:32:24 +00:00
// Request Exit
compat_request_exit();
// Disable Special Behavior After Requesting Exit
only_generate = false;
}
2020-11-03 22:39:55 +00:00
// Handle Commands
handle_commands(minecraft);
2020-11-04 21:05:31 +00:00
// Server Stop
handle_server_stop(minecraft);
2020-11-03 22:39:55 +00:00
}
2022-06-26 03:32:31 +00:00
// Check Blacklist/Whitelist
static bool is_ip_in_blacklist(const char *ip) {
static std::vector<std::string> ips;
2024-04-02 23:22:01 +00:00
if (ip == nullptr) {
2022-06-26 03:32:31 +00:00
// Reload
ips.clear();
// Check banned-ips.txt
2024-09-21 01:30:47 +00:00
const std::string blacklist_file_path = get_blacklist_file();
2022-06-26 03:32:31 +00:00
std::ifstream blacklist_file(blacklist_file_path);
if (blacklist_file) {
if (blacklist_file.good()) {
std::string line;
while (std::getline(blacklist_file, line)) {
// Check Line
if (line.length() > 0 && line[0] != '#') {
ips.push_back(line);
2020-11-03 22:39:55 +00:00
}
}
}
2022-06-26 03:32:31 +00:00
if (blacklist_file.is_open()) {
blacklist_file.close();
}
} else {
2022-06-26 03:32:31 +00:00
ERR("Unable To Read Blacklist/Whitelist");
}
2022-06-26 03:32:31 +00:00
return false;
} else {
// Check List
2022-07-14 03:35:05 +00:00
for (std::string &x : ips) {
2024-06-15 12:52:15 +00:00
if (x == ip) {
2022-06-26 03:32:31 +00:00
return true;
}
}
return false;
}
}
// Ban Players
2024-05-05 00:46:15 +00:00
static bool RakNet_RakPeer_IsBanned_injection(__attribute__((unused)) RakNet_RakPeer_IsBanned_t original, __attribute__((unused)) RakNet_RakPeer *rakpeer, const char *ip) {
2022-06-26 03:32:31 +00:00
// Check List
2024-09-21 01:30:47 +00:00
const bool ret = is_ip_in_blacklist(ip);
2022-06-26 03:32:31 +00:00
if (is_whitelist()) {
return !ret;
} else {
2022-06-26 03:32:31 +00:00
return ret;
2020-10-10 23:02:13 +00:00
}
}
2021-09-28 18:04:05 +00:00
// Log IPs
2024-07-15 07:05:05 +00:00
static Player *ServerSideNetworkHandler_onReady_ClientGeneration_ServerSideNetworkHandler_popPendingPlayer_injection(ServerSideNetworkHandler *server_side_network_handler, const RakNet_RakNetGUID &guid) {
2021-09-28 18:04:05 +00:00
// Call Original Method
2024-05-15 09:02:19 +00:00
Player *player = server_side_network_handler->popPendingPlayer(guid);
2021-09-28 18:04:05 +00:00
// Check If Player Is Null
2024-04-02 23:22:01 +00:00
if (player != nullptr) {
2021-09-28 18:04:05 +00:00
// Get Data
2024-09-21 01:30:47 +00:00
const std::string *username = &player->username;
const Minecraft *minecraft = server_side_network_handler->minecraft;
2024-01-06 23:03:48 +00:00
RakNet_RakPeer *rak_peer = get_rak_peer(minecraft);
2024-07-15 07:05:05 +00:00
char *ip = get_rak_net_guid_ip(rak_peer, guid);
2021-09-28 18:04:05 +00:00
// Log
2021-12-01 02:54:43 +00:00
INFO("%s Has Joined (IP: %s)", username->c_str(), ip);
2021-09-28 18:04:05 +00:00
}
// Return
return player;
}
2022-04-13 00:38:44 +00:00
// Get MOTD
static std::string get_motd() {
2024-09-21 05:46:52 +00:00
std::string motd(get_server_properties().get_string(ServerPropertyTypes::message_of_the_day));
2022-04-13 00:38:44 +00:00
return motd;
}
// Get Feature Flags
2020-12-01 17:02:48 +00:00
static bool loaded_features = false;
2020-12-02 23:18:49 +00:00
static const char *get_features() {
2020-12-01 17:02:48 +00:00
static std::string features;
if (!loaded_features) {
loaded_features = true;
2021-07-04 23:02:45 +00:00
features.clear();
2024-09-21 05:46:52 +00:00
if (get_server_properties().get_bool(ServerPropertyTypes::force_mob_spawning)) {
2021-07-05 01:23:12 +00:00
features += "Force Mob Spawning|";
}
2024-09-21 05:46:52 +00:00
if (get_server_properties().get_bool(ServerPropertyTypes::enable_death_messages)) {
features += "Implement Death Messages|";
}
2024-09-21 05:46:52 +00:00
if (get_server_properties().get_bool(ServerPropertyTypes::enable_cave_generation)) {
2023-02-25 05:26:45 +00:00
features += "Generate Caves|";
}
2020-12-01 17:02:48 +00:00
}
return features.c_str();
2020-10-10 23:02:13 +00:00
}
2020-12-01 17:02:48 +00:00
// Get Max Players
2020-12-01 17:02:48 +00:00
static unsigned char get_max_players() {
2024-09-21 05:46:52 +00:00
int val = get_server_properties().get_int(ServerPropertyTypes::max_players);
2020-10-11 19:38:48 +00:00
if (val < 0) {
val = 0;
}
if (val > 255) {
val = 255;
}
return (unsigned char) val;
}
2020-10-10 23:02:13 +00:00
2022-09-21 21:34:19 +00:00
// Real Init Server
2020-12-02 23:18:49 +00:00
static void server_init() {
2020-10-10 23:02:13 +00:00
// Open Properties File
2021-06-28 02:16:37 +00:00
std::string file(home_get());
2021-06-17 21:32:24 +00:00
file.append("/server.properties");
2020-10-10 23:02:13 +00:00
std::ifstream properties_file(file);
2021-11-14 04:29:48 +00:00
// Check Properties File
2021-06-28 02:16:37 +00:00
if (!properties_file.good()) {
2020-10-10 23:02:13 +00:00
// Write Defaults
std::ofstream properties_file_output(file);
2024-09-21 05:46:52 +00:00
for (const ServerProperty *property : ServerProperty::all) {
properties_file_output << "# " << property->comment << '\n';
properties_file_output << property->key << '=' << property->def << '\n';
}
2020-10-10 23:02:13 +00:00
properties_file_output.close();
// Re-Open File
properties_file = std::ifstream(file);
}
2021-06-28 02:16:37 +00:00
// Check Properties File
2020-10-10 23:02:13 +00:00
if (!properties_file.is_open()) {
2021-06-28 02:16:37 +00:00
ERR("Unable To Open %s", file.c_str());
2020-10-10 23:02:13 +00:00
}
// Load Properties
get_server_properties().load(properties_file);
// Close Properties File
2020-10-10 23:02:13 +00:00
properties_file.close();
// Create Empty Blacklist/Whitelist File
std::string blacklist_file_path = get_blacklist_file();
std::ifstream blacklist_file(blacklist_file_path);
2021-06-28 02:16:37 +00:00
if (!blacklist_file.good()) {
2020-11-03 22:39:55 +00:00
// Write Default
std::ofstream blacklist_output(blacklist_file_path);
blacklist_output << "# Blacklist/Whitelist; Each Line Is One IP Address\n";
blacklist_output.close();
2020-11-03 22:39:55 +00:00
}
if (blacklist_file.is_open()) {
blacklist_file.close();
2020-11-03 22:39:55 +00:00
}
2022-06-26 03:32:31 +00:00
// Load Blacklist/Whitelist
2024-04-02 23:22:01 +00:00
is_ip_in_blacklist(nullptr);
2020-11-03 22:39:55 +00:00
2020-10-10 23:02:13 +00:00
// Prevent Main Player From Loading
2021-03-05 00:27:24 +00:00
unsigned char player_patch[4] = {0x00, 0x20, 0xa0, 0xe3}; // "mov r2, #0x0"
2020-10-10 23:02:13 +00:00
patch((void *) 0x1685c, player_patch);
// Start World On Launch
2021-11-14 04:29:48 +00:00
misc_run_on_update(Minecraft_update_injection);
2020-10-11 19:38:48 +00:00
// Set Max Players
2021-03-05 00:27:24 +00:00
unsigned char max_players_patch[4] = {get_max_players(), 0x30, 0xa0, 0xe3}; // "mov r3, #MAX_PLAYERS"
2020-10-11 19:38:48 +00:00
patch((void *) 0x166d0, max_players_patch);
2020-11-03 22:39:55 +00:00
// Custom Banned IP List
2024-05-24 08:44:53 +00:00
overwrite_calls(RakNet_RakPeer_IsBanned, RakNet_RakPeer_IsBanned_injection);
2021-06-17 21:32:24 +00:00
// Show The MineCon Icon Next To MOTD In Server List
2024-09-21 05:46:52 +00:00
if (get_server_properties().get_bool(ServerPropertyTypes::show_minecon_badge)) {
2021-03-05 00:27:24 +00:00
unsigned char minecon_badge_patch[4] = {0x04, 0x1a, 0x9f, 0xe5}; // "ldr r1, [0x741f0]"
2020-11-10 20:16:42 +00:00
patch((void *) 0x737e4, minecon_badge_patch);
2020-11-05 01:12:48 +00:00
}
2021-09-28 18:04:05 +00:00
// Log IPs
overwrite_call((void *) 0x75e54, (void *) ServerSideNetworkHandler_onReady_ClientGeneration_ServerSideNetworkHandler_popPendingPlayer_injection);
// Track TPS
misc_run_on_tick(Minecraft_tick_injection);
// Start Reading STDIN
2024-04-02 23:22:01 +00:00
pthread_create(&read_stdin_thread_obj, nullptr, read_stdin_thread, nullptr);
2020-10-10 23:02:13 +00:00
}
2020-12-02 23:18:49 +00:00
2021-06-17 21:32:24 +00:00
// Init Server
2020-12-02 23:18:49 +00:00
void init_server() {
2021-06-17 21:32:24 +00:00
server_init();
set_and_print_env(MCPI_FEATURE_FLAGS_ENV, get_features());
set_and_print_env(MCPI_RENDER_DISTANCE_ENV, "Tiny");
set_and_print_env(MCPI_USERNAME_ENV, get_motd().c_str());
2021-06-17 21:32:24 +00:00
}