This commit is contained in:
2025-02-24 12:16:42 -06:00
parent 58d37086c6
commit 206607b04d
33 changed files with 11 additions and 1521 deletions

View File

@ -19,13 +19,10 @@ target_include_directories(${DUSK_TARGET_NAME}
target_sources(${DUSK_TARGET_NAME}
PRIVATE
game.c
input.c
gametime.c
)
# Subdirs
add_subdirectory(assert)
add_subdirectory(console)
add_subdirectory(net)
add_subdirectory(entity)
add_subdirectory(display)

View File

@ -1,12 +0,0 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_TARGET_NAME}
PRIVATE
console.c
)
# Subdirs

View File

@ -1,59 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "console.h"
#include "assert/assert.h"
console_t CONSOLE;
void consoleInit() {
memset(&CONSOLE, 0, sizeof(console_t));
}
const consolecmd_t * consoleCommand(const char_t *cmd) {
assertTrue(
CONSOLE.commandCount < CONSOLE_COMMAND_COUNT_MAX,
"Command buffer full."
);
assertStrLen(cmd, CONSOLE_CMD_LENGTH_MAX, "Command too long.");
consolecmd_t *command = &CONSOLE.commands[CONSOLE.commandCount++];
strcpy(command->cmd, cmd);
return command;
}
void consolePrint(const char_t *fmt, ...) {
// Do we need to shift the log buffer?
if (CONSOLE.logCount == CONSOLE_LOG_COUNT_MAX) {
memcpy(
CONSOLE.log[0],
CONSOLE.log[1],
sizeof(char_t) *
CONSOLE_LOG_MESSAGE_LENGTH_MAX *
(CONSOLE_LOG_COUNT_MAX - 1)
);
}
// Print the message
va_list args;
va_start(args, fmt);
// buffer but don't let it overflow the string length.
int ret = vsnprintf(
CONSOLE.log[CONSOLE.logCount++],
CONSOLE_LOG_MESSAGE_LENGTH_MAX,
fmt,
args
);
assertTrue(ret >= 0, "Log message error.");
assertTrue(ret < CONSOLE_LOG_MESSAGE_LENGTH_MAX, "Log message overflow.");
printf("%s\n", CONSOLE.log[CONSOLE.logCount - 1]);
va_end(args);
}

View File

@ -1,43 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "consolecmd.h"
#define CONSOLE_COMMAND_COUNT_MAX 64
#define CONSOLE_LOG_MESSAGE_LENGTH_MAX 1024
#define CONSOLE_LOG_COUNT_MAX 256
typedef struct {
consolecmd_t commands[CONSOLE_COMMAND_COUNT_MAX];
uint8_t commandCount;
char_t log[CONSOLE_LOG_COUNT_MAX][CONSOLE_LOG_MESSAGE_LENGTH_MAX + 1];
uint8_t logCount;
} console_t;
extern console_t CONSOLE;
/**
* Initializes the console.
*/
void consoleInit();
/**
* Run a command against the console.
*
* @param cmd The command string to run.
*/
const consolecmd_t * consoleCommand(const char_t *cmd);
/**
* Prints a message to the console.
*
* @param fmt The format string.
* @param ... The format arguments.
*/
void consolePrint(const char_t *fmt, ...);

View File

@ -1,15 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
#define CONSOLE_CMD_LENGTH_MAX 256
typedef struct {
char_t cmd[CONSOLE_CMD_LENGTH_MAX + 1];
} consolecmd_t;

View File

