miku gamer
This commit is contained in:
@ -10,29 +10,54 @@
|
|||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "console/console.h"
|
#include "console/console.h"
|
||||||
#include "net/server/server.h"
|
#include "net/server/server.h"
|
||||||
|
#include "net/client/client.h"
|
||||||
|
|
||||||
#include "entity/entity.h"
|
int32_t status = 0;
|
||||||
|
|
||||||
void gameInit() {
|
void gameInit() {
|
||||||
consoleInit();
|
consoleInit();
|
||||||
gameTimeInit();
|
gameTimeInit();
|
||||||
inputInit();
|
inputInit();
|
||||||
|
|
||||||
serverInit((serverinit_t){
|
consolePrint("Press LEFT to start server, RIGHT to join server.");
|
||||||
.type = SERVER_TYPE_ONLINE,
|
|
||||||
.online = {
|
|
||||||
.port = SERVER_PORT_DEFAULT
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
entityInit(&ENTITY_TEST);
|
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) {
|
void gameUpdate(const float delta) {
|
||||||
gameTimeUpdate(delta);
|
gameTimeUpdate(delta);
|
||||||
inputUpdate();
|
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() {
|
void gameDispose() {
|
||||||
|
clientDispose();
|
||||||
serverDispose();
|
serverDispose();
|
||||||
}
|
}
|
@ -9,4 +9,5 @@ target_sources(${DUSK_TARGET_NAME}
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Subdirs
|
# Subdirs
|
||||||
|
add_subdirectory(client)
|
||||||
add_subdirectory(server)
|
add_subdirectory(server)
|
10
src/dusk/net/client/CMakeLists.txt
Normal file
10
src/dusk/net/client/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# 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
|
||||||
|
)
|
119
src/dusk/net/client/client.c
Normal file
119
src/dusk/net/client/client.c
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
43
src/dusk/net/client/client.h
Normal file
43
src/dusk/net/client/client.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* 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);
|
@ -9,8 +9,7 @@
|
|||||||
#include "dusk.h"
|
#include "dusk.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PACKET_TYPE_HELLO,
|
PACKET_TYPE_CONNECTED
|
||||||
PACKET_TYPE_PING
|
|
||||||
} packettype_t;
|
} packettype_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -54,6 +54,8 @@ void serverInit(const serverinit_t init) {
|
|||||||
|
|
||||||
// Wait for server to start
|
// Wait for server to start
|
||||||
while(SERVER.state == SERVER_STATE_STARTING) usleep(1000);
|
while(SERVER.state == SERVER_STATE_STARTING) usleep(1000);
|
||||||
|
|
||||||
|
consolePrint("Server started");
|
||||||
}
|
}
|
||||||
|
|
||||||
void * serverThread(void *arg) {
|
void * serverThread(void *arg) {
|
||||||
@ -141,5 +143,7 @@ void serverDispose() {
|
|||||||
assertUnreachable("Invalid server type.");
|
assertUnreachable("Invalid server type.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
consolePrint("Server stopped");
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -31,29 +31,40 @@ void * serverClientThread(void *arg) {
|
|||||||
serverclient_t *client = (serverclient_t*)arg;
|
serverclient_t *client = (serverclient_t*)arg;
|
||||||
assertNotNull(client, "Client cannot be NULL.");
|
assertNotNull(client, "Client cannot be NULL.");
|
||||||
|
|
||||||
// Set the client state to connected
|
|
||||||
client->state = SERVER_CLIENT_STATE_CONNECTED;
|
|
||||||
|
|
||||||
// Send hello to client, as well as the version number.
|
// Send hello to client, as well as the version number.
|
||||||
{
|
{
|
||||||
uint8_t hello[16];
|
uint8_t hello[16];
|
||||||
memset(hello, 0, sizeof(hello));
|
memset(hello, 0, sizeof(hello));
|
||||||
memcpy(hello, "Dusk", 4);
|
memcpy(hello, "Dusk", 4);
|
||||||
strcpy((char*)&hello[4], DUSK_VERSION);
|
strcpy((char*)&hello[4], DUSK_VERSION);
|
||||||
|
ssize_t bytesSent = serverClientSend(client, hello, sizeof(hello));
|
||||||
_serverClientSend(client, hello, sizeof(hello));
|
assertTrue(
|
||||||
|
bytesSent == sizeof(hello),
|
||||||
|
"Failed to send hello to client."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client should respond "OK"
|
// Client should respond "OK"
|
||||||
{
|
{
|
||||||
uint8_t response[2];
|
uint8_t response[2];
|
||||||
_serverClientReceive(client, response, sizeof(response));
|
ssize_t bytesReceived = serverClientReceive(client, response, sizeof(response));
|
||||||
assertTrue(
|
assertTrue(
|
||||||
|
bytesReceived == sizeof(response) &&
|
||||||
response[0] == 'O' &&
|
response[0] == 'O' &&
|
||||||
response[1] == 'K',
|
response[1] == 'K',
|
||||||
"Client did not respond with OK."
|
"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) {
|
while(client->state == SERVER_CLIENT_STATE_CONNECTED) {
|
||||||
// Do nothing for now.
|
// Do nothing for now.
|
||||||
@ -65,7 +76,7 @@ void * serverClientThread(void *arg) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _serverClientSend(
|
ssize_t serverClientSend(
|
||||||
serverclient_t *client,
|
serverclient_t *client,
|
||||||
const uint8_t *data,
|
const uint8_t *data,
|
||||||
const size_t size
|
const size_t size
|
||||||
@ -73,9 +84,11 @@ void _serverClientSend(
|
|||||||
assertNotNull(client, "Client cannot be NULL.");
|
assertNotNull(client, "Client cannot be NULL.");
|
||||||
assertNotNull(data, "Data cannot be NULL.");
|
assertNotNull(data, "Data cannot be NULL.");
|
||||||
assertTrue(size > 0, "Size cannot be zero.");
|
assertTrue(size > 0, "Size cannot be zero.");
|
||||||
|
|
||||||
|
return send(client->socket, data, size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _serverClientReceive(
|
ssize_t serverClientReceive(
|
||||||
serverclient_t *client,
|
serverclient_t *client,
|
||||||
uint8_t *data,
|
uint8_t *data,
|
||||||
const size_t size
|
const size_t size
|
||||||
@ -83,8 +96,33 @@ void _serverClientReceive(
|
|||||||
assertNotNull(client, "Client cannot be NULL.");
|
assertNotNull(client, "Client cannot be NULL.");
|
||||||
assertNotNull(data, "Data cannot be NULL.");
|
assertNotNull(data, "Data cannot be NULL.");
|
||||||
assertTrue(size > 0, "Size cannot be zero.");
|
assertTrue(size > 0, "Size cannot be zero.");
|
||||||
|
|
||||||
recv(client->socket, data, size, 0);
|
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) {
|
void serverClientDispose(serverclient_t *client) {
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "dusk.h"
|
#include "dusk.h"
|
||||||
|
#include "net/packet.h"
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
@ -30,16 +31,21 @@ typedef struct {
|
|||||||
void serverClientInit(serverclient_t *client, const serverclientinit_t init);
|
void serverClientInit(serverclient_t *client, const serverclientinit_t init);
|
||||||
void * serverClientThread(void *arg);
|
void * serverClientThread(void *arg);
|
||||||
|
|
||||||
void _serverClientSend(
|
ssize_t serverClientSend(
|
||||||
serverclient_t *client,
|
serverclient_t *client,
|
||||||
const uint8_t *data,
|
const uint8_t *data,
|
||||||
const size_t size
|
const size_t size
|
||||||
);
|
);
|
||||||
|
|
||||||
void _serverClientReceive(
|
ssize_t serverClientReceive(
|
||||||
serverclient_t *client,
|
serverclient_t *client,
|
||||||
uint8_t *buffer,
|
uint8_t *buffer,
|
||||||
const size_t size
|
const size_t size
|
||||||
);
|
);
|
||||||
|
|
||||||
|
bool_t serverClientSendPacket(
|
||||||
|
serverclient_t *client,
|
||||||
|
const packet_t *packet
|
||||||
|
);
|
||||||
|
|
||||||
void serverClientDispose(serverclient_t *client);
|
void serverClientDispose(serverclient_t *client);
|
Reference in New Issue
Block a user