Switch from NetWrap to net_hi (allow more than 2 player games)

This commit is contained in:
mid 2025-01-26 20:25:23 +02:00
parent 1c165601c2
commit aef3de3df9
9 changed files with 318 additions and 274 deletions

View File

@ -5,20 +5,26 @@
struct k3MScreen;
#include"stoon.h"
struct NetWrap {
/*struct NetWrap {
struct Stoon stoon;
int stage;
float timeout;
int isHost;
bool isHost;
// Used for punching stage
int gotten;
char otherpeer[STOON_CONN_INFO_SIZE];
// Server-side
#define NETWRAP_BACKLOG 32
char otherpeers[NETWRAP_BACKLOG][STOON_CONN_INFO_SIZE];
bool otherpeersActive[NETWRAP_BACKLOG];
// Client-side
char connectto[STOON_CONN_INFO_SIZE];
};
extern struct NetWrap NetWrap;
extern struct NetWrap NetWrap;*/
extern struct k3MScreen *UiActive;

View File

@ -14,6 +14,7 @@
#include"net.h"
#include"k3menu.h"
#include<assert.h>
#include"net_hi.h"
/*
* This is by far the least clean or well-maintained source in the
@ -2131,18 +2132,42 @@ static int dagame_set_texture_reduction(lua_State *L) {
}
int PeercodeHandler = LUA_NOREF;
static int dagame_net_gen_peercode(lua_State *L) {
if(NetWrap.stage != 0 || PeercodeHandler != LUA_NOREF) {
lua_pushliteral(L, "Peercode generation already in progress");
lua_error(L);
return 0;
static void get_peercode_callback(void *ud, const char *peercode_bin) {
char peercode[STOON_CONN_INFO_SIZE * 2 + 1] = {};
for(int i = 0; i < STOON_CONN_INFO_SIZE; i++) {
snprintf(peercode + i * 2, 3, "%02x", ((uint8_t*) peercode_bin)[i]);
}
NetWrap.stoon = stoon_init("stun.easybell.de", 3478, 26656);
NetWrap.stage = 1;
if(PeercodeHandler == LUA_NOREF) {
puts("Peercode found but no handler");
return;
}
lua_pushvalue(L, 1);
PeercodeHandler = luaL_ref(L, LUA_REGISTRYINDEX);
lua_rawgeti(L, LUA_REGISTRYINDEX, PeercodeHandler);
if(lua_isnil(L, -1)) {
lua_pop(L, 1);
return;
} else {
lua_pushstring(L, peercode);
if(lua_pcall(L, 1, 0, 0) != LUA_OK) {
puts(lua_tostring(L, -1));
lua_pop(L, 1);
return;
}
}
lua_pop(L, 1);
luaL_unref(L, LUA_REGISTRYINDEX, PeercodeHandler);
PeercodeHandler = LUA_NOREF;
}
static int dagame_net_gen_peercode(lua_State *L) {
if(net_hi_request_peercode(NULL, get_peercode_callback)) {
lua_pushvalue(L, 1);
PeercodeHandler = luaL_ref(L, LUA_REGISTRYINDEX);
} else {
lua_pushliteral(L, "Cannot request peercode");
lua_error(L);
}
return 0;
}
@ -2175,8 +2200,14 @@ static int dagame_clipboard_get(lua_State *L) {
return 0;
}
#define CONN_INVALID_PEERCODE 1
static int conn(const char *peercode, bool host) {
static int get_peercode_bin(const char *peercode, char *peercode_bin) {
if(!peercode) return 0;
if(!peercode_bin) return 0;
if(strlen(peercode) < 2 * STOON_CONN_INFO_SIZE) {
return 0;
}
for(int i = 0; i < STOON_CONN_INFO_SIZE; i++) {
int b = 0;
@ -2184,55 +2215,52 @@ static int conn(const char *peercode, bool host) {
b |= (peercode[i * 2 + 0] - '0') << 4;
} else if(peercode[i * 2 + 0] >= 'a' && peercode[i * 2 + 0] <= 'f') {
b |= (peercode[i * 2 + 0] - 'a' + 10) << 4;
} else return CONN_INVALID_PEERCODE;
} else return 0;
if(peercode[i * 2 + 1] >= '0' && peercode[i * 2 + 1] <= '9') {
b |= (peercode[i * 2 + 1] - '0') << 0;
} else if(peercode[i * 2 + 1] >= 'a' && peercode[i * 2 + 1] <= 'f') {
b |= (peercode[i * 2 + 1] - 'a' + 10) << 0;
} else return CONN_INVALID_PEERCODE;
} else return 0;
NetWrap.otherpeer[i] = b;
peercode_bin[i] = b;
}
NetWrap.isHost = host;
NetWrap.stage = 3;
return 1;
}
static int dagame_net_host(lua_State *L) {
lua_pushboolean(L, net_hi_setup(true));
return 0;
}
static int dagame_net_host(lua_State *L) {
int status = conn(lua_tostring(L, 1), true);
lua_pushboolean(L, !status);
if(status) {
if(status == CONN_INVALID_PEERCODE) {
lua_pushliteral(L, "peercode");
} else {
lua_pushliteral(L, "unknown");
}
return 2;
static int dagame_net_join(lua_State *L) {
char peercode[STOON_CONN_INFO_SIZE];
if(!get_peercode_bin(lua_tostring(L, 1), peercode)) {
lua_pushliteral(L, "Invalid peercode");
lua_error(L);
return 0;
}
net_hi_setup(false);
lua_pushboolean(L, net_hi_connect(peercode));
return 1;
}
static int dagame_net_join(lua_State *L) {
int status = conn(lua_tostring(L, 1), false);
lua_pushboolean(L, !status);
if(status) {
if(status == CONN_INVALID_PEERCODE) {
lua_pushliteral(L, "peercode");
} else {
lua_pushliteral(L, "unknown");
}
return 2;
static int dagame_net_punch(lua_State *L) {
char peercode[STOON_CONN_INFO_SIZE];
if(!get_peercode_bin(lua_tostring(L, 1), peercode)) {
lua_pushliteral(L, "Invalid peercode");
lua_error(L);
return 0;
}
return 1;
net_hi_add_punch(peercode);
return 0;
}
#include<GLFW/glfw3.h>
@ -2403,6 +2431,9 @@ void luaapi_init() {
lua_pushcfunction(L, dagame_net_host);
lua_setfield(L, -2, "host");
lua_pushcfunction(L, dagame_net_punch);
lua_setfield(L, -2, "punch");
lua_pushcfunction(L, dagame_net_join);
lua_setfield(L, -2, "join");
lua_setfield(L, -2, "net");
@ -3337,22 +3368,6 @@ void luaapi_cleanup() {
lua_pop(L, 1);
}
/*void luaapi_perform(const char *statement) {
puts(statement);
if(luaL_loadstring(L, statement) != LUA_OK) {
puts(lua_tostring(L, -1));
lua_pop(L, 1);
return;
}
lua_rawgeti(L, LUA_REGISTRYINDEX, consoleEnvironment);
lua_setupvalue(L, -2, 1);
if(lua_pcall(L, 0, 0, 0) != LUA_OK) {
puts(lua_tostring(L, -1));
lua_pop(L, 1);
return;
}
}*/
void luaapi_ctrlev(int ctrl, int action) {
lua_getglobal(L, "game");
lua_getfield(L, -1, "ctrl");
@ -3430,30 +3445,6 @@ void luaapi_escape() {
lua_pop(L, 1);
}
void luaapi_peercode_found(const char *peercode) {
if(PeercodeHandler == LUA_NOREF) {
puts("Peercode found but no handler");
return;
}
lua_rawgeti(L, LUA_REGISTRYINDEX, PeercodeHandler);
if(lua_isnil(L, -1)) {
lua_pop(L, 1);
return;
} else {
lua_pushstring(L, peercode);
if(lua_pcall(L, 1, 0, 0) != LUA_OK) {
puts(lua_tostring(L, -1));
lua_pop(L, 1);
return;
}
}
lua_pop(L, 1);
luaL_unref(L, LUA_REGISTRYINDEX, PeercodeHandler);
PeercodeHandler = LUA_NOREF;
}
void luaapi_update() {
lua_getglobal(L, "game");
lua_getfield(L, -1, "update");

View File

@ -40,8 +40,6 @@
#include<ctype.h>
struct NetWrap NetWrap;
GLFWwindow *GameWnd;
static int TextureResolutionReduction = 0;
@ -186,7 +184,7 @@ const char *k4_get_arg(const char *name) {
return NULL;
}
static void netwrap_step() {
/*static void netwrap_step() {
if(NetWrap.stage && CurrentTime >= NetWrap.timeout) {
if(NetWrap.stage == 1) {
if(stoon_req(&NetWrap.stoon)) {
@ -201,11 +199,6 @@ static void netwrap_step() {
luaapi_peercode_found(str);
//glfwSetClipboardString(NULL, str);
//screenMain.lblpeerdata->invisible = 0;
//screenMain.btnconnect->invisible = 0;
NetWrap.stage = 2;
} else {
k3Log(k3_INFO, "Stoon listen timeout.");
@ -217,51 +210,59 @@ static void netwrap_step() {
}
} else if(NetWrap.stage == 2) {
stoon_keepalive(&NetWrap.stoon);
NetWrap.timeout = CurrentTime + 1;
} else if(NetWrap.stage == 3) {
int status = stoon_poonch(&NetWrap.stoon, NetWrap.otherpeer);
//screenMain.lblpeerdata->txt = strdup("Trying to connect...\nMay not work if both are\nbehind symmetric NATs.");
if(status == STOON_POONCH_INCOMPATIBLE_NETFAMS) {
NetWrap.stage = 0;
if(NetWrap.isHost) {
stoon_kill(&NetWrap.stoon);
net_server_init();
NetWrap.stage = 4;
}
} else if(NetWrap.stage == 4) {
if(NetWrap.isHost) {
ENetBuffer buf = {.data = "Punch!", .dataLength = 6};
//screenMain.lblpeerdata->txt = strdup("Connection cannot be established:\nIncompatible netfams.");
} else if(status == STOON_POONCH_NO_KNOCK && NetWrap.stoon.poonchstage == POONCH_STAGE_ACK) {
if(NetWrap.gotten++ > 5) {
NetWrap.stage = 0;
stoon_kill(&NetWrap.stoon);
ENetHost *h = net_server_get_enethost();
if(NetWrap.isHost) {
net_server_init();
} else {
char ip[64];
int port;
if(*(uint16_t*) (NetWrap.otherpeer + 22) == 0) {
inet_ntop(AF_INET, NetWrap.otherpeer, ip, sizeof(ip));
port = ntohs(*(uint16_t*) (NetWrap.otherpeer + 4));
} else {
inet_ntop(AF_INET6, NetWrap.otherpeer + 6, ip, sizeof(ip));
port = ntohs(*(uint16_t*) (NetWrap.otherpeer + 22));
}
for(size_t i = 0; i < NETWRAP_BACKLOG; i++) {
if(NetWrap.otherpeersActive[i]) {
ENetAddress v4 = {}, v6 = {};
stoonpeer_to_enets(NetWrap.otherpeers[i], &v4, &v6);
printf("Trying [%s]:%u\n", ip, port);
net_client_init();
net_client_connect(ip, port);
enet_socket_send(h->socket, &v4, &buf, 1);
enet_socket_send(h->socket, &v6, &buf, 1);
}
//screenMain.lblpeerdata->txt = strdup("Connection successful.");
}
} else NetWrap.gotten = 0;
} else {
stoon_keepalive(&NetWrap.stoon);
}
NetWrap.timeout = CurrentTime + 1;
} else if(NetWrap.stage == 5) {
if(!NetWrap.isHost) {
char ip[64];
int port;
if(*(uint16_t*) (NetWrap.otherpeer + 22) == 0) {
inet_ntop(AF_INET, NetWrap.otherpeer, ip, sizeof(ip));
port = ntohs(*(uint16_t*) (NetWrap.otherpeer + 4));
} else {
inet_ntop(AF_INET6, NetWrap.otherpeer + 6, ip, sizeof(ip));
port = ntohs(*(uint16_t*) (NetWrap.otherpeer + 22));
}
printf("Trying [%s]:%u\n", ip, port);
net_client_init();
if(net_client_connect(ip, port)) {
NetWrap.stage = 5;
}
}
NetWrap.timeout = CurrentTime + 0.5;
} else {
NetWrap.timeout = CurrentTime + 1;
}
}
}
}*/
#include<signal.h>
void k4k3LogCallback(enum k3LogLevel lvl, const char *str, size_t len) {
@ -373,150 +374,6 @@ static void fix_resol() {
gr_lowres(roundf(w * ResolPercentage / 100.f / 4) * 4, roundf(h * ResolPercentage / 100.f / 4) * 4);
}
static bool onqualitypress(struct k3MEvent *ev, uint8_t *ud) {
k3GraphicalReduction = (k3GraphicalReduction + 1) % 3;
return true;
}
static bool onresolpress(struct k3MEvent *ev, uint8_t *ud) {
struct k3MTextButton *btn = (void*) ev->target;
ResolPercentage -= 10;
if(ResolPercentage <= 0) {
ResolPercentage = 100;
}
const char *txt = NULL;
switch(ResolPercentage) {
case 10:
txt = "10%";
break;
case 20:
txt = "20%";
break;
case 30:
txt = "30%";
break;
case 40:
txt = "40%";
break;
case 50:
txt = "50%";
break;
case 60:
txt = "60%";
break;
case 70:
txt = "70%";
break;
case 80:
txt = "80%";
break;
case 90:
txt = "90%";
break;
case 100:
txt = "Full Resolution";
break;
}
btn->txt = strdup(txt);
fix_resol();
return true;
}
static bool ontexrespress(struct k3MEvent *ev, uint8_t *ud) {
TextureResolutionReduction = (TextureResolutionReduction + 1) % 3;
refresh_textures();
return true;
}
static bool onresumepress(struct k3MEvent *ev, uint8_t *ud) {
UiActive = NULL;
set_ui_mode(0);
return true;
}
#ifdef LOCALHOST_ONLY
static bool onhostpress(struct k3MEvent *ev, uint8_t *ud) {
net_server_init();
return true;
}
static bool onjoinpress(struct k3MEvent *ev, uint8_t *ud) {
net_client_init();
net_client_connect("127.0.0.1", 26656);
return true;
}
static bool onconnectpress(struct k3MEvent *ev, uint8_t *ud) {
return true;
}
#else
static bool onhostpress(struct k3MEvent *ev, uint8_t *ud) {
screenMain.btnhost->disabled = 1;
screenMain.btnjoin->disabled = 1;
NetWrap.stage = 1;
NetWrap.timeout = glfwGetTime() + 0;
NetWrap.isHost = 1;
NetWrap.stoon = stoon_init("stun.easybell.de", 3478, 26656);
return true;
}
static bool onjoinpress(struct k3MEvent *ev, uint8_t *ud) {
screenMain.btnhost->disabled = 1;
screenMain.btnjoin->disabled = 1;
NetWrap.stage = 1;
NetWrap.timeout = glfwGetTime() + 0;
NetWrap.isHost = 0;
NetWrap.stoon = stoon_init("stun.easybell.de", 3478, 26656);
return true;
}
static bool onconnectpress(struct k3MEvent *ev, uint8_t *ud) {
const char *name = glfwGetClipboardString(NULL);
while(isspace(*name)) name++;
if(strlen(name) < STOON_CONN_INFO_SIZE * 2) {
goto bad;
}
for(int i = 0; i < STOON_CONN_INFO_SIZE; i++) {
int b = 0;
if(name[i * 2 + 0] >= '0' && name[i * 2 + 0] <= '9') {
b |= (name[i * 2 + 0] - '0') << 4;
} else if(name[i * 2 + 0] >= 'a' && name[i * 2 + 0] <= 'f') {
b |= (name[i * 2 + 0] - 'a' + 10) << 4;
} else goto bad;
if(name[i * 2 + 1] >= '0' && name[i * 2 + 1] <= '9') {
b |= (name[i * 2 + 1] - '0') << 0;
} else if(name[i * 2 + 1] >= 'a' && name[i * 2 + 1] <= 'f') {
b |= (name[i * 2 + 1] - 'a' + 10) << 0;
} else goto bad;
NetWrap.otherpeer[i] = b;
}
NetWrap.stage = 3;
screenMain.btnconnect->disabled = 1;
return true;
bad:
screenMain.lblpeerdata->txt = strdup("Incorrect peer conndata.");
return true;
}
#endif
static bool onconsoleenter(struct k3MEvent *ev, uint8_t *ud) {
return true;
}
static void eng_ui_init() {
set_ui_mode(1);
}
@ -663,7 +520,7 @@ int main(int argc_, char **argv_) {
glfwPollEvents();
netwrap_step();
net_hi_update(CurrentTime);
float alpha = fmodf(accumulator * GAME_TPS, 1.f);

View File

@ -26,12 +26,20 @@ void net_client_init() {
Game.isAuthority = 0;
}
void net_client_connect(const char *addr, uint16_t port) {
bool net_client_connect(const char *addr, uint16_t port) {
ENetAddress eaddr;
enet_address_set_host(&eaddr, addr);
eaddr.port = port;
peer = enet_host_connect(host, &eaddr, 1, 0);
ENetEvent ev;
if(enet_host_service(host, &ev, 200) <= 0 || ev.type != ENET_EVENT_TYPE_CONNECT) {
enet_peer_reset(peer);
return false;
}
return true;
}
extern double glfwGetTime();

View File

@ -1,7 +1,7 @@
#pragma once
void net_client_init();
void net_client_connect(const char *addr, uint16_t port);
bool net_client_connect(const char *addr, uint16_t port);
void net_client_receive();
void net_client_update();
void net_client_dejitter();

165
src/net_hi.c Normal file
View File

@ -0,0 +1,165 @@
#include"net_hi.h"
#include<stddef.h>
#include"enet.h"
#include<stdlib.h>
#include"stoon.h"
#include"net_server.h"
#include"net_client.h"
#include<math.h>
static void *ReqPeercodeUD;
static void(*ReqPeercodeCB)(void*, const char *peercode);
static struct Stoon stoon;
static bool inited = false;
static bool isHost;
typedef struct {
#define MASK_IPv4 1
#define MASK_IPv6 2
int mask;
ENetAddress v4;
ENetAddress v6;
} ToPunch;
static ToPunch *topunch = NULL;
static size_t topunchCount = 0;
static double Timeout = 0;
static bool connected = false;
bool net_hi_request_peercode(void *ud, void(*callback)(void*, const char *peercode)) {
if(inited) return false;
ReqPeercodeUD = ud;
ReqPeercodeCB = callback;
stoon = stoon_init("stun.easybell.de", 3478, 26656);
Timeout = 0;
return true;
}
bool net_hi_setup(bool host) {
if(inited) return false;
stoon_kill(&stoon);
inited = true;
isHost = host;
if(host) {
net_server_init();
} else {
net_client_init();
}
return true;
}
void net_hi_update(double now) {
if(now <= Timeout) return;
if(ReqPeercodeCB) {
if(stoon_req(&stoon)) {
if(stoon_listen(&stoon)) {
uint8_t peercode[STOON_CONN_INFO_SIZE] = {};
stoon_serialize(&stoon, peercode);
ReqPeercodeCB(ReqPeercodeUD, peercode);
ReqPeercodeCB = NULL;
} else {
Timeout = now + 1;
}
} else {
Timeout = now + 1;
}
} else if(!inited) {
stoon_keepalive(&stoon);
Timeout = now + 1;
} else {
if(isHost) {
ENetHost *h = net_server_get_enethost();
ENetBuffer buf = {.data = "Punch!", .dataLength = 6};
for(size_t tpi = 0; tpi < topunchCount; tpi++) {
ToPunch *tp = &topunch[tpi];
if(tp->mask & MASK_IPv4) {
enet_socket_send(h->socket, &tp->v4, &buf, 1);
} else if(tp->mask & MASK_IPv6) {
enet_socket_send(h->socket, &tp->v6, &buf, 1);
}
}
}
Timeout = now + 1;
}
}
static void stoonpeer_to_enets(const char *peercode, ENetAddress *v4, ENetAddress *v6, int *mask) {
memset(v4->host.__in6_u.__u6_addr8, 0, 16);
v4->host.__in6_u.__u6_addr8[10] = 0xFF;
v4->host.__in6_u.__u6_addr8[11] = 0xFF;
v4->host.__in6_u.__u6_addr8[12] = peercode[0];
v4->host.__in6_u.__u6_addr8[13] = peercode[1];
v4->host.__in6_u.__u6_addr8[14] = peercode[2];
v4->host.__in6_u.__u6_addr8[15] = peercode[3];
v4->port = ntohs(*(uint16_t*) &peercode[4]);
memcpy(v6->host.__in6_u.__u6_addr8, peercode + 6, 16);
v6->port = ntohs(*(uint16_t*) &peercode[22]);
*mask = 0;
if(v4->port) {
*mask |= MASK_IPv4;
}
if(v6->port) {
*mask |= MASK_IPv6;
}
}
void net_hi_add_punch(const char *peercode) {
int mask;
ENetAddress v4 = {}, v6 = {};
stoonpeer_to_enets(peercode, &v4, &v6, &mask);
topunch = realloc(topunch, sizeof(*topunch) * (++topunchCount));
topunch[topunchCount - 1] = (ToPunch) {
.v4 = v4,
.v6 = v6,
.mask = mask,
};
}
bool net_hi_connect(const char *peercode) {
if(!inited) return false;
if(connected) return false;
char ip[64];
int port;
if(*(uint16_t*) (peercode + 22) == 0) {
inet_ntop(AF_INET, peercode, ip, sizeof(ip));
port = ntohs(*(uint16_t*) (peercode + 4));
} else {
inet_ntop(AF_INET6, peercode + 6, ip, sizeof(ip));
port = ntohs(*(uint16_t*) (peercode + 22));
}
return net_client_connect(ip, port);
}

11
src/net_hi.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include<stdbool.h>
bool net_hi_request_peercode(void *ud, void(*callback)(void*, const char *peercode));
bool net_hi_setup(bool host);
void net_hi_update(double now);
void net_hi_add_punch(const char *peercode);
bool net_hi_connect(const char *peercode);

View File

@ -342,3 +342,7 @@ void net_server_broadcast_msg(struct bstr *data) {
free(b.data);
}
void *net_server_get_enethost() {
return host;
}

View File

@ -14,3 +14,5 @@ void net_server_force_load(struct _ENetPeer *peer, const char *script);
void net_server_send_msg(struct _ENetPeer *peer, struct bstr *data);
void net_server_broadcast_msg(struct bstr *data);
void *net_server_get_enethost();