Improve filename timestamps (screenshots, replays)

* Get rid of timezone information.
    * If possible, add milliseconds precision. This is useful when
    taking several screenshots in quick succession.
This commit is contained in:
Andrei Alexeyev 2018-05-28 11:10:41 +03:00
parent 5329a1f6b1
commit 5a83aa177e
No known key found for this signature in database
GPG key ID: 363707CD4C7FE8A4
10 changed files with 104 additions and 25 deletions

View file

@ -146,11 +146,14 @@ have_posix = cc.has_header_symbol('unistd.h', '_POSIX_VERSION')
have_vla = not cc.has_header_symbol('unistd.h', '__STDC_NO_VLA__')
have_complex = not cc.has_header_symbol('unistd.h', '__STDC_NO_COMPLEX__')
have_backtrace = cc.has_header_symbol('execinfo.h', 'backtrace')
have_timespec = cc.has_header_symbol('time.h', 'timespec_get')
if not (have_vla and have_complex)
error('Your C implementation needs to support complex numbers and variable-length arrays.')
endif
config.set('TAISEI_BUILDCONF_HAVE_TIMESPEC', have_timespec)
macos_app_bundle = get_option('macos_bundle') and host_machine.system() == 'darwin'
if macos_app_bundle

View file

@ -17,27 +17,23 @@
#include "common.h"
static void do_save_replay(Replay *rpy) {
char *strtime, *name;
time_t rawtime;
struct tm *timeinfo;
// time when the game was *initiated*
rawtime = (time_t)rpy->stages[0].seed;
timeinfo = localtime(&rawtime);
strtime = strftimealloc("%Y%m%d_%H-%M-%S%z", timeinfo);
char strtime[FILENAME_TIMESTAMP_MIN_BUF_SIZE], *name;
char prepr[16], drepr[16];
plrmode_repr(prepr, 16, plrmode_find(rpy->stages[0].plr_char, rpy->stages[0].plr_shot));
strlcpy(drepr, difficulty_name(rpy->stages[0].diff), 16);
assert(rpy->numstages > 0);
ReplayStage *stg = rpy->stages;
filename_timestamp(strtime, sizeof(strtime), stg->init_time);
plrmode_repr(prepr, 16, plrmode_find(stg->plr_char, stg->plr_shot));
strlcpy(drepr, difficulty_name(stg->diff), 16);
drepr[0] += 'a' - 'A';
if(rpy->numstages > 1) {
name = strfmt("taisei_%s_%s_%s", strtime, prepr, drepr);
} else {
name = strfmt("taisei_%s_stg%X_%s_%s", strtime, rpy->stages[0].stage, prepr, drepr);
name = strfmt("taisei_%s_stg%X_%s_%s", strtime, stg->stage, prepr, drepr);
}
free(strtime);
replay_save(rpy, name);
free(name);
}

View file

