diff --git a/mods/include/mods/fps/fps.h b/mods/include/mods/fps/fps.h index 702a3447..27cc779e 100644 --- a/mods/include/mods/fps/fps.h +++ b/mods/include/mods/fps/fps.h @@ -1,3 +1,4 @@ #pragma once extern double fps; +extern double tps; \ No newline at end of file diff --git a/mods/src/f3/f3.cpp b/mods/src/f3/f3.cpp index 0faae4a2..0db8abbc 100644 --- a/mods/src/f3/f3.cpp +++ b/mods/src/f3/f3.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -18,20 +19,34 @@ static std::string to_string_with_precision(const double x, const int precision) stream << std::fixed << std::setprecision(precision) << x; return stream.str(); } +static float wrap_degrees(float x) { + x = std::fmod(x, 360); + if (x >= 180) { + x -= 360; + } + if (x < -180) { + x += 360; + } + return x; +} static int debug_precision = 3; -static std::vector get_debug_info(const Minecraft *minecraft) { +static std::vector get_debug_info_left(const Minecraft *minecraft) { std::vector info; // Version info.push_back(std::string("MCPI ") + version_get()); // FPS info.push_back("FPS: " + to_string_with_precision(fps, debug_precision)); - // Seed + // Level Information if (minecraft->level) { info.push_back(""); info.push_back("Seed: " + std::to_string(minecraft->level->data.seed)); + info.push_back("Time: " + std::to_string(minecraft->level->data.time)); + info.push_back("Entities: " + std::to_string(minecraft->level->entities.size())); + info.push_back("Players: " + std::to_string(minecraft->level->players.size())); } - // X/Y/Z + // Player Information if (minecraft->player) { + // X/Y/Z info.push_back(""); float x = minecraft->player->x; float y = minecraft->player->y - minecraft->player->height_offset; @@ -40,6 +55,93 @@ static std::vector get_debug_info(const Minecraft *minecraft) { info.push_back("X: " + to_string_with_precision(x, debug_precision)); info.push_back("Y: " + to_string_with_precision(y, debug_precision)); info.push_back("Z: " + to_string_with_precision(z, debug_precision)); + // Rotation + info.push_back(""); + const float yaw = wrap_degrees(minecraft->player->yaw); + info.push_back("Yaw: " + to_string_with_precision(yaw, debug_precision)); + const float pitch = wrap_degrees(minecraft->player->pitch); + info.push_back("Pitch: " + to_string_with_precision(pitch, debug_precision)); + // Facing + char axis[3] = {}; + bool is_positive_on_axis; + std::string direction; + if (const float abs_yaw = std::abs(yaw); abs_yaw < 45 || abs_yaw > 135) { + // Z-Axis + axis[1] = 'Z'; + is_positive_on_axis = abs_yaw < 90; + direction = is_positive_on_axis ? "South" : "North"; + } else { + // X-Axis + axis[1] = 'X'; + is_positive_on_axis = yaw < 0; + direction = is_positive_on_axis ? "East" : "West"; + } + axis[0] = is_positive_on_axis ? '+' : '-'; + info.push_back("Facing: " + direction + " (" + axis + ")"); + } + // Return + return info; +} +static std::vector get_debug_info_right(const Minecraft *minecraft) { + std::vector info; + // TPS + info.push_back("TPS: " + to_string_with_precision(tps, debug_precision)); + // Target Information + const HitResult &target = minecraft->hit_result; + if (target.type != 2) { + float x; + float y; + float z; + std::string type; + std::vector type_info; + int xyz_precision; + if (target.type == 0) { + // Tile + x = float(target.x); + y = float(target.y); + z = float(target.z); + type = "Tile"; + if (minecraft->level) { + const int id = minecraft->level->getTile(x, y, z); + std::string id_info = "ID: " + std::to_string(id); + if (Tile *tile = Tile::tiles[id]) { + const std::string description_id = tile->getDescriptionId(); + std::string name = description_id + ".name"; + if (I18n::_strings.contains(name)) { + name = I18n::_strings[name]; + } else { + name = description_id; + } + if (!name.empty()) { + id_info += " (" + name + ')'; + } + } + type_info.push_back(id_info); + type_info.push_back("Data: " + std::to_string(minecraft->level->getData(x, y, z))); + } + xyz_precision = 0; + } else { + // Entity + Entity *entity = target.entity; + x = entity->x; + y = entity->y; + z = entity->z; + type = "Entity"; + type_info.push_back("Type ID: " + std::to_string(entity->getEntityTypeId())); // TODO: Specify name when RJ PR is merged + type_info.push_back("ID: " + std::to_string(entity->id)); + if (entity->isMob()) { + Mob *mob = (Mob *) entity; + type_info.push_back("Health: " + std::to_string(mob->health) + '/' + std::to_string(mob->getMaxHealth())); + } + xyz_precision = debug_precision; + } + info.push_back(""); + info.push_back("Target X: " + to_string_with_precision(x, xyz_precision)); + info.push_back("Target Y: " + to_string_with_precision(y, xyz_precision)); + info.push_back("Target Z: " + to_string_with_precision(z, xyz_precision)); + info.push_back(""); + info.push_back("Target Type: " + type); + info.insert(info.end(), type_info.begin(), type_info.end()); } // Return return info; @@ -48,12 +150,16 @@ static std::vector get_debug_info(const Minecraft *minecraft) { // Render Text With Background static constexpr uint32_t debug_background_color = 0x90505050; static constexpr int debug_text_color = 0xe0e0e0; -static void render_debug_line(Gui *gui, std::string &line, const int x, const int y) { +static void render_debug_line(Gui *gui, const std::string &line, int x, const int y, const bool right_aligned) { // Draw Background const int width = gui->minecraft->font->width(line); if (width == 0) { return; } + if (right_aligned) { + const int screen_width = int(float(gui->minecraft->screen_width) * Gui::InvGuiScale); + x = screen_width - x - width + 1; + } int x1 = x - 1; int y1 = y - 1; int x2 = x + width; @@ -66,15 +172,18 @@ static void render_debug_line(Gui *gui, std::string &line, const int x, const in static bool debug_info_shown = false; static constexpr int debug_margin = 2; static constexpr int debug_line_padding = 1; +static void render_debug_info(Gui *self, const std::vector &info, const bool right_aligned) { + int y = debug_margin; + for (const std::string &line : info) { + render_debug_line(self, line, debug_margin, y, right_aligned); + y += line_height; + y += debug_line_padding; + } +} static void Gui_renderDebugInfo_injection(__attribute__((unused)) Gui_renderDebugInfo_t original, Gui *self) { if (debug_info_shown) { - std::vector info = get_debug_info(self->minecraft); - int y = debug_margin; - for (std::string &line : info) { - render_debug_line(self, line, debug_margin, y); - y += line_height; - y += debug_line_padding; - } + render_debug_info(self, get_debug_info_left(self->minecraft), false); + render_debug_info(self, get_debug_info_right(self->minecraft), true); } } diff --git a/mods/src/fps/fps.cpp b/mods/src/fps/fps.cpp index 03609504..3e6ef9fa 100644 --- a/mods/src/fps/fps.cpp +++ b/mods/src/fps/fps.cpp @@ -16,32 +16,65 @@ static long long int get_time() { return a + b; } +// Tracker +struct Tracker { + // State + long long int counter = 0; + long long int last_time = get_time(); + // Properties + double &out; + const std::function callback; + // Constructor + Tracker(double &out_, const std::function &callback_): + out(out_), + callback(callback_) {} + // Update + void update() { + // Update Counter + counter++; + // Get Delta + const long long int time = get_time(); + const long long int delta = time - last_time; + const double delta_seconds = double(delta) / double(NANOSECONDS_IN_SECOND); + // Calculate FPS + if (delta_seconds >= 1) { + out = double(counter) / delta_seconds; + counter = 0; + last_time = time; + // Callback + if (callback) { + callback(); + } + } + } +}; + // Track FPS static bool log_fps; double fps = 0; -static void update_fps() { - // Track Frames - static long long int frames = 0; - frames++; - // Get Delta - const long long int time = get_time(); - static long long int last_time = time; - const long long int delta = time - last_time; - const double delta_seconds = double(delta) / double(NANOSECONDS_IN_SECOND); - // Calculate FPS - if (delta_seconds >= 1) { - fps = double(frames) / delta_seconds; - frames = 0; - last_time = time; - // Log - if (log_fps) { - INFO("FPS: %f", fps); - } +static void fps_callback() { + // Log + if (log_fps) { + INFO("FPS: %f", fps); } } +static Tracker fps_tracker(fps, fps_callback); +static void update_fps() { + fps_tracker.update(); +} + +// Track TPS +double tps = 0; +static Tracker tps_tracker(tps, nullptr); +static void update_tps(__attribute__((unused)) Minecraft *minecraft) { + tps_tracker.update(); +} // Init void init_fps() { - misc_run_on_swap_buffers(update_fps); - log_fps = feature_has("Log FPS", server_disabled); + if (!reborn_is_headless()) { + misc_run_on_swap_buffers(update_fps); + log_fps = feature_has("Log FPS", server_disabled); + } + misc_run_on_tick(update_tps); } diff --git a/mods/src/init/init.cpp b/mods/src/init/init.cpp index 8675e099..72435b83 100644 --- a/mods/src/init/init.cpp +++ b/mods/src/init/init.cpp @@ -24,8 +24,8 @@ __attribute__((constructor)) static void init() { init_title_screen(); if (!reborn_is_headless()) { init_skin(); - init_fps(); } + init_fps(); init_touch(); init_textures(); init_creative(); diff --git a/mods/src/server/server.cpp b/mods/src/server/server.cpp index 61c732ba..af182b7a 100644 --- a/mods/src/server/server.cpp +++ b/mods/src/server/server.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -21,6 +20,7 @@ #include #include #include +#include // --only-generate: Ony Generate World And Then Exit static bool only_generate = false; @@ -207,29 +207,6 @@ static void list_callback(Minecraft *minecraft, const std::string &username, Pla INFO(" - %s (%s)", username.c_str(), get_player_ip(minecraft, player)); } -// Track TPS -#define NANOSECONDS_IN_SECOND 1000000000ll -static long long int get_time() { - timespec ts = {}; - clock_gettime(CLOCK_MONOTONIC_RAW, &ts); - 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; -static void Minecraft_tick_injection(__attribute__((unused)) const Minecraft *minecraft) { - const long long int time = get_time(); - if (is_last_tick_time_set) { - 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; -} - // Get ServerSideNetworkHandler From Minecraft static ServerSideNetworkHandler *get_server_side_network_handler(const Minecraft *minecraft) { return (ServerSideNetworkHandler *) minecraft->network_handler; @@ -612,9 +589,6 @@ static void server_init() { // 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 pthread_create(&read_stdin_thread_obj, nullptr, read_stdin_thread, nullptr); } diff --git a/symbols/src/entity/Mob.def b/symbols/src/entity/Mob.def index 9e1efbee..e72f91c9 100644 --- a/symbols/src/entity/Mob.def +++ b/symbols/src/entity/Mob.def @@ -10,6 +10,7 @@ virtual-method ItemInstance *getCarriedItem() = 0x1ac; virtual-method void updateAi() = 0x1cc; virtual-method float getWalkingSpeedModifier() = 0x1e8; virtual-method void aiStep() = 0x180; +virtual-method int getMaxHealth() = 0x168; method bool getSharedFlag(int flag) = 0x81fd8; method void setSharedFlag(int flag, bool value) = 0x81ef8; diff --git a/symbols/src/tile/Tile.def b/symbols/src/tile/Tile.def index cec5e486..8c38f6e1 100644 --- a/symbols/src/tile/Tile.def +++ b/symbols/src/tile/Tile.def @@ -48,6 +48,7 @@ virtual-method bool getSignal2(LevelSource *level, int x, int y, int z, int dire // Called by Level_hasDirectSignal virtual-method bool getDirectSignal(Level *level, int x, int y, int z, int direction) = 0xc8; virtual-method void entityInside(Level *level, int x, int y, int z, Entity *entity) = 0xcc; +virtual-method std::string getName() = 0xd8; virtual-method std::string getDescriptionId() = 0xdc; virtual-method Tile *setDescriptionId(const std::string &description_id) = 0xe0; virtual-method Tile *setSoundType(const Tile_SoundType &sound_type) = 0xe8;