Add timer infrastructure to engine, can now schedule lua func calls
This commit is contained in:
parent
823f3b0e60
commit
0338155b3a
2
Makefile
2
Makefile
|
@ -5,7 +5,7 @@ BIN=open_card_table
|
||||||
DEBUG=-g
|
DEBUG=-g
|
||||||
CFLAGS=`pkg-config --cflags lua5.3` -D_XOPEN_SOURCE=700 -D_DEFAULT_SOURCE
|
CFLAGS=`pkg-config --cflags lua5.3` -D_XOPEN_SOURCE=700 -D_DEFAULT_SOURCE
|
||||||
|
|
||||||
open_card_table: main.o oct_networking.o oct_termbox_sprite.o oct_log.o
|
open_card_table: main.o oct_networking.o oct_termbox_sprite.o oct_timer.o oct_log.o
|
||||||
$(CC) $(DEBUG) $(CFLAGS) $(INC) $(CLIB) -o $(BIN) $^
|
$(CC) $(DEBUG) $(CFLAGS) $(INC) $(CLIB) -o $(BIN) $^
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
|
|
11
main.c
11
main.c
|
@ -5,6 +5,7 @@
|
||||||
#include "termbox_render.h"
|
#include "termbox_render.h"
|
||||||
#include "oct_termbox_sprite.h"
|
#include "oct_termbox_sprite.h"
|
||||||
#include "oct_networking.h"
|
#include "oct_networking.h"
|
||||||
|
#include "oct_timer.h"
|
||||||
#include "oct_log.h"
|
#include "oct_log.h"
|
||||||
|
|
||||||
#define TB_IMPL
|
#define TB_IMPL
|
||||||
|
@ -53,6 +54,7 @@ int main(int argc, char* argv[]) {
|
||||||
sigaction(SIGINT, &sa, NULL);
|
sigaction(SIGINT, &sa, NULL);
|
||||||
|
|
||||||
struct tb_event ev;
|
struct tb_event ev;
|
||||||
|
// Main loop if we are using termbox
|
||||||
if (config.needs_termbox) {
|
if (config.needs_termbox) {
|
||||||
while (!finish) {
|
while (!finish) {
|
||||||
tb_clear();
|
tb_clear();
|
||||||
|
@ -70,9 +72,11 @@ int main(int argc, char* argv[]) {
|
||||||
}
|
}
|
||||||
tb_present();
|
tb_present();
|
||||||
oct_network_send_msgs();
|
oct_network_send_msgs();
|
||||||
|
oct_timer_tick(L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// Main loop if we are not using termbox
|
||||||
while (!finish) {
|
while (!finish) {
|
||||||
oct_network_recv_msgs();
|
oct_network_recv_msgs();
|
||||||
lua_getglobal(L, "oct_loop");
|
lua_getglobal(L, "oct_loop");
|
||||||
|
@ -83,6 +87,7 @@ int main(int argc, char* argv[]) {
|
||||||
finish = 1;
|
finish = 1;
|
||||||
}
|
}
|
||||||
oct_network_send_msgs();
|
oct_network_send_msgs();
|
||||||
|
oct_timer_tick(L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deinitialize_everything();
|
deinitialize_everything();
|
||||||
|
@ -211,6 +216,11 @@ int initialize_everything(char* lua_file) {
|
||||||
deinitialize_everything();
|
deinitialize_everything();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize timers
|
||||||
|
oct_timer_list_initialize();
|
||||||
|
oct_timer_initialize_lua(L);
|
||||||
|
|
||||||
OCT_LOG_INFO("Begin running oct_init()");
|
OCT_LOG_INFO("Begin running oct_init()");
|
||||||
lua_getglobal(L, "oct_init");
|
lua_getglobal(L, "oct_init");
|
||||||
lua_pushstring(L, lua_args);
|
lua_pushstring(L, lua_args);
|
||||||
|
@ -254,6 +264,7 @@ int deinitialize_everything() {
|
||||||
if (L) lua_close(L);
|
if (L) lua_close(L);
|
||||||
oct_tb_sprite_list_deinitialize();
|
oct_tb_sprite_list_deinitialize();
|
||||||
oct_network_ab_deinit();
|
oct_network_ab_deinit();
|
||||||
|
oct_timer_list_deinitialize();
|
||||||
//oct_network_node_deinit();
|
//oct_network_node_deinit();
|
||||||
oct_log_deinit();
|
oct_log_deinit();
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
#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;
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/**
|
||||||
|
Timer library for OCT
|
||||||
|
Lua functions will be able to register a function to be called after a certain amount of time. Timer values are updated on every call to the rendering loop, and when timer hits 0 the corresponding function is called
|
||||||
|
Optionally, we can also specify a string argument to be passed to the function when called
|
||||||
|
**/
|
||||||
|
#ifndef OCT_TIMER_H
|
||||||
|
#define OCT_TIMER_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <lua5.3/lualib.h>
|
||||||
|
#include <lua5.3/lauxlib.h>
|
||||||
|
|
||||||
|
#define OCT_TIMER_MAXIMUM_FUNCTION_NAME_LENGTH 128
|
||||||
|
#define OCT_TIMER_MAXIMUM_ARGUMENT_LENGTH 128
|
||||||
|
#define OCT_TIMER_MAXIMUM_ID_LENGTH 128
|
||||||
|
#define OCT_TIMER_INITIAL_NUM_TIMERS 10
|
||||||
|
#define OCT_TIMER_LIST_REALLOC_LENGTH 10
|
||||||
|
|
||||||
|
struct oct_timer_elem {
|
||||||
|
char id[OCT_TIMER_MAXIMUM_ID_LENGTH];
|
||||||
|
int64_t millis;
|
||||||
|
char lua_function[OCT_TIMER_MAXIMUM_FUNCTION_NAME_LENGTH];
|
||||||
|
char lua_argument[OCT_TIMER_MAXIMUM_ARGUMENT_LENGTH];
|
||||||
|
struct oct_timer_elem* next;
|
||||||
|
struct oct_timer_elem* prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Timer list is a doubly-linked list with O(1) inserts
|
||||||
|
// I can't imagine we're cancelling timers that often so this is fine
|
||||||
|
// Instead I think we will be inserting most of the time
|
||||||
|
// I could optimize this by inserting new timers in order of time to execution, but I don't see a reason to optimize yet
|
||||||
|
// O(1) inserts, O(n) accesses
|
||||||
|
struct oct_timer_list_ {
|
||||||
|
uint32_t size;
|
||||||
|
struct oct_timer_elem* first;
|
||||||
|
struct oct_timer_elem* last;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct oct_timer_list_ oct_timer_list;
|
||||||
|
|
||||||
|
int oct_timer_list_initialize();
|
||||||
|
int oct_timer_list_deinitialize();
|
||||||
|
int oct_timer_initialize_lua(lua_State *L);
|
||||||
|
int oct_timer_register(lua_State *L);
|
||||||
|
int oct_timer_unregister_lua(lua_State *L);
|
||||||
|
int oct_timer_unregister(char* id, int do_free); // free = 0 => depend on user to free the unregistered elem, free = 1 => free the unregistered elem
|
||||||
|
struct oct_timer_elem* oct_timer_find(char* id);
|
||||||
|
int oct_timer_tick(lua_State *L);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,23 @@
|
||||||
|
require("oct_utils")
|
||||||
|
|
||||||
|
function emit_message(arg)
|
||||||
|
OCT_LOG_INFO("EMIT_MESSAGE_CALLED!")
|
||||||
|
oct_timer_register("emit_message_timer", 500, "emit_message", "")
|
||||||
|
end
|
||||||
|
|
||||||
|
function emit_message2(arg)
|
||||||
|
OCT_LOG_INFO("EMIT_MESSAGE2 CALLED!")
|
||||||
|
oct_timer_register("emit_message_timer2", 100, "emit_message2", "")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function oct_init()
|
||||||
|
oct_timer_register("emit_message_timer", 500, "emit_message", "")
|
||||||
|
oct_timer_register("emit_message_timer2", 100, "emit_message2", "")
|
||||||
|
return OCT_NOT_NEEDS_NETWORKING, OCT_NOT_NEEDS_TERMBOX;
|
||||||
|
end
|
||||||
|
|
||||||
|
function oct_loop(key)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in New Issue