-- used when muted local disableUpdates = false local isListenerEnabled = false local plyCoords = GetEntityCoords(PlayerPedId()) proximity = MumbleGetTalkerProximity() currentTargets = {} function orig_addProximityCheck(ply) local tgtPed = GetPlayerPed(ply) local voiceRange = GetConvar('voice_useNativeAudio', 'false') == 'true' and proximity * 3 or proximity local distance = #(plyCoords - GetEntityCoords(tgtPed)) return distance < voiceRange, distance end local addProximityCheck = orig_addProximityCheck exports("overrideProximityCheck", function(fn) addProximityCheck = fn end) exports("resetProximityCheck", function() addProximityCheck = orig_addProximityCheck end) function addNearbyPlayers() if disableUpdates then return end -- update here so we don't have to update every call of addProximityCheck plyCoords = GetEntityCoords(PlayerPedId()) proximity = MumbleGetTalkerProximity() currentTargets = {} MumbleClearVoiceTargetChannels(voiceTarget) if LocalPlayer.state.disableProximity then return end MumbleAddVoiceChannelListen(playerServerId) MumbleAddVoiceTargetChannel(voiceTarget, playerServerId) for source, _ in pairs(callData) do if source ~= playerServerId then MumbleAddVoiceTargetChannel(voiceTarget, source) end end local players = GetActivePlayers() for i = 1, #players do local ply = players[i] local serverId = GetPlayerServerId(ply) local shouldAdd, distance = addProximityCheck(ply) if shouldAdd then -- if distance then -- currentTargets[serverId] = distance -- else -- -- backwards compat, maybe remove in v7 -- currentTargets[serverId] = 15.0 -- end -- logger.verbose('Added %s as a voice target', serverId) MumbleAddVoiceTargetChannel(voiceTarget, serverId) end end end function setSpectatorMode(enabled) logger.info('Setting spectate mode to %s', enabled) isListenerEnabled = enabled local players = GetActivePlayers() if isListenerEnabled then for i = 1, #players do local ply = players[i] local serverId = GetPlayerServerId(ply) if serverId == playerServerId then goto skip_loop end logger.verbose("Adding %s to listen table", serverId) MumbleAddVoiceChannelListen(serverId) ::skip_loop:: end else for i = 1, #players do local ply = players[i] local serverId = GetPlayerServerId(ply) if serverId == playerServerId then goto skip_loop end logger.verbose("Removing %s from listen table", serverId) MumbleRemoveVoiceChannelListen(serverId) ::skip_loop:: end end end RegisterNetEvent('onPlayerJoining', function(serverId) if isListenerEnabled then MumbleAddVoiceChannelListen(serverId) logger.verbose("Adding %s to listen table", serverId) end end) RegisterNetEvent('onPlayerDropped', function(serverId) if isListenerEnabled then MumbleRemoveVoiceChannelListen(serverId) logger.verbose("Removing %s from listen table", serverId) end end) local listenerOverride = false exports("setListenerOverride", function(enabled) type_check({enabled, "boolean"}) listenerOverride = enabled end) -- cache talking status so we only send a nui message when its not the same as what it was before local lastTalkingStatus = false local lastRadioStatus = false local voiceState = "proximity" CreateThread(function() TriggerEvent('chat:addSuggestion', '/muteply', 'Muter spilleren med det angivede ID', { { name = "id", help = "Spilleren der skal mutes" }, { name = "tid", help = "(Valgfrit) Tid i sekunder (default: 900)" } }) while true do -- wait for mumble to reconnect while not MumbleIsConnected() do Wait(100) end -- Leave the check here as we don't want to do any of this logic if GetConvarInt('voice_enableUi', 1) == 1 then local curTalkingStatus = MumbleIsPlayerTalking(PlayerId()) == 1 if lastRadioStatus ~= radioPressed or lastTalkingStatus ~= curTalkingStatus then lastRadioStatus = radioPressed lastTalkingStatus = curTalkingStatus sendUIMessage({ usingRadio = lastRadioStatus, talking = lastTalkingStatus }) end end if voiceState == "proximity" then addNearbyPlayers() -- What a name, wowza local cam = GetConvarInt("voice_disableAutomaticListenerOnCamera", 0) ~= 1 and GetRenderingCam() or -1 local isSpectating = NetworkIsInSpectatorMode() or cam ~= -1 if not isListenerEnabled and (isSpectating or listenerOverride) then setSpectatorMode(true) elseif isListenerEnabled and not isSpectating and not listenerOverride then setSpectatorMode(false) end end Wait(GetConvarInt('voice_refreshRate', 200)) end end) exports("setVoiceState", function(_voiceState, channel) if _voiceState ~= "proximity" and _voiceState ~= "channel" then logger.error("Didn't get a proper voice state, expected proximity or channel, got %s", _voiceState) end voiceState = _voiceState if voiceState == "channel" then type_check({channel, "number"}) -- 65535 is the highest a client id can go, so we add that to the base channel so we don't manage to get onto a players channel channel = channel + 65535 MumbleSetVoiceChannel(channel) while MumbleGetVoiceChannelFromServerId(playerServerId) ~= channel do Wait(250) end MumbleAddVoiceTargetChannel(voiceTarget, channel) elseif voiceState == "proximity" then handleInitialState() end end) AddEventHandler("onClientResourceStop", function(resource) if type(addProximityCheck) == "table" then local proximityCheckRef = addProximityCheck.__cfx_functionReference if proximityCheckRef then local isResource = string.match(proximityCheckRef, resource) if isResource then addProximityCheck = orig_addProximityCheck logger.warn('Reset proximity check to default, the original resource [%s] which provided the function restarted', resource) end end end end) exports("addVoiceMode", function(distance, name) for i = 1, #Cfg.voiceModes do local voiceMode = Cfg.voiceModes[i] if voiceMode[2] == name then logger.verbose("Already had %s, overwritting instead", name) voiceMode[1] = distance return end end Cfg.voiceModes[#Cfg.voiceModes + 1] = {distance, name} end) exports("removeVoiceMode", function(name) for i = 1, #Cfg.voiceModes do local voiceMode = Cfg.voiceModes[i] if voiceMode[2] == name then table.remove(Cfg.voiceModes, i) -- Reset our current range if we had it if mode == i then local newMode = Cfg.voiceModes[1] mode = 1 setProximityState(newMode[i], false) end return true end end return false end)