1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
|
/* bzflag
* Copyright (c) 1993-2025 Tim Riker
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the license found in the file
* named COPYING that should have accompanied this file.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
// chathistory.cpp : Defines the entry point for the DLL application.
//
#include "bzfsAPI.h"
#include <map>
class LastChatCommand : public bz_CustomSlashCommandHandler
{
public:
virtual ~LastChatCommand() {};
virtual bool SlashCommand (int playerID, bz_ApiString command, bz_ApiString message, bz_APIStringList *param);
};
LastChatCommand lastChatCommand;
// event handler callback
class ChatEvents : public bz_Plugin
{
public:
virtual ~ChatEvents() {};
virtual const char* Name ()
{
return "Chat History";
}
virtual void Init (const char* c);
virtual void Cleanup (void);
virtual void Event (bz_EventData *eventData);
};
BZ_PLUGIN(ChatEvents)
typedef std::vector<std::string> tvChatHistory;
std::map<std::string, tvChatHistory> chatHistories;
unsigned int maxChatLines;
void ChatEvents::Init (const char* commandLine)
{
// Default to 50 lines per player
maxChatLines = 50;
// Allow configuring how many lines to store
if (commandLine && strlen(commandLine) > 0)
{
int realLines = atoi(commandLine);
maxChatLines = realLines;
}
// Register our custom slash commands
bz_registerCustomSlashCommand("last", &lastChatCommand);
bz_registerCustomSlashCommand("flushchat", &lastChatCommand);
// Register the raw chat event
Register(bz_eRawChatMessageEvent);
}
void ChatEvents::Cleanup(void)
{
// Remove our custom slash commands
bz_removeCustomSlashCommand("last");
bz_removeCustomSlashCommand("flushchat");
// Remove our events
Flush();
}
bool LastChatCommand::SlashCommand (int playerID, bz_ApiString command, bz_ApiString message,
bz_APIStringList * /*_param*/)
{
// Only admins can run this command
if (!bz_getAdmin(playerID))
{
bz_sendTextMessage(BZ_SERVER, playerID, "You must be admin to use the ChatHistory plugin");
return true;
}
// The 'last' command show the last X lines of text for a callsign
if (command == "last")
{
// Create a string list and tokenize the message
bz_APIStringList *params = bz_newStringList();
params->tokenize(message.c_str(), " ", 0, true);
// Must have two parameters
if (params->size() != 2)
{
bz_sendTextMessage(BZ_SERVER, playerID, "Usage: /last <NUMBER OF LINES> <CALLSIGN>");
return true;
}
// Parse the number of lines to return
unsigned int numLines = (unsigned int)atoi(params->get(0).c_str());
if (numLines == 0)
numLines = 5;
// Look up the player's chat history container
std::map<std::string, tvChatHistory>::iterator itr = chatHistories.find(bz_tolower(params->get(1).c_str()));
// If the container doesn't exist or has a 0 size, bail out
if (itr == chatHistories.end() || !itr->second.size())
{
bz_sendTextMessage(BZ_SERVER, playerID, "That player has no chat history.");
return true;
}
// Store a reference to the chat history container
tvChatHistory &history = itr->second;
// If the number of lines stored is less than the number requested, reduce the requested amount
if (history.size() < numLines)
numLines = (unsigned int)history.size();
// Send the messages to the requester
bz_sendTextMessage(BZ_SERVER, playerID, bz_format("Last %d message(s) for %s", numLines, params->get(1).c_str()));
for (unsigned int i = numLines; i > 0; i--)
{
std::string chatItem = history[history.size()-i];
bz_sendTextMessage(BZ_SERVER, playerID, bz_format(" <%s> %s", params->get(1).c_str(), chatItem.c_str()));
}
return true;
}
// Clear all the chat histories
if (command == "flushchat")
{
chatHistories.clear();
bz_sendTextMessage(BZ_SERVER, playerID, "Chat History has been flushed");
return true;
}
return false;
}
void ChatEvents::Event (bz_EventData *eventData)
{
// We only handle raw chat messages
if (eventData->eventType != bz_eRawChatMessageEvent)
return;
// Cast the event data
bz_ChatEventData_V1 *chatEventData = (bz_ChatEventData_V1*)eventData;
// Retrieve the sender information
bz_BasePlayerRecord *fromPlayer = bz_getPlayerByIndex(chatEventData->from);
// Bail if we can't find the player
if (!fromPlayer)
return;
// Store the message in a std::string
std::string message = chatEventData->message.c_str();
// Store the callsign
std::string callsign = bz_tolower(fromPlayer->callsign.c_str());
// Create a new chat history log for this callsign if necessary
if (chatHistories.find(callsign) == chatHistories.end())
{
tvChatHistory h;
chatHistories[callsign] = h;
}
// Store a reference to the chat history for this callsign
tvChatHistory &history = chatHistories[callsign];
// Add the new message
history.push_back(message);
// Check if the number of chat history items exceeds the per-callsign limit.
// If it does, remove the oldest entry
if (history.size() > maxChatLines)
history.erase(history.begin());
// Free the memory from the player record
bz_freePlayerRecord(fromPlayer);
}
// Local Variables: ***
// mode: C++ ***
// tab-width: 4 ***
// c-basic-offset: 4 ***
// indent-tabs-mode: nil ***
// End: ***
// ex: shiftwidth=4 tabstop=4
|