RyanHub - file viewer
filename: src/core/engine.c
branch: main
back to repo
// 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;
}