Current Working Tree on <2023-10-13>

This commit is contained in:
Barra Ó Catháin 2023-10-13 14:44:24 +01:00
parent ce76166c3f
commit 1e00257754
7 changed files with 176 additions and 83 deletions

Binary file not shown.

View File

@ -4,11 +4,13 @@
// | See end of file for copyright notice. | // | See end of file for copyright notice. |
// ========================================= // =========================================
#include <stdbool.h> #include <stdbool.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-Server.h"
#include "Spacewar-Graphics.h" #include "Spacewar-Graphics.h"
int main(int argc, char ** argv) int main(int argc, char ** argv)
@ -48,6 +50,10 @@ int main(int argc, char ** argv)
SDL_Event event; SDL_Event event;
bool keepRunning = true; bool keepRunning = true;
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)
{ {
@ -81,33 +87,31 @@ int main(int argc, char ** argv)
SDL_Delay(1000 / 60); SDL_Delay(1000 / 60);
} }
// Give me a socket, and make sure it's working:
// Connect to server: int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
while (keepRunning) if (serverSocket == -1)
{ {
// Update events and input: printf("Socket creation failed.\n");
SDL_PumpEvents(); exit(EXIT_FAILURE);
SDL_GetKeyboardState(&keyCount);
// Check windowing system events:
while (SDL_PollEvent(&event) != 0)
{
switch (event.type)
{
case SDL_QUIT:
{
keepRunning = false;
continue;
}
}
}
drawMenuScreen(&titlescreen);
// Delay enough so that we run at 60 frames in the menu:
SDL_Delay(1000 / 60);
} }
// Create an address struct to point at the server:
struct sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
serverAddress.sin_port = htons(5200);
// Connect to the server:
if (connect(serverSocket, (struct sockaddr *)&serverAddress, sizeof(struct sockaddr_in)) != 0)
{
fprintf(stderr, "Connecting to the server failed.\n");
exit(0);
}
while(true)
{
usleep(1);
}
// Spawn network thread: // Spawn network thread:
// Spawn game thread: // Spawn game thread:
@ -134,5 +138,5 @@ int main(int argc, char ** argv)
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
// Local Variables: // Local Variables:
// compile-command: "gcc `sdl2-config --libs --cflags` Spacewar-Client.c Spacewar-Graphics.c -lSDL2_image -lSDL2_ttf -lm -o 'Spacewar-Client'" // compile-command: "gcc `sdl2-config --libs --cflags` Spacewar-Client.c Spacewar-Graphics.c Spacewar-Server.c -lSDL2_image -lSDL2_ttf -lm -o 'Spacewar-Client'"
// End: // End:

View File

@ -121,37 +121,37 @@ void drawTitleScreen(SpacewarTitlescreen * titlescreen)
SDL_RenderPresent(titlescreen->renderer); SDL_RenderPresent(titlescreen->renderer);
} }
void drawMenuScreen(SpacewarMenuscreen * menuscreen) /* void drawMenuScreen(SpacewarMenuscreen * menuscreen) */
{ /* { */
// Get the current size of the window: /* // Get the current size of the window: */
int width = 0, height = 0; /* int width = 0, height = 0; */
SDL_GetWindowSize(titlescreen->window, &width, &height); /* SDL_GetWindowSize(menuscreen->window, &width, &height); */
// Set the renderer colour to black and clear the screen: /* // Set the renderer colour to black and clear the screen: */
SDL_SetRenderDrawColor(titlescreen->renderer, 0, 0, 0, 255); /* SDL_SetRenderDrawColor(menuscreen->renderer, 0, 0, 0, 255); */
SDL_RenderClear(titlescreen->renderer); /* SDL_RenderClear(menuscreen->renderer); */
// Set the correct position to begin the starfield, and scroll it back for the next frame: /* // Set the correct position to begin the starfield, and scroll it back for the next frame: */
titlescreen->starfieldRectangle->x = 0 - titlescreen->xScroll++; /* menuscreen->starfieldRectangle->x = 0 - menuscreen->xScroll++; */
titlescreen->starfieldRectangle->y = 0; /* menuscreen->starfieldRectangle->y = 0; */
// Draw the starfield by tiling the starfield texture: /* // Draw the starfield by tiling the starfield texture: */
while (titlescreen->starfieldRectangle->x <= (width + titlescreen->starfieldRectangle->w)) /* while (menuscreen->starfieldRectangle->x <= (width + menuscreen->starfieldRectangle->w)) */
{ /* { */
// Go down, covering a column of the screen: /* // Go down, covering a column of the screen: */
while(titlescreen->starfieldRectangle->y <= (height + titlescreen->starfieldRectangle->h)) /* while(menuscreen->starfieldRectangle->y <= (height + menuscreen->starfieldRectangle->h)) */
{ /* { */
SDL_RenderCopy(titlescreen->renderer, titlescreen->starfieldTexture, NULL, /* SDL_RenderCopy(menuscreen->renderer, menuscreen->starfieldTexture, NULL, */
titlescreen->starfieldRectangle); /* menuscreen->starfieldRectangle); */
titlescreen->starfieldRectangle->y += titlescreen->starfieldRectangle->h; /* menuscreen->starfieldRectangle->y += menuscreen->starfieldRectangle->h; */
} /* } */
// Back to the top, move over one texture width: /* // Back to the top, move over one texture width: */
titlescreen->starfieldRectangle->y = 0; /* menuscreen->starfieldRectangle->y = 0; */
titlescreen->starfieldRectangle->x += titlescreen->starfieldRectangle->w; /* menuscreen->starfieldRectangle->x += menuscreen->starfieldRectangle->w; */
} /* } */
// Display to the renderer: /* // Display to the renderer: */
SDL_RenderPresent(titlescreen->renderer); /* SDL_RenderPresent(menuscreen->renderer); */
} /* } */

