Current Working Tree On <2023-10-13>

Signed-off-by: Barry Kane <barra@ocathain.ie>
This commit is contained in:
Barra Ó Catháin 2023-10-14 00:27:03 +01:00
parent 1e00257754
commit 17401d3d02
6 changed files with 172 additions and 69 deletions

View File

@ -3,15 +3,18 @@
// | Copyright (C) 2023, Barra Ó Catháin | // | Copyright (C) 2023, Barra Ó Catháin |
// | See end of file for copyright notice. | // | See end of file for copyright notice. |
// ========================================= // =========================================
#include <unistd.h>
#include <stdbool.h> #include <stdbool.h>
#include <pthread.h> #include <pthread.h>
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h> #include <SDL2/SDL_ttf.h>
#include <SDL2/SDL_image.h> #include <SDL2/SDL_image.h>
#include <SDL2/SDL_timer.h> #include <SDL2/SDL_timer.h>
#include "Spacewar-Messages.h"
#include "Spacewar-Server.h"
#include "Spacewar-Graphics.h" #include "Spacewar-Graphics.h"
#include "Spacewar-Server.h"
const char * messageStrings[] = {"HELLO", "GOODBYE", "PING", "PONG", "SECRET"};
int main(int argc, char ** argv) int main(int argc, char ** argv)
{ {
@ -49,10 +52,7 @@ int main(int argc, char ** argv)
// Set up event handling: // Set up event handling:
SDL_Event event; SDL_Event event;
bool keepRunning = true; bool keepRunning = true;
bool runServer = false;
SpacewarServerConfiguration serverConfig = {5200};
pthread_t serverThread;
pthread_create(&serverThread, NULL, runSpacewarServer, &serverConfig);
// Display the titlescreen until we get an input: // Display the titlescreen until we get an input:
while (!titlescreenInput && keepRunning) while (!titlescreenInput && keepRunning)
@ -79,6 +79,11 @@ int main(int argc, char ** argv)
{ {
titlescreenInput = true; titlescreenInput = true;
} }
if(keyboardState[SDL_SCANCODE_SPACE] == 1 && !runServer)
{
runServer = true;
printf("Running server!\n");
}
// Draw the title screen: // Draw the title screen:
drawTitleScreen(&titlescreen); drawTitleScreen(&titlescreen);
@ -87,6 +92,14 @@ int main(int argc, char ** argv)
SDL_Delay(1000 / 60); SDL_Delay(1000 / 60);
} }
if (runServer)
{
SpacewarServerConfiguration serverConfig = {5200};
pthread_t serverThread;
pthread_create(&serverThread, NULL, runSpacewarServer, &serverConfig);
sleep(1);
}
// Give me a socket, and make sure it's working: // Give me a socket, and make sure it's working:
int serverSocket = socket(AF_INET, SOCK_STREAM, 0); int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == -1) if (serverSocket == -1)
@ -108,13 +121,40 @@ int main(int argc, char ** argv)
exit(0); exit(0);
} }
while(true) printf("Connected.\n");
bool playerNumberSet, secretKeySet;
uint32_t playerNumber, secretKey;
SpacewarMessage message;
while (!playerNumberSet || !secretKeySet)
{ {
usleep(1); recv(serverSocket, &message, sizeof(SpacewarMessage), 0);
switch (message.type)
{
case 0:
{
playerNumberSet = true;
playerNumber = message.content;
break;
} }
case 4:
{
secretKeySet = true;
secretKey = message.content;
}
}
}
printf("Player Number: %u\n"
"Secret Key: %u\n", playerNumber, secretKey);
// Spawn network thread: // Spawn network thread:
// Spawn game thread: // Spawn game thread:
while(keepRunning)
{
}
// Spawn graphics thread: // Spawn graphics thread:

View File

@ -3,8 +3,8 @@
// | Copyright (C) 2023, Barra Ó Catháin | // | Copyright (C) 2023, Barra Ó Catháin |
// | See end of file for copyright notice. | // | See end of file for copyright notice. |
// ========================================= // =========================================
#ifndef SPACEWAR_GRAPHICS #ifndef SPACEWAR_GRAPHICS_H
#define SPACEWAR_GRAPHICS #define SPACEWAR_GRAPHICS_H
#include <stdint.h> #include <stdint.h>
#include <SDL2/SDL.h> #include <SDL2/SDL.h>

View File

@ -3,13 +3,10 @@
// | Copyright (C) 2023, Barra Ó Catháin | // | Copyright (C) 2023, Barra Ó Catháin |
// | See end of file for copyright notice. | // | See end of file for copyright notice. |
// ========================================= // =========================================
#ifndef SPACEWAR_MESSAGES #ifndef SPACEWAR_MESSAGES_H
#define SPACEWAR_MESSAGES #define SPACEWAR_MESSAGES_H
#include <stdint.h> #include <stdint.h>
const char * messageStrings[] = {"HELLO", "GOODBYE", "PING", "PONG", "SECRET"};
typedef struct SpacewarMessage typedef struct SpacewarMessage
{ {
uint8_t type; uint8_t type;

View File

@ -20,6 +20,8 @@ typedef struct SpacewarShipState
typedef struct SpacewarClientInput typedef struct SpacewarClientInput
{ {
uint8_t playerNumber;
uint32_t secret;
double turningAmount, acceleratingAmount; double turningAmount, acceleratingAmount;
bool turningClockwise, turningAnticlockwise, accelerating; bool turningClockwise, turningAnticlockwise, accelerating;
} SpacewarClientInput; } SpacewarClientInput;
@ -35,9 +37,6 @@ typedef struct SpacewarState
// Does a single step of the physics: // Does a single step of the physics:
void doPhysicsTick(SpacewarState * state); void doPhysicsTick(SpacewarState * state);
// Adds a new player to a physics simulation:
void addNewPlayer(SpacewarConnection * connection, SpacewarState * state);
#endif #endif
// ======================================================== // ========================================================
// | End of Spacewar-Physics.h, copyright notice follows. | // | End of Spacewar-Physics.h, copyright notice follows. |

View File

@ -14,8 +14,20 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include "Spacewar-Physics.h"
#include "Spacewar-Messages.h" #include "Spacewar-Messages.h"
#include "Spacewar-Physics.h"
SpacewarConnection * getConnectionBySocket(SpacewarConnection * connections, size_t connectionCount, int socket)
{
for (size_t connectionIndex = 0; connectionIndex < connectionCount; connectionIndex++)
{
if (connections[connectionIndex].clientSocket == socket)
{
return &connections[connectionIndex];
}
}
return NULL;
}
void * runServerPhysics(void * parameters) void * runServerPhysics(void * parameters)
{ {
@ -23,42 +35,80 @@ void * runServerPhysics(void * parameters)
while (true) while (true)
{ {
// doPhysicsTick(state); //doPhysicsTick(state);
//sendCurrentState();
usleep(15625); usleep(15625);
} }
return NULL;
}
void * runUDPSocket(void * parameters)
{
SpacewarServerSharedState * sharedState = (SpacewarServerSharedState *)parameters;
int udpSocket, bytesRead;
socklen_t socketAddressLength;
struct sockaddr_in clientAddress, serverAddress;
if ((udpSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
exit(EXIT_FAILURE);
}
memset(&serverAddress, 0, sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(5200);
serverAddress.sin_addr.s_addr = INADDR_ANY;
SpacewarClientInput input;
bind(udpSocket, (struct sockaddr *)&serverAddress, sizeof(struct sockaddr_in));
while (true)
{
bytesRead = recvfrom(udpSocket, &input, sizeof(SpacewarClientInput), 0,
(struct sockaddr *)&clientAddress, &socketAddressLength);
if (bytesRead == sizeof(SpacewarClientInput))
{
if (input.playerNumber < 32)
{
if (input.secret == sharedState->connections[input.playerNumber].playerSecret)
{
memcpy(&sharedState->connections[input.playerNumber].clientAddress,
&clientAddress, sizeof(struct sockaddr_in));
memcpy(&sharedState->state->playerInputs[input.playerNumber], &input,
sizeof(struct SpacewarClientInput));
}
}
}
bzero(&input, sizeof(struct SpacewarClientInput));
}
return NULL;
}
// Adds a new player to a physics simulation. Returns a randomly generated secret key:
uint32_t addPlayer(SpacewarConnection * connection, int playerNumber, SpacewarState * state)
{
connection->playerSecret = rand();
state->playerStates[playerNumber].inPlay = false;
return connection->playerSecret;
} }
// Creates a Spacewar server, intended to be ran by the standalone server or forked by the game client: // Creates a Spacewar server, intended to be ran by the standalone server or forked by the game client:
void * runSpacewarServer(void * configuration) void * runSpacewarServer(void * configuration)
{ {
SpacewarServerConfiguration * serverConfig = (SpacewarServerConfiguration *)configuration; SpacewarServerConfiguration * serverConfig = (SpacewarServerConfiguration *)configuration;
printf("Starting Server. \n"); printf("Starting Server.\n");
// Initialize a simulation:
SpacewarState * currentState = calloc(1, sizeof(SpacewarState));
// Create our network listeners: // Create our network listeners:
int masterSocket = socket(AF_INET, SOCK_STREAM, 0); int masterSocket = socket(AF_INET, SOCK_STREAM, 0);
int masterListeningSocket = socket(AF_INET, SOCK_DGRAM, 0); if (masterSocket < 0)
int masterSendingSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (masterListeningSocket < 0 || masterSendingSocket < 0 || masterSocket < 0)
{ {
fprintf(stderr, "Failed to create socket.\n"); fprintf(stderr, "Failed to create socket.\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
setsockopt(masterSocket, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));
// Make the socket timeout: setsockopt(masterSocket, SOL_SOCKET, SO_REUSEPORT, &(int){1}, sizeof(int));
struct timeval readTimeout;
readTimeout.tv_sec = 0;
readTimeout.tv_usec = 800;
setsockopt(masterListeningSocket, SOL_SOCKET, SO_RCVTIMEO, &readTimeout, sizeof(readTimeout));
// Create a structure to store the address we're sending to:
struct sockaddr_in sendingAddress;
sendingAddress.sin_family = AF_INET; // IPv4
sendingAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
sendingAddress.sin_port = htons(serverConfig->port);
// Create a structure to bind the listening socket: // Create a structure to bind the listening socket:
struct sockaddr_in listeningAddress; struct sockaddr_in listeningAddress;
@ -73,16 +123,13 @@ void * runSpacewarServer(void * configuration)
fprintf(stderr, "Failed to bind socket.\n"); fprintf(stderr, "Failed to bind socket.\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (bind(masterListeningSocket, (const struct sockaddr *)&listeningAddress, sizeof(listeningAddress)) < 0)
{
fprintf(stderr, "Failed to bind socket.\n");
exit(EXIT_FAILURE);
}
// Begin listening on the master socket: // Begin listening on the master socket:
listen(masterSocket, 32); listen(masterSocket, 32);
// Create an epoll descriptor to keep track of clients: // Create an epoll descriptor to keep track of clients:
int recievedEventCount = 0;
struct epoll_event receivedEvents[32];
int epollDescriptor = epoll_create(1); int epollDescriptor = epoll_create(1);
// Add the master socket to the epoll set: // Add the master socket to the epoll set:
@ -91,15 +138,21 @@ void * runSpacewarServer(void * configuration)
requestedEvents.data.fd = masterSocket; requestedEvents.data.fd = masterSocket;
epoll_ctl(epollDescriptor, EPOLL_CTL_ADD, masterSocket, &requestedEvents); epoll_ctl(epollDescriptor, EPOLL_CTL_ADD, masterSocket, &requestedEvents);
int recievedEventCount = 0;
struct epoll_event receivedEvents[32];
// Create a set of connection structs to store the current connection information: // Create a set of connection structs to store the current connection information:
SpacewarConnection connectedClients[32]; SpacewarConnection * connectedClients = calloc(32, sizeof(SpacewarConnection));
for(int index = 0; index < 32; index++)
{
connectedClients[index].active = false;
}
// Begin the simulation: // Begin the simulation:
pthread_t physicsThread; pthread_t physicsThread, udpThread;
pthread_create(&physicsThread, NULL, runServerPhysics, currentState); SpacewarState * currentState = calloc(1, sizeof(SpacewarState));
SpacewarServerSharedState threadState;
threadState.state = currentState;
threadState.connections = connectedClients;
pthread_create(&physicsThread, NULL, runServerPhysics, &threadState);
pthread_create(&udpThread, NULL, runUDPSocket, &threadState);
// Manage clients and sending packets back and forth: // Manage clients and sending packets back and forth:
while (true) while (true)
@ -111,9 +164,7 @@ void * runSpacewarServer(void * configuration)
if (receivedEvents[eventIndex].data.fd == masterSocket) if (receivedEvents[eventIndex].data.fd == masterSocket)
{ {
struct sockaddr_in clientAddress; struct sockaddr_in clientAddress;
socklen_t clientSocketLength = sizeof(struct sockaddr_in); int newClientSocket = accept(masterSocket, NULL, NULL);
int newClientSocket = accept(masterSocket, (struct sockaddr *)&clientAddress,
&clientSocketLength);
// Check that the socket is functional: // Check that the socket is functional:
if (newClientSocket < 0) if (newClientSocket < 0)
@ -135,8 +186,6 @@ void * runSpacewarServer(void * configuration)
connectedClients[index].active = true; connectedClients[index].active = true;
connectedClients[index].missedPongs = false; connectedClients[index].missedPongs = false;
connectedClients[index].clientSocket = newClientSocket; connectedClients[index].clientSocket = newClientSocket;
memcpy(&connectedClients[index].clientAddress, &clientAddress,
sizeof(struct sockaddr_in));
// Send the HELLO packet to the player: // Send the HELLO packet to the player:
SpacewarMessage helloMessage; SpacewarMessage helloMessage;
@ -145,9 +194,12 @@ void * runSpacewarServer(void * configuration)
send(newClientSocket, &helloMessage, sizeof(SpacewarMessage), 0); send(newClientSocket, &helloMessage, sizeof(SpacewarMessage), 0);
// Add the player to the simulation: // Add the player to the simulation:
//addPlayer(&connectedClients[index], index, currentState); uint32_t secret = addPlayer(&connectedClients[index], index, currentState);
// Send the SECRET packet to the player: // Send the SECRET packet to the player:
helloMessage.type = 4;
helloMessage.content = secret;
send(newClientSocket, &helloMessage, sizeof(SpacewarMessage), 0);
break; break;
} }
@ -156,8 +208,11 @@ void * runSpacewarServer(void * configuration)
// Otherwise, we've been sent a packet from one of the connected clients: // Otherwise, we've been sent a packet from one of the connected clients:
else else
{ {
SpacewarConnection * client = getConnectionBySocket(connectedClients, 32,
receivedEvents->data.fd);
SpacewarMessage receivedMessage; SpacewarMessage receivedMessage;
size_t bytesRead = recv(receivedEvents->data.fd, &receivedMessage, size_t bytesRead = recv(client->clientSocket, &receivedMessage,
sizeof(SpacewarMessage), 0); sizeof(SpacewarMessage), 0);
if (bytesRead == 0) if (bytesRead == 0)
@ -166,19 +221,19 @@ void * runSpacewarServer(void * configuration)
SpacewarMessage goodbyeMessage; SpacewarMessage goodbyeMessage;
goodbyeMessage.type = 1; goodbyeMessage.type = 1;
goodbyeMessage.content = 0; goodbyeMessage.content = 0;
send(receivedEvents->data.fd, &goodbyeMessage, sizeof(SpacewarMessage), 0); send(client->clientSocket, &goodbyeMessage, sizeof(SpacewarMessage), 0);
// Remove the socket from the epoll interest set: // Remove the socket from the epoll interest set:
epoll_ctl(epollDescriptor, EPOLL_CTL_DEL, receivedEvents->data.fd, NULL); epoll_ctl(epollDescriptor, EPOLL_CTL_DEL, client->clientSocket, NULL);
// Remove the player from the simulation: // Remove the player from the simulation:
// removePlayer(&connectedClients[index], currentState); //removePlayer(&connectedClients[index], currentState);
// Clear the player struct:
// clearPlayer(findPlayerBySocket(connectedClients, 32, receivedEvents->data.fd));
// Shutdown the socket: // Shutdown the socket:
shutdown(receivedEvents->data.fd, SHUT_RDWR); shutdown(client->clientSocket, SHUT_RDWR);
// Deactivate the connection:
client->active = false;
} }
else else

View File

@ -10,6 +10,10 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include "Spacewar-Physics.h"
typedef struct SpacewarState SpacewarState;
typedef struct SpacewarConnection typedef struct SpacewarConnection
{ {
bool active; bool active;
@ -19,11 +23,19 @@ typedef struct SpacewarConnection
struct sockaddr_in clientAddress; struct sockaddr_in clientAddress;
} SpacewarConnection; } SpacewarConnection;
typedef struct SpacewarServerConfiguration typedef struct SpacewarServerConfiguration
{ {
uint16_t port; uint16_t port;
} SpacewarServerConfiguration; } SpacewarServerConfiguration;
typedef struct SpacewarServerSharedState
{
SpacewarState * state;
SpacewarConnection * connections;
} SpacewarServerSharedState;
// Creates a spacewar server, intended to be ran by the standalone server or forked by the game client: // Creates a spacewar server, intended to be ran by the standalone server or forked by the game client:
void * runSpacewarServer(void * configuration); void * runSpacewarServer(void * configuration);