Compare commits
2 Commits
577e88551d
...
9c7ccfe0b0
Author | SHA1 | Date | |
---|---|---|---|
9c7ccfe0b0 | |||
65414c2d64 |
187
formatspec.md
Normal file
187
formatspec.md
Normal file
@ -0,0 +1,187 @@
|
||||
Introduction
|
||||
============
|
||||
The quest file format is a declarative computer language. It is made up
|
||||
of statements that when read by the software define how it should behave and
|
||||
statements that are written by the software to declare what it recorded.
|
||||
Each statement begins with a directive followed by options or arguments indented
|
||||
by one tab on the following lines.
|
||||
The order of the directives is important, they are read by the program
|
||||
line by line and may inherit data from those placed above.
|
||||
If a line does not begin with a recognizable directive, it is ignored.
|
||||
Care should be taken when inserting comments as one program may recognize
|
||||
directives that another does not, for this reason double backslashes (//) are
|
||||
reserved for leaving comments
|
||||
|
||||
List of directives
|
||||
==================
|
||||
The indented section of the directives reference show example values first,
|
||||
followed by the range of possible values or brief explaination in brackets
|
||||
|
||||
Option directives
|
||||
-----------------
|
||||
Any client is free to define their own directives to look for in this section.
|
||||
These directives override a programs defaults, they should be placed at the
|
||||
top of the file alongside MetaData directives
|
||||
|
||||
Foreground-Color
|
||||
247, 248, 242 (0-255, 0-255, 0-255)
|
||||
|
||||
Background-Color
|
||||
47, 53, 66 (0-255, 0-255, 0-255)
|
||||
|
||||
Best-Color
|
||||
249, 255, 79 (0-255, 0-255, 0-255)
|
||||
|
||||
Ahead-Gaining-Color
|
||||
24, 240, 31 (0-255, 0-255, 0-255)
|
||||
|
||||
Ahead-Losing-Color
|
||||
79, 255, 85 (0-255, 0-255, 0-255)
|
||||
|
||||
Behind-Gaining-Color
|
||||
255, 79, 79 (0-255, 0-255, 0-255)
|
||||
|
||||
Behind-Losing-Color
|
||||
224, 34, 34 (0-255, 0-255, 0-255)
|
||||
|
||||
Comparison
|
||||
Personal-Best (Personal-Best/World-Record/Sum-of-Best)
|
||||
|
||||
Show-Delta-Column
|
||||
True (True/False)
|
||||
|
||||
Show-Segment-Column
|
||||
True (True/False)
|
||||
|
||||
Show-Time-Column
|
||||
True (True/False)
|
||||
|
||||
Show-Comparison-Column
|
||||
True (True/False)
|
||||
|
||||
Toggle-Hotkeys
|
||||
t (See key name section)
|
||||
|
||||
Start-Key
|
||||
r (See key name section)
|
||||
|
||||
Stop-Key
|
||||
f (See key name section)
|
||||
|
||||
Pause-Key
|
||||
y (See key name section)
|
||||
|
||||
Split-Key
|
||||
e (See key name section)
|
||||
|
||||
Unsplit-Key
|
||||
g (See key name section)
|
||||
|
||||
Skip-Key
|
||||
v (See key name section)
|
||||
|
||||
MetaData directives
|
||||
---------------
|
||||
These directives provide metadata to runs that follow them,
|
||||
multiple of these can appear in a single file if multiple
|
||||
games or categories are run after one another
|
||||
|
||||
Title
|
||||
Elden Ring (Title of the game being run)
|
||||
|
||||
Category
|
||||
Any% (Name of the category being run)
|
||||
|
||||
Runner
|
||||
SuperCoolGuy04 (The name you as the runner are known by)
|
||||
|
||||
Segment and Route Directives
|
||||
----------------------------
|
||||
Runs by themselves are simply a list of events that occured
|
||||
(such as splitting or pausing) in the quest language, in order to give meaning
|
||||
to this data, these more complicated directives are used to define segments
|
||||
that are played between splits and routes made up of these segments.
|
||||
Define all your possible segments first, followed by all routes.
|
||||
If no segments are defined, a single unnamed segment is assumed.
|
||||
If no routes are defined, a single unnamed route that passes through all
|
||||
segments in the order of their definition is assumed.
|
||||
|
||||
Segment
|
||||
Shortname
|
||||
Stage One (A name for the segment that should identify it
|
||||
within the file and refer to the single
|
||||
objective completed.
|
||||
This name should not change.)
|
||||
Longname
|
||||
Murderize Chad (The display name for the segment if it should
|
||||
differ from the proper name, this name can be
|
||||
changed freely and may be used for
|
||||
inside-jokes without issue.)
|
||||
Description
|
||||
Go to the golden palace and kill
|
||||
the big dude with the ugly sunglasses
|
||||
(Optional third argument for use as a more
|
||||
detailed note or reminder of the objective
|
||||
for the segment that may be displayed
|
||||
alongside the name)
|
||||
|
||||
Route
|
||||
Name
|
||||
Magic Swordless (Name for the route, keeping in mind routes
|
||||
are not categories, you may simply run
|
||||
multiple different routes because you're unsure
|
||||
yet which strategies are the fastest)
|
||||
Segments
|
||||
Stage One (The ordered list of segments the route
|
||||
Stage Two consists of, these names should match the
|
||||
Stage Four segment Shortnames)
|
||||
|
||||
Run Directives
|
||||
--------------
|
||||
These directives are much more complicated and are not intended to be written
|
||||
by a human but rather by the timer software, they will make up the majority
|
||||
of a file as they are the run history which may be quite long.
|
||||
These data passed by these directives exists agnostic of segments, route, games,
|
||||
or categories, rather they are either explicitly matched with metadata that is
|
||||
applicable, or by default is matched with the last set of metadata declared by
|
||||
the time of the run directive
|
||||
|
||||
Run
|
||||
Route
|
||||
Magic Swordless
|
||||
Start
|
||||
2016-10-23 10:03:12.034Z
|
||||
(The first event in a run must be Start, and it
|
||||
must be accompanied by an RFC 3339 timestamp)
|
||||
Split
|
||||
120052 (Following events may be accompanied by
|
||||
RFC 3339 timestamps or simply a millisecond
|
||||
offset from the previous event)
|
||||
Skip
|
||||
323481
|
||||
Split
|
||||
3121111
|
||||
Pause
|
||||
421397
|
||||
Unpause
|
||||
2016-10-23 11:16:04.175Z
|
||||
Stop (The last event in a run is always a Stop)
|
||||
123111
|
||||
|
||||
The 'Then' Directive
|
||||
------------------
|
||||
The default behaviour the timer should exhibit when multiple games, catagories,
|
||||
or routes exist in the same quest file is to allow the user to select
|
||||
which one should be run, but the 'Then' directive instead allows for multiple
|
||||
routes or catagories to be run one straight after the other as a single longer
|
||||
"route". The timer should insert a dummy "segment" between the two routes for
|
||||
the user to spend resetting the game and record the resulting run in two places:
|
||||
A run directive should be recorded with every event including the dummy split
|
||||
that can be exported and shared as one marathon attempt
|
||||
AND
|
||||
Individual run directives for each of the individual routes should be created
|
||||
without the other included routes or the dummy split that can contribute to the
|
||||
attempt history and stats of those individual catagories
|
||||
If multiple routes exist on both or either side of a Then directive, the routes
|
||||
to be stitched together should be selectable out of the options given, just as
|
||||
they are normally.
|
118
src2/client.c
Normal file
118
src2/client.c
Normal file
@ -0,0 +1,118 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int sockfd, portno, n;
|
||||
struct sockaddr_in serv_addr;
|
||||
struct hostent *server;
|
||||
|
||||
char buffer[256];
|
||||
char commandcode;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr,"usage %s command\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
portno = 8101;
|
||||
|
||||
/* Create a socket point */
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (sockfd < 0) {
|
||||
perror("ERROR opening socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
server = gethostbyname("localhost");
|
||||
|
||||
if (server == NULL) {
|
||||
fprintf(stderr,"ERROR, no such host\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
bzero((char *) &serv_addr, sizeof(serv_addr));
|
||||
serv_addr.sin_family = AF_INET;
|
||||
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
|
||||
serv_addr.sin_port = htons(portno);
|
||||
|
||||
/* Now connect to the server */
|
||||
if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
|
||||
perror("ERROR connecting");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "time")) {
|
||||
commandcode = 1;
|
||||
} else if (!strcmp(argv[1], "start")) {
|
||||
commandcode = 2;
|
||||
} else if (!strcmp(argv[1], "stop")) {
|
||||
commandcode = 3;
|
||||
} else if (!strcmp(argv[1], "kill")) {
|
||||
commandcode = 4;
|
||||
} else if (!strcmp(argv[1], "split")) {
|
||||
commandcode = 5;
|
||||
} else if (!strcmp(argv[1], "skip")) {
|
||||
commandcode = 6;
|
||||
} else if (!strcmp(argv[1], "pause")) {
|
||||
commandcode = 7;
|
||||
} else if (!strcmp(argv[1], "resume")) {
|
||||
commandcode = 8;
|
||||
} else if (!strcmp(argv[1], "undo")) {
|
||||
commandcode = 9;
|
||||
} else if (!strcmp(argv[1], "redo")) {
|
||||
commandcode = 10;
|
||||
} else if (!strcmp(argv[1], "foreground")) {
|
||||
commandcode = 11;
|
||||
} else if (!strcmp(argv[1], "background")) {
|
||||
commandcode = 12;
|
||||
} else {
|
||||
perror("No valid command given");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Send message to the server */
|
||||
n = write(sockfd, &commandcode, 1);
|
||||
|
||||
if (n < 0) {
|
||||
perror("ERROR writing to socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Now read server response */
|
||||
//bzero(buffer,256);
|
||||
|
||||
//read an int response
|
||||
if (commandcode < 11) {
|
||||
int x = -1;
|
||||
n = read(sockfd, &x, sizeof(int));
|
||||
|
||||
if (n < 0) {
|
||||
perror("ERROR reading from socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (x != -1)
|
||||
printf("%d\n",x);
|
||||
}
|
||||
//read a string response
|
||||
else {
|
||||
bzero(buffer,256);
|
||||
n = read(sockfd, &buffer, 255);
|
||||
|
||||
if (n < 0) {
|
||||
perror("ERROR reading from socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (buffer != NULL)
|
||||
printf("%s", buffer);
|
||||
}
|
||||
return 0;
|
||||
}
|
416
src2/server.c
Normal file
416
src2/server.c
Normal file
@ -0,0 +1,416 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define NS_PER_S 1000000000
|
||||
|
||||
struct timespec finish, delta;
|
||||
int pausedTime = 0;
|
||||
bool timerActive = false;
|
||||
bool paused = false;
|
||||
bool alive = true;
|
||||
int timerOffset = 0;
|
||||
enum event_type {
|
||||
START,
|
||||
SPLIT,
|
||||
SKIP,
|
||||
PAUSE,
|
||||
RESUME,
|
||||
STOP
|
||||
};
|
||||
struct run_event {
|
||||
enum event_type type;
|
||||
struct timespec time;
|
||||
};
|
||||
|
||||
struct run_event *run;
|
||||
//Enough to hold a sm64 16 star, can realloc later
|
||||
int runMaxLength = 12;
|
||||
int runMarker = 0;
|
||||
int runMarker2 = 0;
|
||||
|
||||
//save file stuff
|
||||
int files = 0;
|
||||
char **filePaths = NULL;
|
||||
char **names, **values;
|
||||
int valuecount;
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
void offset_timespec(int milliseconds, struct timespec* t)
|
||||
{
|
||||
//this should leave milliseconds with just the remainder
|
||||
int second_offset = milliseconds / 1000;
|
||||
milliseconds -= second_offset * 1000;
|
||||
|
||||
int nanosecond_offset = milliseconds * 1000000;
|
||||
|
||||
t->tv_nsec -= nanosecond_offset;
|
||||
if (t->tv_nsec < 0) {
|
||||
second_offset++;
|
||||
t->tv_nsec += 1000000000;
|
||||
}
|
||||
t->tv_sec -= second_offset;
|
||||
}
|
||||
|
||||
int timespecToMS(struct timespec t)
|
||||
{
|
||||
return (t.tv_nsec / 1000000) + (t.tv_sec * 1000);
|
||||
}
|
||||
|
||||
void extend_run()
|
||||
{
|
||||
runMaxLength *= 2;
|
||||
run = realloc(run, sizeof(struct run_event) * runMaxLength);
|
||||
}
|
||||
|
||||
void add_event(enum event_type t)
|
||||
{
|
||||
if (runMarker == runMaxLength)
|
||||
extend_run();
|
||||
run[runMarker].type = t;
|
||||
clock_gettime(CLOCK_REALTIME, &run[runMarker].time);
|
||||
if (t == START)
|
||||
offset_timespec(timerOffset, &run[runMarker].time);
|
||||
runMarker++;
|
||||
runMarker2 = runMarker;
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
//TODO: Save the old run to the file before the new one starts,
|
||||
//the reason to do this here is it gives the runner a chance to undo
|
||||
//if they accidentally hit the stop button
|
||||
//TODO: Clear the run data first
|
||||
timerActive = true;
|
||||
add_event(START);
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
timerActive = false;
|
||||
add_event(STOP);
|
||||
//this makes sure the time clients recieve from time
|
||||
//requests match the time on the stop event
|
||||
finish = run[runMarker - 1].time;
|
||||
}
|
||||
|
||||
void split()
|
||||
{
|
||||
add_event(SPLIT);
|
||||
}
|
||||
|
||||
void skip()
|
||||
{
|
||||
add_event(SKIP);
|
||||
}
|
||||
|
||||
void addPauseTime()
|
||||
{
|
||||
int pauseEvent = 0;
|
||||
for (int i = runMarker - 2; i >= 1; i--) {
|
||||
if (run[i].type == PAUSE) {
|
||||
pauseEvent = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sub_timespec(run[pauseEvent].time, run[runMarker - 1].time, &delta);
|
||||
pausedTime += timespecToMS(delta);
|
||||
}
|
||||
|
||||
void subtractPauseTime()
|
||||
{
|
||||
int pauseEvent = 0;
|
||||
for (int i = runMarker - 1; i >= i; i--) {
|
||||
if (run[i].type == PAUSE) {
|
||||
pauseEvent = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sub_timespec(run[pauseEvent].time, run[runMarker].time, &delta);
|
||||
pausedTime -= timespecToMS(delta);
|
||||
}
|
||||
|
||||
void undo()
|
||||
{
|
||||
if (runMarker > 0) {
|
||||
runMarker--;
|
||||
if (run[runMarker].type == STOP)
|
||||
timerActive = true;
|
||||
if (run[runMarker].type == START)
|
||||
timerActive = false;
|
||||
if (run[runMarker].type == PAUSE)
|
||||
paused = false;
|
||||
if (run[runMarker].type == RESUME) {
|
||||
paused = true;
|
||||
subtractPauseTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void redo()
|
||||
{
|
||||
if (runMarker < runMarker2) {
|
||||
runMarker++;
|
||||
if (run[runMarker - 1].type == STOP)
|
||||
timerActive = false;
|
||||
if (run[runMarker - 1].type == START)
|
||||
timerActive = true;
|
||||
if (run[runMarker - 1].type == PAUSE)
|
||||
paused = true;
|
||||
if (run[runMarker - 1].type == RESUME) {
|
||||
paused = false;
|
||||
addPauseTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//this isnt just called pause() because that would overlap with <unistd.h>
|
||||
void pause_timer()
|
||||
{
|
||||
if (!paused) {
|
||||
add_event(PAUSE);
|
||||
paused = true;
|
||||
}
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
if (paused) {
|
||||
add_event(RESUME);
|
||||
paused = false;
|
||||
addPauseTime();
|
||||
}
|
||||
}
|
||||
|
||||
void loadFiles()
|
||||
{
|
||||
FILE* fp;
|
||||
//TODO: for now we're just looking for the metadata values
|
||||
char buff[255];
|
||||
char buff2[255];
|
||||
|
||||
for (int i = 0; i < files; i++) {
|
||||
fp = fopen(filePaths[i], "r");
|
||||
|
||||
while(1) {
|
||||
char *x = fgets(buff, 255, fp);
|
||||
if (buff[0] == '/' && buff[1] == '/' || buff[0] == '\n')
|
||||
continue;
|
||||
if (!strcmp(buff, "Segment") || !strcmp(buff, "Route") || x == NULL)
|
||||
break;
|
||||
fgets(buff2, 255, fp);
|
||||
if (buff2[0] == '\t') {
|
||||
valuecount++;
|
||||
names = realloc(names, sizeof(char*) * valuecount);
|
||||
names[valuecount - 1] = malloc(strlen(buff) - 1);
|
||||
strncpy(names[valuecount - 1], buff, strlen(buff) - 1);
|
||||
names[valuecount - 1][strlen(buff)] = '\0';
|
||||
values = realloc(values, sizeof(char*) * valuecount);
|
||||
values[valuecount - 1] = malloc(strlen(buff2) - 2);
|
||||
strncpy(values[valuecount - 1], buff2 + 1, strlen(buff2) - 1);
|
||||
values[valuecount - 1][strlen(buff2)] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
//Print metadata arrays
|
||||
for (int i = 0; i < valuecount; i++) {
|
||||
printf("%s | %s", names[i], values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: eventually file loading should support loading multiple files
|
||||
void addFile(char *path)
|
||||
{
|
||||
files++;
|
||||
filePaths = realloc(filePaths, sizeof(char*) * files);
|
||||
filePaths[files - 1] = path;
|
||||
loadFiles();
|
||||
}
|
||||
|
||||
void sendTime(int sock)
|
||||
{
|
||||
int n, x;
|
||||
if (timerActive)
|
||||
clock_gettime(CLOCK_REALTIME, &finish);
|
||||
if (paused) {
|
||||
sub_timespec(run[0].time, run[runMarker - 1].time, &delta);
|
||||
} else {
|
||||
sub_timespec(run[0].time, finish, &delta);
|
||||
}
|
||||
x = timespecToMS(delta) - pausedTime;
|
||||
n = write(sock, &x, sizeof(int));
|
||||
|
||||
if (n < 0) {
|
||||
perror("ERROR writing to socket");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void sendValue(int sock, char* name)
|
||||
{
|
||||
int n, x;
|
||||
bool namefound = false;
|
||||
for(int i = 0; i < valuecount; i++) {
|
||||
if (!strcmp(names[i], name)) {
|
||||
x = i;
|
||||
namefound = true;
|
||||
}
|
||||
}
|
||||
if (namefound)
|
||||
n = write(sock, values[x], strlen(values[x]));
|
||||
else
|
||||
n = write(sock, "DATA NOT PRESENT", 17);
|
||||
|
||||
if (n < 0) {
|
||||
perror("ERROR writing to socket");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void doprocessing (int sock)
|
||||
{
|
||||
int n;
|
||||
char commandcode;
|
||||
n = read(sock,&commandcode,1);
|
||||
|
||||
if (n < 0) {
|
||||
perror("ERROR reading from socket");
|
||||
exit(1);
|
||||
}
|
||||
if (commandcode == 1) {
|
||||
//printf("Recieved time command\n");
|
||||
sendTime(sock);
|
||||
} else if (commandcode == 2) {
|
||||
printf("Recieved start command\n");
|
||||
start();
|
||||
} else if (commandcode == 3) {
|
||||
printf("Recieved stop command\n");
|
||||
stop();
|
||||
} else if (commandcode == 4) {
|
||||
printf("Recieved kill command\n");
|
||||
alive = false;
|
||||
} else if (commandcode == 5) {
|
||||
printf("Recieved split command\n");
|
||||
split();
|
||||
} else if (commandcode == 6) {
|
||||
printf("Recieved skip command\n");
|
||||
skip();
|
||||
} else if (commandcode == 7) {
|
||||
printf("Recieved pause command\n");
|
||||
pause_timer();
|
||||
} else if (commandcode == 8) {
|
||||
printf("Recieved resume command\n");
|
||||
resume();
|
||||
} else if (commandcode == 9) {
|
||||
printf("Recieved undo command\n");
|
||||
undo();
|
||||
} else if (commandcode == 10) {
|
||||
printf("Recieved redo command\n");
|
||||
redo();
|
||||
} else if (commandcode == 11) {
|
||||
printf("Recieved request for foreground color\n");
|
||||
sendValue(sock, "Foreground-Color");
|
||||
} else if (commandcode == 12) {
|
||||
printf("Recieved request for background color\n");
|
||||
sendValue(sock, "Background-Color");
|
||||
} else {
|
||||
printf("Recieved invalid command code, ignoring...\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int sockfd, newsockfd, portno, clilen;
|
||||
char buffer[256];
|
||||
struct sockaddr_in serv_addr, cli_addr;
|
||||
int n, pid;
|
||||
run = malloc(sizeof(struct run_event) * runMaxLength);
|
||||
//TODO: remove this file testing boilerplate
|
||||
if (argc > 1)
|
||||
addFile(argv[1]);
|
||||
|
||||
/* First call to socket() function */
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (sockfd < 0) {
|
||||
perror("ERROR opening socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Initialize socket structure */
|
||||
bzero((char *) &serv_addr, sizeof(serv_addr));
|
||||
portno = 8101;
|
||||
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
serv_addr.sin_port = htons(portno);
|
||||
|
||||
/* Now bind the host address using bind() call.*/
|
||||
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
|
||||
perror("ERROR on binding");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Now start listening for the clients, here
|
||||
* process will go in sleep mode and will wait
|
||||
* for the incoming connection
|
||||
*/
|
||||
|
||||
listen(sockfd,5);
|
||||
clilen = sizeof(cli_addr);
|
||||
|
||||
while (alive) {
|
||||
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
|
||||
|
||||
if (newsockfd < 0) {
|
||||
perror("ERROR on accept");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Create child process */
|
||||
//pid = fork();
|
||||
pid = 1;
|
||||
|
||||
if (pid < 0) {
|
||||
perror("ERROR on fork");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
/* This is the child process */
|
||||
//close(sockfd);
|
||||
//doprocessing(newsockfd);
|
||||
//exit(0);
|
||||
}
|
||||
else {
|
||||
doprocessing(newsockfd);
|
||||
close(newsockfd);
|
||||
}
|
||||
|
||||
} /* end of while */
|
||||
free(run);
|
||||
close(sockfd);
|
||||
}
|
||||
|
235
src2/tui.c
Normal file
235
src2/tui.c
Normal file
@ -0,0 +1,235 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
|
||||
char numbermap[5][44] = {
|
||||
"xxx..x..xxx.xxx.x.x.xxx.xxx.xxx.xxx.xxx.....",
|
||||
"x.x..x....x...x.x.x.x...x.....x.x.x.x.x.x...",
|
||||
"x.x..x..xxx.xxx.xxx.xxx.xxx...x.xxx.xxx.....",
|
||||
"x.x..x..x.....x...x...x.x.x...x.x.x...x.x...",
|
||||
"xxx..x..xxx.xxx...x.xxx.xxx...x.xxx...x...x."
|
||||
};
|
||||
struct termios base;
|
||||
int fps = 60;
|
||||
struct color {
|
||||
int r;
|
||||
int g;
|
||||
int b;
|
||||
};
|
||||
struct color b = { 47, 53, 66}; //Background color
|
||||
struct color f = {247, 248, 242}; //Text foreground color
|
||||
struct color g = {249, 255, 79}; //Best ever segment time color
|
||||
struct color ag = { 24, 240, 31}; //Ahead, and gaining time segment color
|
||||
struct color al = { 79, 255, 85}; //Ahead, but losing time segment color
|
||||
struct color bg = {255, 79, 79}; //Behind, but gaining time segment color
|
||||
struct color bl = {224, 34, 34}; //Behind, and losing time segment color
|
||||
|
||||
int w, h;
|
||||
|
||||
int timestringDigits(int ms)
|
||||
{
|
||||
int chars = 4;
|
||||
if (ms >= 10000)
|
||||
chars += 1;
|
||||
if (ms >= 60000)
|
||||
chars += 2;
|
||||
if (ms >= 600000)
|
||||
chars += 1;
|
||||
if (ms >= 3600000)
|
||||
chars += 2;
|
||||
if (ms >= 36000000)
|
||||
chars += 1;
|
||||
if (ms >= 360000000)
|
||||
chars += 1;
|
||||
return chars;
|
||||
}
|
||||
|
||||
//Attempt 2 at thinking through how to print the big numbies
|
||||
void printbig(int x, int y, int ms)
|
||||
{
|
||||
char small[13];
|
||||
timestring(&small, ms);
|
||||
if (w < strlen(small)) {
|
||||
printf("2smol\n");
|
||||
return;
|
||||
}
|
||||
int bigstringw = 42; //Minimum width and height the big timer string
|
||||
int bigstringh = 5; //bigger sizes are just multiples of these numbers.
|
||||
int bigstrings = 1;
|
||||
x = (w - (bigstringw - 1 * bigstrings)) / 2; //theres a -1 because theres extra whitespace on the last printed digit
|
||||
y = (h - (bigstringh * bigstrings)) / 2;
|
||||
for (int sy = 0; sy < 5; sy++) { //for every row
|
||||
printf("\033[%d;%dH", y + sy, x); //go to position
|
||||
for (int cc = 0; cc < 12; cc++) { //then, for every character
|
||||
int c = small[cc]; //check what character we're on
|
||||
if (c >= 48 && c <= 57) { //if its a number, print 4 pixels
|
||||
for (int xx = 0; xx < 4; xx++) {
|
||||
int xxx = c - 48;
|
||||
if (numbermap[sy][(xxx * 4) + xx] == 'x')
|
||||
printf("\033[48;2;%d;%d;%dm ", f.r, f.g, f.b);
|
||||
if (numbermap[sy][(xxx * 4) + xx] == '.')
|
||||
printf("\033[48;2;%d;%d;%dm ", b.r, b.g, b.b);
|
||||
}
|
||||
}
|
||||
if (c == 46 || c == 58) { //if its punctuation, print 2 pixels
|
||||
for (int xx = 0; xx < 2; xx++) {
|
||||
if (c == 46) {
|
||||
if (numbermap[sy][42 + xx] == 'x')
|
||||
printf("\033[48;2;%d;%d;%dm ", f.r, f.g, f.b);
|
||||
if (numbermap[sy][42 + xx] == '.')
|
||||
printf("\033[48;2;%d;%d;%dm ", b.r, b.g, b.b);
|
||||
}
|
||||
if (c == 58) {
|
||||
if (numbermap[sy][40 + xx] == 'x')
|
||||
printf("\033[48;2;%d;%d;%dm ", f.r, f.g, f.b);
|
||||
if (numbermap[sy][40 + xx] == '.')
|
||||
printf("\033[48;2;%d;%d;%dm ", b.r, b.g, b.b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
//printf("\033[%d;%dH%s\n", y, x, small + (12 - timestringDigits(time)));
|
||||
}
|
||||
|
||||
void timestring(char *str, int ms)
|
||||
{
|
||||
int msdigits = (ms / 10) % 100;
|
||||
int seconds = (ms / 1000) % 60;
|
||||
int minutes = ((ms / 1000) / 60) % 60;
|
||||
int hours = ((ms / 1000) / 60) / 60;
|
||||
sprintf(str, "%03d:%02d:%02d.%02d", hours, minutes, seconds, msdigits);
|
||||
}
|
||||
|
||||
void resize(int i)
|
||||
{
|
||||
struct winsize ws;
|
||||
ioctl(1, TIOCGWINSZ, &ws);
|
||||
w = ws.ws_col;
|
||||
h = ws.ws_row;
|
||||
}
|
||||
|
||||
void initScreen()
|
||||
{
|
||||
struct termios t;
|
||||
tcgetattr(1, &base);
|
||||
t = base;
|
||||
t.c_lflag &= (~ECHO & ~ICANON);
|
||||
tcsetattr(1, TCSANOW, &t);
|
||||
//TODO:Figure out why i did this
|
||||
dup(0);
|
||||
fcntl(0, F_SETFL, O_NONBLOCK);
|
||||
printf("\033[?1049h\n"); //Switch to TUI mode (alternate buffer)
|
||||
printf("\033[?25l\n"); //Hide text cursor
|
||||
printf("\033[2J\n"); //Clear screen
|
||||
}
|
||||
|
||||
void resetScreen()
|
||||
{
|
||||
tcsetattr(1, TCSANOW, &base);
|
||||
printf("\033[2J\n"); //Clear screen
|
||||
printf("\033[?1049l\n"); //Switch back to regular mode
|
||||
printf("\033[?25h\n"); //Show cursor
|
||||
}
|
||||
|
||||
void die(int i)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void processColorString(struct color *c, char* s)
|
||||
{
|
||||
int i = 0;
|
||||
int length = strlen(s);
|
||||
char comp[4];
|
||||
int compcount = 0;
|
||||
int colorcompsdone = 0;
|
||||
//TODO: if we know the length now that we're not doing fgetc we dont
|
||||
//need a while loop; convert to for loop.
|
||||
//Why? what makes a for loop better than a while loop?
|
||||
while (1) {
|
||||
char x = s[i++];
|
||||
if (x >= 48 && x <= 57) {
|
||||
comp[compcount] = x;
|
||||
compcount++;
|
||||
}
|
||||
if (x == 44 || i == length) {
|
||||
comp[compcount] = '\0';
|
||||
switch(colorcompsdone) {
|
||||
case 0:
|
||||
c->r = atoi(comp);
|
||||
break;
|
||||
case 1:
|
||||
c->g = atoi(comp);
|
||||
break;
|
||||
case 2:
|
||||
c->b = atoi(comp);
|
||||
}
|
||||
colorcompsdone++;
|
||||
compcount = 0;
|
||||
}
|
||||
if (i == length)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
initScreen();
|
||||
atexit(resetScreen);
|
||||
signal(SIGTERM, die);
|
||||
signal(SIGINT, die);
|
||||
signal(SIGWINCH, resize);
|
||||
resize(0);
|
||||
|
||||
FILE *fp;
|
||||
char path[1000];
|
||||
char ti[13];
|
||||
|
||||
//Request foreground color from config file
|
||||
fp = popen("./result/bin/quest-log foreground", "r");
|
||||
fgets(path, sizeof(path), fp);
|
||||
if (strcmp(path, "DATA NOT PRESENT"))
|
||||
processColorString(&f, path);
|
||||
printf("\033[38;2;%d;%d;%dm", f.r, f.g, f.b);
|
||||
pclose(fp);
|
||||
|
||||
//Request background color from config file
|
||||
fp = popen("./result/bin/quest-log background", "r");
|
||||
fgets(path, sizeof(path), fp);
|
||||
if (strcmp(path, "DATA NOT PRESENT"))
|
||||
processColorString(&b, path);
|
||||
printf("\033[48;2;%d;%d;%dm", b.r, b.g, b.b);
|
||||
pclose(fp);
|
||||
|
||||
//Set fps from command line argument
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-fps"))
|
||||
fps = atoi(argv[i + 1]);
|
||||
}
|
||||
while (1) {
|
||||
int time = 0;
|
||||
fp = popen("./result/bin/quest-log time", "r");
|
||||
if (fp == NULL) {
|
||||
printf("Failed to run command\n");
|
||||
exit(1);
|
||||
}
|
||||
//TODO: why is this a while loop?
|
||||
while (fgets(path, sizeof(path), fp) != NULL) {
|
||||
time = atoi(path);
|
||||
}
|
||||
pclose(fp);
|
||||
|
||||
printf("\033[2J\n");
|
||||
//timestring(&ti, time);
|
||||
//printf("%s\n", ti + (12 - timestringDigits(time)));
|
||||
printbig(3, 4, time);
|
||||
usleep(1000000 / fps);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user