Refactored the outputQueue to use the new queue type

- Patched a bug where I didn't set the correct type for queue nodes.
- Removed all traces of the previous outputMessageQueue type.
- Removed the pointer "next" in outputMessage.
- Rewrote the the main thread and game logic thread to use a queue for output.
- Refactored outputMessage to allow for a variable amount of playerInfo pointers.
This commit is contained in:
Barry Kane 2022-12-20 15:55:24 +00:00
parent 9b3df5928b
commit 15d82f59ee
6 changed files with 137 additions and 233 deletions

View File

@ -43,28 +43,40 @@ void * gameLogicLoop(void * parameters)
queueMessagedCommand(commandQueue, currentInput); 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); strncpy(currentInput->content->senderName, currentInput->sender->playerName, 32);
// Create an array of players in the same area to receive the message: currentInput->content->senderName[31] = '\0';
playerInfo ** recipients = malloc(sizeof(playerInfo*) * *threadParameters->playerCount);
for(int index = 0; index < *threadParameters->playerCount; index++) // 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; 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]; recipients[recipientIndex] = &threadParameters->connectedPlayers[playerIndex];
recipientCount++; recipientIndex++;
} }
} }
if(currentInput->content->messageContent[0] != '\n')
{ // Create the outputMessage for the queue:
queueTargetedOutputMessage(threadParameters->outputQueue, currentInput->content, recipients, recipientCount); outputMessage * newOutputMessage = createTargetedOutputMessage(currentInput->content, recipients, recipientIndex);
}
// Push the message onto the queue:
pushQueue(threadParameters->outputQueue, newOutputMessage, OUTPUT_MESSAGE);
// Free the array;
free(recipients); free(recipients);
} }
currentInput = NULL; currentInput = NULL;
@ -320,16 +332,31 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue)
break; break;
} }
} }
queueTargetedOutputMessage(parameters->outputQueue, tryMessage, &currentCommand->caller, 1);
// Allocate an outputMessage for the queue:
outputMessage * tryOutputMessage = createTargetedOutputMessage(tryMessage, &currentCommand->caller, 1);
// Queue the outputMessage:
pushQueue(parameters->outputQueue, tryOutputMessage, OUTPUT_MESSAGE);
// Free the userMessage:
free(tryMessage); free(tryMessage);
} }
// Exit command: Sends an "empty" exit message to disconnect a client: // Exit command: Sends an "empty" exit message to disconnect a client:
if(strncmp(currentCommand->command, "exit", 4) == 0) 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)); userMessage * exitMessage = malloc(sizeof(userMessage));
exitMessage->senderName[0] = '\0'; exitMessage->senderName[0] = '\0';
exitMessage->messageContent[0] = '\0'; exitMessage->messageContent[0] = '\0';
queueTargetedOutputMessage(parameters->outputQueue, exitMessage, &currentCommand->caller, 1);
// Allocate an outputMessage for the queue:
outputMessage * exitOutputMessage = createTargetedOutputMessage(exitMessage, &currentCommand->caller, 1);
// Queue the outputMessage:
pushQueue(parameters->outputQueue, exitOutputMessage, OUTPUT_MESSAGE);
// Free the userMessage
free(exitMessage); free(exitMessage);
} }
@ -362,7 +389,14 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue)
strncat(lookMessage->messageContent, currentCommand->caller->currentArea->areaName, 33); strncat(lookMessage->messageContent, currentCommand->caller->currentArea->areaName, 33);
strncat(lookMessage->messageContent, "\n", 2); strncat(lookMessage->messageContent, "\n", 2);
strncat(lookMessage->messageContent, currentCommand->caller->currentArea->areaDescription, MAX - 35); strncat(lookMessage->messageContent, currentCommand->caller->currentArea->areaDescription, MAX - 35);
queueTargetedOutputMessage(parameters->outputQueue, lookMessage, &currentCommand->caller, 1);
// Allocate an outputMessage for the queue:
outputMessage * lookOutputMessage = createTargetedOutputMessage(lookMessage, &currentCommand->caller, 1);
// Queue the outputMessage:
pushQueue(parameters->outputQueue, lookOutputMessage, OUTPUT_MESSAGE);
//queueTargetedOutputMessage(parameters->outputQueue, lookMessage, &currentCommand->caller, 1);
bzero(lookMessage, sizeof(userMessage)); bzero(lookMessage, sizeof(userMessage));
// Loop through the paths and send the appropriate amount of messages: // 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) if((charCount + 64) >= MAX)
{ {
queueTargetedOutputMessage(parameters->outputQueue, lookMessage, &currentCommand->caller, 1); lookOutputMessage = createTargetedOutputMessage(lookMessage, &currentCommand->caller, 1);
// Queue the outputMessage:
pushQueue(parameters->outputQueue, lookOutputMessage, OUTPUT_MESSAGE);
bzero(lookMessage, sizeof(userMessage)); bzero(lookMessage, sizeof(userMessage));
charCount = 0; charCount = 0;
} }
@ -384,7 +422,11 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue)
strncat(lookMessage->messageContent, formattedString, 64); strncat(lookMessage->messageContent, formattedString, 64);
charCount += 64; charCount += 64;
} }
queueTargetedOutputMessage(parameters->outputQueue, lookMessage, &currentCommand->caller, 1); // Allocate another outputMessage for the queue:
lookOutputMessage = createTargetedOutputMessage(lookMessage, &currentCommand->caller, 1);
// Queue the outputMessage:
pushQueue(parameters->outputQueue, lookOutputMessage, OUTPUT_MESSAGE);
} }
free(lookMessage); free(lookMessage);
} }
@ -423,14 +465,6 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue)
{ {
// TODO: Implement. // 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, &currentCommand->caller, 1);
free(statMessage);
}
// Stat command: Displays the current character's sheet. // Stat command: Displays the current character's sheet.
if(strncmp(currentCommand->command, "stat", 4) == 0) if(strncmp(currentCommand->command, "stat", 4) == 0)
{ {
@ -463,7 +497,12 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue)
} }
strncat(statMessage->messageContent, formattedString, 120); strncat(statMessage->messageContent, formattedString, 120);
queueTargetedOutputMessage(parameters->outputQueue, statMessage, &currentCommand->caller, 1); // Allocate an outputMessage for the queue:
outputMessage * statOutputMessage = createTargetedOutputMessage(statMessage, &currentCommand->caller, 1);
// Queue the outputMessage:
pushQueue(parameters->outputQueue, statOutputMessage, OUTPUT_MESSAGE);
bzero(statMessage->messageContent, sizeof(char) * MAX); bzero(statMessage->messageContent, sizeof(char) * MAX);
if(currentCommand->caller->skills->head != NULL) if(currentCommand->caller->skills->head != NULL)
{ {
@ -480,8 +519,11 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue)
strncat(statMessage->messageContent, formattedString, 120); strncat(statMessage->messageContent, formattedString, 120);
if((charCount + 43) >= MAX) if((charCount + 43) >= MAX)
{ {
// strncat(statMessage->messageContent, "\n", 2); // Allocate an outputMessage for the queue:
queueTargetedOutputMessage(parameters->outputQueue, statMessage, &currentCommand->caller, 1); statOutputMessage = createTargetedOutputMessage(statMessage, &currentCommand->caller, 1);
// Queue the outputMessage:
pushQueue(parameters->outputQueue, statOutputMessage, OUTPUT_MESSAGE);
bzero(statMessage, sizeof(userMessage)); bzero(statMessage, sizeof(userMessage));
charCount = 0; charCount = 0;
break; break;
@ -497,7 +539,11 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue)
addNewline = true; addNewline = true;
} }
} }
queueTargetedOutputMessage(parameters->outputQueue, statMessage, &currentCommand->caller, 1); // Allocate an outputMessage for the queue:
statOutputMessage = createTargetedOutputMessage(statMessage, &currentCommand->caller, 1);
// Queue the outputMessage:
pushQueue(parameters->outputQueue, statOutputMessage, OUTPUT_MESSAGE);
} }
free(statMessage); free(statMessage);
free(formattedString); free(formattedString);
@ -570,8 +616,11 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue)
strncat(specMessage->messageContent, "You have no spec points available.", 35); strncat(specMessage->messageContent, "You have no spec points available.", 35);
} }
// Send the message: // Allocate an outputMessage for the queue:
queueTargetedOutputMessage(parameters->outputQueue, specMessage, &currentCommand->caller, 1); outputMessage * specOutputMessage = createTargetedOutputMessage(specMessage, &currentCommand->caller, 1);
// Queue the outputMessage:
pushQueue(parameters->outputQueue, specOutputMessage, OUTPUT_MESSAGE);
// Show the new stat sheet: // Show the new stat sheet:
queue->lock = false; 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"); strcpy(skillMessage->messageContent, "You don't have enough skill points to take this skill.\n");
} }
queueTargetedOutputMessage(parameters->outputQueue, skillMessage, &currentCommand->caller, 1);
// Allocate an outputMessage for the queue:
outputMessage * skillOutputMessage = createTargetedOutputMessage(skillMessage, &currentCommand->caller, 1);
// Queue the outputMessage:
pushQueue(parameters->outputQueue, skillOutputMessage, OUTPUT_MESSAGE);
free(skillMessage); free(skillMessage);
} }
if(strncmp(currentCommand->command, "listskills", 10) == 0) if(strncmp(currentCommand->command, "listskills", 10) == 0)
@ -630,7 +685,12 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue)
strncat(listMessage->messageContent, formattedString, 120); strncat(listMessage->messageContent, formattedString, 120);
if((charCount + 46) >= MAX) if((charCount + 46) >= MAX)
{ {
queueTargetedOutputMessage(parameters->outputQueue, listMessage, &currentCommand->caller, 1); // Allocate an outputMessage for the queue:
outputMessage * listOutputMessage = createTargetedOutputMessage(listMessage, &currentCommand->caller, 1);
// Queue the outputMessage:
pushQueue(parameters->outputQueue, listOutputMessage, OUTPUT_MESSAGE);
bzero(listMessage, sizeof(userMessage)); bzero(listMessage, sizeof(userMessage));
charCount = 0; charCount = 0;
addNewline = false; addNewline = false;
@ -647,7 +707,11 @@ int evaluateNextCommand(gameLogicParameters * parameters, commandQueue * queue)
} }
skillIndex++; skillIndex++;
} }
queueTargetedOutputMessage(parameters->outputQueue, listMessage, &currentCommand->caller, 1); // Allocate an outputMessage for the queue:
outputMessage * listOutputMessage = createTargetedOutputMessage(listMessage, &currentCommand->caller, 1);
// Queue the outputMessage:
pushQueue(parameters->outputQueue, listOutputMessage, OUTPUT_MESSAGE);
free(listMessage); free(listMessage);
free(formattedString); free(formattedString);
} }

