From 241ac7a92b6a335d780486f3c23a3b8385e3d408 Mon Sep 17 00:00:00 2001 From: Barry Date: Thu, 4 Nov 2021 23:14:47 +0000 Subject: [PATCH] Added area and path creation functions - Added missing header guards. - Increased the size of message contents to 2048. - Added area and path initialization functions. - movePlayerToArea no longer segfaults. - /LOOK added to allow players to find exits. - Amount of paths allowed out of an area has been decreased to 16. - Debug builds are now available from the Makefile. - Removed unused variables. - Input sanatization has been moved to the server-side, phew. - Server messages are now displayed differently to player messages. - New area initialization has been added until I can integrate Guile. - Server's sendBuffer has been renamed messageBuffer. - Areas now have descriptions. - Descriptions are sent to the player upon joining an area and /LOOK-ing. --- Makefile | 15 ++++-- src/SilverMUDClient.c | 25 ++++++--- src/SilverMUDServer.c | 108 ++++++++++++++++++++++++++------------- src/misc/inputhandling.c | 2 + src/misc/playerdata.c | 69 ++++++++++++++++++++++--- src/misc/playerdata.h | 18 +++++-- 6 files changed, 181 insertions(+), 56 deletions(-) diff --git a/Makefile b/Makefile index 0bccd36..3d4b140 100644 --- a/Makefile +++ b/Makefile @@ -8,13 +8,22 @@ serverobj = $(serversrc:.c=.o) CLIENTLDFLAGS= -lpthread -lncurses SERVERLDFLAGS= -lncurses SilverMUDClient: $(clientobj) - gcc -o $@ $^ $(CLIENTLDFLAGS) + gcc -s -O3 -o $@ $^ $(CLIENTLDFLAGS) SilverMUDServer: $(serverobj) - gcc -o $@ $^ $(SERVERLDFLAGS) + gcc -s -O3 -o $@ $^ $(SERVERLDFLAGS) + +SilverMUDClientDebug: $(clientobj) + gcc -ggdb -Wall $^ $(CLIENTLDFLAGS) -o $@ + +SilverMUDServerDebug: $(serverobj) + gcc -ggdb -Wall $^ $(SERVERLDFLAGS) -o $@ .PHONY: clean clean: - rm -f $(clientobj) $(serverobj) SilverMUDClient SilverMUDServer + rm -f $(clientobj) $(serverobj) SilverMUDClient SilverMUDServer SilverMUDClientDebug SilverMUDServerDebug all: SilverMUDClient SilverMUDServer + +debug: CFLAGS += -Wall -ggdb +debug: SilverMUDClientDebug SilverMUDServerDebug diff --git a/src/SilverMUDClient.c b/src/SilverMUDClient.c index f64bb66..0e1e197 100644 --- a/src/SilverMUDClient.c +++ b/src/SilverMUDClient.c @@ -12,7 +12,7 @@ #include "misc/playerdata.h" #include "misc/texteffects.h" #include "misc/inputhandling.h" -#define MAX 1024 +#define MAX 2048 #define PORT 5000 #define SA struct sockaddr @@ -36,7 +36,6 @@ void * messageSender(void * parameters) // Takes user input in a window, sanatizes it, and sends it to the server: struct threadparameters *threadParameters = parameters; char sendBuffer[MAX]; - int characterindex; while (!shouldExit) { @@ -47,7 +46,6 @@ void * messageSender(void * parameters) // Quit if there's any funny business with getting input: pthread_exit(NULL); } - userInputSanatize(sendBuffer, MAX); if(sendBuffer[0] == '\n') { continue; @@ -67,9 +65,20 @@ void * messageReceiver(void * parameters) { read(threadParameters->socketDescriptor, &receiveBuffer.senderName, sizeof(receiveBuffer.senderName)); read(threadParameters->socketDescriptor, &receiveBuffer.messageContent, sizeof(receiveBuffer.messageContent)); - slowPrintNcurses(receiveBuffer.senderName, 8000, threadParameters->window); - slowPrintNcurses(": ", 8000, threadParameters->window); - slowPrintNcurses(receiveBuffer.messageContent, 8000, threadParameters->window); + + if(receiveBuffer.senderName[0] == '\0') + { + slowPrintNcurses("\n --====<>====-- \n", 8000, threadParameters->window); + slowPrintNcurses(receiveBuffer.messageContent, 8000, threadParameters->window); + slowPrintNcurses("\n --====<>====-- \n", 8000, threadParameters->window); + } + else + { + slowPrintNcurses(receiveBuffer.senderName, 8000, threadParameters->window); + slowPrintNcurses(": ", 8000, threadParameters->window); + slowPrintNcurses(receiveBuffer.messageContent, 8000, threadParameters->window); + } + bzero(receiveBuffer.senderName, sizeof(receiveBuffer.senderName)); bzero(receiveBuffer.messageContent, sizeof(receiveBuffer.messageContent)); } @@ -78,8 +87,8 @@ void * messageReceiver(void * parameters) int main(int argc, char **argv) { - int sockfd, connfd; - struct sockaddr_in servaddr, cli; + int sockfd; + struct sockaddr_in servaddr; pthread_t sendingThread; pthread_t receivingThread; diff --git a/src/SilverMUDServer.c b/src/SilverMUDServer.c index 86cf7bb..f6b1dd5 100644 --- a/src/SilverMUDServer.c +++ b/src/SilverMUDServer.c @@ -14,39 +14,35 @@ #include #include "misc/playerdata.h" #include "misc/texteffects.h" +#include "misc/inputhandling.h" const int PORT = 5000; -const int MAX = 1024; typedef struct sockaddr sockaddr; int main() -{ +{ int socketFileDesc, connectionFileDesc, length, clientsAmount, socketCheck, activityCheck, readLength; int clientSockets[64]; int maxClients = 64; - userMessage sendBuffer; - playerArea areaA, areaB; - playerPath pathA, pathB; - char receiveBuffer[MAX]; + userMessage messageBuffer; + char receiveBuffer[2048]; fd_set connectedClients; + playerArea * areaA, * areaB, * areaC; playerInfo connectedPlayers[64]; struct sockaddr_in serverAddress, clientAddress; - // Initialize areas: - strncpy(areaA.areaName, "Spawn - North", 32); - strncpy(areaB.areaName, "Spawn - South", 32); - strncpy(pathA.pathName, "To South Spawn", 32); - strncpy(pathB.pathName, "To North Spawn", 32); - pathA.areaToJoin = &areaB; - pathB.areaToJoin = &areaA; - areaA.areaExits[0] = &pathA; - areaB.areaExits[0] = &pathB; + // Initialize areas: + areaA = createArea("Spawn - North", "A large area, mostly empty, as if the designer hadn't bothered to put anything in it, just yet."); + areaB = createArea("Spawn - South", "A strange, white void. You feel rather uncomfortable."); + areaC = createArea("Temple of Emacs", "A beautifully ornate statue of GNU is above you on a pedestal. Inscribed into the pillar, over and over, is the phrase \"M-x exalt\", in delicate gold letters. You can't help but be awestruck."); + createPath(areaA, areaB, "To South Spawn", "To North Spawn"); + createPath(areaC, areaB, "Back to South Spawn", "Path to Enlightenment."); - // Initialize playerdata: - for (int index = 0; index < maxClients; index++) + // Initialize playerdata: + for (int index = 0; index < maxClients; index++) { strcpy(connectedPlayers[index].playerName, "UNNAMED"); - connectedPlayers[index].currentArea = &areaA; + connectedPlayers[index].currentArea = areaA; } // Give an intro: Display the Silverkin Industries logo and splash text. @@ -96,7 +92,7 @@ int main() perror("Server listening is \033[33;40mRED.\033[0m Aborting launch.\n"); exit(0); } - else + else { slowPrint(" Server listening is \033[32;40mGREEN.\033[0m\n", 5000); } @@ -130,7 +126,7 @@ int main() activityCheck = select((clientsAmount + 1), &connectedClients, NULL, NULL, NULL); // Check if select() worked: - if ((activityCheck < 0) && (errno != EINTR)) + if ((activityCheck < 0) && (errno != EINTR)) { perror("Error in select(), retrying.\n"); } @@ -139,7 +135,7 @@ int main() if (FD_ISSET(socketFileDesc, &connectedClients)) { if ((connectionFileDesc = accept(socketFileDesc, - (struct sockaddr *)&clientAddress, (socklen_t*)&length))<0) + (struct sockaddr *)&clientAddress, (socklen_t*)&length))<0) { perror("Failed to accept connection. Aborting.\n"); exit(EXIT_FAILURE); @@ -147,8 +143,8 @@ int main() // Print new connection details: printf("Client connected: Socket file descriptor: #%d, IP address: %s, Port: %d.\n", - connectionFileDesc, inet_ntoa(clientAddress.sin_addr) , ntohs - (clientAddress.sin_port)); + connectionFileDesc, inet_ntoa(clientAddress.sin_addr) , ntohs + (clientAddress.sin_port)); // See if we can put in the client: for (int i = 0; i < maxClients; i++) @@ -174,17 +170,18 @@ int main() //Check if it was for closing, and also read the incoming message explicit_bzero(receiveBuffer, sizeof(receiveBuffer)); readLength = read(socketCheck, receiveBuffer, sizeof(receiveBuffer)); + userInputSanatize(receiveBuffer, 2048); if (readLength == 0) { // Somebody disconnected , get his details and print: getpeername(socketCheck, (struct sockaddr*)&clientAddress, (socklen_t*)&length); printf("Client disconnected: IP Address: %s, Port: %d.\n", - inet_ntoa(clientAddress.sin_addr) , ntohs(clientAddress.sin_port)); + inet_ntoa(clientAddress.sin_addr) , ntohs(clientAddress.sin_port)); // Close the socket and mark as 0 in list for reuse: close(socketCheck); - clientSockets[i] = 0; - } + clientSockets[i] = 0; + } // Name change command: Move logic to a command interpreter later: else if (receiveBuffer[0] == '/') { @@ -207,12 +204,33 @@ int main() break; } } - strncpy(connectedPlayers[i].playerName, newName, 32); + if(newName[0] != '\0') + { + strncpy(connectedPlayers[i].playerName, newName, 32); + } } - else if(strncmp(receiveBuffer, "/MOVE", 5) == 0) + else if(strncmp(receiveBuffer, "/LOOK", 5) == 0) + { + strcat(messageBuffer.messageContent, connectedPlayers[i].currentArea->areaDescription); + strcat(messageBuffer.messageContent, "\nYou see:"); + for(int index = 0; index < 16; index++) + { + if(connectedPlayers[i].currentArea->areaExits[index] != NULL) + { + strcat(messageBuffer.messageContent, "\n - "); + strcat(messageBuffer.messageContent, connectedPlayers[i].currentArea->areaExits[index]->pathName); + } + } + write(socketCheck, messageBuffer.senderName, sizeof(messageBuffer.senderName)); + write(socketCheck, messageBuffer.messageContent, sizeof(messageBuffer.messageContent)); + bzero(messageBuffer.senderName, sizeof(messageBuffer.senderName)); + bzero(messageBuffer.messageContent, sizeof(messageBuffer.messageContent)); + } + else if(strncmp(receiveBuffer, "/MOVE", 5) == 0) { char requestedPath[32]; strncpy(requestedPath, &receiveBuffer[6], 32); + userInputSanatize(requestedPath, 32); // Remove newlines: for (int index = 0; index < 32; index++) { @@ -221,26 +239,46 @@ int main() requestedPath[index] = '\0'; } } - movePlayerToArea(&connectedPlayers[i], requestedPath); + requestedPath[31] = '\0'; + if(movePlayerToArea(&connectedPlayers[i], requestedPath) == 0) + { + strcpy(messageBuffer.senderName, "\0"); + strcpy(messageBuffer.messageContent, connectedPlayers[i].currentArea->areaDescription); + write(socketCheck, messageBuffer.senderName, sizeof(messageBuffer.senderName)); + write(socketCheck, messageBuffer.messageContent, sizeof(messageBuffer.messageContent)); + } + else + { + strcpy(messageBuffer.senderName, ""); + strcpy(messageBuffer.messageContent, "You can't go somewhere that doesn't exist!"); + write(socketCheck, messageBuffer.senderName, sizeof(messageBuffer.senderName)); + write(socketCheck, messageBuffer.messageContent, sizeof(messageBuffer.messageContent)); + bzero(messageBuffer.senderName, sizeof(messageBuffer.senderName)); + bzero(messageBuffer.messageContent, sizeof(messageBuffer.messageContent)); + } } } // Echo back the message that came in: + else if (receiveBuffer[0] == '\n') + { + continue; + } else { printf("%d/%s/%s: %s", clientSockets[i], connectedPlayers[i].currentArea->areaName, connectedPlayers[i].playerName, receiveBuffer); fflush(stdout); - strcpy(sendBuffer.senderName, connectedPlayers[i].playerName); - strcpy(sendBuffer.messageContent, receiveBuffer); + strcpy(messageBuffer.senderName, connectedPlayers[i].playerName); + strcpy(messageBuffer.messageContent, receiveBuffer); for (int sendIndex = 0; sendIndex < clientsAmount; sendIndex++) { if(clientSockets[sendIndex] != STDIN_FILENO && (connectedPlayers[i].currentArea == connectedPlayers[sendIndex].currentArea)) { - write(clientSockets[sendIndex], sendBuffer.senderName, sizeof(sendBuffer.senderName)); - write(clientSockets[sendIndex], sendBuffer.messageContent, sizeof(sendBuffer.messageContent)); + write(clientSockets[sendIndex], messageBuffer.senderName, sizeof(messageBuffer.senderName)); + write(clientSockets[sendIndex], messageBuffer.messageContent, sizeof(messageBuffer.messageContent)); } } - bzero(sendBuffer.senderName, sizeof(sendBuffer.senderName)); - bzero(sendBuffer.messageContent, sizeof(sendBuffer.messageContent)); + bzero(messageBuffer.senderName, sizeof(messageBuffer.senderName)); + bzero(messageBuffer.messageContent, sizeof(messageBuffer.messageContent)); } } } diff --git a/src/misc/inputhandling.c b/src/misc/inputhandling.c index 0f4824b..a90315a 100644 --- a/src/misc/inputhandling.c +++ b/src/misc/inputhandling.c @@ -13,4 +13,6 @@ void userInputSanatize(char * inputString, int length) break; } } + inputString[length - 1] = '\0'; } + diff --git a/src/misc/playerdata.c b/src/misc/playerdata.c index b8279ad..e2f5d88 100644 --- a/src/misc/playerdata.c +++ b/src/misc/playerdata.c @@ -1,19 +1,74 @@ // playerdata.c: Contains functions definitions for working with player data. // Barry Kane, 2021 +#include #include +#include #include "playerdata.h" -// Move a player to a different area given a path in the area. +// Move a player to a different area given a path in the area: int movePlayerToArea(playerInfo * player, char * requestedPath) { - for (int index = 0; index < 32; index++) - { - if(strncmp(player->currentArea->areaExits[index]->pathName, requestedPath, 32) == 0) + for (int index = 0; index < 16; index++) + { + if(player->currentArea->areaExits[index] != NULL) { - player->currentArea = player->currentArea->areaExits[index]->areaToJoin; - return 0; - } + if(strncmp(player->currentArea->areaExits[index]->pathName, requestedPath, 32) == 0) + { + printf("%s: %s\n", player->playerName, player->currentArea->areaExits[index]->pathName); + player->currentArea = player->currentArea->areaExits[index]->areaToJoin; + return 0; + } + } } return 1; } +// Create an area given a name and description: +playerArea * createArea(char * nameString, char * descriptionString) +{ + playerArea * createdArea = calloc(1, sizeof(playerArea)); + strncpy(createdArea->areaName, nameString, 32); + strncpy(createdArea->areaDescription, descriptionString, 256); + for(int index = 0; index < 16; index++) + { + createdArea->areaExits[index] = NULL; + } + return createdArea; +} + +// Create a path between two areas given two areas and two strings: +int createPath(playerArea * fromArea, playerArea * toArea, char * fromDescription, char * toDescription) +{ + int fromAreaSlot, toAreaSlot; + for(fromAreaSlot = 0; fromAreaSlot < 16; fromAreaSlot++) + { + if(fromArea->areaExits[fromAreaSlot] == NULL) + { + break; + } + if((fromArea->areaExits[fromAreaSlot] != NULL) && (fromAreaSlot == 15)) + { + return 1; + } + } + for(toAreaSlot = 0; toAreaSlot < 32; toAreaSlot++) + { + if(toArea->areaExits[toAreaSlot] == 0) + { + break; + } + if((toArea->areaExits[toAreaSlot] != 0) && (toAreaSlot == 31)) + { + return 2; + } + } + playerPath * fromPath = calloc(1, sizeof(playerPath)); + playerPath * toPath = calloc(1, sizeof(playerPath)); + fromArea->areaExits[fromAreaSlot] = fromPath; + toArea->areaExits[toAreaSlot] = toPath; + strncpy(fromArea->areaExits[fromAreaSlot]->pathName, fromDescription, 32); + strncpy(toArea->areaExits[toAreaSlot]->pathName, toDescription, 32); + fromArea->areaExits[fromAreaSlot]->areaToJoin = toArea; + toArea->areaExits[toAreaSlot]->areaToJoin = fromArea; +} + diff --git a/src/misc/playerdata.h b/src/misc/playerdata.h index b986f53..1c13f2f 100644 --- a/src/misc/playerdata.h +++ b/src/misc/playerdata.h @@ -1,11 +1,14 @@ // playerdata.h: Header file containing data structures for player data and function // definitions for interacting with said data. // Barry Kane, 2021. +#ifndef PLAYERDATA_H +#define PLAYERDATA_H +#include typedef struct userMessage { char senderName[32]; - char messageContent[1024]; + char messageContent[2048]; } userMessage; @@ -21,7 +24,8 @@ struct playerPath struct playerArea { char areaName[32]; - playerPath * areaExits[32]; + char areaDescription[256]; + playerPath * areaExits[16]; }; typedef struct playerInfo @@ -30,5 +34,13 @@ typedef struct playerInfo playerArea * currentArea; } playerInfo; -// Move a player to a different area given a path in the area. +// Move a player to a different area given a path in the area: int movePlayerToArea(playerInfo * player, char * requestedPath); + +// Create an area given a name and description: +playerArea * createArea(char * nameString, char * descriptionString); + +// Create a path between two areas given two areas and a string: +int createPath(playerArea * fromArea, playerArea * toArea, char * pathFromString, char * pathToString); + +#endif