diff --git a/source/Spacewar-Client b/source/Spacewar-Client deleted file mode 100755 index 19b37ac..0000000 Binary files a/source/Spacewar-Client and /dev/null differ diff --git a/source/Spacewar-Client.c b/source/Spacewar-Client.c index f15fd90..0ca4651 100644 --- a/source/Spacewar-Client.c +++ b/source/Spacewar-Client.c @@ -4,11 +4,13 @@ // | See end of file for copyright notice. | // ========================================= #include +#include #include #include #include #include +#include "Spacewar-Server.h" #include "Spacewar-Graphics.h" int main(int argc, char ** argv) @@ -47,6 +49,10 @@ int main(int argc, char ** argv) // Set up event handling: SDL_Event event; bool keepRunning = true; + + SpacewarServerConfiguration serverConfig = {5200}; + pthread_t serverThread; + pthread_create(&serverThread, NULL, runSpacewarServer, &serverConfig); // Display the titlescreen until we get an input: while (!titlescreenInput && keepRunning) @@ -81,35 +87,33 @@ int main(int argc, char ** argv) SDL_Delay(1000 / 60); } - - // Connect to server: - while (keepRunning) + // Give me a socket, and make sure it's working: + int serverSocket = socket(AF_INET, SOCK_STREAM, 0); + if (serverSocket == -1) { - // Update events and input: - SDL_PumpEvents(); - 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); + printf("Socket creation failed.\n"); + exit(EXIT_FAILURE); } - - // Spawn network thread: + // 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 game thread: // Spawn graphics thread: @@ -134,5 +138,5 @@ int main(int argc, char ** argv) // along with this program. If not, see . // 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: diff --git a/source/Spacewar-Graphics.c b/source/Spacewar-Graphics.c index b469864..183cf54 100644 --- a/source/Spacewar-Graphics.c +++ b/source/Spacewar-Graphics.c @@ -121,37 +121,37 @@ void drawTitleScreen(SpacewarTitlescreen * titlescreen) SDL_RenderPresent(titlescreen->renderer); } -void drawMenuScreen(SpacewarMenuscreen * menuscreen) -{ - // Get the current size of the window: - int width = 0, height = 0; - SDL_GetWindowSize(titlescreen->window, &width, &height); +/* void drawMenuScreen(SpacewarMenuscreen * menuscreen) */ +/* { */ +/* // Get the current size of the window: */ +/* int width = 0, height = 0; */ +/* SDL_GetWindowSize(menuscreen->window, &width, &height); */ - // Set the renderer colour to black and clear the screen: - SDL_SetRenderDrawColor(titlescreen->renderer, 0, 0, 0, 255); - SDL_RenderClear(titlescreen->renderer); +/* // Set the renderer colour to black and clear the screen: */ +/* SDL_SetRenderDrawColor(menuscreen->renderer, 0, 0, 0, 255); */ +/* SDL_RenderClear(menuscreen->renderer); */ - // Set the correct position to begin the starfield, and scroll it back for the next frame: - titlescreen->starfieldRectangle->x = 0 - titlescreen->xScroll++; - titlescreen->starfieldRectangle->y = 0; +/* // Set the correct position to begin the starfield, and scroll it back for the next frame: */ +/* menuscreen->starfieldRectangle->x = 0 - menuscreen->xScroll++; */ +/* menuscreen->starfieldRectangle->y = 0; */ - // Draw the starfield by tiling the starfield texture: - while (titlescreen->starfieldRectangle->x <= (width + titlescreen->starfieldRectangle->w)) - { - // Go down, covering a column of the screen: - while(titlescreen->starfieldRectangle->y <= (height + titlescreen->starfieldRectangle->h)) - { - SDL_RenderCopy(titlescreen->renderer, titlescreen->starfieldTexture, NULL, - titlescreen->starfieldRectangle); - titlescreen->starfieldRectangle->y += titlescreen->starfieldRectangle->h; - } +/* // Draw the starfield by tiling the starfield texture: */ +/* while (menuscreen->starfieldRectangle->x <= (width + menuscreen->starfieldRectangle->w)) */ +/* { */ +/* // Go down, covering a column of the screen: */ +/* while(menuscreen->starfieldRectangle->y <= (height + menuscreen->starfieldRectangle->h)) */ +/* { */ +/* SDL_RenderCopy(menuscreen->renderer, menuscreen->starfieldTexture, NULL, */ +/* menuscreen->starfieldRectangle); */ +/* menuscreen->starfieldRectangle->y += menuscreen->starfieldRectangle->h; */ +/* } */ - // Back to the top, move over one texture width: - titlescreen->starfieldRectangle->y = 0; - titlescreen->starfieldRectangle->x += titlescreen->starfieldRectangle->w; - } +/* // Back to the top, move over one texture width: */ +/* menuscreen->starfieldRectangle->y = 0; */ +/* menuscreen->starfieldRectangle->x += menuscreen->starfieldRectangle->w; */ +/* } */ - // Display to the renderer: - SDL_RenderPresent(titlescreen->renderer); -} +/* // Display to the renderer: */ +/* SDL_RenderPresent(menuscreen->renderer); */ +/* } */ diff --git a/source/Spacewar-Messages.h b/source/Spacewar-Messages.h index 0540f84..d0c8775 100644 --- a/source/Spacewar-Messages.h +++ b/source/Spacewar-Messages.h @@ -8,19 +8,20 @@ #include -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 content; -}; + uint32_t content; +} SpacewarMessage; /* Message Types: 0 - HELLO: Contents sent to client indicate a given player number. 1 - GOODBYE: No contents, end the connection. 2 - PING: Contents indicate the missed amount of pongs. 3 - PONG: No contents. + 4 - SECRET: Contents indicate the secret key that must be sent with UDP packets to the server. */ #endif diff --git a/source/Spacewar-Physics.h b/source/Spacewar-Physics.h index 4e0aac3..8745bec 100644 --- a/source/Spacewar-Physics.h +++ b/source/Spacewar-Physics.h @@ -5,9 +5,9 @@ // ========================================= #ifndef SPACEWAR_PHYSICS #define SPACEWAR_PHYSICS - #include #include "xyVector.h" +#include "Spacewar-Server.h" typedef struct SpacewarShipState { @@ -35,6 +35,9 @@ typedef struct SpacewarState // Does a single step of the physics: void doPhysicsTick(SpacewarState * state); +// Adds a new player to a physics simulation: +void addNewPlayer(SpacewarConnection * connection, SpacewarState * state); + #endif // ======================================================== // | End of Spacewar-Physics.h, copyright notice follows. | diff --git a/source/Spacewar-Server.c b/source/Spacewar-Server.c index f05a4a0..d3c629f 100644 --- a/source/Spacewar-Server.c +++ b/source/Spacewar-Server.c @@ -3,24 +3,39 @@ // | Copyright (C) 2023, Barra Ó Catháin | // | See end of file for copyright notice. | // ========================================= +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include "Spacewar-Physics.h" +#include "Spacewar-Messages.h" void * runServerPhysics(void * parameters) { - struct SpacewarState * state = (struct SpacewarState *)parameters; + SpacewarState * state = (SpacewarState *)parameters; while (true) { - doPhysicsTick(state); +// doPhysicsTick(state); usleep(15625); } } // 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: - struct SpacewarState * currentState = calloc(1, sizeof(struct SpacewarState)); + SpacewarState * currentState = calloc(1, sizeof(SpacewarState)); // Create our network listeners: int masterSocket = socket(AF_INET, SOCK_STREAM, 0); @@ -43,59 +58,62 @@ int runSpacewarServer(uint16_t port) 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(12000); + sendingAddress.sin_port = htons(serverConfig->port); // Create a structure to bind the listening socket: struct sockaddr_in listeningAddress; memset(&listeningAddress, 0, sizeof(listeningAddress)); listeningAddress.sin_family = AF_INET; // IPv4 listeningAddress.sin_addr.s_addr = INADDR_ANY; - listeningAddress.sin_port = port; + listeningAddress.sin_port = htons(serverConfig->port); // 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"); 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"); exit(EXIT_FAILURE); } - // Begin the simulation: - pthread_t physicsThread; - pthread_create(&physicsThread, NULL, runServerPhysics, currentState); - // Begin listening on the master socket: listen(masterSocket, 32); // 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: struct epoll_event requestedEvents; - requestedEvents.events = EPOLLIN; + requestedEvents.events = EPOLLIN | EPOLLET; requestedEvents.data.fd = masterSocket; 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: + SpacewarConnection connectedClients[32]; + + // Begin the simulation: + pthread_t physicsThread; + pthread_create(&physicsThread, NULL, runServerPhysics, currentState); // Manage clients and sending packets back and forth: while (true) { - receivedEventCount = epoll_wait(epollDescriptor, receivedEvents, 32, -1); - - for (int eventIndex = 0; eventIndex < receivedEventCount, eventIndex++) + int receivedEventCount = epoll_wait(epollDescriptor, receivedEvents, 32, -1); + for (int eventIndex = 0; eventIndex < receivedEventCount; eventIndex++) { // If there's activity on the master socket, there's a new connection: if (receivedEvents[eventIndex].data.fd == masterSocket) { struct sockaddr_in clientAddress; + socklen_t clientSocketLength = sizeof(struct sockaddr_in); int newClientSocket = accept(masterSocket, (struct sockaddr *)&clientAddress, - sizeof(struct sockaddr_in)); + &clientSocketLength); // Check that the socket is functional: if (newClientSocket < 0) @@ -105,19 +123,76 @@ int runSpacewarServer(uint16_t port) } // Register the new client in the epoll set: - requestedEvents.events = EPOLLIN; + requestedEvents.events = EPOLLIN | EPOLLET; requestedEvents.data.fd = newClientSocket; 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: 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; } // ======================================================= diff --git a/source/Spacewar-Server.h b/source/Spacewar-Server.h index 29ad545..4974d8d 100644 --- a/source/Spacewar-Server.h +++ b/source/Spacewar-Server.h @@ -5,17 +5,27 @@ // ========================================= #ifndef SPACEWAR_SERVER #define SPACEWAR_SERVER +#include +#include +#include +#include typedef struct SpacewarConnection { - uint8_t missedPongs; + bool active; int clientSocket; - int playerNumber; + uint8_t missedPongs; + uint32_t playerSecret; struct sockaddr_in clientAddress; } 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: -int runSpacewarServer(uint16_t port); +void * runSpacewarServer(void * configuration); #endif // =======================================================