@ -6,58 +6,15 @@
*/
#include "game.h"
#include "gametime.h"
#include "input.h"
#include "console/console.h"
#include "net/server/server.h"
#include "net/client/client.h"
int32_t status = 0;
void gameInit() {
consoleInit();
gameTimeInit();
inputInit();
consolePrint("Press LEFT to start server, RIGHT to join server.");
memset(&SERVER, 0, sizeof(server_t));
memset(&CLIENT, 0, sizeof(client_t));
// serverInit((serverinit_t){
// .type = SERVER_TYPE_ONLINE,
// .online = {
// .port = SERVER_PORT_DEFAULT
// }
// });
}
void gameUpdate(const float delta) {
gameTimeUpdate(delta);
void gameUpdate() {
inputUpdate();
switch(status) {
case 0:
if(inputWasPressed(INPUT_LEFT)) {
serverInit((serverinit_t){
.type = SERVER_TYPE_ONLINE,
.online = {
.port = SERVER_PORT_DEFAULT
}
});
} else if(inputWasPressed(INPUT_RIGHT)) {
clientInit((clientinit_t){
.host = "127.0.0.1",
.port = SERVER_PORT_DEFAULT
});
}
break;
}
}
void gameDispose() {
clientDispose();
serverDispose();
}

View File

@ -14,11 +14,12 @@
void gameInit();
/**
* Updates the game.
*
* @param delta Game time update delta since last tick.
* Updates the game. The game is setup to handle "frames", aka 1/60th of a
* second. Typically more modern engines would use floats to tick game engine
* by a semi random delta time, but this engine is intended to work on really
* weak machines so we take the simple approach.
*/
void gameUpdate(const float_t delta);
void gameUpdate();
/**
* Disposes the game.

View File

@ -1,20 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "gametime.h"
gametime_t GAME_TIME;
void gameTimeInit() {
memset(&GAME_TIME, 0, sizeof(gametime_t));
GAME_TIME.delta = GAME_TIME_STEP_DEFAULT;
}
void gameTimeUpdate(const float_t delta) {
GAME_TIME.delta = delta;
GAME_TIME.time += GAME_TIME.delta;
}

View File

@ -1,30 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef struct {
float_t delta;
float_t time;
} gametime_t;
extern gametime_t GAME_TIME;
#define GAME_TIME_STEP_DEFAULT 0.016f
/**
* Initializes the game time.
*/
void gameTimeInit();
/**
* Updates the game time.
*
* @param delta The time since the last frame.
*/
void gameTimeUpdate(const float_t delta);

View File

@ -1,46 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "input.h"
inputstate_t INPUT;
void inputInit() {
memset(&INPUT, 0, sizeof(inputstate_t));
}
void inputUpdate() {
memcpy(INPUT.previous, INPUT.current, sizeof(inputvalue_t) * INPUT_BIND_COUNT);
for(int i = 0; i < INPUT_BIND_COUNT; i++) {
INPUT.current[i] = inputStateGet(i);
}
}
inputvalue_t inputGet(inputbind_t bind) {
return INPUT.current[bind];
}
inputvalue_t inputGetPrevious(inputbind_t bind) {
return INPUT.previous[bind];
}
bool_t inputWasPressed(inputbind_t bind) {
return inputGet(bind) != 0.0f && inputGetPrevious(bind) == 0.0f;
}
bool_t inputWasReleased(inputbind_t bind) {
return inputGet(bind) == 0.0f && inputGetPrevious(bind) != 0.0f;
}
bool_t inputIsDown(inputbind_t bind) {
return inputGet(bind) != 0.0f;
}
bool_t inputIsUp(inputbind_t bind) {
return inputGet(bind) == 0.0f;
}

View File

@ -6,91 +6,14 @@
*/
#pragma once
#include "dusk.h"
typedef float_t inputvalue_t;
typedef uint16_t inputstate_t;
typedef enum {
INPUT_UP,
INPUT_DOWN,
INPUT_LEFT,
INPUT_RIGHT,
INPUT_ACCEPT,
INPUT_BACK,
INPUT_QUIT,
} inputbind_t;
#define INPUT_BIND_COUNT INPUT_QUIT + 1
typedef struct {
inputvalue_t current[INPUT_BIND_COUNT];
inputvalue_t previous[INPUT_BIND_COUNT];
} inputstate_t;
extern inputstate_t INPUT;
extern inputstate_t INPUT_CURRENT;
extern inputstate_t INPUT_LAST_FRAME;
/**
* Initializes the input system.
* Initializes the input system
*/
void inputInit();
/**
* Updates the input system.
*/
void inputUpdate();
/**
* Calls on the platform to get the current state of a given input bind.
*
* @param input Input to check.
* @return Current state of the input.
*/
inputvalue_t inputStateGet(const inputbind_t input);
/**
* Returns the current value of the input bind.
*
* @param input Input to get.
* @return Current value of the input.
*/
inputvalue_t inputGet(const inputbind_t input);
/**
* Returns the previous value of the input bind.
*
* @param input Input to get.
* @return Previous value of the input.
*/
inputvalue_t inputGetPrevious(const inputbind_t input);
/**
* Returns whether the input was pressed this frame.
*
* @param input Input to check.
* @return Whether the input was pressed this frame.
*/
bool_t inputWasPressed(inputbind_t input);
/**
* Returns whether the input was released this frame.
*
* @param input Input to check.
* @return Whether the input was released this frame.
*/
bool_t inputWasReleased(inputbind_t input);
/**
* Returns whether the input is currently down.
*
* @param input Input to check.
* @return Whether the input is currently down.
*/
bool_t inputIsDown(inputbind_t input);
/**
* Returns whether the input is currently up.
*
* @param input Input to check.
* @return Whether the input is currently up.
*/
bool_t inputIsUp(inputbind_t input);
void inputUpdate();

View File

@ -1,13 +0,0 @@
# Copyright (c) 2023 Dominic Masters
#
# This software is released under the MIT License.
# https:#opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_TARGET_NAME}
PRIVATE
)
# Subdirs
add_subdirectory(client)
add_subdirectory(server)

