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.
This commit is contained in:
parent
85a31a2933
commit
241ac7a92b
15
Makefile
15
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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -14,39 +14,35 @@
|
|||
#include <netinet/in.h>
|
||||
#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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,4 +13,6 @@ void userInputSanatize(char * inputString, int length)
|
|||
break;
|
||||
}
|
||||
}
|
||||
inputString[length - 1] = '\0';
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +1,74 @@
|
|||
// playerdata.c: Contains functions definitions for working with player data.
|
||||
// Barry Kane, 2021
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <stdlib.h>
|
||||
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue