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
|
||||
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) $^
|
||||
|
||||
%.o: %.c
|
||||
|
|
11
main.c
11
main.c
|
@ -5,6 +5,7 @@
|
|||
#include "termbox_render.h"
|
||||
#include "oct_termbox_sprite.h"
|
||||
#include "oct_networking.h"
|
||||
#include "oct_timer.h"
|
||||
#include "oct_log.h"
|
||||
|
||||
#define TB_IMPL
|
||||
|
@ -53,6 +54,7 @@ int main(int argc, char* argv[]) {
|
|||
sigaction(SIGINT, &sa, NULL);
|
||||
|
||||
struct tb_event ev;
|
||||
// Main loop if we are using termbox
|
||||
if (config.needs_termbox) {
|
||||
while (!finish) {
|
||||
tb_clear();
|
||||
|
@ -70,9 +72,11 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
tb_present();
|
||||
oct_network_send_msgs();
|
||||
oct_timer_tick(L);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Main loop if we are not using termbox
|
||||
while (!finish) {
|
||||
oct_network_recv_msgs();
|
||||
lua_getglobal(L, "oct_loop");
|
||||
|
@ -83,6 +87,7 @@ int main(int argc, char* argv[]) {
|
|||
finish = 1;
|
||||
}
|
||||
oct_network_send_msgs();
|
||||
oct_timer_tick(L);
|
||||
}
|
||||
}
|
||||
deinitialize_everything();
|
||||
|
@ -211,6 +216,11 @@ int initialize_everything(char* lua_file) {
|
|||
deinitialize_everything();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initialize timers
|
||||
oct_timer_list_initialize();
|
||||
oct_timer_initialize_lua(L);
|
||||
|
||||
OCT_LOG_INFO("Begin running oct_init()");
|
||||
lua_getglobal(L, "oct_init");
|
||||
lua_pushstring(L, lua_args);
|
||||
|
@ -254,6 +264,7 @@ int deinitialize_everything() {
|
|||
if (L) lua_close(L);
|
||||
oct_tb_sprite_list_deinitialize();
|
||||
oct_network_ab_deinit();
|
||||
oct_timer_list_deinitialize();
|
||||
//oct_network_node_deinit();
|
||||
oct_log_deinit();
|
||||
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