View File

@ -1,10 +0,0 @@
# Copyright (c) 2023 Dominic Masters
#
# This software is released under the MIT License.
# https:#opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_TARGET_NAME}
PRIVATE
client.c
)

View File

@ -1,119 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "client.h"
#include "console/console.h"
#include "assert/assert.h"
client_t CLIENT;
void clientInit(const clientinit_t init) {
memset(&CLIENT, 0, sizeof(client_t));
CLIENT.state = CLIENT_STATE_CONNECTING;
CLIENT.socket = socket(AF_INET, SOCK_STREAM, 0);
CLIENT.serverAddress.sin_family = AF_INET;
CLIENT.serverAddress.sin_port = htons(init.port);
if(inet_pton(AF_INET, init.host, &CLIENT.serverAddress.sin_addr) <= 0) {
assertUnreachable("Invalid address or address not supported.");
}
if(connect(CLIENT.socket, (struct sockaddr *)&CLIENT.serverAddress, sizeof(CLIENT.serverAddress)) < 0) {
assertUnreachable("Connection failed.");
}
pthread_create(&CLIENT.thread, NULL, clientThread, NULL);
// Wait for client to connect
while(CLIENT.state == CLIENT_STATE_CONNECTING) usleep(1000);
consolePrint("Connected to server.");
}
void * clientThread(void* arg) {
assertNull(arg, "Client thread does not accept arguments.");
// Server sends 16 bytes.
{
char_t buffer[16];
consolePrint("Reading first packet.");
if(_clientReceive((uint8_t*)buffer, sizeof(buffer)) != sizeof(buffer)) {
assertUnreachable("Failed to read initial server data.");
}
// First 4 bytes must be "Dusk"
if(memcmp(buffer, "Dusk", 4) != 0) {
assertUnreachable("Invalid server data.");
}
// Next, server will send its version number, we compare to DUSK_VERSION
char_t cmp[] = DUSK_VERSION;
if(memcmp(buffer+4, cmp, 4) != 0) {
assertUnreachable("Server version mismatch.");
}
}
// Send "OK" and nothing else (don't send NULL term)
if(_clientSend((uint8_t*)"OK", 2) != 2) {
assertUnreachable("Failed to send OK to server.");
}
// Server will send the first properly formed packet now.
CLIENT.state = CLIENT_STATE_CONNECTED;
while(CLIENT.state == CLIENT_STATE_CONNECTED) {
usleep(1000);
}
CLIENT.state = CLIENT_STATE_DISCONNECTED;
close(CLIENT.socket);
return NULL;
}
ssize_t _clientSend(const uint8_t *data, const size_t size) {
assertNotNull(data, "Data cannot be NULL.");
assertTrue(size > 0, "Size cannot be zero.");
return send(CLIENT.socket, data, size, 0);
}
ssize_t _clientReceive(uint8_t *data, const size_t size) {
assertNotNull(data, "Data cannot be NULL.");
assertTrue(size > 0, "Size cannot be zero.");
fd_set readfds;
struct timeval timeout;
int32_t activity;
FD_ZERO(&readfds);
FD_SET(CLIENT.socket, &readfds);
timeout.tv_sec = 5; // 5 seconds timeout
timeout.tv_usec = 0;
activity = select(CLIENT.socket + 1, &readfds, NULL, NULL, &timeout);
if(activity <= 0) {
assertUnreachable("Timeout or error while waiting for server data.");
}
return recv(CLIENT.socket, data, size, 0);
}
void clientDispose() {
if(CLIENT.state == CLIENT_STATE_CONNECTED) {
CLIENT.state = CLIENT_STATE_DISCONNECTING;
// Wait for client to disconnect
while(CLIENT.state == CLIENT_STATE_DISCONNECTING) usleep(1000);
pthread_join(CLIENT.thread, NULL);
consolePrint("Disconnected from server.");
}
close(CLIENT.socket);
}

