Working on client code.

This commit is contained in:
2025-02-21 16:13:35 -06:00
parent 00ad38e87b
commit ec4312c189
27 changed files with 767 additions and 7 deletions

View File

@ -3,6 +3,12 @@
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Libs
target_link_libraries(${DUSK_TARGET_NAME}
PUBLIC
cglm
)
# Includes
target_include_directories(${DUSK_TARGET_NAME}
PUBLIC
@ -20,4 +26,7 @@ target_sources(${DUSK_TARGET_NAME}
# Subdirs
add_subdirectory(assert)
add_subdirectory(console)
add_subdirectory(client)
add_subdirectory(server)
add_subdirectory(entity)
add_subdirectory(display)

View File

@ -54,6 +54,10 @@ void assertNotNullImpl(
pointer != NULL,
message
);
// Ensure we can touch it
volatile char temp;
temp = *((char*)pointer);
}
void assertNullImpl(

View File

@ -0,0 +1,13 @@
# 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
client.c
clientremote.c
)
# Subdirs

71
src/dusk/client/client.c Normal file
View File

@ -0,0 +1,71 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "client.h"
#include "assert/assert.h"
void clientInit(
client_t *client,
const clientinit_t init
) {
assertNotNull(client, "Client cannot be NULL.");
memset(client, 0, sizeof(client_t));
client->type = init.type;
client->state = CLIENT_STATE_CONNECTING;
// Perform connection
switch(init.type) {
case CLIENT_TYPE_REMOTE:
clientRemoteInit(client, init.remote);
break;
default:
assertUnreachable("Invalid client type.");
}
// Begin exchanging.
// clientSend(client, (packet_t){
// .type = PACKET_TYPE_HELLO
// });
}
void clientSend(
client_t *client,
const packet_t packet
) {
assertNotNull(client, "Client cannot be NULL.");
assertTrue(
client->state == CLIENT_STATE_CONNECTED,
"Client must be connected to send packets."
);
switch(client->type) {
case CLIENT_TYPE_REMOTE:
clientRemoteSend(client, packet);
break;
default:
assertUnreachable("Invalid client type.");
}
}
void clientDispose(client_t *client) {
assertNotNull(client, "Client cannot be NULL.");
client->state = CLIENT_STATE_DISCONNECTING;
switch(client->type) {
case CLIENT_TYPE_REMOTE:
clientRemoteDispose(client);
break;
default:
assertUnreachable("Invalid client type.");
}
client->state = CLIENT_STATE_DISCONNECTED;
}

51
src/dusk/client/client.h Normal file
View File

@ -0,0 +1,51 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "clientremote.h"
typedef enum {
CLIENT_TYPE_SINGLE_PLAYER,
CLIENT_TYPE_LOCAL,
CLIENT_TYPE_REMOTE
} clienttype_t;
typedef enum {
CLIENT_STATE_DISCONNECTED,
CLIENT_STATE_DISCONNECTING,
CLIENT_STATE_CONNECTING,
CLIENT_STATE_CONNECTED
} clientstate_t;
typedef struct _client_t {
clienttype_t type;
clientstate_t state;
union {
clientremote_t remote;
};
} client_t;
typedef struct {
clienttype_t type;
union {
clientremoteinit_t remote;
};
} clientinit_t;
void clientInit(
client_t *client,
const clientinit_t init
);
void clientSend(
client_t *client,
const packet_t packet
);
void clientDispose(client_t *client);

View File

@ -0,0 +1,45 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "client.h"
#include "assert/assert.h"
#include "console/console.h"
void* clientRemoteThreadFunc(void* arg) {
client_t *client = (client_t*)arg;
assertNotNull(client, "Client is NULL");
client->state = CLIENT_STATE_CONNECTED;
// Send some data
write(client->remote.clientSockDesc, "Hello, World!", 13);
printf("Thread func\n");
return NULL;
}
void clientRemoteInit(
client_t *client,
const clientremoteinit_t init
) {
client->remote.clientSockDesc = init.clientSockDesc;
consolePrint("Accepted a new connection.");
pthread_create(&client->remote.thread, NULL, clientRemoteThreadFunc, client);
}
void clientRemoteSend(client_t *client, const packet_t packet) {
printf("send pack\n");
}
void clientRemoteDispose(client_t *client) {
pthread_join(client->remote.thread, NULL);
close(client->remote.clientSockDesc);
consolePrint("Client disconnected.");
}

View File

@ -0,0 +1,26 @@
/**
* 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"
typedef struct _client_t client_t;
typedef struct {
int32_t clientSockDesc;
} clientremoteinit_t;
typedef struct {
int32_t clientSockDesc;
pthread_t thread;
} clientremote_t;
void clientRemoteInit(client_t *client, const clientremoteinit_t init);
void clientRemoteSend(client_t *client, const packet_t packet);
void * clientRemoteThread(void *arg);
void clientRemoteDispose(client_t *client);

View File

@ -6,6 +6,7 @@
# Sources
target_sources(${DUSK_TARGET_NAME}
PRIVATE
camera.c
)
# Subdirs

44
src/dusk/display/camera.c Normal file
View File

@ -0,0 +1,44 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "camera.h"
void cameraInit(camera_t *camera) {
glm_mat4_identity(camera->projection);
glm_mat4_identity(camera->view);
}
void cameraLookAt(
camera_t *camera,
const vec3 eye,
const vec3 center,
const vec3 up
) {
glm_lookat(eye, center, up, camera->view);
}
void cameraPerspective(
camera_t *camera,
float aspect,
float fovy,
float zNear,
float zFar
) {
glm_perspective(fovy, aspect, zNear, zFar, camera->projection);
}
void cameraOrtho(
camera_t *camera,
float left,
float right,
float bottom,
float top,
float near,
float far
) {
glm_ortho(left, right, bottom, top, near, far, camera->projection);
}

74
src/dusk/display/camera.h Normal file
View File

@ -0,0 +1,74 @@
/**
* 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 {
mat4 projection;
mat4 view;
} camera_t;
/**
* Initializes the camera.
*
* @param camera The camera to initialize.
*/
void cameraInit(camera_t *camera);
/**
* Changes a camera to look at a specific point.
*
* @param camera The camera to modify.
* @param eye The position of the camera.
* @param center The point to look at.
* @param up The up vector.
*/
void cameraLookAt(
camera_t *camera,
const vec3 eye,
const vec3 center,
const vec3 up
);
/**
* Changes the camera's perspective.
*
* @param camera The camera to modify.
* @param fovy The field of view in the y direction.
* @param aspect The aspect ratio.
* @param zNear The near plane.
* @param zFar The far plane.
*/
void cameraPerspective(
camera_t *camera,
const float fovy,
const float aspect,
const float zNear,
const float zFar
);
/**
* Changes the camera's orthographic perspective.
*
* @param camera The camera to modify.
* @param left The left plane.
* @param right The right plane.
* @param bottom The bottom plane.
* @param top The top plane.
* @param near The near plane.
* @param far The far plane.
*/
void cameraOrtho(
camera_t *camera,
const float left,
const float right,
const float bottom,
const float top,
const float near,
const float far
);

View File

@ -14,6 +14,12 @@
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <cglm/cglm.h>
#include <float.h>
#include <pthread.h>
#include <unistd.h>
typedef float float_t;
typedef double double_t;
typedef bool bool_t;
typedef char char_t;

View File

@ -0,0 +1,12 @@
# 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
entity.c
)
# Subdirs

17
src/dusk/entity/entity.c Normal file
View File

@ -0,0 +1,17 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "entity.h"
#include "assert/assert.h"
entity_t ENTITY_TEST;
void entityInit(entity_t *ent) {
assertNotNull(ent, "Entity cannot be NULL");
memset(ent, 0, sizeof(entity_t));
}

17
src/dusk/entity/entity.h Normal file
View File

@ -0,0 +1,17 @@
/**
* 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 {
vec3 position;
} entity_t;
extern entity_t ENTITY_TEST;
void entityInit(entity_t *entity);

View File

@ -9,14 +9,32 @@
#include "gametime.h"
#include "input.h"
#include "console/console.h"
#include "server/server.h"
#include "entity/entity.h"
void gameInit() {
consoleInit();
gameTimeInit();
inputInit();
serverInit();
serverStart((serverstart_t){
.type = SERVER_TYPE_LOCAL,
.local = {
.port = SERVER_LOCAL_PORT_DEFAULT
}
});
entityInit(&ENTITY_TEST);
}
void gameUpdate(const float delta) {
gameTimeUpdate(delta);
inputUpdate();
serverUpdate();
}
void gameDispose() {
serverDispose();
}

View File

@ -18,4 +18,9 @@ void gameInit();
*
* @param delta Game time update delta since last tick.
*/
void gameUpdate(const float_t delta);
void gameUpdate(const float_t delta);
/**
* Disposes the game.
*/
void gameDispose();

