diff --git a/src/gamelogic.c b/src/gamelogic.c index 698a917..b3ef2a4 100644 --- a/src/gamelogic.c +++ b/src/gamelogic.c @@ -43,28 +43,40 @@ void * gameLogicLoop(void * parameters) queueMessagedCommand(commandQueue, currentInput); } - else if (!(currentInput->sender->currentArea == getFromList(threadParameters->areaList, 0)->area)) + else if (!(currentInput->sender->currentArea == getFromList(threadParameters->areaList, 0)->area) && + currentInput->content->messageContent[0] != '\n') { + // Copy the correct name into the sender name field: strncpy(currentInput->content->senderName, currentInput->sender->playerName, 32); - // Create an array of players in the same area to receive the message: - playerInfo ** recipients = malloc(sizeof(playerInfo*) * *threadParameters->playerCount); - for(int index = 0; index < *threadParameters->playerCount; index++) + currentInput->content->senderName[31] = '\0'; + + // Allocate an array of playerInfo to store the current players in the area for the output message: + playerInfo ** recipients = malloc(sizeof(playerInfo*) * PLAYERCOUNT); + + // Initialize them all to NULL: + for (int index = 0; index < PLAYERCOUNT; index++) { recipients[index] = NULL; } - int recipientCount = 0; - for(int playerIndex = 0; playerIndex < *threadParameters->playerCount; playerIndex++) + + // Get the players in the current area and add them to our array: + int recipientIndex = 0; + for (int playerIndex = 0; playerIndex < *threadParameters->playerCount; playerIndex++) { - if(threadParameters->connectedPlayers[playerIndex].currentArea == currentInput->sender->currentArea) + if (threadParameters->connectedPlayers[playerIndex].currentArea == currentInput->sender->currentArea) { - recipients[recipientCount] = &threadParameters->connectedPlayers[playerIndex]; - recipientCount++; + recipients[recipientIndex] = &threadParameters->connectedPlayers[playerIndex]; + recipientIndex++; } } - if(currentInput->content->messageContent[0] != '\n') - { - queueTargetedOutputMessage(threadParameters->outputQueue, currentInput->content, recipients, recipientCount); - } + + // Create the outputMessage for the queue: + outputMessage * newOutputMessage = createTargetedOutputMessage(currentInput->content, recipients, recipientIndex); + + // Push the message onto the queue: + pushQueue(threadParameters->outputQueue, newOutputMessage, OUTPUT_MESSAGE); + + // Free the array; free(recipients); } currentInput = NULL; @@ -320,16 +332,31 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue) break; } } - queueTargetedOutputMessage(parameters->outputQueue, tryMessage, ¤tCommand->caller, 1); + + // Allocate an outputMessage for the queue: + outputMessage * tryOutputMessage = createTargetedOutputMessage(tryMessage, ¤tCommand->caller, 1); + + // Queue the outputMessage: + pushQueue(parameters->outputQueue, tryOutputMessage, OUTPUT_MESSAGE); + + // Free the userMessage: free(tryMessage); } // Exit command: Sends an "empty" exit message to disconnect a client: if(strncmp(currentCommand->command, "exit", 4) == 0) { + // Allocate a userMessage containing null characters as the first char in both fields: userMessage * exitMessage = malloc(sizeof(userMessage)); exitMessage->senderName[0] = '\0'; exitMessage->messageContent[0] = '\0'; - queueTargetedOutputMessage(parameters->outputQueue, exitMessage, ¤tCommand->caller, 1); + + // Allocate an outputMessage for the queue: + outputMessage * exitOutputMessage = createTargetedOutputMessage(exitMessage, ¤tCommand->caller, 1); + + // Queue the outputMessage: + pushQueue(parameters->outputQueue, exitOutputMessage, OUTPUT_MESSAGE); + + // Free the userMessage free(exitMessage); } @@ -362,7 +389,14 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue) strncat(lookMessage->messageContent, currentCommand->caller->currentArea->areaName, 33); strncat(lookMessage->messageContent, "\n", 2); strncat(lookMessage->messageContent, currentCommand->caller->currentArea->areaDescription, MAX - 35); - queueTargetedOutputMessage(parameters->outputQueue, lookMessage, ¤tCommand->caller, 1); + + // Allocate an outputMessage for the queue: + outputMessage * lookOutputMessage = createTargetedOutputMessage(lookMessage, ¤tCommand->caller, 1); + + // Queue the outputMessage: + pushQueue(parameters->outputQueue, lookOutputMessage, OUTPUT_MESSAGE); + + //queueTargetedOutputMessage(parameters->outputQueue, lookMessage, ¤tCommand->caller, 1); bzero(lookMessage, sizeof(userMessage)); // Loop through the paths and send the appropriate amount of messages: @@ -375,7 +409,11 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue) { if((charCount + 64) >= MAX) { - queueTargetedOutputMessage(parameters->outputQueue, lookMessage, ¤tCommand->caller, 1); + lookOutputMessage = createTargetedOutputMessage(lookMessage, ¤tCommand->caller, 1); + + // Queue the outputMessage: + pushQueue(parameters->outputQueue, lookOutputMessage, OUTPUT_MESSAGE); + bzero(lookMessage, sizeof(userMessage)); charCount = 0; } @@ -384,7 +422,11 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue) strncat(lookMessage->messageContent, formattedString, 64); charCount += 64; } - queueTargetedOutputMessage(parameters->outputQueue, lookMessage, ¤tCommand->caller, 1); + // Allocate another outputMessage for the queue: + lookOutputMessage = createTargetedOutputMessage(lookMessage, ¤tCommand->caller, 1); + + // Queue the outputMessage: + pushQueue(parameters->outputQueue, lookOutputMessage, OUTPUT_MESSAGE); } free(lookMessage); } @@ -423,14 +465,6 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue) { // TODO: Implement. } - if(strncmp(currentCommand->command, "skillissue", 10) == 0) - { - userMessage * statMessage = calloc(1, sizeof(userMessage)); - statMessage->senderName[0] = '\0'; - strcpy(statMessage->messageContent, "Have you tried getting good?"); - queueTargetedOutputMessage(parameters->outputQueue, statMessage, ¤tCommand->caller, 1); - free(statMessage); - } // Stat command: Displays the current character's sheet. if(strncmp(currentCommand->command, "stat", 4) == 0) { @@ -462,8 +496,13 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue) snprintf(formattedString, 120, "Current Experience: %ld", currentCommand->caller->stats->experience); } strncat(statMessage->messageContent, formattedString, 120); + + // Allocate an outputMessage for the queue: + outputMessage * statOutputMessage = createTargetedOutputMessage(statMessage, ¤tCommand->caller, 1); + + // Queue the outputMessage: + pushQueue(parameters->outputQueue, statOutputMessage, OUTPUT_MESSAGE); - queueTargetedOutputMessage(parameters->outputQueue, statMessage, ¤tCommand->caller, 1); bzero(statMessage->messageContent, sizeof(char) * MAX); if(currentCommand->caller->skills->head != NULL) { @@ -480,8 +519,11 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue) strncat(statMessage->messageContent, formattedString, 120); if((charCount + 43) >= MAX) { -// strncat(statMessage->messageContent, "\n", 2); - queueTargetedOutputMessage(parameters->outputQueue, statMessage, ¤tCommand->caller, 1); + // Allocate an outputMessage for the queue: + statOutputMessage = createTargetedOutputMessage(statMessage, ¤tCommand->caller, 1); + + // Queue the outputMessage: + pushQueue(parameters->outputQueue, statOutputMessage, OUTPUT_MESSAGE); bzero(statMessage, sizeof(userMessage)); charCount = 0; break; @@ -497,7 +539,11 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue) addNewline = true; } } - queueTargetedOutputMessage(parameters->outputQueue, statMessage, ¤tCommand->caller, 1); + // Allocate an outputMessage for the queue: + statOutputMessage = createTargetedOutputMessage(statMessage, ¤tCommand->caller, 1); + + // Queue the outputMessage: + pushQueue(parameters->outputQueue, statOutputMessage, OUTPUT_MESSAGE); } free(statMessage); free(formattedString); @@ -570,8 +616,11 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue) strncat(specMessage->messageContent, "You have no spec points available.", 35); } - // Send the message: - queueTargetedOutputMessage(parameters->outputQueue, specMessage, ¤tCommand->caller, 1); + // Allocate an outputMessage for the queue: + outputMessage * specOutputMessage = createTargetedOutputMessage(specMessage, ¤tCommand->caller, 1); + + // Queue the outputMessage: + pushQueue(parameters->outputQueue, specOutputMessage, OUTPUT_MESSAGE); // Show the new stat sheet: queue->lock = false; @@ -611,7 +660,13 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue) { strcpy(skillMessage->messageContent, "You don't have enough skill points to take this skill.\n"); } - queueTargetedOutputMessage(parameters->outputQueue, skillMessage, ¤tCommand->caller, 1); + + // Allocate an outputMessage for the queue: + outputMessage * skillOutputMessage = createTargetedOutputMessage(skillMessage, ¤tCommand->caller, 1); + + // Queue the outputMessage: + pushQueue(parameters->outputQueue, skillOutputMessage, OUTPUT_MESSAGE); + free(skillMessage); } if(strncmp(currentCommand->command, "listskills", 10) == 0) @@ -630,7 +685,12 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue) strncat(listMessage->messageContent, formattedString, 120); if((charCount + 46) >= MAX) { - queueTargetedOutputMessage(parameters->outputQueue, listMessage, ¤tCommand->caller, 1); + // Allocate an outputMessage for the queue: + outputMessage * listOutputMessage = createTargetedOutputMessage(listMessage, ¤tCommand->caller, 1); + + // Queue the outputMessage: + pushQueue(parameters->outputQueue, listOutputMessage, OUTPUT_MESSAGE); + bzero(listMessage, sizeof(userMessage)); charCount = 0; addNewline = false; @@ -647,7 +707,11 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue) } skillIndex++; } - queueTargetedOutputMessage(parameters->outputQueue, listMessage, ¤tCommand->caller, 1); + // Allocate an outputMessage for the queue: + outputMessage * listOutputMessage = createTargetedOutputMessage(listMessage, ¤tCommand->caller, 1); + + // Queue the outputMessage: + pushQueue(parameters->outputQueue, listOutputMessage, OUTPUT_MESSAGE); free(listMessage); free(formattedString); } diff --git a/src/gamelogic.h b/src/gamelogic.h index e1da35c..97d7d76 100644 --- a/src/gamelogic.h +++ b/src/gamelogic.h @@ -18,11 +18,16 @@ typedef struct queue queue; // A data-structure containing the needed parameters for a main game loop: typedef struct gameLogicParameters { + // Players: int * playerCount; - list * areaList; playerInfo * connectedPlayers; + + // Queues: queue * inputQueue; - outputMessageQueue * outputQueue; + queue * outputQueue; + + // Lists: + list * areaList; list * globalSkillList; } gameLogicParameters; diff --git a/src/inputoutput.c b/src/inputoutput.c index b780ae4..93912d6 100644 --- a/src/inputoutput.c +++ b/src/inputoutput.c @@ -46,170 +46,22 @@ int messageReceive(gnutls_session_t receiveFromSession, userMessage * receiveToM return returnValue; } -outputMessageQueue * createOutputMessageQueue(void) +outputMessage * createTargetedOutputMessage(userMessage * messageToQueue, playerInfo ** recipients, int recipientsCount) { - outputMessageQueue * newQueue = malloc(sizeof(outputMessageQueue)); - newQueue->front = NULL; - newQueue->back = NULL; - newQueue->currentLength = 0; - newQueue->lock = false; - return newQueue; -} - -int queueOutputMessage(outputMessageQueue * queue, userMessage messageToQueue) -{ - // Copy the message into a new output message: + // Allocate a new output message: outputMessage * newOutputMessage = malloc(sizeof(outputMessage)); - - // Allocate the internal userMessage to store the message: - newOutputMessage->content = malloc(sizeof(userMessage)); - - // Copy the userMessage to the internal userMessage: - strncpy(newOutputMessage->content->senderName, messageToQueue.senderName, 32); - strncpy(newOutputMessage->content->messageContent, messageToQueue.messageContent, MAX); - - // We have no targets, NULL sends to all players in an area: - newOutputMessage->targets[0] = NULL; - - // Wait for the queue to unlock: - while (queue->lock); - - // Lock the queue: - queue->lock = true; - - // Check that we're not overflowing the queue: - if ((queue->currentLength + 1) > MAXQUEUELENGTH) - { - // Unlock the queue: - queue->lock = false; - return -1; - } - else - { - // If the queue is empty, set the first message as both the front and back of the queue: - if(queue->front == NULL) - { - queue->front = newOutputMessage; - queue->back = newOutputMessage; - queue->currentLength++; - - // Unlock the queue: - queue->lock = false; - return 0; - } - else - { - queue->back->next = newOutputMessage; - queue->back = newOutputMessage; - queue->currentLength++; - - // Unlock the queue: - queue->lock = false; - return 0; - } - } -} - -int queueTargetedOutputMessage(outputMessageQueue * queue, - userMessage * messageToQueue, playerInfo ** targets, int numberOfTargets) -{ - // Copy the message into a new output message: - outputMessage * newOutputMessage = malloc(sizeof(outputMessage)); - - // Allocate the internal userMessage to store the message: newOutputMessage->content = malloc(sizeof(userMessage)); - // Set the appropriate recipients: - for(int index = 0; index < numberOfTargets && index < PLAYERCOUNT; index++) - { - newOutputMessage->targets[index] = targets[index]; - } - for(int index = numberOfTargets; index < PLAYERCOUNT; index++) - { - newOutputMessage->targets[index] = NULL; - } - - // Copy the userMessage to the internal userMessage: - strncpy(newOutputMessage->content->senderName, messageToQueue->senderName, 32); - strncpy(newOutputMessage->content->messageContent, messageToQueue->messageContent, MAX); - - // Wait for the queue to unlock: - while (queue->lock); + // Allocate an array of playerInfo for the output message recepients: + newOutputMessage->recipients = malloc(sizeof(playerInfo*) * recipientsCount); - // Lock the queue: - queue->lock = true; + // Copy in the appropriate data: + memcpy(newOutputMessage->recipients, recipients, sizeof(playerInfo *) * recipientsCount); + memcpy(newOutputMessage->content, messageToQueue, sizeof(userMessage)); + newOutputMessage->recipientsCount = recipientsCount; - // Check that we're not overflowing the queue: - if ((queue->currentLength + 1) > MAXQUEUELENGTH) - { - // Unlock the queue: - queue->lock = false; - return -1; - } - else - { - // If the queue is empty, set the first message as both the front and back of the queue: - if(queue->front == NULL) - { - queue->front = newOutputMessage; - queue->back = newOutputMessage; - queue->currentLength++; - - // Unlock the queue: - queue->lock = false; - return 0; - } - else - { - queue->back->next = newOutputMessage; - queue->back = newOutputMessage; - queue->currentLength++; - - // Unlock the queue: - queue->lock = false; - return 0; - } - } -} - -int dequeueOutputMessage(outputMessageQueue * queue) -{ - // Wait for the queue to unlock: - while (queue->lock); - - // Lock the queue: - queue->lock = true; - - // Check the list isn't empty: - if(queue->front == NULL) - { - queue->lock = false; - return -1; - } - - // If there is only one item in the queue: - else if(queue->front == queue->back) - { - free(queue->front->content); - free(queue->front); - queue->front = NULL; - queue->back = NULL; - queue->currentLength--; - queue->lock = false; - return 0; - } - - // Remove the front item: - else - { - outputMessage * messageToDelete = queue->front; - queue->front = queue->front->next; - free(messageToDelete->content); - free(messageToDelete); - queue->currentLength--; - queue->lock = false; - return 0; - } + // Return a pointer to the new outputMessage: + return newOutputMessage; } void userInputSanatize(char * inputString, int length) @@ -238,8 +90,3 @@ void userNameSanatize(char * inputString, int length) } inputString[length - 1] = '\0'; } - -outputMessage * peekOutputMessage(outputMessageQueue * queue) -{ - return queue->front; -} diff --git a/src/inputoutput.h b/src/inputoutput.h index 1fea866..72ad893 100644 --- a/src/inputoutput.h +++ b/src/inputoutput.h @@ -33,33 +33,13 @@ int messageReceive(gnutls_session_t receiveFromSession, userMessage * receiveToM typedef struct outputMessage outputMessage; typedef struct outputMessage { - outputMessage * next; - playerInfo * targets[PLAYERCOUNT]; + int recipientsCount; userMessage * content; + playerInfo ** recipients; } outputMessage; -// A first-in first-out queue for message output to players: -typedef struct outputMessageQueue -{ - bool lock; - int currentLength; - outputMessage * back; - outputMessage * front; -} outputMessageQueue; - -// Creates and initializes a outputMessageQueue: -outputMessageQueue * createOutputMessageQueue(void); - -// Enqueue a userMessage to an outputMessageQueue: -int queueOutputMessage(outputMessageQueue * queue, userMessage messageToQueue); -int queueTargetedOutputMessage(outputMessageQueue * queue, userMessage * messageToQueue, - playerInfo ** targets, int numberOfTargets); - -// Dequeue the front outputMessage from an outputMessageQueue: -int dequeueOutputMessage(outputMessageQueue * queue); - -// Return the front outputMessage from an outputMessageQueue: -outputMessage * peekOutputMessage(outputMessageQueue * queue); +// Create a targetedOutput message to be delivered to the players pointed to in recipients: +outputMessage * createTargetedOutputMessage(userMessage * messageToQueue, playerInfo ** recipients, int recipientCount); // ================== // -=[Input Queue]=-: diff --git a/src/queue.c b/src/queue.c index df83496..22fc1bf 100644 --- a/src/queue.c +++ b/src/queue.c @@ -151,7 +151,7 @@ void pushQueue(queue * queue, void * data, queueDataType type) { // Create a new node: queueNode * newNode = malloc(sizeof(queueNode)); - + newNode->type = type; // Copy the data into the correct slot for the type: switch (type) { diff --git a/src/server/SilverMUDServer.c b/src/server/SilverMUDServer.c index 2b9613c..adf6a60 100644 --- a/src/server/SilverMUDServer.c +++ b/src/server/SilverMUDServer.c @@ -46,8 +46,7 @@ int main(int argc, char ** argv) playerInfo connectedPlayers[PLAYERCOUNT]; char testString[32] = "Hehe."; struct sockaddr_in serverAddress, clientAddress; - queue * inputQueue = createQueue(); - outputMessageQueue * outputQueue = createOutputMessageQueue(); + queue * inputQueue = createQueue(), * outputQueue = createQueue(); // Parse command-line options: int currentopt = 0; @@ -343,38 +342,47 @@ int main(int argc, char ** argv) } // Run through the output queue and send all unused messages: - while(outputQueue->currentLength != 0) + while(outputQueue->itemCount != 0) { + // Wait until the queue unlocks: while(outputQueue->lock); + + // Lock the queue: outputQueue->lock = true; - outputMessage * message = peekOutputMessage(outputQueue); + + // Get a message off the queue: + outputMessage * message = peekQueue(outputQueue)->data.outputMessage; + + // Unlock the queue: outputQueue->lock = false; // If the first target is set to NULL, it's intended for all connected: - if(message->targets[0] == NULL) + if(message->recipientsCount == 0) { for (int index = 0; index < PLAYERCOUNT; index++) { messageSend(tlssessions[index], message->content); } } + // Otherwise, send it only to the targeted players: else { int targetIndex = 0; for(int index = 0; index < PLAYERCOUNT; index++) { - if(message->targets[targetIndex] == NULL) + if(targetIndex == message->recipientsCount) { break; } - if(&connectedPlayers[index] == message->targets[targetIndex]) + if(&connectedPlayers[index] == message->recipients[targetIndex]) { targetIndex++; messageSend(tlssessions[index], message->content); } } } - dequeueOutputMessage(outputQueue); + // Remove the output message from the queue: + popQueue(outputQueue); } } pthread_cancel(gameLogicThread);