View File

@ -1,43 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#define CLIENT_HOST_STR_LEN 256
typedef enum {
CLIENT_STATE_DISCONNECTED,
CLIENT_STATE_CONNECTING,
CLIENT_STATE_CONNECTED,
CLIENT_STATE_DISCONNECTING
} clientstate_t;
typedef struct {
clientstate_t state;
int32_t socket;
pthread_t thread;
struct sockaddr_in serverAddress;
} client_t;
typedef struct {
char_t host[CLIENT_HOST_STR_LEN+1];
uint32_t port;
} clientinit_t;
extern client_t CLIENT;
void clientInit(const clientinit_t init);
void clientDispose();
void * clientThread(void* arg);
ssize_t _clientSend(const uint8_t *data, const size_t size);
ssize_t _clientReceive(uint8_t *data, const size_t size);

View File

@ -1,17 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef enum {
PACKET_TYPE_CONNECTED
} packettype_t;
typedef struct {
packettype_t type;
} packet_t;

View File

@ -1,11 +0,0 @@
# Copyright (c) 2023 Dominic Masters
#
# This software is released under the MIT License.
# https:#opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_TARGET_NAME}
PRIVATE
server.c
serverclient.c
)

View File

@ -1,149 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "server.h"
#include "assert/assert.h"
#include "console/console.h"
server_t SERVER;
void serverInit(const serverinit_t init) {
memset(&SERVER, 0, sizeof(server_t));
SERVER.state = SERVER_STATE_STARTING;
SERVER.type = init.type;
// Create the server
switch(init.type) {
case SERVER_TYPE_ONLINE:
SERVER.online.socket = socket(AF_INET, SOCK_STREAM, 0);
SERVER.online.address.sin_family = AF_INET;
SERVER.online.address.sin_addr.s_addr = INADDR_ANY;
SERVER.online.address.sin_port = htons(init.online.port);
// Bind
if(bind(
SERVER.online.socket,
(struct sockaddr *)&SERVER.online.address,
sizeof(SERVER.online.address)
) < 0) {
assertUnreachable("Failed to bind server.");
}
// Begin listening
if(listen(SERVER.online.socket, SERVER_CLIENT_COUNT_MAX) < 0) {
assertUnreachable("Failed to listen on server.");
}
// Set the socket to non-blocking mode
int flags = fcntl(SERVER.online.socket, F_GETFL, 0);
fcntl(SERVER.online.socket, F_SETFL, flags | O_NONBLOCK);
break;
default:
assertUnreachable("Invalid server type.");
break;
}
// Start thread
pthread_create(&SERVER.thread, NULL, serverThread, NULL);
// Wait for server to start
while(SERVER.state == SERVER_STATE_STARTING) usleep(1000);
consolePrint("Server started");
}
void * serverThread(void *arg) {
assertNull(arg, "Server thread does not accept arguments.");
// Server now running
SERVER.state = SERVER_STATE_RUNNING;
fd_set readfds;
int32_t activity;
int32_t error;
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 1000;
// Start server
while(SERVER.state == SERVER_STATE_RUNNING) {
FD_ZERO(&readfds);
FD_SET(SERVER.online.socket, &readfds);
activity = select(
SERVER.online.socket + 1,
&readfds,
NULL,
NULL,
&timeout
);
if(activity < 0) assertUnreachable("Select error");
if(!FD_ISSET(SERVER.online.socket, &readfds)) {
continue;
}
// Accept incoming connections
int32_t clientSockDesc = accept(SERVER.online.socket, NULL, NULL);
if(clientSockDesc < 0) {
printf("Failed to accept connection\n");
continue;
}
// Now, is the server full?
if(SERVER.clientCount >= SERVER_CLIENT_COUNT_MAX) {
consolePrint("Server is full, rejecting connection.");
// TODO: Write a reason to client.
close(clientSockDesc);
continue;
}
// Create server client for handling
serverclient_t *client = &SERVER.clients[SERVER.clientCount];
serverClientInit(client, (serverclientinit_t){
.socket = clientSockDesc
});
SERVER.clientCount++;
}
SERVER.state = SERVER_STATE_STOPPED;
return NULL;
}
void serverDispose() {
// Disconnect clients
for(uint8_t i = 0; i < SERVER.clientCount; i++) {
serverClientDispose(&SERVER.clients[i]);
}
SERVER.clientCount = 0;
// Stop server thread.
if(SERVER.state == SERVER_STATE_RUNNING) {
// Request thread to stop
SERVER.state = SERVER_STATE_STOPPING;
// Wait for server to stop
while(SERVER.state == SERVER_STATE_STOPPING) usleep(1000);
pthread_join(SERVER.thread, NULL);
// Close the socket
switch(SERVER.type) {
case SERVER_TYPE_ONLINE:
close(SERVER.online.socket);
break;
default:
assertUnreachable("Invalid server type.");
break;
}
consolePrint("Server stopped");
}
}

