eco2d/code/foundation/src/core/game.c

332 lines
8.9 KiB
C

#include "core/game.h"
#include "zpl.h"
#include "platform/platform.h"
#include "world/world.h"
#include "pkt/packet.h"
#include "platform/signal_handling.h"
#include "net/network.h"
#include "models/entity.h"
#include "world/world_view.h"
#include "world/entity_view.h"
#include "core/camera.h"
#include "platform/profiler.h"
#include "platform/renderer.h"
#include "flecs/flecs_os_api_stdcpp.h"
#include "flecs.h"
#include "models/components.h"
#include "systems/systems.h"
#include "packets/pkt_00_init.h"
#include "packets/pkt_01_welcome.h"
#include "packets/pkt_switch_viewer.h"
static uint8_t game_mode;
static uint8_t game_should_close;
static world_view *world_viewers;
static world_view *active_viewer;
static WORLD_PKT_READER(pkt_reader) {
pkt_header header = {0};
uint32_t ok = pkt_header_decode(&header, data, datalen);
header.udata = udata;
if (ok && header.ok) {
return pkt_handlers[header.id].handler(&header) >= 0;
} else {
zpl_printf("[warn] unknown packet id %d (header %d data %d)\n", header.id, ok, header.ok);
}
return -1;
}
static WORLD_PKT_WRITER(sp_pkt_writer) {
(void)udata;
return world_read(pkt->data, pkt->datalen, 0);
}
static WORLD_PKT_WRITER(mp_pkt_writer) {
if (pkt->is_reliable) {
return network_msg_send(udata, pkt->data, pkt->datalen, pkt->channel_id);
}
else {
return network_msg_send_unreliable(udata, pkt->data, pkt->datalen, pkt->channel_id);
}
}
static WORLD_PKT_WRITER(mp_cli_pkt_writer) {
(void)udata;
if (pkt->is_reliable) {
return network_msg_send(0, pkt->data, pkt->datalen, pkt->channel_id);
}
else {
return network_msg_send_unreliable(0, pkt->data, pkt->datalen, pkt->channel_id);
}
}
void world_viewers_init(uint32_t num_viewers) {
zpl_buffer_init(world_viewers, zpl_heap(), num_viewers);
for (uint32_t i = 0; i < num_viewers; i++) {
zpl_buffer_append(world_viewers, world_view_create(i));
}
}
void world_viewers_destroy() {
for (zpl_isize i = 0; i < zpl_buffer_count(world_viewers); i++) {
world_view_destroy(&world_viewers[i]);
}
zpl_buffer_free(world_viewers);
}
world_view *game_world_view_get(uint16_t idx) {
return &world_viewers[idx];
}
world_view *game_world_view_get_active(void) {
return active_viewer;
}
void game_world_view_cycle_active(int8_t dir) {
uint16_t idx = (uint16_t)(active_viewer - world_viewers);
game_world_view_set_active_by_idx(zpl_max(0, (idx+dir)%zpl_buffer_count(world_viewers)));
}
void game_world_view_set_active_by_idx(uint16_t idx) {
ZPL_ASSERT(idx >= 0 && idx < zpl_buffer_count(world_viewers));
game_world_view_set_active(&world_viewers[idx]);
}
void game_world_view_active_entity_map(void (*map_proc)(uint64_t key, entity_view * value)) {
entity_view_map(&active_viewer->entities, map_proc);
}
entity_view *game_world_view_active_get_entity(uint64_t ent_id) {
return entity_view_get(&active_viewer->entities, ent_id);
}
void game_world_view_set_active(world_view *view) {
active_viewer = view;
camera_set_follow(view->owner_id);
pkt_switch_viewer_send(view->view_id);
}
size_t game_world_view_count(void) {
return zpl_buffer_count(world_viewers);
}
void flecs_dash_init() {
#if !defined(ZPL_SYSTEM_EMSCRIPTEN)
ecs_singleton_set(world_ecs(), EcsRest, {0});
ECS_IMPORT(world_ecs(), FlecsMonitor);
#endif
}
float game_time() {
return (float)get_cached_time();
}
void game_init(const char *ip, uint16_t port, game_kind play_mode, uint32_t num_viewers, int32_t seed, uint16_t chunk_size, uint16_t chunk_amount, int8_t is_dash_enabled) {
game_mode = play_mode;
game_should_close = false;
#ifndef _DEBUG
const char *host_ip = "lab.zakto.pw";
#else
const char *host_ip = "127.0.0.1";
#endif
uint16_t host_port = (port > 0) ? port : 27000;
if (ip != NULL) {
host_ip = ip;
}
if (game_mode != GAMEKIND_HEADLESS) {
platform_init();
world_viewers_init(num_viewers);
active_viewer = &world_viewers[0];
camera_reset();
}
if (game_mode != GAMEKIND_SINGLE) {
network_init();
}
if (game_mode == GAMEKIND_CLIENT) {
world_setup_pkt_handlers(pkt_reader, mp_cli_pkt_writer);
network_client_connect(host_ip, host_port);
} else {
stdcpp_set_os_api();
world_setup_pkt_handlers(pkt_reader, game_mode == GAMEKIND_SINGLE ? sp_pkt_writer : mp_pkt_writer);
world_init(seed, chunk_size, chunk_amount);
if (is_dash_enabled) flecs_dash_init();
if (game_mode == GAMEKIND_HEADLESS) {
network_server_start(0, 27000);
//ecs_set_target_fps(world_ecs(), 60);
}
}
if (game_mode == GAMEKIND_SINGLE) {
for (uint32_t i = 0; i < num_viewers; i++) {
pkt_00_init_send(i);
}
}
}
int8_t game_is_networked() {
return game_mode != GAMEKIND_SINGLE;
}
void game_shutdown() {
if (game_mode == GAMEKIND_CLIENT) {
network_client_disconnect();
} else {
world_destroy();
if (game_mode == GAMEKIND_HEADLESS) {
network_server_stop();
}
}
if (game_mode != GAMEKIND_SINGLE) {
network_destroy();
}
if (game_mode != GAMEKIND_HEADLESS) {
world_viewers_destroy();
// TODO(zaklaus): crashes on exit
//platform_shutdown();
}
}
uint8_t game_is_running() {
uint8_t is_running = !game_should_close;
if (game_mode != GAMEKIND_HEADLESS) {
is_running = platform_is_running();
}
return is_running;
}
game_kind game_get_kind(void) {
return game_mode;
}
void game_input() {
if (game_mode != GAMEKIND_HEADLESS) {
platform_input();
}
}
void game_update() {
static double last_update = 0.0f;
if (game_mode == GAMEKIND_CLIENT) {
network_client_tick();
}
else {
world_update();
if (game_mode == GAMEKIND_HEADLESS) {
network_server_tick();
static float ms_report = 2.5f;
if (ms_report < get_cached_time()) {
ms_report = get_cached_time() + 5.f;
zpl_printf("delta: %f ms.\n", (get_cached_time() - last_update)*1000.0f);
}
}
}
last_update = get_cached_time();
}
void game_render() {
if (game_mode != GAMEKIND_HEADLESS) {
platform_render();
}
}
void game_action_send_keystate(game_keystate_data *data) {
pkt_send_keystate_send(active_viewer->view_id, data);
}
void game_action_send_blockpos(float mx, float my) {
pkt_send_blockpos data = {
.mx = mx,
.my = my
};
pkt_send_blockpos_send(active_viewer->view_id, &data);
}
void game_request_close() {
game_should_close = true;
if (game_mode != GAMEKIND_HEADLESS) {
platform_request_close();
}
}
static game_world_render_entry* render_queue = NULL;
static void game__world_view_render_push_entry(uint64_t key, entity_view * data) {
if (!data) return;
if (data->kind == EKIND_CHUNK) {
world_view *view = game_world_view_get_active();
float size = (float)(view->chunk_size * WORLD_BLOCK_SIZE);
float offset = 0.0;
for (size_t ty = 0; ty < view->chunk_size; ty++) {
for (size_t tx = 0; tx < view->chunk_size; tx++) {
block_id blk_id = data->outer_blocks[(ty*view->chunk_size)+tx];
if (blk_id != 0) {
game_world_render_entry entry = {
.key = key,
.data = data,
.blk_id = blk_id,
.x = (data->x*size + offset) + (float)tx*WORLD_BLOCK_SIZE + WORLD_BLOCK_SIZE/2,
.y = (data->y*size + offset) + (float)ty*WORLD_BLOCK_SIZE + WORLD_BLOCK_SIZE/2,
};
zpl_array_append(render_queue, entry);
}
}
}
return;
}
game_world_render_entry entry = {
.key = key,
.data = data,
.x = data->x,
.y = data->y,
.blk_id = 0,
};
zpl_array_append(render_queue, entry);
}
static void game__world_view_render_ground(uint64_t key, entity_view * data) {
if (data->kind != EKIND_CHUNK) return;
renderer_draw_entry(key, data, 0);
}
void game_world_view_render_world(void) {
if (!render_queue) {
zpl_array_init(render_queue, zpl_heap());
}
zpl_array_clear(render_queue);
profile(PROF_RENDER_PUSH_AND_SORT_ENTRIES) {
game_world_view_active_entity_map(game__world_view_render_push_entry);
zpl_sort_array(render_queue, zpl_array_count(render_queue), zpl_f32_cmp(zpl_offset_of(game_world_render_entry, y)));
}
game_world_view_active_entity_map(game__world_view_render_ground);
for (zpl_isize i = 0; i < zpl_array_count(render_queue); i++) {
renderer_draw_entry(render_queue[i].key, render_queue[i].data, &render_queue[i]);
}
}