361 lines
10 KiB
C++
361 lines
10 KiB
C++
// Copyright (C) 2007-2025 EQ2EMulator
|
|
// Licensed under GPL v3
|
|
|
|
#include "Chat.h"
|
|
#include "../../common/Log.h"
|
|
#include "../../common/ConfigReader.h"
|
|
#include "../../common/PacketStruct.h"
|
|
#include "../Rules/Rules.h"
|
|
extern RuleManager rule_manager;
|
|
|
|
//devn00b
|
|
#ifdef DISCORD
|
|
#ifndef WIN32
|
|
#include <dpp/dpp.h>
|
|
#include "ChatChannel.h"
|
|
|
|
extern ChatChannel channel;
|
|
#endif
|
|
#endif
|
|
|
|
#include "../Web/PeerManager.h"
|
|
|
|
extern ConfigReader configReader;
|
|
extern PeerManager peer_manager;
|
|
|
|
|
|
|
|
Chat::Chat() {
|
|
m_channels.SetName("Chat::Channels");
|
|
}
|
|
|
|
Chat::~Chat() {
|
|
vector<ChatChannel *>::iterator itr;
|
|
|
|
m_channels.writelock(__FUNCTION__, __LINE__);
|
|
for (itr = channels.begin(); itr != channels.end(); itr++)
|
|
safe_delete(*itr);
|
|
m_channels.releasewritelock(__FUNCTION__, __LINE__);
|
|
}
|
|
|
|
void Chat::AddChannel(ChatChannel *channel) {
|
|
m_channels.writelock(__FUNCTION__, __LINE__);
|
|
channels.push_back(channel);
|
|
m_channels.releasewritelock(__FUNCTION__, __LINE__);
|
|
}
|
|
|
|
unsigned int Chat::GetNumChannels() {
|
|
unsigned int ret;
|
|
|
|
m_channels.readlock(__FUNCTION__, __LINE__);
|
|
ret = (unsigned int)channels.size();
|
|
m_channels.releasereadlock(__FUNCTION__, __LINE__);
|
|
|
|
return ret;
|
|
}
|
|
|
|
EQ2Packet * Chat::GetWorldChannelList(Client *client) {
|
|
PacketStruct *packet_struct = configReader.getStruct("WS_AvailWorldChannels", client->GetVersion());
|
|
Player *player = client->GetPlayer();
|
|
vector<ChatChannel *> channels_to_send;
|
|
vector<ChatChannel *>::iterator itr;
|
|
ChatChannel *channel;
|
|
EQ2Packet *packet;
|
|
int32 i = 0;
|
|
bool add;
|
|
|
|
if (packet_struct == NULL) {
|
|
LogWrite(CHAT__ERROR, 0, "Chat", "Could not find packet 'WS_AvailWorldChannels' for client %s on version %i\n", player->GetName(), client->GetVersion());
|
|
return NULL;
|
|
}
|
|
|
|
m_channels.readlock(__FUNCTION__, __LINE__);
|
|
for (itr = channels.begin(); itr != channels.end(); itr++) {
|
|
channel = *itr;
|
|
|
|
if (channel->GetType() == CHAT_CHANNEL_TYPE_WORLD) {
|
|
add = true;
|
|
|
|
if (add && !channel->CanJoinChannelByLevel(player->GetLevel()))
|
|
add = false;
|
|
if (add && !channel->CanJoinChannelByRace(player->GetRace()))
|
|
add = false;
|
|
if (add && !channel->CanJoinChannelByClass(player->GetAdventureClass()))
|
|
add = false;
|
|
|
|
if (add)
|
|
channels_to_send.push_back(channel);
|
|
}
|
|
}
|
|
m_channels.releasereadlock(__FUNCTION__, __LINE__);
|
|
|
|
packet_struct->setArrayLengthByName("num_channels", channels_to_send.size());
|
|
for (itr = channels_to_send.begin(); itr != channels_to_send.end(); itr++, i++) {
|
|
packet_struct->setArrayDataByName("channel_name", (*itr)->GetName(), i);
|
|
packet_struct->setArrayDataByName("unknown", 0, i);
|
|
}
|
|
|
|
packet = packet_struct->serialize();
|
|
safe_delete(packet_struct);
|
|
|
|
return packet;
|
|
}
|
|
|
|
bool Chat::ChannelExists(const char *channel_name) {
|
|
vector<ChatChannel *>::iterator itr;
|
|
bool ret = false;
|
|
|
|
m_channels.readlock(__FUNCTION__, __LINE__);
|
|
for (itr = channels.begin(); itr != channels.end(); itr++) {
|
|
if (strncasecmp(channel_name, (*itr)->GetName(), CHAT_CHANNEL_MAX_NAME) == 0) {
|
|
ret = true;
|
|
break;
|
|
}
|
|
}
|
|
m_channels.releasereadlock(__FUNCTION__, __LINE__);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool Chat::HasPassword(const char *channel_name) {
|
|
vector<ChatChannel *>::iterator itr;
|
|
bool ret = false;
|
|
|
|
m_channels.readlock(__FUNCTION__, __LINE__);
|
|
for (itr = channels.begin(); itr != channels.end(); itr++) {
|
|
if (strncasecmp(channel_name, (*itr)->GetName(), CHAT_CHANNEL_MAX_NAME) == 0) {
|
|
ret = (*itr)->HasPassword();
|
|
break;
|
|
}
|
|
}
|
|
m_channels.releasereadlock(__FUNCTION__, __LINE__);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool Chat::PasswordMatches(const char *channel_name, const char *password) {
|
|
vector<ChatChannel *>::iterator itr;
|
|
bool ret = false;
|
|
|
|
m_channels.readlock(__FUNCTION__, __LINE__);
|
|
for (itr = channels.begin(); itr != channels.end(); itr++) {
|
|
if (strncasecmp(channel_name, (*itr)->GetName(), CHAT_CHANNEL_MAX_NAME) == 0) {
|
|
ret = (*itr)->PasswordMatches(password);
|
|
break;
|
|
}
|
|
}
|
|
m_channels.releasereadlock(__FUNCTION__, __LINE__);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool Chat::CreateChannel(const char *channel_name, bool fromPeer) {
|
|
return CreateChannel(channel_name, NULL, fromPeer);
|
|
}
|
|
|
|
bool Chat::CreateChannel(const char *channel_name, const char *password, bool fromPeer) {
|
|
LogWrite(CHAT__DEBUG, 0, "Chat", "Channel %s being created", channel_name);
|
|
|
|
ChatChannel *channel = new ChatChannel();
|
|
channel->SetName(channel_name);
|
|
channel->SetType(CHAT_CHANNEL_TYPE_CUSTOM);
|
|
if (password != NULL && strlen(password) > 0)
|
|
channel->SetPassword(password);
|
|
|
|
if(!fromPeer) {
|
|
peer_manager.sendPeersAddChatChannel(std::string(channel_name), password != nullptr ? std::string(password) : std::string(""));
|
|
}
|
|
|
|
m_channels.writelock(__FUNCTION__, __LINE__);
|
|
channels.push_back(channel);
|
|
m_channels.releasewritelock(__FUNCTION__, __LINE__);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Chat::IsInChannel(Client *client, const char *channel_name) {
|
|
vector<ChatChannel *>::iterator itr;
|
|
bool ret = false;
|
|
|
|
m_channels.readlock(__FUNCTION__, __LINE__);
|
|
for (itr = channels.begin(); itr != channels.end(); itr++) {
|
|
if (strncasecmp(channel_name, (*itr)->GetName(), CHAT_CHANNEL_MAX_NAME) == 0) {
|
|
ret = (*itr)->IsInChannel(client->GetCharacterID());
|
|
break;
|
|
}
|
|
}
|
|
m_channels.releasereadlock(__FUNCTION__, __LINE__);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool Chat::JoinChannel(Client *client, const char *channel_name) {
|
|
vector<ChatChannel *>::iterator itr;
|
|
bool ret = false;
|
|
|
|
LogWrite(CHAT__DEBUG, 1, "Chat", "Client %s is joining channel %s", client->GetPlayer()->GetName(), channel_name);
|
|
|
|
m_channels.writelock(__FUNCTION__, __LINE__);
|
|
for (itr = channels.begin(); itr != channels.end(); itr++) {
|
|
if (strncasecmp(channel_name, (*itr)->GetName(), CHAT_CHANNEL_MAX_NAME) == 0) {
|
|
ret = (*itr)->JoinChannel(client);
|
|
break;
|
|
}
|
|
}
|
|
m_channels.releasewritelock(__FUNCTION__, __LINE__);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool Chat::LeaveChannel(Client *client, const char *channel_name) {
|
|
vector<ChatChannel *>::iterator itr;
|
|
bool ret = false;
|
|
|
|
LogWrite(CHAT__DEBUG, 1, "Chat", "Client %s is leaving channel %s", client->GetPlayer()->GetName(), channel_name);
|
|
|
|
m_channels.writelock(__FUNCTION__, __LINE__);
|
|
for (itr = channels.begin(); itr != channels.end(); itr++) {
|
|
if (strncasecmp(channel_name, (*itr)->GetName(), CHAT_CHANNEL_MAX_NAME) == 0) {
|
|
ret = (*itr)->LeaveChannel(client);
|
|
|
|
if ((*itr)->GetType() == CHAT_CHANNEL_TYPE_CUSTOM && (*itr)->GetNumClients() == 0) {
|
|
LogWrite(CHAT__DEBUG, 0, "Chat", "Custom channel %s has 0 clients left, deleting channel", channel_name);
|
|
safe_delete(*itr);
|
|
channels.erase(itr);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
m_channels.releasewritelock(__FUNCTION__, __LINE__);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool Chat::LeaveAllChannels(Client *client) {
|
|
vector<ChatChannel *>::iterator itr;
|
|
ChatChannel *channel;
|
|
bool erased;
|
|
|
|
m_channels.writelock(__FUNCTION__, __LINE__);
|
|
itr = channels.begin();
|
|
while (itr != channels.end()) {
|
|
channel = *itr;
|
|
erased = false;
|
|
|
|
if (channel->IsInChannel(client->GetCharacterID())) {
|
|
LogWrite(CHAT__DEBUG, 1, "Chat", "Client %s is leaving channel %s", client->GetPlayer()->GetName(), channel->GetName());
|
|
channel->LeaveChannel(client);
|
|
|
|
if (channel->GetType() == CHAT_CHANNEL_TYPE_CUSTOM && channel->GetNumClients() == 0) {
|
|
LogWrite(CHAT__DEBUG, 0, "Chat", "Custom channel %s has 0 clients left, deleting channel", channel->GetName());
|
|
safe_delete(*itr);
|
|
itr = channels.erase(itr);
|
|
erased = true;
|
|
}
|
|
}
|
|
|
|
if (!erased)
|
|
itr++;
|
|
}
|
|
m_channels.releasewritelock(__FUNCTION__, __LINE__);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Chat::TellChannel(Client *client, std::string charName, int8 charLanguage, const char *channel_name, const char *message, const char* name) {
|
|
vector<ChatChannel *>::iterator itr;
|
|
bool ret = false;
|
|
bool enablediscord = rule_manager.GetGlobalRule(R_Discord, DiscordEnabled)->GetBool();
|
|
const char* discordchan = rule_manager.GetGlobalRule(R_Discord, DiscordChannel)->GetString();
|
|
|
|
m_channels.readlock(__FUNCTION__, __LINE__);
|
|
for (itr = channels.begin(); itr != channels.end(); itr++) {
|
|
if (strncasecmp(channel_name, (*itr)->GetName(), CHAT_CHANNEL_MAX_NAME) == 0) {
|
|
if (client && name)
|
|
ret = (*itr)->TellChannelClient(client, message, name);
|
|
else
|
|
ret = (*itr)->TellChannel(charName, charLanguage, message, name);
|
|
|
|
if(enablediscord == true && client){
|
|
|
|
if (strcmp(channel_name, discordchan) != 0){
|
|
m_channels.releasereadlock(__FUNCTION__, __LINE__);
|
|
return ret;
|
|
}
|
|
#ifdef DISCORD
|
|
if (client) {
|
|
std::string whofrom = client->GetPlayer()->GetName();
|
|
std::string msg = string(message);
|
|
ret = PushDiscordMsg(msg.c_str(), whofrom.c_str());
|
|
}
|
|
#endif
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
m_channels.releasereadlock(__FUNCTION__, __LINE__);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool Chat::SendChannelUserList(Client *client, const char *channel_name) {
|
|
vector<ChatChannel *>::iterator itr;
|
|
bool ret = false;
|
|
|
|
m_channels.readlock(__FUNCTION__, __LINE__);
|
|
for (itr = channels.begin(); itr != channels.end(); itr++) {
|
|
if (strncasecmp(channel_name, (*itr)->GetName(), CHAT_CHANNEL_MAX_NAME) == 0) {
|
|
ret = (*itr)->SendChannelUserList(client);
|
|
break;
|
|
}
|
|
}
|
|
m_channels.releasereadlock(__FUNCTION__, __LINE__);
|
|
|
|
return ret;
|
|
}
|
|
|
|
ChatChannel* Chat::GetChannel(const char *channel_name) {
|
|
vector<ChatChannel *>::iterator itr;
|
|
ChatChannel* ret = 0;
|
|
|
|
m_channels.readlock(__FUNCTION__, __LINE__);
|
|
for (itr = channels.begin(); itr != channels.end(); itr++) {
|
|
if (strncasecmp(channel_name, (*itr)->GetName(), CHAT_CHANNEL_MAX_NAME) == 0) {
|
|
ret = (*itr);
|
|
break;
|
|
}
|
|
}
|
|
m_channels.releasereadlock(__FUNCTION__, __LINE__);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef DISCORD
|
|
//this sends chat from EQ2EMu to Discord. Currently using webhooks. Makes things simpler code wise.
|
|
int Chat::PushDiscordMsg(const char* msg, const char* from) {
|
|
bool enablediscord = rule_manager.GetGlobalRule(R_Discord, DiscordEnabled)->GetBool();
|
|
|
|
if(enablediscord == false) {
|
|
LogWrite(INIT__INFO, 0,"Discord","Bot Disabled By Rule...");
|
|
return 0;
|
|
}
|
|
|
|
m_channels.readlock(__FUNCTION__, __LINE__);
|
|
const char* hook = rule_manager.GetGlobalRule(R_Discord, DiscordWebhookURL)->GetString();
|
|
std::string servername = net.GetWorldName();
|
|
char ourmsg[4096];
|
|
|
|
//form our message
|
|
sprintf(ourmsg,"[%s] [%s] Says: %s",from, servername.c_str(), msg);
|
|
|
|
/* send a message with this webhook */
|
|
dpp::cluster bot("");
|
|
dpp::webhook wh(hook);
|
|
bot.execute_webhook(wh, dpp::message(ourmsg));
|
|
m_channels.releasereadlock(__FUNCTION__, __LINE__);
|
|
|
|
return 1;
|
|
}
|
|
#endif |