open-card-table/oct_timer.c

180 lines
4.4 KiB
C

#include <string.h>
#include <stdlib.h>
#include <lua5.3/lualib.h>
#include <lua5.3/lauxlib.h>
#include <time.h>
#include "oct_timer.h"
#include "oct_log.h"
struct oct_timer_list_ oct_timer_list;
int64_t prev_millis;
int oct_timer_list_initialize() {
OCT_LOG_INFO("Initializing timer list")
oct_timer_list.size = 0;
oct_timer_list.first = NULL;
oct_timer_list.last = NULL;
struct timespec now;
timespec_get(&now, TIME_UTC);
prev_millis = ((int64_t) now.tv_sec) * 1000 + ((int64_t) now.tv_nsec) / 1000000;
return 1;
}
int oct_timer_list_deinitialize() {
struct oct_timer_elem* crawler = oct_timer_list.first;
while (crawler != NULL) {
struct oct_timer_elem* temp = crawler->next;
free(crawler);
crawler = temp;
}
oct_timer_list.first = NULL;
oct_timer_list.last = NULL;
oct_timer_list.size = 0;
return 1;
}
int oct_timer_register(lua_State *L) {
// Gather the arguments
char id[OCT_TIMER_MAXIMUM_ID_LENGTH];
int64_t millis;
char function[OCT_TIMER_MAXIMUM_ID_LENGTH];
char argument[OCT_TIMER_MAXIMUM_ID_LENGTH];
strncpy(id, luaL_checkstring(L, -4), OCT_TIMER_MAXIMUM_ID_LENGTH);
millis = luaL_checkinteger(L, -3);
strncpy(function, luaL_checkstring(L, -2), OCT_TIMER_MAXIMUM_FUNCTION_NAME_LENGTH);
strncpy(argument, luaL_checkstring(L, -1), OCT_TIMER_MAXIMUM_ARGUMENT_LENGTH);
// Check for any duplicate ids in the list
if (oct_timer_find(id)) {
OCT_LOG_ERROR("Tried to register a timer with a duplicate ID");
lua_pushnil(L);
return 1;
}
// We're good to go, insert at the end
struct oct_timer_elem* e = (struct oct_timer_elem*)malloc(sizeof(struct oct_timer_elem));
strncpy(e->id, id, OCT_TIMER_MAXIMUM_ID_LENGTH);
e->millis = millis;
strncpy(e->lua_function, function, OCT_TIMER_MAXIMUM_FUNCTION_NAME_LENGTH);
strncpy(e->lua_argument, argument, OCT_TIMER_MAXIMUM_ARGUMENT_LENGTH);
if (!oct_timer_list.first) {
oct_timer_list.first = e;
}
e->next = NULL;
e->prev = oct_timer_list.last;
if (oct_timer_list.last) {
oct_timer_list.last->next = e;
}
oct_timer_list.last = e;
oct_timer_list.size++;
// not sure if i have to return something
return 0;
}
struct oct_timer_elem* oct_timer_find(char* id) {
struct oct_timer_elem* crawler = oct_timer_list.first;
while (crawler != NULL) {
if (strncmp(id, crawler->id, OCT_TIMER_MAXIMUM_ID_LENGTH) == 0) {
return crawler;
}
crawler = crawler->next;
}
return NULL;
}
int oct_timer_unregister(char* id, int do_free) {
struct oct_timer_elem* e = oct_timer_find(id);
if (!e) {
OCT_LOG_WARNING("Tried to unregister a nonexistent timer");
return 0;
}
if (e == oct_timer_list.first) {
oct_timer_list.first = e->next;
if (e->next) {
e->next->prev = NULL;
}
}
else if (e == oct_timer_list.last) {
oct_timer_list.last = e->prev;
if (e->prev) {
e->prev->next = NULL;
}
}
else {
e->next->prev = e->prev;
e->prev->next = e->next;
}
oct_timer_list.size--;
if (do_free) {
free(e);
}
// Not sure if I have to return something
return 0;
}
int oct_timer_unregister_lua(lua_State *L) {
char id[OCT_TIMER_MAXIMUM_ID_LENGTH];
strncpy(id, luaL_checkstring(L, -1), OCT_TIMER_MAXIMUM_ID_LENGTH);
int res = oct_timer_unregister(id, 1);
if (!res) {
lua_pushnil(L);
return 1;
}
return 0;
}
int oct_timer_initialize_lua(lua_State *L) {
OCT_LOG_INFO("Exporting timer lua functions");
lua_pushcfunction(L, oct_timer_register);
lua_setglobal(L, "oct_timer_register");
lua_pushcfunction(L, oct_timer_unregister_lua);
lua_setglobal(L, "oct_timer_unregister");
// I don't think we need a metatable...
return 1;
}
int oct_timer_tick(lua_State *L) {
struct timespec now;
timespec_get(&now, TIME_UTC);
int64_t millis = ((int64_t) now.tv_sec) * 1000 + ((int64_t) now.tv_nsec) / 1000000;
int64_t elapsed = millis - prev_millis;
struct oct_timer_elem* crawler = oct_timer_list.first;
while (crawler != NULL) {
crawler->millis -= elapsed;
if (crawler->millis <= 0) {
struct oct_timer_elem* temp = crawler;
crawler = crawler->next;
// First, remove the timer
// lua can add a timer at the end of the function, don't want to complicate things by making the developer come up with a unique name
// So we unregister it, but don't free it yet
oct_timer_unregister(temp->id, 0);
// call lua function with argument
lua_getglobal(L, temp->lua_function);
lua_pushstring(L, temp->lua_argument);
lua_call(L, 1, 0);
// Now free the timer
free(temp);
}
else {
crawler = crawler->next;
}
}
prev_millis = millis;
return 0;
}