View File

@ -1,55 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "serverclient.h"
#define SERVER_CLIENT_COUNT_MAX 8
#define SERVER_PORT_DEFAULT 24555
typedef enum {
SERVER_STATE_STOPPED,
SERVER_STATE_STARTING,
SERVER_STATE_RUNNING,
SERVER_STATE_STOPPING
} serverstate_t;
typedef enum {
SERVER_TYPE_OFFLINE,
SERVER_TYPE_ONLINE
} servertype_t;
typedef struct {
serverstate_t state;
servertype_t type;
serverclient_t clients[SERVER_CLIENT_COUNT_MAX];
uint8_t clientCount;
pthread_t thread;
union {
struct {
int32_t socket;
struct sockaddr_in address;
} online;
};
} server_t;
typedef struct {
servertype_t type;
union {
struct {
int32_t port;
} online;
};
} serverinit_t;
extern server_t SERVER;
void serverInit(const serverinit_t init);
void * serverThread(void* arg);
void serverDispose();

View File

@ -1,139 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "serverclient.h"
#include "assert/assert.h"
#include "console/console.h"
void serverClientInit(serverclient_t *client, const serverclientinit_t init) {
assertNotNull(client, "Client cannot be NULL.");
client->socket = init.socket;
consolePrint("Accepted client %i", client->socket);
client->state = SERVER_CLIENT_STATE_CONNECTING;
// Set socket to non-blocking
int flags = fcntl(client->socket, F_GETFL, 0);
fcntl(client->socket, F_SETFL, flags | O_NONBLOCK);
// Start thread
pthread_create(&client->thread, NULL, serverClientThread, client);
// Wait for client to connect
while(client->state == SERVER_CLIENT_STATE_CONNECTING) usleep(1000);
}
void * serverClientThread(void *arg) {
serverclient_t *client = (serverclient_t*)arg;
assertNotNull(client, "Client cannot be NULL.");
// Send hello to client, as well as the version number.
{
uint8_t hello[16];
memset(hello, 0, sizeof(hello));
memcpy(hello, "Dusk", 4);
strcpy((char*)&hello[4], DUSK_VERSION);
ssize_t bytesSent = serverClientSend(client, hello, sizeof(hello));
assertTrue(
bytesSent == sizeof(hello),
"Failed to send hello to client."
);
}
// Client should respond "OK"
{
uint8_t response[2];
ssize_t bytesReceived = serverClientReceive(client, response, sizeof(response));
assertTrue(
bytesReceived == sizeof(response) &&
response[0] == 'O' &&
response[1] == 'K',
"Client did not respond with OK."
);
}
// At this point we can start communicating "properly", so let's send the
// first real packet.
packet_t packet = { .type = PACKET_TYPE_CONNECTED };
if(!serverClientSendPacket(client, &packet)) {
assertUnreachable("Failed to send connected packet to client.");
}
// Set the client state to connected
client->state = SERVER_CLIENT_STATE_CONNECTED;
while(client->state == SERVER_CLIENT_STATE_CONNECTED) {
// Do nothing for now.
usleep(1000);
}
// Disconnect
client->state = SERVER_CLIENT_STATE_DISCONNECTED;
return NULL;
}
ssize_t serverClientSend(
serverclient_t *client,
const uint8_t *data,
const size_t size
) {
assertNotNull(client, "Client cannot be NULL.");
assertNotNull(data, "Data cannot be NULL.");
assertTrue(size > 0, "Size cannot be zero.");
return send(client->socket, data, size, 0);
}
ssize_t serverClientReceive(
serverclient_t *client,
uint8_t *data,
const size_t size
) {
assertNotNull(client, "Client cannot be NULL.");
assertNotNull(data, "Data cannot be NULL.");
assertTrue(size > 0, "Size cannot be zero.");
fd_set readfds;
struct timeval timeout;
int32_t activity;
FD_ZERO(&readfds);
FD_SET(client->socket, &readfds);
timeout.tv_sec = 5; // 5 seconds timeout
timeout.tv_usec = 0;
activity = select(client->socket + 1, &readfds, NULL, NULL, &timeout);
if(activity <= 0) {
assertUnreachable("Timeout or error while waiting for client data.");
}
return recv(client->socket, data, size, 0);
}
bool_t serverClientSendPacket(
serverclient_t *client,
const packet_t *packet
) {
assertNotNull(client, "Client cannot be NULL.");
assertNotNull(packet, "Packet cannot be NULL.");
ssize_t sent = serverClientSend(client, (const uint8_t*)packet, sizeof(packet_t));
return sent == sizeof(packet_t);
}
void serverClientDispose(serverclient_t *client) {
assertNotNull(client, "Client cannot be NULL.");
if(client->state == SERVER_CLIENT_STATE_CONNECTED) {
// Let the thread know we are disconnecting
client->state = SERVER_CLIENT_STATE_DISCONNECTING;
// Wait for the thread to finish
while(client->state == SERVER_CLIENT_STATE_DISCONNECTING) usleep(1000);
pthread_join(client->thread, NULL);
}
}

View File

@ -1,51 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
#include "net/packet.h"
#include <netinet/in.h>
#include <fcntl.h>
typedef enum {
SERVER_CLIENT_STATE_DISCONNECTED,
SERVER_CLIENT_STATE_CONNECTING,
SERVER_CLIENT_STATE_CONNECTED,
SERVER_CLIENT_STATE_DISCONNECTING
} serverclientstate_t;
typedef struct {
serverclientstate_t state;
pthread_t thread;
int32_t socket;
} serverclient_t;
typedef struct {
int32_t socket;
} serverclientinit_t;
void serverClientInit(serverclient_t *client, const serverclientinit_t init);
void * serverClientThread(void *arg);
ssize_t serverClientSend(
serverclient_t *client,
const uint8_t *data,
const size_t size
);
ssize_t serverClientReceive(
serverclient_t *client,
uint8_t *buffer,
const size_t size
);
bool_t serverClientSendPacket(
serverclient_t *client,
const packet_t *packet
);
void serverClientDispose(serverclient_t *client);