Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Voice Chat support #668

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,7 @@ cmake_install.cmake
#
# Module files
#
src/modules/
src/modules/

# Voice Chat server
src/voicechat-server/
2 changes: 2 additions & 0 deletions cmake/options.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ option(BUILD_EXTRACTORS "Build map/dbc/vmap/mmap extractors"
option(BUILD_SCRIPTDEV "Build ScriptDev. (OFF Speedup build)" ON)
option(BUILD_PLAYERBOTS "Build Playerbots mod" OFF)
option(BUILD_AHBOT "Build Auction House Bot mod" OFF)
option(BUILD_VOICECHAT "Build VoiceChat server and handlers" OFF)
option(BUILD_METRICS "Build Metrics, generate data for Grafana" OFF)
option(BUILD_RECASTDEMOMOD "Build map/vmap/mmap viewer" OFF)
option(BUILD_GIT_ID "Build git_id" OFF)
Expand Down Expand Up @@ -36,6 +37,7 @@ message(STATUS
BUILD_EXTRACTORS Build map/dbc/vmap/mmap extractor
BUILD_PLAYERBOTS Build Playerbots mod
BUILD_AHBOT Build Auction House Bot mod
BUILD_VOICECHAT Build VoiceChat server and handlers
BUILD_METRICS Build Metrics, generate data for Grafana
BUILD_RECASTDEMOMOD Build map/vmap/mmap viewer
BUILD_GIT_ID Build git_id
Expand Down
6 changes: 6 additions & 0 deletions cmake/showoptions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ else()
message(STATUS "Build AHBot : No (default)")
endif()

if(BUILD_VOICECHAT)
message(STATUS "Build VoiceChat : Yes")
else()
message(STATUS "Build VoiceChat : No (default)")
endif()

if(BUILD_METRICS)
message(STATUS "Build METRICS : Yes")
else()
Expand Down
32 changes: 31 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,34 @@ endif()

if(BUILD_LOGIN_SERVER)
add_subdirectory(realmd)
endif()
endif()

# Voice Chat server and handlers
if(BUILD_VOICECHAT)
include(FetchContent)

FetchContent_Declare(
voicechat-server
GIT_REPOSITORY "https://github.com/celguar/voicechat-server.git"
GIT_TAG "main"
)

if(NOT voicechat-server_POPULATED)
message(STATUS "Fetching VoiceChat server...")

FetchContent_Populate(voicechat-server)

if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/voicechat-server)
file(REMOVE_RECURSE ${CMAKE_CURRENT_SOURCE_DIR}/voicechat-server)
endif()

file(COPY ${voicechat-server_SOURCE_DIR}/. DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/voicechat-server)
message(STATUS "VoiceChat Server fetched and populated in ${CMAKE_CURRENT_SOURCE_DIR}/voicechat-server")
endif()

add_subdirectory(voicechat-server)
else()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/voicechat-server)
file(REMOVE_RECURSE ${CMAKE_CURRENT_SOURCE_DIR}/voicechat-server)
endif()
endif()
15 changes: 15 additions & 0 deletions src/game/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ if(NOT BUILD_SCRIPTDEV)
endforeach()
endif()

if(NOT BUILD_VOICECHAT)
set (EXCLUDE_DIR "VoiceChat")
foreach (TMP_PATH ${LIBRARY_SRCS})
string (FIND ${TMP_PATH} ${EXCLUDE_DIR} EXCLUDE_DIR_FOUND)
if (NOT ${EXCLUDE_DIR_FOUND} EQUAL -1)
list(REMOVE_ITEM LIBRARY_SRCS ${TMP_PATH})
endif ()
endforeach()
endif()

if(NOT BUILD_DEPRECATED_PLAYERBOT)
# exclude Playerbot folder
set (EXCLUDE_DIR "PlayerBot/")
Expand Down Expand Up @@ -145,6 +155,11 @@ if (BUILD_AHBOT)
add_definitions(-DBUILD_AHBOT)
endif()

# Define BUILD_VOICECHAT if need
if (BUILD_VOICECHAT)
add_definitions(-DBUILD_VOICECHAT)
endif()

