176 lines
5.5 KiB
C++
Raw Normal View History

2021-11-13 23:29:48 -05:00
#include <ctime>
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <media-layer/core.h>
#include <SDL/SDL.h>
2022-06-25 17:30:08 -04:00
#include <mods/init/init.h>
#include <mods/compat/compat.h>
#include <mods/misc/misc.h>
2021-11-13 23:29:48 -05:00
// Constants
#define NANOSECONDS_IN_SECOND 1000000000ll
// Config
#define BENCHMARK_GAME_MODE 0 // Survival Mode
2021-11-13 23:29:48 -05:00
#define BENCHMARK_SEED 2048 // Random Number
#define BENCHMARK_WORLD_NAME "_Benchmark" // Random Number
#define BENCHMARK_LENGTH (180ll * NANOSECONDS_IN_SECOND) // 3 Minutes
#define BENCHMARK_ROTATION_INTERVAL ((long long int) (0.02f * NANOSECONDS_IN_SECOND))
#define BENCHMARK_ROTATION_AMOUNT 10
// Create/Start World
2024-01-06 06:30:23 -05:00
static void start_world(Minecraft *minecraft) {
2021-11-13 23:29:48 -05:00
// Log
2022-04-14 21:12:42 -04:00
INFO("Loading Benchmark");
2021-11-13 23:29:48 -05:00
// Specify Level Settings
LevelSettings settings;
settings.game_type = BENCHMARK_GAME_MODE;
settings.seed = BENCHMARK_SEED;
// Delete World If It Already Exists
2024-05-15 05:02:19 -04:00
LevelStorageSource *level_source = minecraft->getLevelSource();
2024-01-06 06:30:23 -05:00
std::string name = BENCHMARK_WORLD_NAME;
2024-05-15 05:02:19 -04:00
level_source->deleteLevel(&name);
2021-11-13 23:29:48 -05:00
// Select Level
2024-05-15 05:02:19 -04:00
minecraft->selectLevel(&name, &name, &settings);
2021-11-13 23:29:48 -05:00
// Open ProgressScreen
2024-05-17 00:36:28 -04:00
ProgressScreen *screen = new ProgressScreen;
2021-11-13 23:29:48 -05:00
ALLOC_CHECK(screen);
2024-05-15 05:02:19 -04:00
screen = screen->constructor();
minecraft->setScreen((Screen *) screen);
2021-11-13 23:29:48 -05:00
}
// Track Frames
#ifndef MCPI_HEADLESS_MODE
2021-11-13 23:29:48 -05:00
static unsigned long long int frames = 0;
HOOK(media_swap_buffers, void, ()) {
ensure_media_swap_buffers();
2024-01-07 03:23:43 -05:00
real_media_swap_buffers();
2021-11-13 23:29:48 -05:00
frames++;
}
#endif
// Track Ticks
static unsigned long long int ticks = 0;
2024-01-06 06:30:23 -05:00
static void Minecraft_tick_injection(__attribute__((unused)) Minecraft *minecraft) {
ticks++;
}
2021-11-13 23:29:48 -05:00
// Get Time
static long long int get_time() {
2024-04-03 03:19:12 -04:00
timespec ts = {};
2021-11-13 23:29:48 -05:00
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
long long int a = (long long int) ts.tv_nsec;
long long int b = ((long long int) ts.tv_sec) * NANOSECONDS_IN_SECOND;
return a + b;
}
// Store Time When World Loaded
static int world_loaded = 0;
static long long int world_loaded_time;
#ifndef MCPI_HEADLESS_MODE
2021-11-13 23:29:48 -05:00
static unsigned long long int world_loaded_frames;
#endif
static unsigned long long int world_loaded_ticks;
// Last Logged Status Update
static int32_t last_logged_status = -1;
2021-11-13 23:29:48 -05:00
// Runs Every Tick
static bool loaded = false;
static bool exit_requested = false;
2024-01-06 06:30:23 -05:00
static void Minecraft_update_injection(Minecraft *minecraft) {
2021-11-13 23:29:48 -05:00
// Create/Start World
if (!loaded) {
start_world(minecraft);
loaded = true;
}
// Detect World Loaded
2024-05-15 05:02:19 -04:00
if (!world_loaded && minecraft->isLevelGenerated()) {
2021-11-13 23:29:48 -05:00
world_loaded = 1;
world_loaded_time = get_time();
#ifndef MCPI_HEADLESS_MODE
2021-11-13 23:29:48 -05:00
world_loaded_frames = frames;
#endif
world_loaded_ticks = ticks;
2021-11-13 23:29:48 -05:00
}
// Run Benchmark
if (!exit_requested && world_loaded) {
// Get Time
long long int current_time = get_time() - world_loaded_time;
#ifndef MCPI_HEADLESS_MODE
2021-11-13 23:29:48 -05:00
unsigned long long int current_frames = frames - world_loaded_frames;
#endif
unsigned long long int current_ticks = ticks - world_loaded_ticks;
// Log
int32_t status = (((double) current_time) / ((double) BENCHMARK_LENGTH)) * 100;
if (status > 100) {
status = 100;
}
if (is_progress_difference_significant(status, last_logged_status)) {
INFO("Benchmark Status: %i%%", status);
last_logged_status = status;
}
2021-11-13 23:29:48 -05:00
// Rotate Player
2024-06-10 18:55:22 -04:00
static long long int rotation_so_far = 0;
long long int ideal_rotation = (BENCHMARK_ROTATION_AMOUNT * current_time) / BENCHMARK_ROTATION_INTERVAL;
long long int rotation_diff = ideal_rotation - rotation_so_far;
if (rotation_diff >= BENCHMARK_ROTATION_AMOUNT) {
2021-11-13 23:29:48 -05:00
SDL_Event event;
event.type = SDL_MOUSEMOTION;
event.motion.x = 0;
event.motion.y = 0;
2024-06-10 18:55:22 -04:00
event.motion.xrel = (rotation_diff > INT16_MAX) ? INT16_MAX : int16_t(rotation_diff);
2021-11-13 23:29:48 -05:00
event.motion.yrel = 0;
SDL_PushEvent(&event);
// Reset Rotation Timer
2024-06-10 18:55:22 -04:00
rotation_so_far += event.motion.xrel;
2021-11-13 23:29:48 -05:00
}
// Check If Benchmark Is Over
if (current_time >= BENCHMARK_LENGTH) {
// Request Exit
compat_request_exit();
// Disable Special Behavior After Requesting Exit
exit_requested = true;
// Calculate FPS & TPS
INFO("Benchmark Completed");
INFO(" Total Time: %lld Nanoseconds", current_time);
#ifndef MCPI_HEADLESS_MODE
2021-11-13 23:29:48 -05:00
static double frames_per_nanosecond = ((double) current_frames) / ((double) current_time);
static double frames_per_second = frames_per_nanosecond * NANOSECONDS_IN_SECOND;
INFO(" FPS: %f (%llu Total Frames)", frames_per_second, current_frames);
#endif
static double ticks_per_nanosecond = ((double) current_ticks) / ((double) current_time);
static double ticks_per_second = ticks_per_nanosecond * NANOSECONDS_IN_SECOND;
INFO(" TPS: %f (%llu Total Ticks)", ticks_per_second, current_ticks);
2021-11-13 23:29:48 -05:00
}
}
}
// Init Benchmark
2024-05-12 03:19:01 -04:00
void init_benchmark() {
2024-01-23 23:00:22 -05:00
// --benchmark: Activate Benchmark
2024-05-12 03:19:01 -04:00
bool active = getenv("_MCPI_BENCHMARK") != nullptr;
2021-11-13 23:29:48 -05:00
if (active) {
misc_run_on_update(Minecraft_update_injection);
// Track Ticks
misc_run_on_tick(Minecraft_tick_injection);
2021-11-13 23:29:48 -05:00
// Disable Interaction
media_set_interactable(0);
// Disable V-Sync
media_disable_vsync();
}
}