18
src/dusk/net/packet.h Normal file
View File

@ -0,0 +1,18 @@
/**
* 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_HELLO,
PACKET_TYPE_PING
} packettype_t;
typedef struct {
packettype_t type;
} packet_t;

View File

@ -0,0 +1,14 @@
# 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
server.c
serverlocal.c
serversingleplayer.c
)
# Subdirs

77
src/dusk/server/server.c Normal file
View File

@ -0,0 +1,77 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "server.h"
#include "console/console.h"
#include "assert/assert.h"
server_t SERVER;
void serverInit() {
memset(&SERVER, 0, sizeof(server_t));
}
void serverStart(const serverstart_t start) {
assertTrue(SERVER.state==SERVER_STATE_STOPPED, "Server is already running.");
SERVER.type = start.type;
SERVER.clientCount = 0;
switch(start.type) {
case SERVER_TYPE_SINGLE_PLAYER:
serverSinglePlayerStart(start.singlePlayer);
break;
case SERVER_TYPE_LOCAL:
serverLocalStart(start.local);
break;
case SERVER_TYPE_REMOTE:
assertUnreachable("Remote server not implemented.");
break;
default:
assertUnreachable("Unknown server type.");
}
SERVER.state = SERVER_STATE_RUNNING;
}
void serverStop() {
assertTrue(SERVER.state == SERVER_STATE_RUNNING,"Server is already stopped.");
for(uint8_t i = 0; i < SERVER.clientCount; i++) {
clientDispose(&SERVER.clients[i]);
}
switch(SERVER.type) {
case SERVER_TYPE_SINGLE_PLAYER:
assertUnreachable("Single player server not implemented.");
break;
case SERVER_TYPE_LOCAL:
serverLocalStop();
break;
case SERVER_TYPE_REMOTE:
assertUnreachable("Remote server not implemented.");
break;
default:
assertUnreachable("Unknown server type.");
}
SERVER.state = SERVER_STATE_STOPPED;
}
void serverUpdate() {
if(SERVER.state == SERVER_STATE_STOPPED) return;
}
void serverDispose() {
if(SERVER.state == SERVER_STATE_RUNNING) serverStop();
}

53
src/dusk/server/server.h Normal file
View File

@ -0,0 +1,53 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "client/client.h"
#include "serversingleplayer.h"
#include "serverlocal.h"
#define SERVER_CLIENT_COUNT_MAX 4
typedef enum {
SERVER_TYPE_SINGLE_PLAYER = 0,
SERVER_TYPE_LOCAL = 1,
SERVER_TYPE_REMOTE = 2
} servertype_t;
typedef enum {
SERVER_STATE_STOPPED = 0,
SERVER_STATE_RUNNING = 1
} serverstate_t;
typedef struct {
servertype_t type;
union {
serversingleplayerstart_t singlePlayer;
serverlocalstart_t local;
};
} serverstart_t;
typedef struct {
serverstate_t state;
servertype_t type;
client_t clients[SERVER_CLIENT_COUNT_MAX];
uint8_t clientCount;
union {
serverlocal_t local;
};
} server_t;
extern server_t SERVER;
void serverInit();
void serverStart(const serverstart_t start);
void serverStop();
void serverUpdate();
void serverDispose();

View File

@ -0,0 +1,127 @@
/**
* 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"
#include <fcntl.h>
void serverLocalStart(const serverlocalstart_t start) {
//Create the socket
SERVER.local.sockDesc = socket(AF_INET, SOCK_STREAM, 0);
if(SERVER.local.sockDesc < 0) {
assertUnreachable("Failed to create socket");
}
// Set the socket to non-blocking mode
int flags = fcntl(SERVER.local.sockDesc, F_GETFL, 0);
fcntl(SERVER.local.sockDesc, F_SETFL, flags | O_NONBLOCK);
//Bind the socket
SERVER.local.sockAddr.sin_family = AF_INET;
SERVER.local.sockAddr.sin_addr.s_addr = INADDR_ANY;
SERVER.local.sockAddr.sin_port = htons(start.port);
if(bind(
SERVER.local.sockDesc,
(struct sockaddr*)&SERVER.local.sockAddr,
sizeof(SERVER.local.sockAddr)
) < 0) {
assertUnreachable("Failed to bind socket");
}
//Listen on the socket
if(listen(SERVER.local.sockDesc, 5) < 0) {
assertUnreachable("Failed to listen on socket");
}
// Begin the server thread.
consolePrint("Server started.");
// Start the server thread
SERVER.local.threadState = SERVER_LOCAL_THREAD_STATE_STARTING;
pthread_create(&SERVER.local.thread, NULL, serverLocalThread, NULL);
while(SERVER.local.threadState == SERVER_LOCAL_THREAD_STATE_STARTING) {
usleep(SERVER_LOCAL_THREAD_SLEEP_TIME);
}
}
void serverLocalStop() {
SERVER.local.threadState = SERVER_LOCAL_THREAD_STATE_STOPPING;
while(SERVER.local.threadState == SERVER_LOCAL_THREAD_STATE_STOPPING) {
usleep(SERVER_LOCAL_THREAD_SLEEP_TIME);
}
// Stop the server thread.
pthread_cancel(SERVER.local.thread);
//Close the socket
close(SERVER.local.sockDesc);
// End the server thread.
consolePrint("Server stopped.");
}
void * serverLocalThread(void *arg) {
SERVER.local.threadState = SERVER_LOCAL_THREAD_STATE_RUNNING;
fd_set readfds;
int32_t activity;
int32_t error;
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = SERVER_LOCAL_THREAD_ACCEPT_SLEEP_TIME;
while(SERVER.local.threadState == SERVER_LOCAL_THREAD_STATE_RUNNING) {
FD_ZERO(&readfds);
FD_SET(SERVER.local.sockDesc, &readfds);
activity = select(
SERVER.local.sockDesc + 1,
&readfds,
NULL,
NULL,
&timeout
);
if(activity < 0) assertUnreachable("Select error");
if(!FD_ISSET(SERVER.local.sockDesc, &readfds)) {
continue;
}
// Accept incoming connections
int32_t clientSockDesc = accept(SERVER.local.sockDesc, 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 client.
client_t *client = &SERVER.clients[SERVER.clientCount];
clientInit(client, (clientinit_t){
.type = CLIENT_TYPE_REMOTE,
.remote = {
.clientSockDesc = clientSockDesc
}
});
SERVER.clientCount++;
}
SERVER.local.threadState = SERVER_LOCAL_THREAD_STATE_STOPPED;
return NULL;
}

View File

@ -0,0 +1,36 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
#include <netinet/in.h>
#define SERVER_LOCAL_PORT_DEFAULT 8080
#define SERVER_LOCAL_THREAD_SLEEP_TIME 1000
#define SERVER_LOCAL_THREAD_ACCEPT_SLEEP_TIME 60000
typedef enum {
SERVER_LOCAL_THREAD_STATE_STOPPED = 0,
SERVER_LOCAL_THREAD_STATE_STARTING = 1,
SERVER_LOCAL_THREAD_STATE_RUNNING = 2,
SERVER_LOCAL_THREAD_STATE_STOPPING = 3
} serverlocalthreadstate_t;
typedef struct {
uint32_t port;
} serverlocalstart_t;
typedef struct {
int32_t sockDesc;
struct sockaddr_in sockAddr;
pthread_t thread;
uint8_t threadState;
} serverlocal_t;
void serverLocalStart(const serverlocalstart_t start);
void serverLocalStop();
void * serverLocalThread(void *arg);

View File

@ -0,0 +1,12 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "server.h"
void serverSinglePlayerStart(const serversingleplayerstart_t start) {
}

View File

@ -0,0 +1,15 @@
/**
* 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 {
int32_t nothing;
} serversingleplayerstart_t;
void serverSinglePlayerStart(const serversingleplayerstart_t start);

View File

@ -6,7 +6,6 @@
# Libs
target_link_libraries(${DUSK_TARGET_NAME}
PUBLIC
cglm
archive_static
m
spng_static

View File

@ -9,12 +9,7 @@
#include "dusk.h"
#include "duskglimpl.h"
#include <cglm/cglm.h>
#include <libgen.h>
#include <float.h>
typedef float float_t;
typedef double double_t;
extern char_t EXECUTABLE_PATH[];
extern char_t EXECUTABLE_DIRECTORY[];

View File

@ -64,6 +64,7 @@ int32_t main(int32_t argc, char_t **argv) {
renderDispose();
windowDispose();
assetDispose();
gameDispose();
return 0;
}