tibia_alpha/network.c

141 lines
3.9 KiB
C

//
// Created by rov on 12/27/25.
//
#include "network.h"
#include <SDL3/SDL.h>
#include <SDL3_net/SDL_net.h>
#define NET_TIMEOUT 30000
typedef enum ConnectionResult {
CONN_SUCCESS = 0,
CONN_ERR_BAD_HOSTNAME = 1,
CONN_ERR_NO_SERVER = 2
} CONNECTION_RESULT;
void Gui_UpdateStatusBar(const Gui_t* gui, const char *message);
bool Network_Init(Network_t *network) {
if (!NET_Init()) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "Failed to initialize SDL_net.", NULL);
return false;
}
network->socket = NULL;
return true;
}
void Network_Shutdown(const Network_t *network) {
NET_DestroyStreamSocket(network->socket);
NET_Quit();
}
CONNECTION_RESULT ConnectToServer(Network_t *network, const ConfigParams_t *configParams, const Gui_t *gui) {
Gui_UpdateStatusBar(gui, "Searching for hostname...");
NET_Address *netAddress = NET_ResolveHostname(configParams->serverAddress);
const NET_Status resolveHostnameStatus = NET_WaitUntilResolved(netAddress, NET_TIMEOUT);
if (resolveHostnameStatus != NET_SUCCESS) {
NET_UnrefAddress(netAddress);
return CONN_ERR_BAD_HOSTNAME;
}
Gui_UpdateStatusBar(gui, "Trying to connect...");
network->socket = NET_CreateClient(netAddress, configParams->serverPort);
const NET_Status createClientStatus = NET_WaitUntilConnected(network->socket, NET_TIMEOUT);
if (createClientStatus != NET_SUCCESS) {
NET_DestroyStreamSocket(network->socket);
network->socket = NULL;
NET_UnrefAddress(netAddress);
return CONN_ERR_NO_SERVER;
}
// TODO: is this okay?
NET_UnrefAddress(netAddress);
return CONN_SUCCESS;
}
void Network_ConnectAndReportStatus(Network_t *network, const ConfigParams_t *configParams, const Gui_t *gui) {
if (network->socket != NULL) {
return;
}
const CONNECTION_RESULT result = ConnectToServer(network, configParams, gui);
const char *message = NULL;
switch (result) {
case CONN_SUCCESS:
message = "Connection established.";
break;
case CONN_ERR_BAD_HOSTNAME:
message = "Error: IP address or host not found.";
break;
case CONN_ERR_NO_SERVER:
message = "Error: No server running on host.";
break;
}
Gui_UpdateStatusBar(gui, message);
}
void Network_Send(NET_StreamSocket* socket, uint8_t* packetBuf, const uint16_t packetLen) {
const uint16_t payloadLength = packetLen - 2;
*(uint16_t*) packetBuf = payloadLength;
if (!NET_WriteToStreamSocket(socket, packetBuf, packetLen)) {
SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "Network_Send: Failed to send packet.");
}
}
void Network_HandleLoginOrCreateChar(const uint16_t opcode, uint8_t* packetBuf, uint16_t* packetLen, const void* data, const int dataLength) {
// Copy the opcode
packetBuf[*packetLen] = (uint8_t) opcode;
*packetLen += 1;
// Write unk0
const uint16_t unk0 = 1;
memcpy(&packetBuf[*packetLen], &unk0, 2);
*packetLen += 2;
// Write unk1
const uint16_t unk1 = 'g';
memcpy(&packetBuf[*packetLen], &unk1, 2);
*packetLen += 2;
memcpy(&packetBuf[*packetLen], data, dataLength);
*packetLen += dataLength;
}
void Network_SendPacket(const Network_t* network, const PACKET_HANDLER handler, const uint16_t opcode, void* data, const int dataLength) {
if (network->socket == NULL) {
return;
}
uint8_t packetBuf[1050];
uint16_t packetLen = 2;
// TODO: need this?
memset(packetBuf, 0, 1049);
// Write handler to buffer at offset 2
memcpy(&packetBuf[packetLen], &handler, 2);
packetLen += 2;
switch (handler) {
case HANDLER_LOGIN_OR_CREATE_CHAR:
Network_HandleLoginOrCreateChar(opcode, packetBuf, &packetLen, data, dataLength);
break;
default:
break;
}
Network_Send(network->socket, packetBuf, packetLen);
}