349 lines
7.7 KiB
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;
|
|
}
|