eco2d/code/apps/server/source/network.c

140 lines
4.2 KiB
C

#include "zpl.h"
#define ENET_IMPLEMENTATION
#include "enet.h"
#define LIBRG_IMPL
#define LIBRG_CUSTOM_ZPL
#include "librg.h"
#include "system.h"
#include "network.h"
#include "packet.h"
#include "world/world.h"
#include "player.h"
#include "modules/general.h"
#include "modules/controllers.h"
#include "modules/net.h"
#include "assets.h"
#include "packets/pkt_01_welcome.h"
#define NETWORK_UPDATE_DELAY 0.100
#define NETWORK_MAX_CLIENTS 32
static ENetHost *server = NULL;
WORLD_PKT_WRITER(mp_pkt_writer) {
if (pkt->is_reliable) {
return network_msg_send(udata, pkt->data, pkt->datalen);
}
else {
return network_msg_send_unreliable(udata, pkt->data, pkt->datalen);
}
}
int32_t network_init(void) {
return enet_initialize() != 0;
}
int32_t network_destroy(void) {
enet_deinitialize();
return 0;
}
int32_t network_server_start(const char *host, uint16_t port) {
zpl_unused(host);
ENetAddress address = {0};
address.host = ENET_HOST_ANY; /* Bind the server to the default localhost. */
address.port = port; /* Bind the server to port. */
/* create a server */
server = enet_host_create(&address, NETWORK_MAX_CLIENTS, 2, 0, 0);
if (server == NULL) {
zpl_printf("[ERROR] An error occurred while trying to create an ENet server host.\n");
return 1;
}
zpl_printf("[INFO] Started an ENet server...\n");
return 0;
}
int32_t network_server_stop(void) {
zpl_printf("[INFO] Shutting down the ENet server...\n");
enet_host_destroy(server);
server = NULL;
return 0;
}
int32_t network_server_tick(void) {
ENetEvent event = {0};
while (enet_host_service(server, &event, 1) > 0) {
switch (event.type) {
case ENET_EVENT_TYPE_CONNECT: {
zpl_printf("[INFO] A new user %d connected.\n", event.peer->incomingPeerID);
uint16_t peer_id = event.peer->incomingPeerID;
uint64_t ent_id = network_client_create(event.peer);
// TODO: Make sure ent_id does not get truncated with large entity numbers.
event.peer->data = (void*)((uint32_t)ent_id);
pkt_01_welcome table = {.ent_id = ent_id, .block_size = world_block_size(), .chunk_size = world_chunk_size(), .world_size = world_world_size()};
pkt_world_write(MSG_ID_01_WELCOME, pkt_01_welcome_encode(&table), 1, event.peer);
} break;
case ENET_EVENT_TYPE_DISCONNECT:
case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: {
zpl_printf("[INFO] A user %d disconnected.\n", event.peer->incomingPeerID);
ecs_entity_t e = (ecs_entity_t)((uint32_t)event.peer->data);
network_client_destroy(e);
} break;
case ENET_EVENT_TYPE_RECEIVE: {
if (!world_read(event.packet->data, event.packet->dataLength, event.peer)) {
zpl_printf("[INFO] User %d sent us a malformed packet.\n", event.peer->incomingPeerID);
ecs_entity_t e = (ecs_entity_t)((uint32_t)event.peer->data);
network_client_destroy(e);
}
/* Clean up the packet now that we're done using it. */
enet_packet_destroy(event.packet);
} break;
case ENET_EVENT_TYPE_NONE: break;
}
}
return 0;
}
uint64_t network_client_create(ENetPeer *peer) {
ECS_IMPORT(world_ecs(), Net);
ecs_entity_t e = (ecs_entity_t)player_spawn(zpl_bprintf("client_%d", peer->incomingPeerID));
ecs_set(world_ecs(), e, ClientInfo, {(uintptr_t)peer});
librg_entity_owner_set(world_tracker(), e, (int64_t)peer);
return (uint64_t)e;
}
void network_client_destroy(uint64_t ent_id) {
player_despawn(ent_id);
}
static int32_t network_msg_send_raw(ENetPeer *peer, void *data, size_t datalen, uint32_t flags) {
ENetPacket *packet = enet_packet_create(data, datalen, flags);
return enet_peer_send(peer, 0, packet);
}
int32_t network_msg_send(ENetPeer *peer, void *data, size_t datalen) {
return network_msg_send_raw(peer, data, datalen, ENET_PACKET_FLAG_RELIABLE);
}
int32_t network_msg_send_unreliable(ENetPeer *peer, void *data, size_t datalen) {
return network_msg_send_raw(peer, data, datalen, 0);
}