quest/src/timer.c

828 lines
19 KiB
C
Raw Normal View History

2021-09-03 13:41:23 +10:00
#include "timer.h"
2021-08-18 16:56:42 +10:00
#define COLSTRLEN 11
2021-09-05 02:50:19 +10:00
//Timekeeping
struct timespec timestart, finish, notif;
2021-09-05 02:50:19 +10:00
int currentMS = 0;
int timeSave = 0;
2021-09-05 02:50:19 +10:00
bool timerActive;
//UI
struct color bg = { 47, 53, 66};
struct color fg = {247, 248, 242};
struct color fade = {210, 210, 210};
struct color gold = {249, 255, 79};
struct color good = { 79, 255, 85};
struct color bad = {255, 79, 79};
2021-08-28 01:43:33 +10:00
int h, w;
bool compact = false;
bool dirty = false;
2021-09-05 02:50:19 +10:00
2021-09-17 05:21:45 +10:00
//Splits.io data
2021-09-05 02:50:19 +10:00
const char *schemaver = "v1.0.1";
const char *timersname = "quest";
const char *timerlname = "Quinn's Utterly Elegant Speedrun Timer";
const char *timerver = "v0.5.1";
2021-09-05 02:50:19 +10:00
const char *timerlink = "https://github.com/SilentFungus/quest";
2021-09-17 05:21:45 +10:00
//Run data
char *filepath;
2021-09-17 09:25:36 +10:00
char *gameTitle = "title not loaded";
2021-09-03 13:41:23 +10:00
char *categoryTitle = "category not loaded";
2021-09-17 09:25:36 +10:00
int attempts = 0;
int bestTime = 0;
int bestAttempt = 0;
2021-09-03 13:41:23 +10:00
struct segment *segments;
2021-09-17 05:21:45 +10:00
struct segment *pbrun;
struct segment *wrrun;
struct segment *bestsegs;
2021-09-17 09:25:36 +10:00
struct pastseg *pastRuns;
int segCount;
int currSeg = -1;
2021-09-03 13:41:23 +10:00
char currentTime[10];
2021-08-18 16:56:42 +10:00
void sub_timespec(struct timespec t1, struct timespec t2, struct timespec* td)
{
td->tv_nsec = t2.tv_nsec - t1.tv_nsec;
td->tv_sec = t2.tv_sec - t1.tv_sec;
if (td->tv_sec > 0 && td->tv_nsec < 0) {
td->tv_nsec += NS_PER_S;
td->tv_sec--;
} else if (td->tv_sec < 0 && td->tv_nsec > 0) {
td->tv_nsec -= NS_PER_S;
td->tv_sec++;
}
}
2021-08-28 01:43:33 +10:00
void start()
2021-08-18 16:56:42 +10:00
{
2021-09-17 09:25:36 +10:00
if (timerActive || segCount == 0)
2021-08-18 16:56:42 +10:00
return;
2021-08-28 01:43:33 +10:00
clock_gettime(CLOCK_REALTIME, &timestart);
2021-09-17 09:25:36 +10:00
timerActive = true;
//Reset state of timer
dirty = true;
for(int i = 0; i < segCount; i++) {
segments[i].ms = 0;
segments[i].isSkipped = false;
segments[i].isReset = false;
}
2021-09-17 09:25:36 +10:00
currSeg = 0;
2021-08-18 16:56:42 +10:00
}
2021-08-28 01:43:33 +10:00
void stop()
2021-08-18 16:56:42 +10:00
{
if (!timerActive)
return;
if (currSeg < segCount)
segments[currSeg].isReset = true;
2021-08-18 16:56:42 +10:00
timerActive = false;
2021-09-17 05:21:45 +10:00
attempts++;
2021-09-17 09:25:36 +10:00
if (pastRuns)
pastRuns = realloc(pastRuns, attempts * segCount * sizeof(struct pastseg));
2021-09-17 05:21:45 +10:00
else
2021-09-17 09:25:36 +10:00
pastRuns = calloc(segCount, sizeof(struct pastseg));
for (int i = 0; i < segCount; i++) {
2021-09-17 05:21:45 +10:00
struct pastseg t;
2021-09-17 09:25:36 +10:00
t.ms = segments[i].ms;
2021-09-17 05:21:45 +10:00
t.isSkipped = segments[i].isSkipped;
t.isReset = segments[i].isReset;
2021-09-17 09:25:36 +10:00
pastRuns[((attempts-1) * segCount) + i] = t;
2021-09-17 05:21:45 +10:00
}
calculatePB();
saveFile();
2021-08-18 16:56:42 +10:00
}
2021-08-28 01:43:33 +10:00
void split()
{
2021-09-05 02:50:19 +10:00
if (!timerActive)
return;
2021-09-17 09:25:36 +10:00
segments[currSeg].ms = currentMS;
currSeg++;
if (currSeg >= segCount)
2021-09-05 02:50:19 +10:00
stop();
2021-09-17 09:25:36 +10:00
}
void unsplit()
{
if (!timerActive)
return;
currSeg--;
2021-08-28 01:43:33 +10:00
}
void tpause()
2021-08-18 16:56:42 +10:00
{
}
void skip()
{
if (!timerActive)
return;
if (currSeg < segCount)
segments[currSeg].isSkipped = true;
currSeg++;
if (currSeg >= segCount)
stop();
}
2021-08-18 16:56:42 +10:00
void loadKeymap()
{
km.START = VC_R;
km.STOP = VC_F;
km.PAUSE = VC_D;
km.SPLIT = VC_E;
2021-09-17 07:14:35 +10:00
km.HOTKS = VC_T;
2021-09-17 09:25:36 +10:00
km.USPLT = VC_G;
km.SKIP = VC_V;
2021-08-28 01:43:33 +10:00
}
void ftime(char *timestr, int rms, int decimals, bool sign)
2021-08-28 01:43:33 +10:00
{
if (decimals > 3 || decimals < 0)
decimals = 0;
2021-09-17 09:25:36 +10:00
int seconds = rms / 1000;
2021-09-05 02:50:19 +10:00
int minutes = seconds / 60;
int hours = minutes / 60;
//A few better formatted variables for displaying these numbers
int thr = rms % 1000;
int two = thr / 10;
int one = two / 10;
2021-09-05 02:50:19 +10:00
int s = seconds % 60;
int m = minutes % 60;
int h = hours;
int d = 0;
switch (decimals) {
case 1:
d = one;
break;
case 2:
d = two;
break;
case 3:
d = thr;
break;
}
char tformat[22];
int i = 0;
int decimalspace = decimals + (decimals != 0);
if (hours) {
tformat[i++] = '%';
if (sign)
tformat[i++] = '+';
tformat[i++] = (colwidth - 6 - decimalspace) + 48;
tformat[i++] = 'd';
tformat[i++] = ':';
}
if (minutes) {
tformat[i++] = '%';
if (sign && !hours)
tformat[i++] = '+';
if (hours) {
tformat[i++] = '0';
tformat[i++] = '2';
} else {
tformat[i++] = (colwidth - 3 - decimalspace) + 48;
}
tformat[i++] = 'd';
tformat[i++] = ':';
}
tformat[i++] = '%';
if (s != 0 && sign && !hours && !minutes)
tformat[i++] = '+';
if (minutes) {
tformat[i++] = '0';
tformat[i++] = '2';
} else {
//This value can push the resulting char out of the numbers
//section of the ascii table so we gotta clamp it
int n = colwidth - decimalspace + 48;
if (n >= 58)
n = 57;
tformat[i++] = n;
}
tformat[i++] = 'd';
if (decimals) {
tformat[i++] = '.';
tformat[i++] = '%';
tformat[i++] = '0';
tformat[i++] = decimals + 48;
tformat[i++] = 'd';
}
tformat[i] = 0;
2021-08-28 01:43:33 +10:00
2021-09-05 02:50:19 +10:00
if (hours) {
if (!decimals)
sprintf(timestr, tformat, h, abs(m), abs(s));
2021-09-05 02:50:19 +10:00
else
sprintf(timestr, tformat, h, abs(m), abs(s), abs(d));
2021-09-05 02:50:19 +10:00
} else if (minutes) {
if (!decimals)
sprintf(timestr, tformat, m, abs(s));
2021-09-05 02:50:19 +10:00
else
sprintf(timestr, tformat, m, abs(s), abs(d));
2021-09-05 02:50:19 +10:00
} else {
if (!decimals) {
sprintf(timestr, tformat, s);
} else {
sprintf(timestr, tformat, s, abs(d));
if (sign && s == 0 && d < 0)
timestr[COLSTRLEN - 4 - decimals] = '-';
if (sign && s == 0 && d >= 0)
timestr[COLSTRLEN - 4 - decimals] = '+';
}
2021-09-05 02:50:19 +10:00
}
2021-09-03 13:41:23 +10:00
}
int timespecToMS(struct timespec t)
{
return (t.tv_nsec / 1000000) + (t.tv_sec * 1000);
2021-09-03 13:41:23 +10:00
}
void drawSegmentNames()
2021-09-03 13:41:23 +10:00
{
char *names[segCount];
2021-09-17 09:25:36 +10:00
for(int i = 0; i < segCount; i++) {
names[i] = segments[i].name;
2021-09-03 13:41:23 +10:00
}
drawColumn(names, segCount, 0, segCount);
}
//TODO: Fix up all this commented garbage
//Really the entire display system needs rethinking first but yea
void drawDeltaColumn(int column)
{
char *times[segCount];
for (int i = 0; i < segCount; i++) {
times[i] = calloc(1, COLSTRLEN);
int time = 0;
if (i == currSeg)
time = currentMS - pbrun[i].ms;
else if (i < currSeg)
time = segments[i].ms - pbrun[i].ms;
ftime(times[i], time, 1, true);
struct color col = {0};
if (time <= 0)
col = good;
else
col = bad;
if (i < currSeg)
drawCell(times[i], column, i + 6, col);
if (i == currSeg && time >= -5000)
drawCell(times[i], column, i + 6, col);
}
//drawColumn(times, segCount, column, currSeg);
//Use drawCell because we're doing colors.
//for (int i = 0; i < segCount; i++) {
// if (i <= currSeg)
// drawCell(times[i], column, i + 6, good);
//}
setFGColor(fg);
for (int i = 0; i < segCount; i++) {
free(times[i]);
}
2021-08-28 01:43:33 +10:00
}
//TODO: try to clean the branching up
void drawTimeColumn(int timeoption, int column)
2021-09-05 02:50:19 +10:00
{
char *times[segCount];
int drawEnd = currSeg;
for (int i = 0; i < segCount; i++) {
times[i] = calloc(1, COLSTRLEN);
int time = 0;
switch (timeoption) {
case 0:
time = pbrun[i].ms;
drawEnd = segCount;
break;
case 2:
if (i > 0 && i < currSeg)
time = segments[i].ms - segments[i - 1].ms;
else if (i > 0 && i == currSeg)
time = currentMS - segments[i - 1].ms;
else if (i == 0 && i == currSeg)
time = currentMS;
else
time = segments[i].ms;
break;
case 3:
if (i == currSeg)
time = currentMS;
else
time = segments[i].ms;
}
ftime(times[i], time, 1, false);
2021-09-05 02:50:19 +10:00
}
drawColumn(times, segCount, column, drawEnd);
for (int i = 0; i < segCount; i++) {
free(times[i]);
2021-09-05 02:50:19 +10:00
}
}
void drawNotif(char* text)
{
clock_gettime(CLOCK_REALTIME, &notif);
clearNotif();
leftPrint(maxrows, w, text);
}
void clearNotif()
{
leftPrint(maxrows, w, "\033[2K");
}
void toggleCompact()
{
compact = !compact;
//Clears the screen rather than dirtying it so the notif doesnt clear
clrScreen();
if (compact)
drawNotif("Compact mode enabled");
else
drawNotif("Compact mode disabled");
2021-09-05 02:50:19 +10:00
}
2021-08-28 01:43:33 +10:00
void drawDisplay()
{
if (dirty) {
2021-09-05 02:50:19 +10:00
clrScreen();
dirty = false;
2021-09-05 02:50:19 +10:00
}
2021-09-03 13:41:23 +10:00
rghtPrint(1, w, "Attempts");
char atmpt[10];
sprintf(atmpt, "%9d", attempts);
rghtPrint(2, w, atmpt);
cntrPrint(1, w / 2, w, gameTitle);
cntrPrint(2, w / 2, w, categoryTitle);
setFGColor(fade);
2021-09-05 02:50:19 +10:00
drawHLine(5, w);
printf("\033[5;3H");
if (hotkeys_enabled || compact)
printf("[");
if (hotkeys_enabled)
printf("h");
if (compact)
printf("c");
if (hotkeys_enabled || compact)
printf("]");
setFGColor(fg);
drawSegmentNames();
//TODO: The column names stuff has to be more dynamic, part of the
//drawColumn function probably
if (!compact) {
char cols[41];
sprintf(cols, "%10s%10s%10s%10s", "Delta", "Sgmt", "Time", "PB");
setFGColor(fade);
rghtPrint(4, w, cols);
setFGColor(fg);
drawTimeColumn(0, 1);
drawTimeColumn(3, 2);
drawTimeColumn(2, 3);
drawDeltaColumn(4);
} else {
char cols[21];
sprintf(cols, "%10s%10s", "Delta", "Time/PB");
setFGColor(fade);
rghtPrint(4, w, cols);
setFGColor(fg);
drawTimeColumn(0, 1);
drawTimeColumn(3, 1);
drawDeltaColumn(2);
2021-09-05 02:50:19 +10:00
}
setFGColor(fade);
2021-09-17 09:25:36 +10:00
drawHLine(segCount + 6, w);
setFGColor(fg);
ftime(currentTime, currentMS, 2, false);
2021-09-17 09:25:36 +10:00
rghtPrint(segCount + 7, w, currentTime);
2021-08-28 01:43:33 +10:00
fflush(stdout);
}
void resize(int i)
{
struct winsize ws;
ioctl(1, TIOCGWINSZ, &ws);
w = ws.ws_col;
h = ws.ws_row;
2021-09-17 05:21:45 +10:00
setMaxCols(w);
setMaxRows(h);
dirty = true;
2021-08-18 16:56:42 +10:00
}
2021-09-17 05:21:45 +10:00
void calculatePB()
2021-09-03 13:41:23 +10:00
{
bool valid = false;
2021-09-17 09:25:36 +10:00
int bestMS = INT_MAX;
2021-09-17 05:21:45 +10:00
int bestAttempt = 0;
if (attempts == 0)
return;
2021-09-17 05:21:45 +10:00
for (int i = 0; i < attempts; i++) {
2021-09-17 09:25:36 +10:00
int run = i * segCount;
valid = true;
2021-09-17 09:25:36 +10:00
for (int j = 0; j < segCount; j++) {
if (pastRuns[run + j].isReset == true)
2021-09-17 05:21:45 +10:00
valid = false;
}
2021-09-17 09:25:36 +10:00
if (valid && pastRuns[run + segCount - 1].ms < bestMS) {
2021-09-17 05:21:45 +10:00
bestAttempt = i;
2021-09-17 09:25:36 +10:00
bestMS = pastRuns[run + segCount - 1].ms;
2021-09-17 05:21:45 +10:00
}
}
if (valid)
for (int i = 0; i < segCount; i++)
pbrun[i].ms = pastRuns[(bestAttempt * segCount) + i].ms;
}
void calculateBestSegs()
{
if (attempts == 0)
return;
2021-09-17 09:25:36 +10:00
for (int i = 0; i < segCount; i++) {
int bms = INT_MAX;
for (int j = 0; j < attempts; j++) {
int cms = pastRuns[(j * segCount) + i].ms;
if (cms != 0 && cms < bms)
bms = cms;
}
bestsegs[i].ms = bms;
2021-09-17 05:21:45 +10:00
}
}
//TODO: it'll be more efficent if all the segments pointers point at the same
//instance of the segments name, instead of copying the contents over
void loadFile()
{
//char path[256];
//strcat(strcpy(path, getenv("HOME")), "/.config/qtimer");
//mkdir(path, 0777);
//strcat(strcpy(path, getenv("HOME")), "/.config/qtimer/keymaps");
//mkdir(path, 0777);
//strcat(strcpy(path, getenv("HOME")), "/.config/qtimer/keymaps/default");
//FILE* fp = fopen(path, "r");
// READING THE FILE TO A BUFFER
//fclose(fp);
2021-09-03 13:41:23 +10:00
char *buffer = NULL;
long length;
2021-09-17 05:21:45 +10:00
FILE *f = fopen(filepath, "rb");
2021-09-03 13:41:23 +10:00
if (f == NULL)
return;
fseek(f, 0, SEEK_END);
length = ftell(f);
fseek(f, 0, SEEK_SET);
buffer = malloc(length + 1);
2021-09-17 05:21:45 +10:00
if (buffer != NULL)
2021-09-03 13:41:23 +10:00
fread(buffer, 1, length, f);
fclose(f);
buffer[length] = '\0';
2021-09-17 05:21:45 +10:00
2021-09-03 13:41:23 +10:00
cJSON *splitfile = cJSON_Parse(buffer);
2021-09-17 05:21:45 +10:00
free(buffer);
2021-09-17 09:25:36 +10:00
cJSON *schema = cJSON_GetItem(splitfile, "_schemaVersion");
2021-09-17 05:21:45 +10:00
if (schema) {
importSplitsIO(splitfile);
return;
}
2021-09-03 13:41:23 +10:00
cJSON *game = NULL;
2021-09-17 05:21:45 +10:00
cJSON *cate = NULL;
cJSON *atts = NULL;
2021-09-03 13:41:23 +10:00
cJSON *segs = NULL;
2021-09-17 05:21:45 +10:00
cJSON *runs = NULL;
2021-09-17 09:25:36 +10:00
game = cJSON_GetItem(splitfile, "game");
cate = cJSON_GetItem(splitfile, "category");
atts = cJSON_GetItem(splitfile, "attempts");
segs = cJSON_GetItem(splitfile, "segments");
runs = cJSON_GetItem(splitfile, "history");
2021-09-17 05:21:45 +10:00
2021-09-03 13:41:23 +10:00
if (game) {
2021-09-17 09:25:36 +10:00
cJSON *title = cJSON_GetItem(game, "name");
2021-09-03 13:41:23 +10:00
if (cJSON_IsString(title) && (title->valuestring != NULL)) {
gameTitle = malloc(strlen(title->valuestring));
strcpy(gameTitle, title->valuestring);
}
}
2021-09-17 05:21:45 +10:00
if (cate) {
2021-09-17 09:25:36 +10:00
cJSON *title = cJSON_GetItem(cate, "name");
2021-09-03 13:41:23 +10:00
if (cJSON_IsString(title) && (title->valuestring != NULL)) {
categoryTitle = malloc(strlen(title->valuestring));
strcpy(categoryTitle, title->valuestring);
}
}
2021-09-17 05:21:45 +10:00
if (atts) {
2021-09-17 09:25:36 +10:00
cJSON *total = cJSON_GetItem(atts, "total");
2021-09-03 13:41:23 +10:00
if (cJSON_IsNumber(total))
attempts = total->valueint;
}
if (segs) {
2021-09-17 09:25:36 +10:00
segCount = cJSON_GetArraySize(segs);
segments = calloc(segCount, sizeof(struct segment));
pbrun = calloc(segCount, sizeof(struct segment));
wrrun = calloc(segCount, sizeof(struct segment));
bestsegs = calloc(segCount, sizeof(struct segment));
2021-09-03 13:41:23 +10:00
int it = 0;
cJSON *iterator = NULL;
cJSON *segname = NULL;
cJSON_ArrayForEach(iterator, segs) {
2021-09-17 09:25:36 +10:00
segname = cJSON_GetItem(iterator, "name");
2021-09-03 13:41:23 +10:00
if (cJSON_IsString(segname) && (segname->valuestring != NULL)) {
segments[it].name = malloc(strlen(segname->valuestring));
strcpy(segments[it].name, segname->valuestring);
}
2021-09-17 05:21:45 +10:00
it++;
}
}
if (runs) {
2021-09-17 09:25:36 +10:00
pastRuns = calloc(cJSON_GetArraySize(runs) * segCount, sizeof(struct pastseg));
2021-09-17 05:21:45 +10:00
int oI = 0;
cJSON *oIterator = NULL;
cJSON_ArrayForEach(oIterator, runs) {
int iI = 0;
cJSON *iIterator = NULL;
cJSON_ArrayForEach(iIterator, oIterator) {
struct pastseg t;
cJSON *rms = cJSON_GetItem(iIterator, "m");
cJSON *skp = cJSON_GetItem(iIterator, "s");
cJSON *rst = cJSON_GetItem(iIterator, "r");
2021-09-17 05:21:45 +10:00
2021-09-17 09:25:36 +10:00
t.ms = rms->valueint;
2021-09-17 05:21:45 +10:00
if (cJSON_IsTrue(skp))
t.isSkipped = true;
else
t.isSkipped = false;
if (cJSON_IsTrue(rst))
t.isReset = true;
else
t.isReset = false;
2021-09-17 09:25:36 +10:00
pastRuns[(oI * segCount) + iI] = t;
2021-09-17 05:21:45 +10:00
iI++;
}
oI++;
}
}
cJSON_Delete(splitfile);
calculatePB();
calculateBestSegs();
2021-09-17 05:21:45 +10:00
}
//Imports game/catagory names and segment names
void importSplitsIO(cJSON *splitfile)
{
cJSON *game = NULL;
cJSON *cate = NULL;
cJSON *segs = NULL;
2021-09-17 09:25:36 +10:00
game = cJSON_GetItem(splitfile, "game");
cate = cJSON_GetItem(splitfile, "category");
segs = cJSON_GetItem(splitfile, "segments");
2021-09-17 05:21:45 +10:00
if (game) {
2021-09-17 09:25:36 +10:00
cJSON *title = cJSON_GetItem(game, "longname");
2021-09-17 05:21:45 +10:00
if (cJSON_IsString(title) && (title->valuestring != NULL)) {
gameTitle = malloc(strlen(title->valuestring));
strcpy(gameTitle, title->valuestring);
}
}
if (cate) {
2021-09-17 09:25:36 +10:00
cJSON *title = cJSON_GetItem(cate, "longname");
2021-09-17 05:21:45 +10:00
if (cJSON_IsString(title) && (title->valuestring != NULL)) {
categoryTitle = malloc(strlen(title->valuestring));
strcpy(categoryTitle, title->valuestring);
}
}
if (segs) {
2021-09-17 09:25:36 +10:00
segCount = cJSON_GetArraySize(segs);
segments = calloc(segCount, sizeof(struct segment));
pbrun = calloc(segCount, sizeof(struct segment));
wrrun = calloc(segCount, sizeof(struct segment));
bestsegs = calloc(segCount, sizeof(struct segment));
2021-09-17 05:21:45 +10:00
cJSON *segname = NULL;
int it = 0;
cJSON *iterator = NULL;
cJSON_ArrayForEach(iterator, segs) {
2021-09-17 09:25:36 +10:00
segname = cJSON_GetItem(iterator, "name");
2021-09-17 05:21:45 +10:00
if (cJSON_IsString(segname) && (segname->valuestring != NULL)) {
segments[it].name = malloc(strlen(segname->valuestring));
strcpy(segments[it].name, segname->valuestring);
2021-09-03 13:41:23 +10:00
}
it++;
}
}
cJSON_Delete(splitfile);
}
void exportSplitsIO()
{
//cJSON root node
cJSON *export = NULL;
//Schema version
cJSON *schema = NULL;
//Links
cJSON *links_root = NULL;
cJSON *speedruncom_id = NULL;
cJSON *splitsio_id = NULL;
//Timer
cJSON *timer_root = NULL;
cJSON *timer_shortname = NULL;
cJSON *timer_longname = NULL;
cJSON *timer_version = NULL;
cJSON *timer_website = NULL;
//Attempts
cJSON *attempts_root = NULL;
cJSON *attempts_total = NULL;
cJSON *histories = NULL;
cJSON *history_root = NULL;
cJSON *history_attmpt = NULL;
cJSON *history_dur = NULL;
cJSON *history_dur_rms = NULL;
cJSON *history_dur_gms = NULL;
//Supplementary data
cJSON *image_url = NULL;
cJSON *video_url = NULL;
//Time
cJSON *started_at = NULL;
cJSON *ended_at = NULL;
//Pauses
cJSON *pauses_root = NULL;
cJSON *pause_started = NULL;
cJSON *pause_ended = NULL;
//Game
cJSON *game_root = NULL;
cJSON *game_longname = NULL;
cJSON *game_shortname = NULL;
cJSON *game_links = NULL;
cJSON *game_srcom_id = NULL;
cJSON *game_splits_id = NULL;
//Catagory
cJSON *cate_root = NULL;
cJSON *cate_longname = NULL;
cJSON *cate_shortname = NULL;
cJSON *cate_links = NULL;
cJSON *cate_splits_id = NULL;
cJSON *cate_spdrun_id = NULL;
//Runners
cJSON *runner_root = NULL;
cJSON *runner_longname = NULL;
cJSON *runner_shrtname = NULL;
cJSON *runner_links = NULL;
cJSON *runner_twitch = NULL;
cJSON *runner_spltsio = NULL;
cJSON *runner_spdrun = NULL;
cJSON *runner_twitter = NULL;
//Segments
cJSON *seg_root = NULL;
cJSON *seg_name = NULL;
cJSON *seg_ended = NULL;
cJSON *seg_ended_rms = NULL;
cJSON *seg_ended_gms = NULL;
cJSON *seg_best = NULL;
cJSON *seg_best_rms = NULL;
cJSON *seg_best_gms = NULL;
cJSON *seg_is_skipped = NULL;
cJSON *seg_is_reset = NULL;
cJSON *seg_histories = NULL;
cJSON *seg_hst_attmp = NULL;
cJSON *seg_hst_end = NULL;
cJSON *seg_hst_end_rms = NULL;
cJSON *seg_hst_end_gms = NULL;
cJSON *seg_hst_skp = NULL;
cJSON *seg_hst_rst = NULL;
}
2021-09-17 05:21:45 +10:00
void saveFile()
{
if (timerActive)
return;
cJSON *splitfile = cJSON_CreateObject();
cJSON *game = cJSON_CreateObject();
cJSON *cate = cJSON_CreateObject();
cJSON *atts = cJSON_CreateObject();
cJSON *segs = cJSON_CreateArray();
cJSON *runs = cJSON_CreateArray();
cJSON *gameName = cJSON_CreateString(gameTitle);
cJSON *cateName = cJSON_CreateString(categoryTitle);
cJSON *attCount = cJSON_CreateNumber(attempts);
cJSON_AddItemToObject(game, "name", gameName);
cJSON_AddItemToObject(cate, "name", cateName);
cJSON_AddItemToObject(atts, "total", attCount);
cJSON_AddItemToObject(splitfile, "game", game);
cJSON_AddItemToObject(splitfile, "category", cate);
cJSON_AddItemToObject(splitfile, "attempts", atts);
2021-09-17 09:25:36 +10:00
for(int i = 0; i < segCount; i++) {
2021-09-17 05:21:45 +10:00
cJSON *seg = cJSON_CreateObject();
cJSON *segn = cJSON_CreateString(segments[i].name);
cJSON_AddItemToObject(seg, "name", segn);
cJSON_AddItemToArray(segs, seg);
}
cJSON_AddItemToObject(splitfile, "segments", segs);
for (int i = 0; i < attempts; i++) {
cJSON *run = cJSON_CreateArray();
2021-09-17 09:25:36 +10:00
for (int j = 0; j < segCount; j++) {
struct pastseg t = pastRuns[(i * segCount) + j];
2021-09-17 05:21:45 +10:00
cJSON *seg = cJSON_CreateObject();
2021-09-17 09:25:36 +10:00
cJSON *tim = cJSON_CreateNumber(t.ms);
2021-09-17 05:21:45 +10:00
cJSON *skp = cJSON_CreateBool(t.isSkipped);
cJSON *rst = cJSON_CreateBool(t.isReset);
cJSON_AddItemToObject(seg, "m", tim);
cJSON_AddItemToObject(seg, "s", skp);
cJSON_AddItemToObject(seg, "r", rst);
2021-09-17 05:21:45 +10:00
cJSON_AddItemToArray(run, seg);
}
cJSON_AddItemToArray(runs, run);
}
cJSON_AddItemToObject(splitfile, "history", runs);
char *string = cJSON_Print(splitfile);
if (string != NULL) {
FILE *f = fopen(filepath, "w");
if (f == NULL)
return;
fwrite(string, 1, strlen(string), f);
fclose(f);
}
cJSON_Delete(splitfile);
}
2021-08-28 01:43:33 +10:00
int main(int argc, char **argv)
2021-08-18 16:56:42 +10:00
{
timerActive = false;
2021-09-17 05:21:45 +10:00
filepath = argv[1];
2021-08-18 16:56:42 +10:00
hook_set_logger_proc(&logger_proc);
hook_set_dispatch_proc(&dispatch_proc);
//IPC pipe
pid_t cpid;
pipe(pipefd);
fcntl(pipefd[0], F_SETFL, O_NONBLOCK);
loadKeymap();
cpid = fork();
2021-09-17 05:21:45 +10:00
2021-08-18 16:56:42 +10:00
if (cpid == 0) {
close(pipefd[0]);
hook_run();
} else {
close(pipefd[1]);
2021-08-28 01:43:33 +10:00
signal(SIGWINCH, resize);
resize(0);
initScreen(bg, fg);
2021-09-17 05:21:45 +10:00
loadFile();
2021-08-28 01:43:33 +10:00
while(!handleInput()) {
struct timespec delta;
clock_gettime(CLOCK_REALTIME, &finish);
sub_timespec(notif, finish, &delta);
if (delta.tv_sec == 3)
clearNotif();
2021-08-18 16:56:42 +10:00
if (timerActive) {
sub_timespec(timestart, finish, &delta);
currentMS = timespecToMS(delta);
2021-08-18 16:56:42 +10:00
}
drawDisplay();
2021-09-17 05:21:45 +10:00
usleep(4000);
2021-08-18 16:56:42 +10:00
}
2021-08-28 01:43:33 +10:00
resetScreen();
kill(cpid, SIGTERM);
2021-08-18 16:56:42 +10:00
}
2021-09-17 05:21:45 +10:00
2021-08-11 23:50:59 +10:00
return 0;
}
2021-09-03 13:41:23 +10:00