k4/src/net_server.c

349 lines
7.7 KiB
C

#include"net_server.h"
#include"enet.h"
#include<stdio.h>
#include"luaapi.h"
#include"net.h"
#include"game.h"
static ENetHost *host;
struct Conn {
ENetPeer *e;
uint16_t lastTick;
uint16_t assigned;
int lua;
};
#define MAX_PLAYERS 64
static struct Conn conns[MAX_PLAYERS];
void net_server_init(uint16_t port) {
host = enet_host_create(&(ENetAddress) {.host = ENET_HOST_ANY, .port = port}, 16, 1, 0, 0);
Game.isMultiplayer = 1;
Game.isAuthority = 1;
memset(conns, 0, sizeof(conns));
}
static void send_full_state(ENetPeer **peers, size_t peerCount) {
struct bstr b;
bstr(&b, 1024);
b_wu16(&b, Game.entities.physicsCount + Game.entities.renderCount + Game.entities.movementCount + Game.entities.bonedCount);
b_wu16(&b, Game.frame);
for(size_t i = 0; i < Game.entities.physicsCount; i++) {
b_wu16(&b, CMD_SC_SINGLE_COMPONENT);
b_wu8(&b, CMD_CTYPE_PHYSICS);
struct CPhysics *c = Game.entities.physics + i;
b_wu16(&b, c->entity);
b_wu16(&b, c->trigger);
b_wu8(&b, c->type);
b_wu8(&b, c->dynamics);
if(c->type == CPHYSICS_BOX) {
b_wf32(&b, c->box.w);
b_wf32(&b, c->box.h);
b_wf32(&b, c->box.l);
} else if(c->type == CPHYSICS_CAPSULE) {
b_wf32(&b, c->capsule.length);
b_wf32(&b, c->capsule.radius);
} else abort();
if(c->geom) {
const float *p = dGeomGetPosition(c->geom);
b_wf32(&b, p[0]);
b_wf32(&b, p[1]);
b_wf32(&b, p[2]);
} else {
b_wf32(&b, c->start[0]);
b_wf32(&b, c->start[1]);
b_wf32(&b, c->start[2]);
}
if((c->dynamics & ~CPHYSICS_GHOST) == CPHYSICS_DYNAMIC) {
if(c->geom) {
const float *p = dBodyGetLinearVel(dGeomGetBody(c->geom));
b_wf32(&b, p[0]);
b_wf32(&b, p[1]);
b_wf32(&b, p[2]);
} else {
b_wf32(&b, c->vel[0]);
b_wf32(&b, c->vel[1]);
b_wf32(&b, c->vel[2]);
}
b_wf32(&b, c->speed);
}
b_wf32(&b, c->mass);
b_wf32(&b, c->friction);
b_wu32(&b, c->collide);
}
for(size_t i = 0; i < Game.entities.renderCount; i++) {
b_wu16(&b, CMD_SC_SINGLE_COMPONENT);
b_wu8(&b, CMD_CTYPE_RENDER);
struct CRender *c = Game.entities.render + i;
b_wu16(&b, c->entity);
b_wzstr(&b, c->mdl);
}
for(size_t i = 0; i < Game.entities.movementCount; i++) {
b_wu16(&b, CMD_SC_SINGLE_COMPONENT);
b_wu8(&b, CMD_CTYPE_MOVEMENT);
struct CMovement *c = Game.entities.movement + i;
b_wu16(&b, c->entity);
b_wf32(&b, c->dir[0]);
b_wf32(&b, c->dir[1]);
b_wf32(&b, c->dir[2]);
b_wf32(&b, c->pointing);
b_wu8(&b, c->jump);
b_wu8(&b, c->canJump);
b_wu16(&b, c->holding);
}
for(size_t i = 0; i < Game.entities.bonedCount; i++) {
b_wu16(&b, CMD_SC_SINGLE_COMPONENT);
b_wu8(&b, CMD_CTYPE_BONED);
struct CBoned *c = Game.entities.boned + i;
b_wu16(&b, c->entity);
b_wu8(&b, c->anim.standard);
}
if(peers) {
for(size_t i = 0; i < peerCount; i++) {
enet_peer_send(peers[i], 0, enet_packet_create(b.data, b.wi, ENET_PACKET_FLAG_RELIABLE));
}
} else {
enet_host_broadcast(host, 0, enet_packet_create(b.data, b.wi, ENET_PACKET_FLAG_RELIABLE));
}
free(b.data);
}
static void pos_update() {
struct bstr b;
bstr(&b, 512);
b_wu16(&b, PKT_PERFRAME | 1);
b_wu16(&b, Game.frame);
b_wu16(&b, CMD_SC_POSUPDATE);
b_wu16(&b, 0); // WARNING: THIS INDEX IS EDITED BELOW
b_wu16(&b, Game.conveyorCount);
for(size_t i = 0; i < Game.conveyorCount; i++) {
b_wf16(&b, Game.conveyors[i]->position);
}
for(size_t i = 0; i < Game.entities.physicsCount; i++) {
if(Game.entities.physics[i].geom) {
const float *p = dGeomGetPosition(Game.entities.physics[i].geom);
b_wf16(&b, p[0]);
b_wf16(&b, p[1]);
b_wf16(&b, p[2]);
if((Game.entities.physics[i].dynamics & ~CPHYSICS_GHOST) == CPHYSICS_DYNAMIC) {
dBodyID bid = dGeomGetBody(Game.entities.physics[i].geom);
p = dBodyGetLinearVel(bid);
b_wf16(&b, p[0]);
b_wf16(&b, p[1]);
b_wf16(&b, p[2]);
p = dBodyGetQuaternion(bid);
b_wf16(&b, p[1]);
b_wf16(&b, p[2]);
b_wf16(&b, p[3]);
b_wf16(&b, p[0]);
}
} else {
b_wf16(&b, Game.entities.physics[i].start[0]);
b_wf16(&b, Game.entities.physics[i].start[1]);
b_wf16(&b, Game.entities.physics[i].start[2]);
if((Game.entities.physics[i].dynamics & ~CPHYSICS_GHOST) == CPHYSICS_DYNAMIC) {
b_wf16(&b, 0);
b_wf16(&b, 0);
b_wf16(&b, 0);
b_wf16(&b, 0);
b_wf16(&b, 0);
b_wf16(&b, 0);
b_wf16(&b, 1);
}
}
}
for(size_t i = 0; i < Game.entities.movementCount; i++) {
b_wf16(&b, Game.entities.movement[i].pointing);
}
for(struct Conn *c = conns; c != conns + MAX_PLAYERS; c++) {
if(c->e) {
*((uint16_t*) &b.data[6]) = c->lastTick;
enet_peer_send(c->e, 0, enet_packet_create(b.data, b.wi, 0));
}
}
free(b.data);
}
void net_server_receive() {
ENetEvent ev;
while(enet_host_service(host, &ev, 0) > 0) {
if(ev.type == ENET_EVENT_TYPE_CONNECT) {
puts("Connect!");
size_t i;
for(i = 0; i < MAX_PLAYERS; i++) {
if(conns[i].e == NULL) {
break;
}
}
if(i == MAX_PLAYERS) {
enet_peer_disconnect(ev.peer, PEER_DISCONNECT_TOO_MANY_PLAYERS);
} else {
conns[i] = (struct Conn) {
.e = ev.peer,
.lastTick = 0,
.assigned = ENT_ID_INVALID,
};
ev.peer->data = conns + i;
conns[i].lua = luaapi_join(ev.peer, 0);
game_synccphysics();
send_full_state(&ev.peer, 1);
}
} else if(ev.type == ENET_EVENT_TYPE_RECEIVE) {
struct bstr b;
bwrap(&b, ev.packet->data, ev.packet->dataLength);
uint16_t cmdCount = b_ru16(&b) & ~PKT_PERFRAME;
uint16_t t = b_ru16(&b);
((struct Conn*) ev.peer->data)->lastTick = t;
for(size_t i = 0; i < cmdCount; i++) {
uint16_t cmd = b_ru16(&b);
if(cmd == CMD_SC_SINGLE_COMPONENT) {
uint8_t ctype = b_ru8(&b);
uint16_t ent = b_ru16(&b);
if(ctype == CMD_CTYPE_PLAYERCTRL) {
struct CPlayerCtrl *c = game_ensurecomponent(ent, playerctrl);
c->yaw = b_rf32(&b);
c->pitch = b_rf32(&b);
c->keys = b_ru32(&b);
game_ensurecomponent(ent, movement)->pointing = c->yaw;
}
} else if(cmd == CMD_SC_MSG) {
if(!luaapi_recvmsg(&b, ((struct Conn*) ev.peer->data)->lua)) {
// Corrupted packet.
break;
}
}
}
enet_packet_destroy(ev.packet);
} else if(ev.type == ENET_EVENT_TYPE_DISCONNECT) {
struct Conn *conn = ev.peer->data;
luaapi_leave(conn->lua);
conn->e = NULL;
}
}
}
void net_server_update() {
pos_update();
enet_host_flush(host);
}
void net_server_assign(ENetPeer *peer, uint16_t idx) {
struct bstr b;
bstr(&b, 64);
b_wu16(&b, 1);
b_wu16(&b, Game.frame);
b_wu16(&b, CMD_SC_ASSIGN);
b_wu16(&b, idx);
enet_peer_send(peer, 0, enet_packet_create(b.data, b.wi, ENET_PACKET_FLAG_RELIABLE));
free(b.data);
((struct Conn*) peer->data)->assigned = idx;
}
void net_server_force_load(ENetPeer *peer, const char *script) {
struct bstr b;
bstr(&b, 64);
b_wu16(&b, 1);
b_wu16(&b, Game.frame);
b_wu16(&b, CMD_SC_LOAD_SCRIPT);
b_wzstr(&b, script);
enet_peer_send(peer, 0, enet_packet_create(b.data, b.wi, ENET_PACKET_FLAG_RELIABLE));
free(b.data);
}
void net_server_send_msg(ENetPeer *peer, struct bstr *data) {
struct bstr b;
bstr(&b, 64);
b_wu16(&b, 1);
b_wu16(&b, Game.frame);
b_wu16(&b, CMD_SC_MSG);
b_wraw(&b, data->data, data->wi);
enet_peer_send(peer, 0, enet_packet_create(b.data, b.wi, ENET_PACKET_FLAG_RELIABLE));
free(b.data);
}
void net_server_broadcast_msg(struct bstr *data) {
struct bstr b;
bstr(&b, 64);
b_wu16(&b, 1);
b_wu16(&b, Game.frame);
b_wu16(&b, CMD_SC_MSG);
b_wraw(&b, data->data, data->wi);
for(size_t i = 0; i < MAX_PLAYERS; i++) {
if(conns[i].e) {
enet_peer_send(conns[i].e, 0, enet_packet_create(b.data, b.wi, ENET_PACKET_FLAG_RELIABLE));
}
}
free(b.data);
}
void *net_server_get_enethost() {
return host;
}