Last active
September 8, 2025 17:12
-
-
Save ilyakurdyukov/fdaa24e0c7c97394c607973d22a83850 to your computer and use it in GitHub Desktop.
A small library for changing the speed of time in games for Linux.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _GNU_SOURCE | |
#define _GNU_SOURCE | |
#endif | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <dlfcn.h> | |
#define HOOK(ret, name, args) ret name args { \ | |
static ret (*old_##name) args = 0; \ | |
if (!old_##name) { \ | |
old_##name = (ret (*) args) dlsym(RTLD_NEXT, #name); \ | |
if (!old_##name) { printf("dlsym \"%s\" failed\n", #name); exit(1); } \ | |
} | |
#include <time.h> | |
#include <sys/time.h> | |
static double speed, rspeed; | |
static int64_t old_timeval; | |
__attribute__((constructor)) | |
static void speed_init() { | |
const char *str = getenv("HOOK_SPEED"); | |
{ | |
struct timeval tv; | |
speed = rspeed = 1; | |
gettimeofday(&tv, NULL); | |
old_timeval = tv.tv_sec * (int64_t)1000000 + tv.tv_usec; | |
rspeed = 1 / (speed = 0.5); | |
} | |
if (str) { | |
double newspeed = atof(str); | |
printf("HOOK_SPEED = %f\n", newspeed); | |
if (newspeed == newspeed && newspeed >= 0.1 && newspeed <= 2.0) { | |
rspeed = 1 / (speed = newspeed); | |
} else { | |
printf("HOOK_SPEED out of range, set to default %f\n", speed); | |
} | |
} | |
} | |
static void change_timeval(const struct timeval *tv, struct timeval *new, double mul) { | |
int64_t n = 1000000, t = tv->tv_sec * n + tv->tv_usec; | |
t -= old_timeval; | |
t *= mul; | |
t += old_timeval; | |
new->tv_usec = t % n; | |
new->tv_sec = t / n; | |
} | |
static void change_timespec(const struct timespec *tp, struct timespec *new, double mul) { | |
int64_t n = 1000000000, t = tp->tv_sec * n + tp->tv_nsec; | |
t *= mul; | |
new->tv_nsec = t % n; | |
new->tv_sec = t / n; | |
} | |
HOOK(int, gettimeofday, (struct timeval *tv, void *tz)) | |
int ret = old_gettimeofday(tv, tz); | |
if (!ret && tv) change_timeval(tv, tv, speed); | |
return ret; | |
} | |
HOOK(int, clock_gettime, (clockid_t clk_id, struct timespec *tp)) | |
int ret = old_clock_gettime(clk_id, tp); | |
if (!ret && tp) change_timespec(tp, tp, speed); | |
return ret; | |
} | |
HOOK(int, nanosleep, (const struct timespec *req, struct timespec *rem)) | |
struct timespec req2, rem2; | |
if (req) change_timespec(req, &req2, rspeed), req = &req2; | |
int ret = old_nanosleep(req, rem); | |
if (!ret && rem) change_timespec(rem, &rem2, speed); | |
return ret; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Build:
Usage: