Added Discord chat support.
This commit is contained in:
parent
a55fda41b5
commit
78f4a6e63b
8 changed files with 289 additions and 13 deletions
4
DB/updates/DiscordBridgeOptions-2-5-24.sql
Executable file
4
DB/updates/DiscordBridgeOptions-2-5-24.sql
Executable file
|
@ -0,0 +1,4 @@
|
|||
INSERT INTO `ruleset_details` (`ruleset_id`, `rule_category`, `rule_type`, `rule_value`, `description`) VALUES (1, 'R_Discord', 'DiscordEnabled', '1', 'Enable (1) or Disable(0) the Discord Bridge System.');
|
||||
INSERT INTO `ruleset_details` (`ruleset_id`, `rule_category`, `rule_type`, `rule_value`, `description`) VALUES (1, 'R_Discord', 'DiscordWebhookURL', 'https://example.com', 'Webhook url for EQ2 -> Discord coms.');
|
||||
INSERT INTO `ruleset_details` (`ruleset_id`, `rule_category`, `rule_type`, `rule_value`, `description`) VALUES (1, 'R_Discord', 'DiscordBotToken', '0', 'This is the token for the bot, given in the discord developer site.');
|
||||
INSERT INTO `ruleset_details` (`ruleset_id`, `rule_category`, `rule_type`, `rule_value`, `description`) VALUES (1, 'R_Discord', 'DiscordListenChan', '0', 'Channe ID you want to listen to chat from. this is for Discord -> EQ2 coms.');
|
|
@ -22,9 +22,24 @@
|
|||
#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
|
||||
|
||||
|
||||
extern ConfigReader configReader;
|
||||
|
||||
|
||||
|
||||
Chat::Chat() {
|
||||
m_channels.SetName("Chat::Channels");
|
||||
}
|
||||
|
@ -262,6 +277,8 @@ bool Chat::LeaveAllChannels(Client *client) {
|
|||
bool Chat::TellChannel(Client *client, 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++) {
|
||||
|
@ -271,6 +288,21 @@ bool Chat::TellChannel(Client *client, const char *channel_name, const char *mes
|
|||
else
|
||||
ret = (*itr)->TellChannel(client, 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;
|
||||
}
|
||||
}
|
||||
|
@ -310,3 +342,31 @@ ChatChannel* Chat::GetChannel(const char *channel_name) {
|
|||
|
||||
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
|
|
@ -27,6 +27,13 @@
|
|||
#include "../client.h"
|
||||
#include "ChatChannel.h"
|
||||
|
||||
#ifdef DISCORD
|
||||
#ifndef WIN32
|
||||
#pragma once
|
||||
#include <dpp/dpp.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
/*
|
||||
|
||||
|
@ -100,6 +107,8 @@ public:
|
|||
bool LeaveAllChannels(Client *client);
|
||||
bool TellChannel(Client *client, const char *channel_name, const char *message, const char* name = 0);
|
||||
bool SendChannelUserList(Client *client, const char *channel_name);
|
||||
//devn00b
|
||||
int PushDiscordMsg(const char*, const char*);
|
||||
ChatChannel* GetChannel(const char* channel_name);
|
||||
|
||||
private:
|
||||
|
|
|
@ -135,23 +135,36 @@ bool ChatChannel::TellChannel(Client *client, const char *message, const char* n
|
|||
packet_struct->setDataByName("from_spawn_id", 0xFFFFFFFF);
|
||||
packet_struct->setDataByName("to_spawn_id", 0xFFFFFFFF);
|
||||
|
||||
if (client)
|
||||
if (client != NULL){
|
||||
packet_struct->setDataByName("from", client->GetPlayer()->GetName());
|
||||
else
|
||||
packet_struct->setDataByName("from", name2);
|
||||
} else {
|
||||
char name3[128];
|
||||
sprintf(name3,"[%s] from discord",name2);
|
||||
packet_struct->setDataByName("from", name3);
|
||||
}
|
||||
|
||||
packet_struct->setDataByName("to", to_client->GetPlayer()->GetName());
|
||||
packet_struct->setDataByName("channel", to_client->GetMessageChannelColor(CHANNEL_CUSTOM_CHANNEL));
|
||||
packet_struct->setDataByName("language", client->GetPlayer()->GetCurrentLanguage());
|
||||
|
||||
if(client != NULL){
|
||||
packet_struct->setDataByName("language", client->GetPlayer()->GetCurrentLanguage());
|
||||
}else{
|
||||
packet_struct->setDataByName("language", 0);
|
||||
}
|
||||
packet_struct->setDataByName("message", message);
|
||||
packet_struct->setDataByName("channel_name", name);
|
||||
packet_struct->setDataByName("show_bubble", 1);
|
||||
|
||||
if (client->GetPlayer()->GetCurrentLanguage() == 0 || to_client->GetPlayer()->HasLanguage(client->GetPlayer()->GetCurrentLanguage())) {
|
||||
|
||||
if(client != NULL){
|
||||
if (client->GetPlayer()->GetCurrentLanguage() == 0 || to_client->GetPlayer()->HasLanguage(client->GetPlayer()->GetCurrentLanguage())) {
|
||||
packet_struct->setDataByName("understood", 1);
|
||||
}
|
||||
} else {
|
||||
packet_struct->setDataByName("understood", 1);
|
||||
}
|
||||
|
||||
packet_struct->setDataByName("unknown4", 0);
|
||||
|
||||
|
||||
to_client->QueuePacket(packet_struct->serialize());
|
||||
safe_delete(packet_struct);
|
||||
}
|
||||
|
@ -210,4 +223,5 @@ bool ChatChannel::SendChannelUserList(Client *client) {
|
|||
safe_delete(packet_struct);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -376,6 +376,12 @@ void RuleManager::Init()
|
|||
|
||||
RULE_INIT(R_World, DatabaseVersion, "0");
|
||||
|
||||
//devn00b
|
||||
RULE_INIT(R_Discord, DiscordEnabled, "0"); //Enable/Disable built in discord bot.
|
||||
RULE_INIT(R_Discord, DiscordWebhookURL, "None"); //Webhook url used for server -> discord messages.
|
||||
RULE_INIT(R_Discord, DiscordBotToken, "None"); //Bot token used to connect to discord and provides discord -> server messages.
|
||||
RULE_INIT(R_Discord, DiscordChannel, "Discord"); // in-game channel used for server -> discord messages.
|
||||
RULE_INIT(R_Discord, DiscordListenChan, "0"); // Discord ChannelID used for discord->server messages.
|
||||
#undef RULE_INIT
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,8 @@ enum RuleCategory {
|
|||
R_Zone,
|
||||
R_Loot,
|
||||
R_Spells,
|
||||
R_Expansion
|
||||
R_Expansion,
|
||||
R_Discord
|
||||
};
|
||||
|
||||
enum RuleType {
|
||||
|
@ -231,7 +232,12 @@ enum RuleType {
|
|||
DatabaseVersion,
|
||||
|
||||
SkipLootGrayMob,
|
||||
LootDistributionTime
|
||||
LootDistributionTime,
|
||||
DiscordEnabled,
|
||||
DiscordWebhookURL,
|
||||
DiscordBotToken,
|
||||
DiscordChannel,
|
||||
DiscordListenChan
|
||||
};
|
||||
|
||||
class Rule {
|
||||
|
|
97
EQ2/source/WorldServer/makefile.discord
Normal file
97
EQ2/source/WorldServer/makefile.discord
Normal file
|
@ -0,0 +1,97 @@
|
|||
# Programs
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
LINKER = g++
|
||||
|
||||
|
||||
# Configuration
|
||||
Build_Dir = build
|
||||
Source_Dir = ..
|
||||
APP = eq2world
|
||||
|
||||
|
||||
# LUA flags
|
||||
Lua_C_Flags = -DLUA_COMPAT_ALL -DLUA_USE_LINUX
|
||||
Lua_W_Flags = -Wall
|
||||
|
||||
|
||||
# World flags
|
||||
C_Flags = -I/usr/include/mariadb -I../depends/fmt/include -I../depends/recastnavigation/Detour/Include -I/usr/local/include/boost -I../depends/glm/ -march=native -pipe -pthread -std=c++17
|
||||
LD_Flags = -L/usr/lib/x86_64-linux-gnu -lz -lpthread -lmariadbclient -L../depends/recastnavigation/RecastDemo/Build/gmake/lib/Debug -lDebugUtils -lDetour -lDetourCrowd -lDetourTileCache -lRecast -L/usr/local/lib -rdynamic -lm -Wl,-E -ldl -lreadline -lboost_system -lboost_filesystem -lboost_iostreams -lboost_regex
|
||||
W_Flags = -Wall -Wno-reorder
|
||||
D_Flags = -DEQ2 -DWORLD -D_GNU_SOURCE
|
||||
|
||||
|
||||
# Setup Debug or Release build
|
||||
ifeq ($(BUILD),debug)
|
||||
# "Debug" build - minimum optimization, and debugging symbols
|
||||
C_Flags += -O -ggdb
|
||||
D_Flags += -DDEBUG -DDISCORD
|
||||
LD_Flags += -ldpp
|
||||
Current_Build_Dir := $(Build_Dir)/debug
|
||||
App_Filename = $(APP)_debug
|
||||
else
|
||||
# "Release" build - optimization, and no debug symbols
|
||||
C_Flags += -O2 -s -DNDEBUG
|
||||
Current_Build_Dir := $(Build_Dir)/release
|
||||
App_Filename = $(APP)
|
||||
endif
|
||||
|
||||
|
||||
# File lists
|
||||
World_Source = $(wildcard $(Source_Dir)/WorldServer/*.cpp) $(wildcard $(Source_Dir)/WorldServer/*/*.cpp)
|
||||
World_Objects = $(patsubst %.cpp,$(Current_Build_Dir)/%.o,$(subst $(Source_Dir)/,,$(World_Source)))
|
||||
Common_Source = $(wildcard $(Source_Dir)/common/*.cpp)
|
||||
Common_Objects = $(patsubst %.cpp,$(Current_Build_Dir)/%.o,$(subst $(Source_Dir)/,,$(Common_Source)))
|
||||
Lua_Source = $(wildcard $(Source_Dir)/LUA/*.c)
|
||||
Lua_Objects = $(patsubst %.c,$(Current_Build_Dir)/%.o,$(subst $(Source_Dir)/,,$(Lua_Source)))
|
||||
|
||||
|
||||
# Receipes
|
||||
all: $(APP)
|
||||
|
||||
$(APP): $(Common_Objects) $(World_Objects) $(Lua_Objects)
|
||||
@echo Linking...
|
||||
@$(LINKER) $(W_Flags) $^ $(LD_Flags) -o $(App_Filename)
|
||||
@test -e $(APP) || /bin/true
|
||||
#@ln -s $(App_Filename) $(APP) || /bin/true
|
||||
@echo Finished building world.
|
||||
|
||||
$(Current_Build_Dir)/LUA/%.o: $(Source_Dir)/LUA/%.c
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) -c $(Lua_C_Flags) $(Lua_W_Flags) $< -o $@
|
||||
|
||||
$(Current_Build_Dir)/%.o: $(Source_Dir)/%.cpp
|
||||
@mkdir -p $(dir $@)
|
||||
$(CXX) -c $(C_Flags) $(D_Flags) $(W_Flags) $< -o $@
|
||||
|
||||
#setup:
|
||||
# @test ! -e volumes.phys && ln -s $(Conf_Dir)/volumes.phys . || /bin/true
|
||||
# @test ! -e vgemu-structs.xml && ln -s $(Conf_Dir)/vgemu-structs.xml . || /bin/true
|
||||
# @$(foreach folder,$(wildcard $(Content_Dir)/scripts/*),test -d $(Content_Dir)/scripts && test ! -e $(notdir $(folder)) && ln -s $(folder) . || /bin/true)
|
||||
# @echo "Symlinks have been created."
|
||||
# @cp -n $(Conf_Dir)/vgemu-world.xml .
|
||||
# @echo "You need to edit your config file: vgemu-world.xml"
|
||||
|
||||
release:
|
||||
@$(MAKE) "BUILD=release"
|
||||
|
||||
debug:
|
||||
@$(MAKE) "BUILD=debug"
|
||||
|
||||
clean:
|
||||
rm -rf $(filter-out %Lua,$(foreach folder,$(wildcard $(Current_Build_Dir)/*),$(folder))) $(App_Filename) $(APP)
|
||||
|
||||
cleanlua:
|
||||
rm -rf $(Current_Build_Dir)/Lua
|
||||
|
||||
cleanall:
|
||||
rm -rf $(Build_Dir) $(App_Filename) $(APP)
|
||||
|
||||
#cleansetup:
|
||||
# rm volumes.phys vgemu-structs.xml $(foreach folder,$(wildcard $(Content_Dir)/scripts/*),$(notdir $(folder)))
|
||||
|
||||
#docs: docs-world
|
||||
|
||||
#docs-world:
|
||||
# @cd ../../doc; doxygen Doxyfile-World
|
|
@ -57,6 +57,16 @@ using namespace std;
|
|||
#include "Transmute.h"
|
||||
#include "Zone/ChestTrap.h"
|
||||
|
||||
//devn00b
|
||||
#ifdef DISCORD
|
||||
//linux only for the moment.
|
||||
#ifndef WIN32
|
||||
#include <dpp/dpp.h>
|
||||
#include "Chat/Chat.h"
|
||||
extern Chat chat;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
double frame_time = 0.0;
|
||||
|
||||
#ifdef WIN32
|
||||
|
@ -113,6 +123,12 @@ extern map<int16, int16> EQOpcodeVersions;
|
|||
ThreadReturnType ItemLoad (void* tmp);
|
||||
ThreadReturnType AchievmentLoad (void* tmp);
|
||||
ThreadReturnType SpellLoad (void* tmp);
|
||||
//devn00b
|
||||
#ifdef DISCORD
|
||||
#ifndef WIN32
|
||||
ThreadReturnType StartDiscord (void* tmp);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
#ifdef PROFILER
|
||||
|
@ -238,9 +254,12 @@ int main(int argc, char** argv) {
|
|||
pthread_t thread2;
|
||||
pthread_create(&thread2, NULL, SpellLoad, &world);
|
||||
pthread_detach(thread2);
|
||||
//pthread_t thread3;
|
||||
//pthread_create(&thread3, NULL, AchievmentLoad, &world);
|
||||
//pthread_detach(thread3);
|
||||
//devn00b
|
||||
#ifdef DISCORD
|
||||
pthread_t thread3;
|
||||
pthread_create(&thread3, NULL, StartDiscord, &world);
|
||||
pthread_detach(thread3);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -930,3 +949,64 @@ void NetConnection::WelcomeHeader()
|
|||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
#ifdef DISCORD
|
||||
ThreadReturnType StartDiscord(void* tmp)
|
||||
{
|
||||
#ifndef DISCORD
|
||||
THREAD_RETURN(NULL);
|
||||
#endif
|
||||
if (tmp == 0) {
|
||||
ThrowError("StartDiscord: tmp = 0!");
|
||||
THREAD_RETURN(NULL);
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
|
||||
#endif
|
||||
|
||||
bool enablediscord = rule_manager.GetGlobalRule(R_Discord, DiscordEnabled)->GetBool();
|
||||
|
||||
if(enablediscord == false) {
|
||||
LogWrite(INIT__INFO, 0,"Discord","Bot Disabled By Rule...");
|
||||
THREAD_RETURN(NULL);
|
||||
}
|
||||
|
||||
LogWrite(INIT__INFO, 0, "Discord", "Starting Discord Bridge...");
|
||||
const char* bottoken = rule_manager.GetGlobalRule(R_Discord, DiscordBotToken)->GetString();
|
||||
|
||||
if(strlen(bottoken)== 0) {
|
||||
LogWrite(INIT__INFO, 0,"Discord","Bot Token Was Empty...");
|
||||
THREAD_RETURN(NULL);
|
||||
}
|
||||
|
||||
dpp::cluster bot(bottoken, dpp::i_default_intents | dpp::i_message_content);
|
||||
|
||||
//if we have debug on, go ahead and show DPP logs.
|
||||
#ifdef DEBUG
|
||||
bot.on_log([&bot](const dpp::log_t & event) {
|
||||
std::cout << "[" << dpp::utility::loglevel(event.severity) << "] " << event.message << "\n";
|
||||
});
|
||||
#endif
|
||||
|
||||
bot.on_message_create([&bot](const dpp::message_create_t& event) {
|
||||
if (event.msg.author.is_bot() == false) {
|
||||
std::string chanid = event.msg.channel_id.str();
|
||||
std::string listenchan = rule_manager.GetGlobalRule(R_Discord, DiscordListenChan)->GetString();
|
||||
|
||||
if(chanid.compare(listenchan) != 0 || !chanid.size() || !listenchan.size()) {
|
||||
return;
|
||||
}
|
||||
chat.TellChannel(NULL, listenchan.c_str(), event.msg.content.c_str(), event.msg.author.username.c_str());
|
||||
}
|
||||
});
|
||||
|
||||
while(true) {
|
||||
bot.start(dpp::st_wait);
|
||||
//wait 30s for reconnect. prevents hammering discord and a potential ban.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(30000));
|
||||
}
|
||||
|
||||
THREAD_RETURN(NULL);
|
||||
}
|
||||
#endif
|
Loading…
Reference in a new issue