View File

@ -18,11 +18,16 @@ typedef struct queue queue;
// A data-structure containing the needed parameters for a main game loop: // A data-structure containing the needed parameters for a main game loop:
typedef struct gameLogicParameters typedef struct gameLogicParameters
{ {
// Players:
int * playerCount; int * playerCount;
list * areaList;
playerInfo * connectedPlayers; playerInfo * connectedPlayers;
// Queues:
queue * inputQueue; queue * inputQueue;
outputMessageQueue * outputQueue; queue * outputQueue;
// Lists:
list * areaList;
list * globalSkillList; list * globalSkillList;
} gameLogicParameters; } gameLogicParameters;

View File

@ -46,170 +46,22 @@ int messageReceive(gnutls_session_t receiveFromSession, userMessage * receiveToM
return returnValue; return returnValue;
} }
outputMessageQueue * createOutputMessageQueue(void) outputMessage * createTargetedOutputMessage(userMessage * messageToQueue, playerInfo ** recipients, int recipientsCount)
{ {
outputMessageQueue * newQueue = malloc(sizeof(outputMessageQueue)); // Allocate a new output message:
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:
outputMessage * newOutputMessage = malloc(sizeof(outputMessage)); outputMessage * newOutputMessage = malloc(sizeof(outputMessage));
// Allocate the internal userMessage to store the message:
newOutputMessage->content = malloc(sizeof(userMessage)); newOutputMessage->content = malloc(sizeof(userMessage));
// Copy the userMessage to the internal userMessage: // Allocate an array of playerInfo for the output message recepients:
strncpy(newOutputMessage->content->senderName, messageToQueue.senderName, 32); newOutputMessage->recipients = malloc(sizeof(playerInfo*) * recipientsCount);
strncpy(newOutputMessage->content->messageContent, messageToQueue.messageContent, MAX);
// We have no targets, NULL sends to all players in an area: // Copy in the appropriate data:
newOutputMessage->targets[0] = NULL; memcpy(newOutputMessage->recipients, recipients, sizeof(playerInfo *) * recipientsCount);
memcpy(newOutputMessage->content, messageToQueue, sizeof(userMessage));
newOutputMessage->recipientsCount = recipientsCount;
// Wait for the queue to unlock: // Return a pointer to the new outputMessage:
while (queue->lock); return newOutputMessage;
// 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);
// 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 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;
}
} }
void userInputSanatize(char * inputString, int length) void userInputSanatize(char * inputString, int length)
@ -238,8 +90,3 @@ void userNameSanatize(char * inputString, int length)
} }
inputString[length - 1] = '\0'; inputString[length - 1] = '\0';
} }
outputMessage * peekOutputMessage(outputMessageQueue * queue)
{
return queue->front;
}