View File

@ -8,19 +8,20 @@
#include <stdint.h> #include <stdint.h>
const char * messageStrings[] = {"HELLO", "GOODBYE", "PING", "PONG"}; const char * messageStrings[] = {"HELLO", "GOODBYE", "PING", "PONG", "SECRET"};
struct SpacewarMessage typedef struct SpacewarMessage
{ {
uint8_t type; uint8_t type;
uint8_t content; uint32_t content;
}; } SpacewarMessage;
/* Message Types: /* Message Types:
0 - HELLO: Contents sent to client indicate a given player number. 0 - HELLO: Contents sent to client indicate a given player number.
1 - GOODBYE: No contents, end the connection. 1 - GOODBYE: No contents, end the connection.
2 - PING: Contents indicate the missed amount of pongs. 2 - PING: Contents indicate the missed amount of pongs.
3 - PONG: No contents. 3 - PONG: No contents.
4 - SECRET: Contents indicate the secret key that must be sent with UDP packets to the server.
*/ */
#endif #endif

View File

@ -5,9 +5,9 @@
// ========================================= // =========================================
#ifndef SPACEWAR_PHYSICS #ifndef SPACEWAR_PHYSICS
#define SPACEWAR_PHYSICS #define SPACEWAR_PHYSICS
#include <stdint.h> #include <stdint.h>
#include "xyVector.h" #include "xyVector.h"
#include "Spacewar-Server.h"
typedef struct SpacewarShipState typedef struct SpacewarShipState
{ {
@ -35,6 +35,9 @@ 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

@ -3,24 +3,39 @@
// | 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 <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <pthread.h>
#include <sys/epoll.h> #include <sys/epoll.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "Spacewar-Physics.h"
#include "Spacewar-Messages.h"
void * runServerPhysics(void * parameters) void * runServerPhysics(void * parameters)
{ {
struct SpacewarState * state = (struct SpacewarState *)parameters; SpacewarState * state = (SpacewarState *)parameters;
while (true) while (true)
{ {
doPhysicsTick(state); // doPhysicsTick(state);
usleep(15625); usleep(15625);
} }
} }
// 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:
int runSpacewarServer(uint16_t port) void * runSpacewarServer(void * configuration)
{ {
SpacewarServerConfiguration * serverConfig = (SpacewarServerConfiguration *)configuration;
printf("Starting Server. \n");
// Initialize a simulation: // Initialize a simulation:
struct SpacewarState * currentState = calloc(1, sizeof(struct SpacewarState)); 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);
@ -43,59 +58,62 @@ int runSpacewarServer(uint16_t port)
struct sockaddr_in sendingAddress; struct sockaddr_in sendingAddress;
sendingAddress.sin_family = AF_INET; // IPv4 sendingAddress.sin_family = AF_INET; // IPv4
sendingAddress.sin_addr.s_addr = inet_addr("127.0.0.1"); sendingAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
sendingAddress.sin_port = htons(12000); 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;
memset(&listeningAddress, 0, sizeof(listeningAddress)); memset(&listeningAddress, 0, sizeof(listeningAddress));
listeningAddress.sin_family = AF_INET; // IPv4 listeningAddress.sin_family = AF_INET; // IPv4
listeningAddress.sin_addr.s_addr = INADDR_ANY; listeningAddress.sin_addr.s_addr = INADDR_ANY;
listeningAddress.sin_port = port; listeningAddress.sin_port = htons(serverConfig->port);
// Bind to the listening socket: // Bind to the listening socket:
if (bind(masterSocket, (const struct sockaddr *)&masterListeningAddress, sizeof(listeningAddress)) < 0) if (bind(masterSocket, (const struct sockaddr *)&listeningAddress, sizeof(listeningAddress)) < 0)
{ {
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 *)&masterListeningAddress, sizeof(listeningAddress)) < 0) if (bind(masterListeningSocket, (const struct sockaddr *)&listeningAddress, sizeof(listeningAddress)) < 0)
{ {
fprintf(stderr, "Failed to bind socket.\n"); fprintf(stderr, "Failed to bind socket.\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Begin the simulation:
pthread_t physicsThread;
pthread_create(&physicsThread, NULL, runServerPhysics, currentState);
// 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 epollDescriptor = epoll_create1(); int epollDescriptor = epoll_create(1);
// Add the master socket to the epoll set: // Add the master socket to the epoll set:
struct epoll_event requestedEvents; struct epoll_event requestedEvents;
requestedEvents.events = EPOLLIN; requestedEvents.events = EPOLLIN | EPOLLET;
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; int recievedEventCount = 0;
struct epoll_event receivedEvents[32]; struct epoll_event receivedEvents[32];
// Create a set of connection structs to store the current connection information:
SpacewarConnection connectedClients[32];
// Begin the simulation:
pthread_t physicsThread;
pthread_create(&physicsThread, NULL, runServerPhysics, currentState);
// Manage clients and sending packets back and forth: // Manage clients and sending packets back and forth:
while (true) while (true)
{ {
receivedEventCount = epoll_wait(epollDescriptor, receivedEvents, 32, -1); int receivedEventCount = epoll_wait(epollDescriptor, receivedEvents, 32, -1);
for (int eventIndex = 0; eventIndex < receivedEventCount; eventIndex++)
for (int eventIndex = 0; eventIndex < receivedEventCount, eventIndex++)
{ {
// If there's activity on the master socket, there's a new connection: // If there's activity on the master socket, there's a new connection:
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, (struct sockaddr *)&clientAddress, int newClientSocket = accept(masterSocket, (struct sockaddr *)&clientAddress,
sizeof(struct sockaddr_in)); &clientSocketLength);
// Check that the socket is functional: // Check that the socket is functional:
if (newClientSocket < 0) if (newClientSocket < 0)
@ -105,19 +123,76 @@ int runSpacewarServer(uint16_t port)
} }
// Register the new client in the epoll set: // Register the new client in the epoll set:
requestedEvents.events = EPOLLIN; requestedEvents.events = EPOLLIN | EPOLLET;
requestedEvents.data.fd = newClientSocket; requestedEvents.data.fd = newClientSocket;
epoll_ctl(epollDescriptor, EPOLL_CTL_ADD, newClientSocket, &requestedEvents); epoll_ctl(epollDescriptor, EPOLL_CTL_ADD, newClientSocket, &requestedEvents);
for (int index = 0; index < 32; index++)
{
if (connectedClients[index].active == false)
{
// Configure the new connection:
connectedClients[index].active = true;
connectedClients[index].missedPongs = false;
connectedClients[index].clientSocket = newClientSocket;
memcpy(&connectedClients[index].clientAddress, &clientAddress,
sizeof(struct sockaddr_in));
// Send the HELLO packet to the player:
SpacewarMessage helloMessage;
helloMessage.type = 0;
helloMessage.content = index;
send(newClientSocket, &helloMessage, sizeof(SpacewarMessage), 0);
// Add the player to the simulation:
//addPlayer(&connectedClients[index], index, currentState);
// Send the SECRET packet to the player:
break;
}
}
} }
// 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
{ {
SpacewarMessage receivedMessage;
size_t bytesRead = recv(receivedEvents->data.fd, &receivedMessage,
sizeof(SpacewarMessage), 0);
if (bytesRead == 0)
{
// Send a goodbye message:
SpacewarMessage goodbyeMessage;
goodbyeMessage.type = 1;
goodbyeMessage.content = 0;
send(receivedEvents->data.fd, &goodbyeMessage, sizeof(SpacewarMessage), 0);
// Remove the socket from the epoll interest set:
epoll_ctl(epollDescriptor, EPOLL_CTL_DEL, receivedEvents->data.fd, NULL);
// Remove the player from the simulation:
// removePlayer(&connectedClients[index], currentState);
// Clear the player struct:
// clearPlayer(findPlayerBySocket(connectedClients, 32, receivedEvents->data.fd));
// Shutdown the socket:
shutdown(receivedEvents->data.fd, SHUT_RDWR);
}
else
{
switch (receivedMessage.content)
{
// Handle message contents:
}
}
} }
} }
} }
return NULL;
} }
// ======================================================= // =======================================================

View File

@ -5,17 +5,27 @@
// ========================================= // =========================================
#ifndef SPACEWAR_SERVER #ifndef SPACEWAR_SERVER
#define SPACEWAR_SERVER #define SPACEWAR_SERVER
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
typedef struct SpacewarConnection typedef struct SpacewarConnection
{ {
uint8_t missedPongs; bool active;
int clientSocket; int clientSocket;
int playerNumber; uint8_t missedPongs;
uint32_t playerSecret;
struct sockaddr_in clientAddress; struct sockaddr_in clientAddress;
} SpacewarConnection; } SpacewarConnection;
typedef struct SpacewarServerConfiguration
{
uint16_t port;
} SpacewarServerConfiguration;
// 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:
int runSpacewarServer(uint16_t port); void * runSpacewarServer(void * configuration);
#endif #endif
// ======================================================= // =======================================================