Replace RNG with xoshiro256+; update replay format
Support for writing older replay versions has been removed.
This commit is contained in:
parent
4669ef291f
commit
fc41ebf89c
7 changed files with 159 additions and 149 deletions
|
@ -235,7 +235,7 @@ static void replayview_drawitem(void *n, int item, int cnt) {
|
|||
int columns = sizeof(sizes)/sizeof(float), i, j;
|
||||
float base_size = (SCREEN_W - 110.0) / columns;
|
||||
|
||||
time_t t = rpy->stages[0].seed;
|
||||
time_t t = rpy->stages[0].start_time;
|
||||
struct tm* timeinfo = localtime(&t);
|
||||
|
||||
for(i = 0; i < columns; ++i) {
|
||||
|
@ -363,7 +363,7 @@ static int replayview_cmp(const void *a, const void *b) {
|
|||
Replay *arpy = actx->replay;
|
||||
Replay *brpy = bctx->replay;
|
||||
|
||||
return brpy->stages[0].seed - arpy->stages[0].seed;
|
||||
return brpy->stages[0].start_time - arpy->stages[0].start_time;
|
||||
}
|
||||
|
||||
static int fill_replayview_menu(MenuData *m) {
|
||||
|
|
128
src/random.c
128
src/random.c
|
@ -16,62 +16,67 @@
|
|||
|
||||
static RandomState *tsrand_current;
|
||||
|
||||
/*
|
||||
* Complementary-multiply-with-carry algorithm
|
||||
*/
|
||||
uint64_t splitmix64(uint64_t *state) {
|
||||
// from http://xoshiro.di.unimi.it/splitmix64.c
|
||||
|
||||
// CMWC engine
|
||||
uint32_t tsrand_p(RandomState *rnd) {
|
||||
assert(!rnd->locked);
|
||||
|
||||
uint64_t const a = 18782; // as Marsaglia recommends
|
||||
uint32_t const m = 0xfffffffe; // as Marsaglia recommends
|
||||
uint64_t t;
|
||||
uint32_t x;
|
||||
|
||||
rnd->i = (rnd->i + 1) & (CMWC_CYCLE - 1);
|
||||
t = a * rnd->Q[rnd->i] + rnd->c;
|
||||
// Let c = t / 0xfffffff, x = t mod 0xffffffff
|
||||
rnd->c = t >> 32;
|
||||
x = t + rnd->c;
|
||||
|
||||
if(x < rnd->c) {
|
||||
x++;
|
||||
rnd->c++;
|
||||
}
|
||||
|
||||
return rnd->Q[rnd->i] = m - x;
|
||||
uint64_t z = (*state += 0x9e3779b97f4a7c15);
|
||||
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
|
||||
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
|
||||
return z ^ (z >> 31);
|
||||
}
|
||||
|
||||
void tsrand_seed_p(RandomState *rnd, uint32_t seed) {
|
||||
static const uint32_t phi = 0x9e3779b9;
|
||||
uint64_t makeseed(void) {
|
||||
static uint64_t s;
|
||||
return splitmix64(&s) ^ SDL_GetPerformanceCounter();
|
||||
}
|
||||
|
||||
rnd->Q[0] = seed;
|
||||
rnd->Q[1] = seed + phi;
|
||||
rnd->Q[2] = seed + phi + phi;
|
||||
static inline uint64_t rotl(uint64_t x, int k) {
|
||||
return (x << k) | (x >> (64 - k));
|
||||
}
|
||||
|
||||
for(int i = 3; i < CMWC_CYCLE; ++i) {
|
||||
rnd->Q[i] = rnd->Q[i - 3] ^ rnd->Q[i - 2] ^ phi ^ i;
|
||||
}
|
||||
static uint64_t xoshiro256plus(uint64_t s[4]) {
|
||||
// from http://xoshiro.di.unimi.it/xoshiro256plus.c
|
||||
|
||||
rnd->c = 0x8edc04;
|
||||
rnd->i = CMWC_CYCLE - 1;
|
||||
const uint64_t result_plus = s[0] + s[3];
|
||||
const uint64_t t = s[1] << 17;
|
||||
|
||||
for(int i = 0; i < CMWC_CYCLE*16; ++i) {
|
||||
tsrand_p(rnd);
|
||||
}
|
||||
s[2] ^= s[0];
|
||||
s[3] ^= s[1];
|
||||
s[1] ^= s[2];
|
||||
s[0] ^= s[3];
|
||||
s[2] ^= t;
|
||||
s[3] = rotl(s[3], 45);
|
||||
|
||||
return result_plus;
|
||||
}
|
||||
|
||||
uint32_t tsrand_p(RandomState *rnd) {
|
||||
assert(!rnd->locked);
|
||||
return xoshiro256plus(rnd->state) >> 32;
|
||||
}
|
||||
|
||||
uint64_t tsrand64_p(RandomState *rnd) {
|
||||
assert(!rnd->locked);
|
||||
return xoshiro256plus(rnd->state);
|
||||
}
|
||||
|
||||
void tsrand_seed_p(RandomState *rnd, uint64_t seed) {
|
||||
rnd->state[0] = splitmix64(&seed);
|
||||
rnd->state[1] = splitmix64(&seed);
|
||||
rnd->state[2] = splitmix64(&seed);
|
||||
rnd->state[3] = splitmix64(&seed);
|
||||
}
|
||||
|
||||
void tsrand_switch(RandomState *rnd) {
|
||||
tsrand_current = rnd;
|
||||
}
|
||||
|
||||
void tsrand_init(RandomState *rnd, uint32_t seed) {
|
||||
void tsrand_init(RandomState *rnd, uint64_t seed) {
|
||||
memset(rnd, 0, sizeof(RandomState));
|
||||
tsrand_seed_p(rnd, seed);
|
||||
}
|
||||
|
||||
void tsrand_seed(uint32_t seed) {
|
||||
void tsrand_seed(uint64_t seed) {
|
||||
tsrand_seed_p(tsrand_current, seed);
|
||||
}
|
||||
|
||||
|
@ -79,17 +84,26 @@ uint32_t tsrand(void) {
|
|||
return tsrand_p(tsrand_current);
|
||||
}
|
||||
|
||||
float frand(void) {
|
||||
return (float)((double)tsrand()/(double)TSRAND_MAX);
|
||||
uint64_t tsrand64(void) {
|
||||
return tsrand64_p(tsrand_current);
|
||||
}
|
||||
|
||||
float nfrand(void) {
|
||||
static inline double makedouble(uint64_t x) {
|
||||
// Range: [0..1)
|
||||
return (x >> 11) * (1.0 / (UINT64_C(1) << 53));
|
||||
}
|
||||
|
||||
double frand(void) {
|
||||
return makedouble(tsrand64());
|
||||
}
|
||||
|
||||
double nfrand(void) {
|
||||
return frand() * 2.0 - 1.0;
|
||||
}
|
||||
|
||||
// we use this to support multiple rands in a single statement without breaking replays across different builds
|
||||
|
||||
static uint32_t tsrand_array[TSRAND_ARRAY_LIMIT];
|
||||
static uint64_t tsrand_array[TSRAND_ARRAY_LIMIT];
|
||||
static int tsrand_array_elems;
|
||||
static uint64_t tsrand_fillflags = 0;
|
||||
|
||||
|
@ -106,32 +120,32 @@ static void tsrand_error(const char *file, const char *func, uint line, const ch
|
|||
|
||||
#define TSRANDERR(...) tsrand_error(file, __func__, line, __VA_ARGS__)
|
||||
|
||||
void __tsrand_fill_p(RandomState *rnd, int amount, const char *file, uint line) {
|
||||
void _tsrand_fill_p(RandomState *rnd, int amount, const char *file, uint line) {
|
||||
if(tsrand_fillflags) {
|
||||
TSRANDERR("Some indices left unused from the previous call");
|
||||
return;
|
||||
}
|
||||
|
||||
tsrand_array_elems = amount;
|
||||
tsrand_fillflags = (1L << amount) - 1;
|
||||
tsrand_fillflags = (UINT64_C(1) << amount) - 1;
|
||||
|
||||
for(int i = 0; i < amount; ++i) {
|
||||
tsrand_array[i] = tsrand_p(rnd);
|
||||
tsrand_array[i] = tsrand64_p(rnd);
|
||||
}
|
||||
}
|
||||
|
||||
void __tsrand_fill(int amount, const char *file, uint line) {
|
||||
__tsrand_fill_p(tsrand_current, amount, file, line);
|
||||
void _tsrand_fill(int amount, const char *file, uint line) {
|
||||
_tsrand_fill_p(tsrand_current, amount, file, line);
|
||||
}
|
||||
|
||||
uint32_t __tsrand_a(int idx, const char *file, uint line) {
|
||||
uint64_t _tsrand64_a(int idx, const char *file, uint line) {
|
||||
if(idx >= tsrand_array_elems || idx < 0) {
|
||||
TSRANDERR("Index out of range (%i / %i)", idx, tsrand_array_elems);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(tsrand_fillflags & (1L << idx)) {
|
||||
tsrand_fillflags &= ~(1L << idx);
|
||||
if(tsrand_fillflags & (UINT64_C(1) << idx)) {
|
||||
tsrand_fillflags &= ~(UINT64_C(1) << idx);
|
||||
return tsrand_array[idx];
|
||||
}
|
||||
|
||||
|
@ -139,12 +153,16 @@ uint32_t __tsrand_a(int idx, const char *file, uint line) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
float __afrand(int idx, const char *file, uint line) {
|
||||
return (float)((double)__tsrand_a(idx, file, line) / (double)TSRAND_MAX);
|
||||
uint32_t _tsrand_a(int idx, const char *file, uint line) {
|
||||
return _tsrand64_a(idx, file, line) >> 32;
|
||||
}
|
||||
|
||||
float __anfrand(int idx, const char *file, uint line) {
|
||||
return __afrand(idx, file, line) * 2 - 1;
|
||||
double _afrand(int idx, const char *file, uint line) {
|
||||
return makedouble(_tsrand64_a(idx, file, line));
|
||||
}
|
||||
|
||||
double _anfrand(int idx, const char *file, uint line) {
|
||||
return _afrand(idx, file, line) * 2 - 1;
|
||||
}
|
||||
|
||||
void tsrand_lock(RandomState *rnd) {
|
||||
|
|
53
src/random.h
53
src/random.h
|
@ -11,48 +11,43 @@
|
|||
|
||||
#include "taisei.h"
|
||||
|
||||
#define CMWC_CYCLE 4096 // as Marsaglia recommends
|
||||
#define CMWC_C_MAX 809430660 // as Marsaglia recommends
|
||||
|
||||
struct RandomState {
|
||||
uint32_t Q[CMWC_CYCLE];
|
||||
uint32_t c; // must be limited with CMWC_C_MAX
|
||||
uint32_t i;
|
||||
typedef struct RandomState {
|
||||
uint64_t state[4];
|
||||
bool locked;
|
||||
};
|
||||
} RandomState;
|
||||
|
||||
typedef struct RandomState RandomState;
|
||||
uint64_t splitmix64(uint64_t *state);
|
||||
uint64_t makeseed(void);
|
||||
|
||||
void tsrand_init(RandomState *rnd, uint32_t seed);
|
||||
void tsrand_init(RandomState *rnd, uint64_t seed);
|
||||
void tsrand_switch(RandomState *rnd);
|
||||
void tsrand_seed_p(RandomState *rnd, uint32_t seed);
|
||||
void tsrand_seed_p(RandomState *rnd, uint64_t seed);
|
||||
uint32_t tsrand_p(RandomState *rnd);
|
||||
uint64_t tsrand64_p(RandomState *rnd);
|
||||
|
||||
void tsrand_seed(uint32_t seed);
|
||||
void tsrand_seed(uint64_t seed);
|
||||
uint32_t tsrand(void);
|
||||
uint64_t tsrand64(void);
|
||||
|
||||
void tsrand_lock(RandomState *rnd);
|
||||
void tsrand_unlock(RandomState *rnd);
|
||||
|
||||
float frand(void);
|
||||
float nfrand(void);
|
||||
double frand(void);
|
||||
double nfrand(void);
|
||||
|
||||
void __tsrand_fill_p(RandomState *rnd, int amount, const char *file, uint line);
|
||||
void __tsrand_fill(int amount, const char *file, uint line);
|
||||
uint32_t __tsrand_a(int idx, const char *file, uint line);
|
||||
float __afrand(int idx, const char *file, uint line);
|
||||
float __anfrand(int idx, const char *file, uint line);
|
||||
void _tsrand_fill_p(RandomState *rnd, int amount, const char *file, uint line);
|
||||
void _tsrand_fill(int amount, const char *file, uint line);
|
||||
uint32_t _tsrand_a(int idx, const char *file, uint line);
|
||||
uint64_t _tsrand64_a(int idx, const char *file, uint line);
|
||||
double _afrand(int idx, const char *file, uint line);
|
||||
double _anfrand(int idx, const char *file, uint line);
|
||||
|
||||
#define tsrand_fill_p(rnd,amount) __tsrand_fill_p(rnd, amount, __FILE__, __LINE__)
|
||||
#define tsrand_fill(amount) __tsrand_fill(amount, __FILE__, __LINE__)
|
||||
#define tsrand_a(idx) __tsrand_a(idx, __FILE__, __LINE__)
|
||||
#define afrand(idx) __afrand(idx, __FILE__, __LINE__)
|
||||
#define anfrand(idx) __anfrand(idx, __FILE__, __LINE__)
|
||||
#define tsrand_fill_p(rnd,amount) _tsrand_fill_p(rnd, amount, __FILE__, __LINE__)
|
||||
#define tsrand_fill(amount) _tsrand_fill(amount, __FILE__, __LINE__)
|
||||
#define tsrand_a(idx) _tsrand_a(idx, __FILE__, __LINE__)
|
||||
#define afrand(idx) _afrand(idx, __FILE__, __LINE__)
|
||||
#define anfrand(idx) _anfrand(idx, __FILE__, __LINE__)
|
||||
|
||||
#define TSRAND_MAX UINT32_MAX
|
||||
|
||||
#define TSRAND_ARRAY_LIMIT 64
|
||||
#define srand USE_tsrand_seed_INSTEAD_OF_srand
|
||||
#define rand USE_tsrand_INSTEAD_OF_rand
|
||||
#define TSRAND_ARRAY_LIMIT 16
|
||||
|
||||
#endif // IGUARD_random_h
|
||||
|
|
84
src/replay.c
84
src/replay.c
|
@ -24,7 +24,7 @@ void replay_init(Replay *rpy) {
|
|||
log_debug("Replay at %p initialized for writing", (void*)rpy);
|
||||
}
|
||||
|
||||
ReplayStage* replay_create_stage(Replay *rpy, StageInfo *stage, uint64_t seed, Difficulty diff, Player *plr) {
|
||||
ReplayStage* replay_create_stage(Replay *rpy, StageInfo *stage, uint64_t start_time, uint64_t seed, Difficulty diff, Player *plr) {
|
||||
ReplayStage *s;
|
||||
|
||||
rpy->stages = (ReplayStage*)realloc(rpy->stages, sizeof(ReplayStage) * (++rpy->numstages));
|
||||
|
@ -37,7 +37,8 @@ ReplayStage* replay_create_stage(Replay *rpy, StageInfo *stage, uint64_t seed, D
|
|||
s->events = (ReplayEvent*)malloc(sizeof(ReplayEvent) * s->capacity);
|
||||
|
||||
s->stage = stage->id;
|
||||
s->seed = seed;
|
||||
s->start_time = start_time;
|
||||
s->rng_seed = seed;
|
||||
s->diff = diff;
|
||||
|
||||
s->plr_pos_x = floor(creal(plr->pos));
|
||||
|
@ -166,7 +167,7 @@ static uint32_t replay_calc_stageinfo_checksum(ReplayStage *stg, uint16_t versio
|
|||
uint32_t cs = 0;
|
||||
|
||||
cs += stg->stage;
|
||||
cs += stg->seed;
|
||||
cs += stg->rng_seed;
|
||||
cs += stg->diff;
|
||||
cs += stg->plr_points;
|
||||
cs += stg->plr_char;
|
||||
|
@ -200,24 +201,15 @@ static uint32_t replay_calc_stageinfo_checksum(ReplayStage *stg, uint16_t versio
|
|||
}
|
||||
|
||||
static bool replay_write_stage(ReplayStage *stg, SDL_RWops *file, uint16_t version) {
|
||||
if(version >= REPLAY_STRUCT_VERSION_TS102000_REV1) {
|
||||
SDL_WriteLE32(file, stg->flags);
|
||||
}
|
||||
assert(version >= REPLAY_STRUCT_VERSION_TS103000_REV2);
|
||||
|
||||
SDL_WriteLE32(file, stg->flags);
|
||||
SDL_WriteLE16(file, stg->stage);
|
||||
SDL_WriteLE32(file, stg->seed);
|
||||
SDL_WriteLE64(file, stg->start_time);
|
||||
SDL_WriteLE64(file, stg->rng_seed);
|
||||
SDL_WriteU8(file, stg->diff);
|
||||
|
||||
if(version >= REPLAY_STRUCT_VERSION_TS103000_REV0) {
|
||||
SDL_WriteLE64(file, stg->plr_points);
|
||||
} else {
|
||||
SDL_WriteLE32(file, stg->plr_points);
|
||||
}
|
||||
|
||||
if(version >= REPLAY_STRUCT_VERSION_TS102000_REV1) {
|
||||
SDL_WriteU8(file, stg->plr_continues_used);
|
||||
}
|
||||
|
||||
SDL_WriteLE64(file, stg->plr_points);
|
||||
SDL_WriteU8(file, stg->plr_continues_used);
|
||||
SDL_WriteU8(file, stg->plr_char);
|
||||
SDL_WriteU8(file, stg->plr_shot);
|
||||
SDL_WriteLE16(file, stg->plr_pos_x);
|
||||
|
@ -225,30 +217,12 @@ static bool replay_write_stage(ReplayStage *stg, SDL_RWops *file, uint16_t versi
|
|||
SDL_WriteU8(file, stg->plr_focus);
|
||||
SDL_WriteLE16(file, stg->plr_power);
|
||||
SDL_WriteU8(file, stg->plr_lives);
|
||||
|
||||
if(version >= REPLAY_STRUCT_VERSION_TS103000_REV1) {
|
||||
SDL_WriteLE16(file, stg->plr_life_fragments);
|
||||
} else {
|
||||
SDL_WriteU8(file, stg->plr_life_fragments);
|
||||
}
|
||||
|
||||
SDL_WriteLE16(file, stg->plr_life_fragments);
|
||||
SDL_WriteU8(file, stg->plr_bombs);
|
||||
|
||||
if(version >= REPLAY_STRUCT_VERSION_TS103000_REV1) {
|
||||
SDL_WriteLE16(file, stg->plr_bomb_fragments);
|
||||
} else {
|
||||
SDL_WriteU8(file, stg->plr_bomb_fragments);
|
||||
}
|
||||
|
||||
SDL_WriteLE16(file, stg->plr_bomb_fragments);
|
||||
SDL_WriteU8(file, stg->plr_inputflags);
|
||||
|
||||
if(version >= REPLAY_STRUCT_VERSION_TS103000_REV0) {
|
||||
SDL_WriteLE32(file, stg->plr_graze);
|
||||
SDL_WriteLE32(file, stg->plr_point_item_value);
|
||||
} else if(version >= REPLAY_STRUCT_VERSION_TS102000_REV2) {
|
||||
SDL_WriteLE16(file, stg->plr_graze);
|
||||
}
|
||||
|
||||
SDL_WriteLE32(file, stg->plr_graze);
|
||||
SDL_WriteLE32(file, stg->plr_point_item_value);
|
||||
SDL_WriteLE16(file, stg->numevents);
|
||||
SDL_WriteLE32(file, 1 + ~replay_calc_stageinfo_checksum(stg, version));
|
||||
|
||||
|
@ -267,20 +241,20 @@ static void fix_flags(Replay *rpy) {
|
|||
}
|
||||
|
||||
bool replay_write(Replay *rpy, SDL_RWops *file, uint16_t version) {
|
||||
assert(version >= REPLAY_STRUCT_VERSION_TS103000_REV2);
|
||||
|
||||
uint16_t base_version = (version & ~REPLAY_VERSION_COMPRESSION_BIT);
|
||||
bool compression = (version & REPLAY_VERSION_COMPRESSION_BIT);
|
||||
|
||||
SDL_RWwrite(file, replay_magic_header, sizeof(replay_magic_header), 1);
|
||||
SDL_WriteLE16(file, version);
|
||||
|
||||
if(base_version >= REPLAY_STRUCT_VERSION_TS102000_REV0) {
|
||||
TaiseiVersion v;
|
||||
TAISEI_VERSION_GET_CURRENT(&v);
|
||||
TaiseiVersion v;
|
||||
TAISEI_VERSION_GET_CURRENT(&v);
|
||||
|
||||
if(taisei_version_write(file, &v) != TAISEI_VERSION_SIZE) {
|
||||
log_error("Failed to write game version: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
if(taisei_version_write(file, &v) != TAISEI_VERSION_SIZE) {
|
||||
log_error("Failed to write game version: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
void *buf;
|
||||
|
@ -295,10 +269,7 @@ bool replay_write(Replay *rpy, SDL_RWops *file, uint16_t version) {
|
|||
replay_write_string(vfile, config_get_str(CONFIG_PLAYERNAME), base_version);
|
||||
fix_flags(rpy);
|
||||
|
||||
if(base_version >= REPLAY_STRUCT_VERSION_TS102000_REV1) {
|
||||
SDL_WriteLE32(vfile, rpy->flags);
|
||||
}
|
||||
|
||||
SDL_WriteLE32(vfile, rpy->flags);
|
||||
SDL_WriteLE16(vfile, rpy->numstages);
|
||||
|
||||
for(int i = 0; i < rpy->numstages; ++i) {
|
||||
|
@ -390,6 +361,7 @@ static bool replay_read_header(Replay *rpy, SDL_RWops *file, int64_t filesize, s
|
|||
case REPLAY_STRUCT_VERSION_TS102000_REV2:
|
||||
case REPLAY_STRUCT_VERSION_TS103000_REV0:
|
||||
case REPLAY_STRUCT_VERSION_TS103000_REV1:
|
||||
case REPLAY_STRUCT_VERSION_TS103000_REV2:
|
||||
{
|
||||
if(taisei_version_read(file, &rpy->game_version) != TAISEI_VERSION_SIZE) {
|
||||
log_error("%s: Failed to read game version", source);
|
||||
|
@ -447,7 +419,15 @@ static bool replay_read_meta(Replay *rpy, SDL_RWops *file, int64_t filesize, con
|
|||
}
|
||||
|
||||
CHECKPROP(stg->stage = SDL_ReadLE16(file), u);
|
||||
CHECKPROP(stg->seed = SDL_ReadLE32(file), u);
|
||||
|
||||
if(version >= REPLAY_STRUCT_VERSION_TS103000_REV2) {
|
||||
CHECKPROP(stg->start_time = SDL_ReadLE64(file), u);
|
||||
CHECKPROP(stg->rng_seed = SDL_ReadLE64(file), u);
|
||||
} else {
|
||||
stg->rng_seed = SDL_ReadLE32(file);
|
||||
stg->start_time = stg->rng_seed;
|
||||
}
|
||||
|
||||
CHECKPROP(stg->diff = SDL_ReadU8(file), u);
|
||||
|
||||
if(version >= REPLAY_STRUCT_VERSION_TS103000_REV0) {
|
||||
|
|
13
src/replay.h
13
src/replay.h
|
@ -46,13 +46,16 @@
|
|||
|
||||
// Taisei v1.3 revision 1: expands life and bomb fragments to 16bit
|
||||
#define REPLAY_STRUCT_VERSION_TS103000_REV1 10
|
||||
|
||||
// Taisei v1.3 revision 2: RNG changed; seed separated from start time; time expanded to 64bit
|
||||
#define REPLAY_STRUCT_VERSION_TS103000_REV2 11
|
||||
/* END supported struct versions */
|
||||
|
||||
#define REPLAY_VERSION_COMPRESSION_BIT 0x8000
|
||||
#define REPLAY_COMPRESSION_CHUNK_SIZE 4096
|
||||
|
||||
// What struct version to use when saving recorded replays
|
||||
#define REPLAY_STRUCT_VERSION_WRITE (REPLAY_STRUCT_VERSION_TS103000_REV1 | REPLAY_VERSION_COMPRESSION_BIT)
|
||||
#define REPLAY_STRUCT_VERSION_WRITE (REPLAY_STRUCT_VERSION_TS103000_REV2 | REPLAY_VERSION_COMPRESSION_BIT)
|
||||
|
||||
#define REPLAY_ALLOC_INITIAL 256
|
||||
|
||||
|
@ -88,8 +91,10 @@ typedef struct ReplayStage {
|
|||
|
||||
// initial game settings
|
||||
uint16_t stage; // must match type of StageInfo.id in stage.h
|
||||
uint32_t seed; // this also happens to be the game initiation time, and we currently use this property
|
||||
// NOTE: this might change eventually
|
||||
/* BEGIN REPLAY_STRUCT_VERSION_TS103000_REV2 and above */
|
||||
uint64_t start_time;
|
||||
/* END REPLAY_STRUCT_VERSION_TS103000_REV2 and above */
|
||||
uint64_t rng_seed; // NOTE: before REPLAY_STRUCT_VERSION_TS103000_REV2: uint32_t, also specifies start_time
|
||||
uint8_t diff;
|
||||
|
||||
// initial player settings
|
||||
|
@ -219,7 +224,7 @@ typedef enum ReplayStageFlags {
|
|||
} ReplayStageFlags;
|
||||
|
||||
void replay_init(Replay *rpy);
|
||||
ReplayStage* replay_create_stage(Replay *rpy, StageInfo *stage, uint64_t seed, Difficulty diff, Player *plr);
|
||||
ReplayStage* replay_create_stage(Replay *rpy, StageInfo *stage, uint64_t start_time, uint64_t seed, Difficulty diff, Player *plr);
|
||||
|
||||
void replay_destroy(Replay *rpy);
|
||||
void replay_destroy_events(Replay *rpy);
|
||||
|
|
18
src/stage.c
18
src/stage.c
|
@ -783,19 +783,22 @@ void stage_loop(StageInfo *stage) {
|
|||
stage_preload();
|
||||
stage_draw_init();
|
||||
|
||||
uint32_t seed = (uint32_t)time(0);
|
||||
tsrand_switch(&global.rand_game);
|
||||
tsrand_seed_p(&global.rand_game, seed);
|
||||
stage_start(stage);
|
||||
|
||||
if(global.replaymode == REPLAY_RECORD) {
|
||||
global.replay_stage = replay_create_stage(&global.replay, stage, seed, global.diff, &global.plr);
|
||||
uint64_t start_time = (uint64_t)time(0);
|
||||
uint64_t seed = makeseed();
|
||||
tsrand_seed_p(&global.rand_game, seed);
|
||||
|
||||
global.replay_stage = replay_create_stage(&global.replay, stage, start_time, seed, global.diff, &global.plr);
|
||||
|
||||
// make sure our player state is consistent with what goes into the replay
|
||||
player_init(&global.plr);
|
||||
replay_stage_sync_player_state(global.replay_stage, &global.plr);
|
||||
|
||||
log_debug("Random seed: %u", seed);
|
||||
log_debug("Start time: %"PRIu64, start_time);
|
||||
log_debug("Random seed: 0x%"PRIx64, seed);
|
||||
|
||||
StageProgress *p = stage_get_progress_from_info(stage, global.diff, true);
|
||||
|
||||
|
@ -812,10 +815,11 @@ void stage_loop(StageInfo *stage) {
|
|||
assert(stg != NULL);
|
||||
assert(stage_get(stg->stage) == stage);
|
||||
|
||||
log_debug("REPLAY_PLAY mode: %d events, stage: \"%s\"", stg->numevents, stage->title);
|
||||
tsrand_seed_p(&global.rand_game, stg->rng_seed);
|
||||
|
||||
tsrand_seed_p(&global.rand_game, stg->seed);
|
||||
log_debug("Random seed: %u", stg->seed);
|
||||
log_debug("REPLAY_PLAY mode: %d events, stage: \"%s\"", stg->numevents, stage->title);
|
||||
log_debug("Start time: %"PRIu64, stg->start_time);
|
||||
log_debug("Random seed: 0x%"PRIx64, stg->rng_seed);
|
||||
|
||||
global.diff = stg->diff;
|
||||
player_init(&global.plr);
|
||||
|
|
|
@ -67,6 +67,14 @@ char* getenv();
|
|||
attr_deprecated("Use env_set instead")
|
||||
int setenv();
|
||||
|
||||
#undef rand
|
||||
attr_deprecated("Use tsrand instead")
|
||||
int rand(void);
|
||||
|
||||
#undef srand
|
||||
attr_deprecated("Use tsrand_seed instead")
|
||||
void srand(uint);
|
||||
|
||||
PRAGMA(GCC diagnostic pop)
|
||||
|
||||
#endif // IGUARD_util_consideredharmful_h
|
||||
|
|
Loading…
Reference in a new issue