@ -31,6 +31,8 @@ ReplayStage* replay_create_stage(Replay *rpy, StageInfo *stage, uint64_t seed, D
s = rpy->stages + rpy->numstages - 1;
memset(s, 0, sizeof(ReplayStage));
get_system_time(&s->init_time);
s->capacity = REPLAY_ALLOC_INITIAL;
s->events = (ReplayEvent*)malloc(sizeof(ReplayEvent) * s->capacity);

View file

@ -80,7 +80,8 @@ 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 use this property, don't break it please
uint32_t seed; // this also happens to be the game initiation time, and we currently use this property
// NOTE: this might change eventually
uint8_t diff;
// initial player settings
@ -111,6 +112,7 @@ typedef struct ReplayStage {
/* END stored fields */
SystemTime init_time;
ReplayEvent *events;
// events allocated (may be higher than numevents)

View file

@ -21,5 +21,10 @@ if is_debug_build
endif
if host_machine.system() == 'windows'
util_src += files('windows_misc.c')
# NOTE: Even if we ever build this with something like Midipix, we'd
# probably still want to use the winapi implementation of this here.
util_src += files('platform_win32.c')
else
# No have_posix check, it might just work.
util_src += files('platform_posix.c')
endif

21
src/util/platform_posix.c Normal file
View file

@ -0,0 +1,21 @@
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (c) 2011-2018, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2018, Andrei Alexeyev <akari@alienslab.net>.
*/
#include "taisei.h"
#include "assert.h"
#include "stringops.h"
void get_system_time(SystemTime *systime) {
#if defined(TAISEI_BUILDCONF_HAVE_TIMESPEC)
timespec_get(systime, TIME_UTC);
#else
systime->tv_sec = time(NULL);
systime->tv_nsec = 0;
#endif
}

View file

@ -8,7 +8,30 @@
#include "taisei.h"
#include <windows.h>
#include "assert.h"
#include "stringops.h"
static time_t win32time_to_posixtime(SYSTEMTIME *wtime) {
struct tm ptime = { 0 };
ptime.tm_year = wtime->wYear - 1900;
ptime.tm_mon = wtime->wMonth - 1;
ptime.tm_mday = wtime->wDay;
ptime.tm_hour = wtime->wHour;
ptime.tm_min = wtime->wMinute;
ptime.tm_sec = wtime->wSecond;
ptime.tm_isdst = -1;
return mktime(&ptime);
}
void get_system_time(SystemTime *systime) {
SYSTEMTIME ltime;
GetLocalTime(&ltime);
systime->tv_sec = win32time_to_posixtime(&ltime);
systime->tv_nsec = ltime.wMilliseconds * 1000000;
}
/*
* This is here for Windows laptops with hybrid graphics.

View file

@ -10,7 +10,6 @@
#include <string.h>
#include <stdlib.h>
#include <SDL.h>
#include "stringops.h"
#include "assert.h"
@ -301,3 +300,18 @@ uint32_t crc32str(uint32_t crc, const char *str) {
return crc ^ ~0U;
}
size_t filename_timestamp(char *buf, size_t buf_size, SystemTime systime) {
assert(buf_size >= FILENAME_TIMESTAMP_MIN_BUF_SIZE);
char buf_msecs[4];
char buf_datetime[FILENAME_TIMESTAMP_MIN_BUF_SIZE - sizeof(buf_msecs)];
attr_unused size_t written;
written = snprintf(buf_msecs, sizeof(buf_msecs), "%03u", (uint)(systime.tv_nsec / 1000000));
assert(written == sizeof(buf_msecs) - 1);
written = strftime(buf_datetime, sizeof(buf_datetime), "%Y%m%d_%H-%M-%S", localtime(&systime.tv_sec));
assert(written != 0);
return snprintf(buf, buf_size, "%s-%s", buf_datetime, buf_msecs);
}

View file

@ -10,6 +10,7 @@
#include "taisei.h"
#include <time.h>
#include <SDL.h>
#undef strlcat
#define strlcat SDL_strlcat
@ -43,3 +44,18 @@ uint32_t* utf8_to_ucs4(const char *utf8);
char* ucs4_to_utf8(const uint32_t *ucs4);
uint32_t crc32str(uint32_t crc, const char *str);
// XXX: Not sure if this is the appropriate header for this
#ifdef TAISEI_BUILDCONF_HAVE_TIMESPEC
typedef struct timespec SystemTime;
#else
typedef struct SystemTime {
time_t tv_sec;
long tv_nsec;
} SystemTime;
#endif
#define FILENAME_TIMESTAMP_MIN_BUF_SIZE 23
void get_system_time(SystemTime *time) attr_nonnull(1);
size_t filename_timestamp(char *buf, size_t buf_size, const SystemTime time) attr_nonnull(1);

View file

@ -321,14 +321,11 @@ void video_take_screenshot(void) {
return;
}
char outfile[128];
time_t rawtime;
struct tm * timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
strftime(outfile, 128, "taisei_%Y%m%d_%H-%M-%S%z.png", timeinfo);
tdata.dest_path = strjoin("storage/screenshots/", outfile, NULL);;
SystemTime systime;
char timestamp[FILENAME_TIMESTAMP_MIN_BUF_SIZE];
get_system_time(&systime);
filename_timestamp(timestamp, sizeof(timestamp), systime);
tdata.dest_path = strfmt("storage/screenshots/taisei_%s.png", timestamp);
task_detach(taskmgr_global_submit((TaskParams) {
.callback = video_screenshot_task,