# Define BUILD_METRICS if need
if (BUILD_METRICS)
add_definitions(-DBUILD_METRICS)
Expand Down
129 changes: 127 additions & 2 deletions src/game/Chat/Channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,15 @@
#include "Chat/Chat.h"
#include "Anticheat/Anticheat.hpp"

#ifdef BUILD_VOICECHAT
#include "VoiceChat/VoiceChatMgr.h"
#endif

Channel::Channel(const std::string& name, uint32 channel_id/* = 0*/)
: m_name(name)
#ifdef BUILD_VOICECHAT
, m_voice(false)
#endif
{
if (ChatChannelsEntry const* builtin = GetChatChannelsEntryFor(name, channel_id))
{
Expand Down Expand Up @@ -122,6 +129,27 @@ void Channel::Join(Player* player, const char* password)
pinfo.player = guid;
pinfo.flags = MEMBER_FLAG_NONE;

#ifdef BUILD_VOICECHAT
// join voice chat
if (!IsConstant() && HasFlag(CHANNEL_FLAG_CUSTOM) && sVoiceChatMgr.CanUseVoiceChat())
{
// first voice chat enabled member turns it on
// only proof is https://www.youtube.com/watch?v=h5oH4ER2cJ0 where voice chat is auto enabled on new channel
if (!IsVoiceEnabled())
{
if (player->GetSession()->IsVoiceChatEnabled())
{
// toggle voice and update player flags
ToggleVoice(player);
}
}
if (IsVoiceEnabled())
{
sVoiceChatMgr.AddToCustomVoiceChatChannel(guid, this->GetName(), player->GetTeam());
}
}
#endif

MakeYouJoined(data, m_name, *this);
SendToOne(data, guid);

Expand Down Expand Up @@ -178,6 +206,14 @@ void Channel::Leave(Player* player, bool send)

if (changeowner && !IsPublic())
SetOwner(SelectNewOwner(), (m_players.size() > 1));

#ifdef BUILD_VOICECHAT
// leave voice chat
if (IsVoiceEnabled())
{
sVoiceChatMgr.RemoveFromCustomVoiceChatChannel(guid, this->GetName(), player->GetTeam());
}
#endif
}

void Channel::KickOrBan(Player* player, const char* targetName, bool ban)
Expand Down Expand Up @@ -333,7 +369,7 @@ void Channel::SetPassword(Player* player, const char* password)
void Channel::SetModeFlags(Player* player, const char* targetName, ChannelMemberFlags flags, bool set)
{
// Restrict input flags to currently supported by this method
flags = ChannelMemberFlags(uint8(flags) & (MEMBER_FLAG_MODERATOR | MEMBER_FLAG_MUTED));
flags = ChannelMemberFlags(uint8(flags) & (MEMBER_FLAG_MODERATOR | MEMBER_FLAG_MIC_MUTED | MEMBER_FLAG_MIC_MUTED | MEMBER_FLAG_VOICED));

if (!flags)
return;
Expand Down Expand Up @@ -766,6 +802,95 @@ void Channel::DeVoice(ObjectGuid /*guid1*/, ObjectGuid /*guid2*/) const
{
}

#ifdef BUILD_VOICECHAT
void Channel::AddVoiceChatMembersAfterCreate()
{
// add voice enabled players to channel after it's created on voice server
for (auto itr = m_players.begin(); itr != m_players.end(); ++itr)
{
if (Player* plr = sObjectMgr.GetPlayer(itr->first, false))
{
if (plr->GetSession()->IsVoiceChatEnabled())
{
sVoiceChatMgr.AddToCustomVoiceChatChannel(itr->first, this->GetName(), plr->GetTeam());
}
}
}
}

void Channel::ToggleVoice(Player* player)
{
// silently disable if voice server disconnected
if (!player)
{
m_voice = !m_voice;
if (m_voice)
m_flags |= CHANNEL_FLAG_VOICE;
else
m_flags &= ~CHANNEL_FLAG_VOICE;

return;
}

ObjectGuid guid = player->GetObjectGuid();

if (!IsOn(guid))
{
WorldPacket data;
MakeNotMember(data, m_name);
SendToOne(data, guid);
return;
}

const uint32 level = sWorld.getConfig(CONFIG_UINT32_GM_LEVEL_CHANNEL_MODERATION);
const bool gm = (level && player->GetSession()->GetSecurity() >= level);

if (!m_players[guid].IsOwner() && !gm)
{
WorldPacket data;
MakeNotOwner(data, m_name);
SendToOne(data, guid);
return;
}

// toggle channel voice
m_voice = !m_voice;

WorldPacket data;
if (m_voice)
MakeVoiceOn(data, m_name, guid);
else
MakeVoiceOff(data, m_name, guid);

SendToAll(data);

if (m_voice)
m_flags |= CHANNEL_FLAG_VOICE;
else
m_flags &= ~CHANNEL_FLAG_VOICE;

// update player flags, maybe used in right click menu in chat UI
for (PlayerList::const_iterator i = m_players.begin(); i != m_players.end(); ++i)
{
if (Player* member = sObjectMgr.GetPlayer(i->first, false))
{
if (WorldSession* session = member->GetSession())
{
if (session->IsVoiceChatEnabled())
{
m_players[i->first].SetVoiced(m_voice);
}
}
}
}

if (m_voice)
{
sVoiceChatMgr.AddToCustomVoiceChatChannel(guid, this->GetName(), player->GetTeam());
}
}
#endif

void Channel::JoinNotify(ObjectGuid guid)
{
WorldPacket data;
Expand Down Expand Up @@ -1033,7 +1158,7 @@ ObjectGuid Channel::SelectNewOwner() const
void Channel::SetModeFlags(ObjectGuid guid, ChannelMemberFlags flags, bool set)
{
// Restrict input flags to currently supported by this method
flags = ChannelMemberFlags(uint8(flags) & (MEMBER_FLAG_MODERATOR | MEMBER_FLAG_MUTED));
flags = ChannelMemberFlags(uint8(flags) & (MEMBER_FLAG_MODERATOR | MEMBER_FLAG_MIC_MUTED | MEMBER_FLAG_MIC_MUTED | MEMBER_FLAG_VOICED));

if (flags && m_players[guid].HasFlag(flags) != set)
{
Expand Down
25 changes: 22 additions & 3 deletions src/game/Chat/Channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ class Channel
inline void SetModerator(bool state) { SetFlag(MEMBER_FLAG_MODERATOR, state); }
inline bool IsMuted() const { return HasFlag(MEMBER_FLAG_MUTED); }
inline void SetMuted(bool state) { SetFlag(MEMBER_FLAG_MUTED, state); }
#ifdef BUILD_VOICECHAT
inline bool IsMicMuted() const { return HasFlag(MEMBER_FLAG_MIC_MUTED); }
inline void SetMicMuted(bool state) { SetFlag(MEMBER_FLAG_MIC_MUTED, state); }
inline bool IsVoiced() const { return HasFlag(MEMBER_FLAG_VOICED); }
inline void SetVoiced(bool state) { SetFlag(MEMBER_FLAG_VOICED, state); }
#endif
};

typedef std::map<ObjectGuid, PlayerInfo> PlayerList;
Expand Down Expand Up @@ -159,6 +165,10 @@ class Channel
void SetModeFlags(Player* player, const char* targetName, ChannelMemberFlags flags, bool set);
inline void SetModerator(Player* player, const char* targetName, bool set) { SetModeFlags(player, targetName, MEMBER_FLAG_MODERATOR, set); }
inline void SetMute(Player* player, const char* targetName, bool set) { SetModeFlags(player, targetName, MEMBER_FLAG_MUTED, set); }
#ifdef BUILD_VOICECHAT
inline void SetMicMute(Player* player, const char* targetName, bool set) { SetModeFlags(player, targetName, MEMBER_FLAG_MIC_MUTED, set); }
inline void SetVoiced(Player* player, const char* targetName, bool set) { SetModeFlags(player, targetName, MEMBER_FLAG_VOICED, set); }
#endif
void SetOwner(Player* player, const char* targetName);
void SendChannelOwnerResponse(Player* player) const;
void SendChannelListResponse(Player* player, bool display = false);
Expand All @@ -171,6 +181,12 @@ class Channel
void JoinNotify(ObjectGuid guid); // invisible notify
void LeaveNotify(ObjectGuid guid); // invisible notify

#ifdef BUILD_VOICECHAT
void AddVoiceChatMembersAfterCreate();
void ToggleVoice(Player* player = nullptr);
bool IsVoiceEnabled() const { return HasFlag(CHANNEL_FLAG_VOICE); }
#endif

// initial packet data (notify type and channel name)
static void MakeNotifyPacket(WorldPacket& data, const std::string& channel, ChatNotify type);
// type specific packet data
Expand Down Expand Up @@ -214,14 +230,14 @@ class Channel
// Make a custom channel acquire global-like properties
bool SetStatic(bool state, bool command = false);

bool IsOn(ObjectGuid who) const { return m_players.find(who) != m_players.end(); }
bool IsBanned(ObjectGuid guid) const { return m_banned.find(guid) != m_banned.end(); }

private:
void SendToOne(WorldPacket const& data, ObjectGuid receiver) const;
void SendToAll(WorldPacket const& data) const;
void SendMessage(WorldPacket const& data, ObjectGuid sender) const;

bool IsOn(ObjectGuid who) const { return m_players.find(who) != m_players.end(); }
bool IsBanned(ObjectGuid guid) const { return m_banned.find(guid) != m_banned.end(); }

uint8 GetPlayerFlags(ObjectGuid guid) const
{
PlayerList::const_iterator p_itr = m_players.find(guid);
Expand All @@ -245,6 +261,9 @@ class Channel
const ChatChannelsEntry* m_entry = nullptr;
bool m_announcements = false;
bool m_moderation = false;
#ifdef BUILD_VOICECHAT
bool m_voice = false;
#endif
uint8 m_flags = CHANNEL_FLAG_NONE;
// Custom features:
bool m_static = false;
Expand Down
10 changes: 10 additions & 0 deletions src/game/Chat/ChannelMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
#include "Policies/Singleton.h"
#include "World/World.h"

#ifdef BUILD_VOICECHAT
#include "VoiceChat/VoiceChatMgr.h"
#endif

INSTANTIATE_SINGLETON_1(AllianceChannelMgr);
INSTANTIATE_SINGLETON_1(HordeChannelMgr);

Expand Down Expand Up @@ -97,6 +101,12 @@ void ChannelMgr::LeftChannel(const std::string& name)

if (channel->GetNumPlayers() == 0 && !channel->IsConstant())
{
#ifdef BUILD_VOICECHAT
// delete voice channel
Team team = this == channelMgr(ALLIANCE) ? ALLIANCE : HORDE;
sVoiceChatMgr.DeleteCustomVoiceChatChannel(channel->GetName(), team);
#endif

channels.erase(wname);
delete channel;
}
Expand Down
14 changes: 14 additions & 0 deletions src/game/Chat/Chat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -941,6 +941,17 @@ ChatCommand* ChatHandler::getCommandTable()
{ nullptr, 0, false, nullptr, "", nullptr }
};

#ifdef BUILD_VOICECHAT
static ChatCommand voiceChatCommandTable[] =
{
{ "disconnect", SEC_ADMINISTRATOR, false, &ChatHandler::HandleVoiceChatDisconnectCommand, "", nullptr },
{ "disable", SEC_ADMINISTRATOR, false, &ChatHandler::HandleVoiceChatDisableCommand, "", nullptr },
{ "enable", SEC_ADMINISTRATOR, false, &ChatHandler::HandleVoiceChatEnableCommand, "", nullptr },
{ "stats", SEC_ADMINISTRATOR, false, &ChatHandler::HandleVoiceChatStatsCommand, "", nullptr },
{ nullptr, 0, false, nullptr, "", nullptr }
};
#endif

static ChatCommand commandTable[] =
{
{ "anticheat", SEC_GAMEMASTER, true, nullptr, "", anticheatCommandTable},
Expand Down Expand Up @@ -1055,6 +1066,9 @@ ChatCommand* ChatHandler::getCommandTable()
{ "loot", SEC_GAMEMASTER, true, nullptr, "", lootCommandTable },
#ifdef BUILD_DEPRECATED_PLAYERBOT
{ "bot", SEC_PLAYER, false, &ChatHandler::HandlePlayerbotCommand, "", nullptr },
#endif
#ifdef BUILD_VOICECHAT
{ "voicechat", SEC_ADMINISTRATOR, false, nullptr, "", voiceChatCommandTable },
#endif
{ nullptr, 0, false, nullptr, "", nullptr }
};
Expand Down
Loading