// engine.c
#include "engine.h"
#include "thing.h"
#include "player.h"
#include "server.h"
#include "renderer.h"
#include "platform.h"
static THREAD_FUNC_RETURN server_thread_func(void* arg) {
server_run(8080);
return THREAD_FUNC_RETURN_VALUE;
}
GameState g_game_state; // global state
extern void game_tick();
extern void game_init();
extern void game_end();
void engine_init() {
for (int i = 0; i < MAX_PLAYERS; ++i) {
g_game_state.players[i].connected = 0;
g_game_state.players[i].sock = 0;
queue_init(&g_game_state.players[i].queue);
}
thread_t server_thread;
server_thread = THREAD_CREATE(&server_thread, server_thread_func, &g_game_state);
if (server_thread != NULL) {
THREAD_DETACH(&server_thread);
}
else {
fprintf(stderr, "Failed to create server thread.\n");
exit(EXIT_FAILURE);
}
window_init();
renderer_init();
game_init();
}
void engine_update(float dt) {
renderer_begin_frame();
poll_inputs();
update_state();
render_frame();
renderer_end_frame();
platform_sleep_ms(10);
}
void poll_inputs() {
for (int i = 0; i < MAX_PLAYERS; ++i) {
Player* p = &g_game_state.players[i];
if (!p->connected) continue;
memcpy(p->inputs.previous, p->inputs.current, MAX_INPUTS);
memset(p->inputs.current, 0, MAX_INPUTS);
p->inputs.joy_x = 0;
p->inputs.joy_y = 0;
p->inputs.touch_down = 0;
Event ev;
while (queue_pop(&p->queue, &ev)) {
switch (ev.type) {
case EVENT_CHAR: {
unsigned char c = (unsigned char)ev.ch;
if (c < MAX_INPUTS)
p->inputs.current[c] = 1;
break;
}
case EVENT_BUTTON: {
unsigned char b = (unsigned char)ev.button.button;
if (b < MAX_INPUTS)
p->inputs.current[b] = ev.button.pressed;
break;
}
case EVENT_JOYSTICK: {
p->inputs.joy_x = ev.joystick.x;
p->inputs.joy_y = ev.joystick.y;
break;
}
case EVENT_TOUCH: {
p->inputs.touch_x = ev.touch.x;
p->inputs.touch_y = ev.touch.y;
p->inputs.touch_down = ev.touch.down;
break;
}
case EVENT_TEXT: {
strncpy_s(p->last_message, sizeof(p->last_message), ev.typed.text, sizeof(p->last_message) - 1);
p->last_message[sizeof(p->last_message) - 1] = '\0';
break;
}
default:
break;
}
//print_event(i, &ev);
}
}
}
void update_state() {
game_tick();
thing_update_all();
thing_physics_all();
}
void render_frame() {
thing_render_all();
}
void engine_reset() {
thing_clear_all();
for (int i = 0; i < MAX_PLAYERS; ++i) {
g_game_state.players[i].connected = 0;
g_game_state.players[i].sock = 0;
memset(&g_game_state.players[i].inputs, 0, sizeof(InputState));
queue_destroy(&g_game_state.players[i].queue);
queue_init(&g_game_state.players[i].queue);
}
g_game_state.player_count = 0;
game_end();
}
int engine_button_down(int player_id, char button) {
if (player_id < 0 || player_id >= MAX_PLAYERS) return -1;
return g_game_state.players[player_id].inputs.current[(unsigned char)button] ? 1 : 0;
}
int engine_button_pressed(int player_id, char button) {
if (player_id < 0 || player_id >= MAX_PLAYERS) return -1;
unsigned char b = (unsigned char)button;
return g_game_state.players[player_id].inputs.current[b] &&
!g_game_state.players[player_id].inputs.previous[b];
}
int engine_button_released(int player_id, char button) {
if (player_id < 0 || player_id >= MAX_PLAYERS) return -1;
unsigned char b = (unsigned char)button;
return !g_game_state.players[player_id].inputs.current[b] &&
g_game_state.players[player_id].inputs.previous[b];
}
float engine_joystick_x(int player_id) {
if (player_id < 0 || player_id >= MAX_PLAYERS) return 0.0f;
return g_game_state.players[player_id].inputs.joy_x;
}
float engine_joystick_y(int player_id) {
if (player_id < 0 || player_id >= MAX_PLAYERS) return 0.0f;
return g_game_state.players[player_id].inputs.joy_y;
}
const char* engine_last_message(int player_id) {
if (player_id < 0 || player_id >= MAX_PLAYERS) return NULL;
return g_game_state.players[player_id].last_message;
}