diff --git a/code/components/gta-net-five/src/MumbleVoice.cpp b/code/components/gta-net-five/src/MumbleVoice.cpp index 1773cc998d..2d75213551 100644 --- a/code/components/gta-net-five/src/MumbleVoice.cpp +++ b/code/components/gta-net-five/src/MumbleVoice.cpp @@ -33,6 +33,8 @@ #include #include +#include "ScriptWarnings.h" + #if __has_include() #include #endif @@ -802,13 +804,17 @@ static fx::TNativeHandler getServerId; static std::shared_ptr getAudioContext(int playerId) { - if (!g_mumble.connected) + int serverId = FxNativeInvoke::Invoke(getServerId, playerId); + + // if the server id is 0 then we don't have a player. + // WARNING: This is a implementation detail + if (!g_mumble.connected || serverId == 0) { return {}; } std::string name = fmt::sprintf("[%d] %s", - FxNativeInvoke::Invoke(getServerId, playerId), + serverId, FxNativeInvoke::Invoke(getPlayerName, playerId)); return g_mumbleClient->GetAudioContext(name); } @@ -824,13 +830,55 @@ static std::shared_ptr getAudioContextByServerId(int serverId return g_mumbleClient->GetAudioContext(name); } -std::wstring getMumbleName(int playerId) +std::optional getMumbleName(int playerId) { + int serverId = FxNativeInvoke::Invoke(getServerId, playerId); + + // if the server id is 0 then we don't have a player. + // WARNING: This is a implementation detail + if (serverId == 0) + { + return std::nullopt; + } + return ToWide(fmt::sprintf("[%d] %s", - FxNativeInvoke::Invoke(getServerId, playerId), + serverId, FxNativeInvoke::Invoke(getPlayerName, playerId))); } + +std::string GetMumbleChannel(int channelId) +{ + return fmt::sprintf("Game Channel %d", channelId); +} + +std::wstring GetMumbleChannelWide(int channelId) +{ + return ToWide(GetMumbleChannel(channelId)); +} + +// Returns true if the voice target id valid to use with the `VoiceTarget` packet (1..30) +bool IsVoiceTargetIdValid(int id) +{ + return id >= 1 && id <= 30; +} + +// Ensures that mumble is connected before calling any mumble related functions +template +inline auto MakeMumbleNative(MumbleFn fn, uintptr_t defaultValue = 0) +{ + return [=](fx::ScriptContext& context) + { + if (!g_mumble.connected) + { + context.SetResult(defaultValue); + return; + } + + fn(context); + }; +}; + #include static HookFunction hookFunction([]() @@ -923,22 +971,18 @@ static HookFunction hookFunction([]() } }); - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_SET_TALKER_PROXIMITY", [](fx::ScriptContext& context) + + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_SET_TALKER_PROXIMITY", MakeMumbleNative([](fx::ScriptContext& context) { float proximity = context.GetArgument(0); - if (g_mumble.connected) - { - g_mumbleClient->SetAudioDistance(proximity); - } - }); + g_mumbleClient->SetAudioDistance(proximity); + })); - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_GET_TALKER_PROXIMITY", [](fx::ScriptContext& context) + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_GET_TALKER_PROXIMITY", MakeMumbleNative([](fx::ScriptContext& context) { - float proximity = (g_mumble.connected) ? g_mumbleClient->GetAudioDistance() : 0.0f; - - context.SetResult(proximity); - }); + context.SetResult(g_mumbleClient->GetAudioDistance()); + }, 0.0f)); fx::ScriptEngine::RegisterNativeHandler("MUMBLE_SET_ACTIVE", [](fx::ScriptContext& context) { @@ -950,313 +994,313 @@ static HookFunction hookFunction([]() context.SetResult(g_voiceActiveByScript); }); - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_IS_PLAYER_TALKING", [](fx::ScriptContext& context) + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_IS_PLAYER_TALKING", MakeMumbleNative([](fx::ScriptContext& context) { int playerId = context.GetArgument(0); bool isTalking = false; - if (g_mumble.connected) + if (playerId >= 0 && playerId < g_talkers.size()) { - if (playerId >= 0 && playerId < g_talkers.size()) - { - isTalking = g_talkers.test(playerId); - } + isTalking = g_talkers.test(playerId); } context.SetResult(isTalking); - }); + }, false)); - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_SET_VOLUME_OVERRIDE", [](fx::ScriptContext& context) + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_SET_VOLUME_OVERRIDE", MakeMumbleNative([](fx::ScriptContext& context) { int playerId = context.GetArgument(0); float volume = context.GetArgument(1); - if (g_mumble.connected) + if (auto name = getMumbleName(playerId)) { - std::wstring name = getMumbleName(playerId); - - g_mumbleClient->SetClientVolumeOverride(name, volume); + g_mumbleClient->SetClientVolumeOverride(*name, volume); } - }); + })); - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_SET_VOLUME_OVERRIDE_BY_SERVER_ID", [](fx::ScriptContext& context) + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_SET_VOLUME_OVERRIDE_BY_SERVER_ID", MakeMumbleNative([](fx::ScriptContext& context) { int serverId = context.GetArgument(0); float volume = context.GetArgument(1); - if (g_mumble.connected) - { - g_mumbleClient->SetClientVolumeOverrideByServerId(serverId, volume); - } - }); + g_mumbleClient->SetClientVolumeOverrideByServerId(serverId, volume); + })); static VoiceTargetConfig vtConfigs[31]; - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_CLEAR_VOICE_TARGET", [](fx::ScriptContext& context) + static auto InvalidTargetIdWarning = [] (const std::string_view& nativeName) + { + fx::scripting::Warningf("mumble", "%s: Tried to use an invalid targetId, the minimum target id is 1, the maximum is 30.", nativeName); + }; + + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_CLEAR_VOICE_TARGET", MakeMumbleNative([](fx::ScriptContext& context) { auto id = context.GetArgument(0); - if (id >= 0 && id < 31) + if (IsVoiceTargetIdValid(id)) { - if (g_mumble.connected) - { - vtConfigs[id] = {}; - g_mumbleClient->UpdateVoiceTarget(id, vtConfigs[id]); - } + vtConfigs[id] = {}; + g_mumbleClient->UpdateVoiceTarget(id, vtConfigs[id]); } - }); + else + { + InvalidTargetIdWarning("MUMBLE_CLEAR_VOICE_TARGET"); + } + })); + - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_REMOVE_VOICE_TARGET_CHANNEL", [](fx::ScriptContext& context) + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_REMOVE_VOICE_TARGET_CHANNEL", MakeMumbleNative([](fx::ScriptContext& context) { auto id = context.GetArgument(0); auto channel = context.GetArgument(1); - if (id >= 0 && id < 31) + if (IsVoiceTargetIdValid(id)) { - if (g_mumble.connected) - { - auto targetChannel = fmt::sprintf("Game Channel %d", channel); - auto& targets = vtConfigs[id].targets; - targets.remove_if([targetChannel](auto& target) - { - return target.channel == targetChannel; - }); + auto targetChannel = GetMumbleChannelWide(channel); + auto& targets = vtConfigs[id]; + // we only want to mark the voice target config as pending if we actually modified it + // `erase()` will return `0` if it didn't remove anything or `1` if it did + if (targets.channels.erase(targetChannel)) + { g_mumbleClient->UpdateVoiceTarget(id, vtConfigs[id]); } } - }); + else + { + InvalidTargetIdWarning("MUMBLE_REMOVE_VOICE_TARGET_CHANNEL"); + } + })); - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_REMOVE_VOICE_TARGET_PLAYER", [](fx::ScriptContext& context) + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_REMOVE_VOICE_TARGET_PLAYER", MakeMumbleNative([](fx::ScriptContext& context) { auto id = context.GetArgument(0); auto playerId = context.GetArgument(1); - if (id >= 0 && id < 31) + if (IsVoiceTargetIdValid(id)) { - if (g_mumble.connected) + if (auto targetName = getMumbleName(playerId)) { - std::wstring targetName = getMumbleName(playerId); + auto& targets = vtConfigs[id]; - auto& targets = vtConfigs[id].targets; - targets.remove_if([targetName](auto& target) + // we only want to mark the voice target config as pending if we actually modified it + // `erase()` will return `0` if it didn't remove anything or `1` if it did + if (targets.users.erase(*targetName)) { - return target.users.size() > 0 && std::find(target.users.begin(), target.users.end(), targetName) != target.users.end(); - }); - - g_mumbleClient->UpdateVoiceTarget(id, vtConfigs[id]); + g_mumbleClient->UpdateVoiceTarget(id, vtConfigs[id]); + } } } - }); + else + { + InvalidTargetIdWarning("MUMBLE_REMOVE_VOICE_TARGET_PLAYER"); + } + })); - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_REMOVE_VOICE_TARGET_PLAYER_BY_SERVER_ID", [](fx::ScriptContext& context) + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_REMOVE_VOICE_TARGET_PLAYER_BY_SERVER_ID", MakeMumbleNative([](fx::ScriptContext& context) { auto id = context.GetArgument(0); auto serverId = context.GetArgument(1); - if (id >= 0 && id < 31) + if (IsVoiceTargetIdValid(id)) { - if (g_mumble.connected) - { - VoiceTargetConfig::Target ch; - std::wstring targetName = g_mumbleClient->GetPlayerNameFromServerId(serverId); + std::wstring targetName = g_mumbleClient->GetPlayerNameFromServerId(serverId); - if (!targetName.empty()) - { - auto& targets = vtConfigs[id].targets; - targets.remove_if([targetName](auto& target) - { - return target.users.size() > 0 && std::find(target.users.begin(), target.users.end(), targetName) != target.users.end(); - }); - } + // if the player doesn't exist then we don't want to update targetting + if (targetName.empty()) + { + return; } + + auto& targets = vtConfigs[id]; - g_mumbleClient->UpdateVoiceTarget(id, vtConfigs[id]); + if (targets.users.erase(targetName)) + { + g_mumbleClient->UpdateVoiceTarget(id, vtConfigs[id]); + } } - }); + else + { + InvalidTargetIdWarning("MUMBLE_REMOVE_VOICE_TARGET_PLAYER_BY_SERVER_ID"); + } + })); - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_CLEAR_VOICE_TARGET_CHANNELS", [](fx::ScriptContext& context) + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_CLEAR_VOICE_TARGET_CHANNELS", MakeMumbleNative([](fx::ScriptContext& context) { auto id = context.GetArgument(0); - if (id >= 0 && id < 31) + if (IsVoiceTargetIdValid(id)) { - if (g_mumble.connected) - { - auto& targets = vtConfigs[id].targets; - targets.remove_if([](auto& target) - { - return !target.channel.empty(); - }); + auto& targets = vtConfigs[id]; + + targets.channels.clear(); - g_mumbleClient->UpdateVoiceTarget(id, vtConfigs[id]); - } + g_mumbleClient->UpdateVoiceTarget(id, vtConfigs[id]); } - }); + else + { + InvalidTargetIdWarning("MUMBLE_CLEAR_VOICE_TARGET_CHANNELS"); + } + })); - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_CLEAR_VOICE_TARGET_PLAYERS", [](fx::ScriptContext& context) + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_CLEAR_VOICE_TARGET_PLAYERS", MakeMumbleNative([](fx::ScriptContext& context) { auto id = context.GetArgument(0); - if (id >= 0 && id < 31) + if (IsVoiceTargetIdValid(id)) { - if (g_mumble.connected) - { - auto& targets = vtConfigs[id].targets; - targets.remove_if([](auto& target) - { - return target.users.size() > 0; - }); + auto& targets = vtConfigs[id]; - g_mumbleClient->UpdateVoiceTarget(id, vtConfigs[id]); - } + targets.users.clear(); + + g_mumbleClient->UpdateVoiceTarget(id, vtConfigs[id]); } - }); + else + { + InvalidTargetIdWarning("MUMBLE_CLEAR_VOICE_TARGET_PLAYERS"); + } + })); - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_ADD_VOICE_CHANNEL_LISTEN", [](fx::ScriptContext& context) + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_ADD_VOICE_CHANNEL_LISTEN", MakeMumbleNative([](fx::ScriptContext& context) { auto channel = context.GetArgument(0); - if (g_mumble.connected) + const std::string channelName = GetMumbleChannel(channel); + if (g_mumbleClient->DoesChannelExist(channelName)) { - g_mumbleClient->AddListenChannel(fmt::sprintf("Game Channel %d", channel)); + g_mumbleClient->AddListenChannel(channelName); } - }); - - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_REMOVE_VOICE_CHANNEL_LISTEN", [](fx::ScriptContext& context) + // TODO: See if we actually want to have a warning here, since this wouldn't cause any noticeable issues, unlike voice targeting which players might + // get confused on why it doesn't work + // else + // { + // fx::scripting::Warningf("mumble", "MUMBLE_ADD_VOICE_CHANNEL_LISTEN: Tried to call native on a channel that didn't exist"); + // } + })); + + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_REMOVE_VOICE_CHANNEL_LISTEN", MakeMumbleNative([](fx::ScriptContext& context) { auto channel = context.GetArgument(0); - if (g_mumble.connected) - { - g_mumbleClient->RemoveListenChannel(fmt::sprintf("Game Channel %d", channel)); - } - }); + g_mumbleClient->RemoveListenChannel(GetMumbleChannel(channel)); + })); - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_ADD_VOICE_TARGET_CHANNEL", [](fx::ScriptContext& context) + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_ADD_VOICE_TARGET_CHANNEL", MakeMumbleNative([](fx::ScriptContext& context) { auto id = context.GetArgument(0); auto channel = context.GetArgument(1); - if (id >= 0 && id < 31) - { - if (g_mumble.connected) - { - VoiceTargetConfig::Target ch; - ch.channel = fmt::sprintf("Game Channel %d", channel); - - vtConfigs[id].targets.push_back(ch); - g_mumbleClient->UpdateVoiceTarget(id, vtConfigs[id]); - } - } - }); - - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_DOES_CHANNEL_EXIST", [](fx::ScriptContext& context) { - auto channel = context.GetArgument(0); - - if (g_mumble.connected) + if (IsVoiceTargetIdValid(id)) { - auto channelName = fmt::sprintf("Game Channel %d", channel); - context.SetResult(g_mumbleClient->DoesChannelExist(channelName)); + auto& targets = vtConfigs[id]; + + targets.channels.emplace(GetMumbleChannelWide(channel)); + + g_mumbleClient->UpdateVoiceTarget(id, vtConfigs[id]); } else { - context.SetResult(false); + InvalidTargetIdWarning("MUMBLE_ADD_VOICE_TARGET_CHANNEL"); } - }); + })); - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_ADD_VOICE_TARGET_PLAYER", [](fx::ScriptContext& context) + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_DOES_CHANNEL_EXIST", MakeMumbleNative([](fx::ScriptContext& context) { + auto channel = context.GetArgument(0); + + context.SetResult(g_mumbleClient->DoesChannelExist(GetMumbleChannel(channel))); + })); + + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_ADD_VOICE_TARGET_PLAYER", MakeMumbleNative([](fx::ScriptContext& context) { auto id = context.GetArgument(0); auto playerId = context.GetArgument(1); - if (id >= 0 && id < 31) + if (IsVoiceTargetIdValid(id)) { - if (g_mumble.connected) + auto& targets = vtConfigs[id]; + if (auto name = getMumbleName(playerId)) { - VoiceTargetConfig::Target ch; - std::wstring name = getMumbleName(playerId); - - ch.users.push_back(name); - - vtConfigs[id].targets.push_back(ch); + targets.users.emplace(*name); g_mumbleClient->UpdateVoiceTarget(id, vtConfigs[id]); } } - }); + else + { + InvalidTargetIdWarning("MUMBLE_ADD_VOICE_TARGET_PLAYER"); + } + })); - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_ADD_VOICE_TARGET_PLAYER_BY_SERVER_ID", [](fx::ScriptContext& context) + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_ADD_VOICE_TARGET_PLAYER_BY_SERVER_ID", MakeMumbleNative([](fx::ScriptContext& context) { auto id = context.GetArgument(0); int serverId = context.GetArgument(1); - if (id >= 0 && id < 31) + if (IsVoiceTargetIdValid(id)) { - if (g_mumble.connected) - { - VoiceTargetConfig::Target ch; - std::wstring name = g_mumbleClient->GetPlayerNameFromServerId(serverId); - - if (!name.empty()) - { - ch.users.push_back(name); + std::wstring name = g_mumbleClient->GetPlayerNameFromServerId(serverId); - vtConfigs[id].targets.push_back(ch); - g_mumbleClient->UpdateVoiceTarget(id, vtConfigs[id]); - } + if (!name.empty()) + { + vtConfigs[id].users.emplace(name); + g_mumbleClient->UpdateVoiceTarget(id, vtConfigs[id]); } } - }); + else + { + InvalidTargetIdWarning("MUMBLE_ADD_VOICE_TARGET_PLAYER_BY_SERVER_ID"); + } + })); - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_SET_VOICE_TARGET", [](fx::ScriptContext& context) + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_SET_VOICE_TARGET", MakeMumbleNative([](fx::ScriptContext& context) { auto id = context.GetArgument(0); + // We can set our voice target to 0..31 here (and only here!) if (id >= 0 && id < 31) { - if (g_mumble.connected) - { - g_mumbleClient->SetVoiceTarget(id); - } + g_mumbleClient->SetVoiceTarget(id); } - }); + else + { + fx::scripting::Warningf("mumble", "Invalid voice target id %d", id); + } + })); - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_GET_VOICE_CHANNEL_FROM_SERVER_ID", [](fx::ScriptContext& context) + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_GET_VOICE_CHANNEL_FROM_SERVER_ID", MakeMumbleNative([](fx::ScriptContext& context) { int serverId = context.GetArgument(0); int channelId = -1; - if (g_mumble.connected) - { - auto channelName = g_mumbleClient->GetVoiceChannelFromServerId(serverId); + auto channelName = g_mumbleClient->GetVoiceChannelFromServerId(serverId); - if (!channelName.empty()) + if (!channelName.empty()) + { + if (channelName.find("Game Channel ") == 0) { - if (channelName.find("Game Channel ") == 0) - { - channelId = std::stoi(channelName.substr(13)); - } - else if (channelName == "Root") - { - channelId = 0; - } + channelId = std::stoi(channelName.substr(13)); + } + else if (channelName == "Root") + { + channelId = 0; } } context.SetResult(channelId); - }); + })); - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_IS_CONNECTED", [](fx::ScriptContext& context) + // MakeMumbleNative will return false automatically if we're not connected. + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_IS_CONNECTED", MakeMumbleNative([](fx::ScriptContext& context) { - context.SetResult(g_mumble.connected ? true : false); - }); + context.SetResult(true); + })); fx::ScriptEngine::RegisterNativeHandler("MUMBLE_SET_SERVER_ADDRESS", [](fx::ScriptContext& context) { auto address = context.GetArgument(0); int port = context.GetArgument(1); - boost::optional overridePeer = net::PeerAddress::FromString(fmt::sprintf("%s:%d", address, port), port); + auto formattedAddress = fmt::sprintf("%s:%d", address, port); + boost::optional overridePeer = net::PeerAddress::FromString(formattedAddress, port); if (overridePeer) { @@ -1266,7 +1310,7 @@ static HookFunction hookFunction([]() } else { - throw std::exception("Couldn't resolve Mumble server address."); + throw std::exception(va("Couldn't resolve Mumble server address %s.", formattedAddress)); } }); @@ -1284,21 +1328,15 @@ static HookFunction hookFunction([]() g_mumbleClient->SetAudioOutputDistance(dist); }); - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_CLEAR_VOICE_CHANNEL", [](fx::ScriptContext& context) + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_CLEAR_VOICE_CHANNEL", MakeMumbleNative([](fx::ScriptContext& context) { - if (g_mumble.connected) - { - g_mumbleClient->SetChannel("Root"); - } - }); + g_mumbleClient->SetChannel("Root"); + })); - fx::ScriptEngine::RegisterNativeHandler("MUMBLE_SET_VOICE_CHANNEL", [](fx::ScriptContext& context) + fx::ScriptEngine::RegisterNativeHandler("MUMBLE_SET_VOICE_CHANNEL", MakeMumbleNative([](fx::ScriptContext& context) { - if (g_mumble.connected) - { - g_mumbleClient->SetChannel(fmt::sprintf("Game Channel %d", context.GetArgument(0))); - } - }); + g_mumbleClient->SetChannel(GetMumbleChannel(context.GetArgument(0))); + })); scrBindGlobal("GET_AUDIOCONTEXT_FOR_CLIENT", getAudioContext); scrBindGlobal("GET_AUDIOCONTEXT_FOR_SERVERID", getAudioContextByServerId); @@ -1355,7 +1393,7 @@ static HookFunction hookFunction([]() if (g_mumble.connected) { - g_mumbleClient->SetChannel(fmt::sprintf("Game Channel %d", context.GetArgument(0))); + g_mumbleClient->SetChannel(GetMumbleChannel(context.GetArgument(0))); } }); diff --git a/code/components/voip-mumble/include/MumbleClient.h b/code/components/voip-mumble/include/MumbleClient.h index f0bbda637c..da0430f8e3 100644 --- a/code/components/voip-mumble/include/MumbleClient.h +++ b/code/components/voip-mumble/include/MumbleClient.h @@ -49,22 +49,8 @@ enum class MumbleVoiceLikelihood struct VoiceTargetConfig { - struct Target - { - std::vector users; - std::string channel; - // ACL is not supported in umurmur, so does not count - bool links; - bool children; - - inline Target() - : links(false), children(false) - { - - } - }; - - std::list targets; + std::set users; + std::set channels; }; class IMumbleClient : public fwRefCountable diff --git a/code/components/voip-mumble/src/MumbleClient.cpp b/code/components/voip-mumble/src/MumbleClient.cpp index d4d5044e5a..6174db7fba 100644 --- a/code/components/voip-mumble/src/MumbleClient.cpp +++ b/code/components/voip-mumble/src/MumbleClient.cpp @@ -165,7 +165,6 @@ void MumbleClient::Initialize() m_idleTimer = m_loop->Get()->resource(); m_idleTimer->on([this](const uvw::TimerEvent& ev, uvw::TimerHandle& t) { - auto lockedIsActive = [this]() { std::unique_lock _(m_clientMutex); @@ -287,35 +286,31 @@ void MumbleClient::Initialize() MumbleProto::VoiceTarget target; target.set_id(idx); - for (auto& t : config.targets) + // Voice targets can all be set in a single target + auto vt = target.add_targets(); + for (auto& userName : config.users) { - auto vt = target.add_targets(); - - for (auto& userName : t.users) + m_state.ForAllUsers([this, &userName, &vt](const std::shared_ptr& user) { - m_state.ForAllUsers([this, &userName, &vt](const std::shared_ptr& user) + if (user->GetName() == userName) { - if (user->GetName() == userName) - { - vt->add_session(user->GetSessionId()); - } - }); - } + vt->add_session(user->GetSessionId()); + } + }); + } + - if (!t.channel.empty()) + for (auto& channelName: config.channels) + { + for (auto& channelPair : m_state.GetChannels()) { - std::wstring wname = ToWide(t.channel); - for (auto& channelPair : m_state.GetChannels()) + if (channelPair.second.GetName() == channelName) { - if (channelPair.second.GetName() == wname) - { - vt->set_channel_id(channelPair.first); - } + // Channel targeting happens per channel, so we need to add a new target per channel + auto vt = target.add_targets(); + vt->set_channel_id(channelPair.first); } } - - vt->set_links(t.links); - vt->set_children(t.children); } Send(MumbleMessageType::VoiceTarget, target); @@ -422,7 +417,6 @@ concurrency::task MumbleClient::ConnectAsync(const net::P m_tcpPingCount = 0; - memset(m_tcpPings, 0, sizeof(m_tcpPings)); m_state.SetClient(this); @@ -775,7 +769,6 @@ void MumbleClient::HandleUDP(const uint8_t* buf, size_t size) return; } - // handle voice packet HandleVoice(outBuf, size - 4); }