View File

@ -33,33 +33,13 @@ int messageReceive(gnutls_session_t receiveFromSession, userMessage * receiveToM
typedef struct outputMessage outputMessage; typedef struct outputMessage outputMessage;
typedef struct outputMessage typedef struct outputMessage
{ {
outputMessage * next; int recipientsCount;
playerInfo * targets[PLAYERCOUNT];
userMessage * content; userMessage * content;
playerInfo ** recipients;
} outputMessage; } outputMessage;
// A first-in first-out queue for message output to players: // Create a targetedOutput message to be delivered to the players pointed to in recipients:
typedef struct outputMessageQueue outputMessage * createTargetedOutputMessage(userMessage * messageToQueue, playerInfo ** recipients, int recipientCount);
{
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);
// ================== // ==================
// -=[Input Queue]=-: // -=[Input Queue]=-:

View File

@ -151,7 +151,7 @@ void pushQueue(queue * queue, void * data, queueDataType type)
{ {
// Create a new node: // Create a new node:
queueNode * newNode = malloc(sizeof(queueNode)); queueNode * newNode = malloc(sizeof(queueNode));
newNode->type = type;
// Copy the data into the correct slot for the type: // Copy the data into the correct slot for the type:
switch (type) switch (type)
{ {

View File

@ -46,8 +46,7 @@ int main(int argc, char ** argv)
playerInfo connectedPlayers[PLAYERCOUNT]; playerInfo connectedPlayers[PLAYERCOUNT];
char testString[32] = "Hehe."; char testString[32] = "Hehe.";
struct sockaddr_in serverAddress, clientAddress; struct sockaddr_in serverAddress, clientAddress;
queue * inputQueue = createQueue(); queue * inputQueue = createQueue(), * outputQueue = createQueue();
outputMessageQueue * outputQueue = createOutputMessageQueue();
// Parse command-line options: // Parse command-line options:
int currentopt = 0; int currentopt = 0;
@ -343,38 +342,47 @@ int main(int argc, char ** argv)
} }
// Run through the output queue and send all unused messages: // 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); while(outputQueue->lock);
// Lock the queue:
outputQueue->lock = true; 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; outputQueue->lock = false;
// If the first target is set to NULL, it's intended for all connected: // 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++) for (int index = 0; index < PLAYERCOUNT; index++)
{ {
messageSend(tlssessions[index], message->content); messageSend(tlssessions[index], message->content);
} }
} }
// Otherwise, send it only to the targeted players:
else else
{ {
int targetIndex = 0; int targetIndex = 0;
for(int index = 0; index < PLAYERCOUNT; index++) for(int index = 0; index < PLAYERCOUNT; index++)
{ {
if(message->targets[targetIndex] == NULL) if(targetIndex == message->recipientsCount)
{ {
break; break;
} }
if(&connectedPlayers[index] == message->targets[targetIndex]) if(&connectedPlayers[index] == message->recipients[targetIndex])
{ {
targetIndex++; targetIndex++;
messageSend(tlssessions[index], message->content); messageSend(tlssessions[index], message->content);
} }
} }
} }
dequeueOutputMessage(outputQueue); // Remove the output message from the queue:
popQueue(outputQueue);
} }
} }
pthread_cancel(gameLogicThread); pthread_cancel(gameLogicThread);