0.0.1
This commit is contained in:
253
resources/[standalone]/pma-voice/client/init/proximity.lua
Normal file
253
resources/[standalone]/pma-voice/client/init/proximity.lua
Normal file
@@ -0,0 +1,253 @@
|
||||
-- used when muted
|
||||
local disableUpdates = false
|
||||
local isListenerEnabled = false
|
||||
local plyCoords = GetEntityCoords(PlayerPedId())
|
||||
proximity = MumbleGetTalkerProximity()
|
||||
currentTargets = {}
|
||||
|
||||
-- a list of all the players the current client us listening to
|
||||
-- the value will be set to false if we didn't actually start listening to them (in situations where their channel didn't exist)
|
||||
-- TODO: PR a native to let us get if we're listening to a certain channel.
|
||||
local listeners = {}
|
||||
|
||||
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(LocalPlayer.state.assignedChannel)
|
||||
MumbleAddVoiceTargetChannel(voiceTarget, LocalPlayer.state.assignedChannel)
|
||||
|
||||
for source, _ in pairs(callData) do
|
||||
if source ~= playerServerId then
|
||||
local channel = MumbleGetVoiceChannelFromServerId(source)
|
||||
if channel ~= -1 then
|
||||
MumbleAddVoiceTargetChannel(voiceTarget, channel)
|
||||
end
|
||||
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)
|
||||
local channel = MumbleGetVoiceChannelFromServerId(serverId)
|
||||
if channel ~= -1 then
|
||||
MumbleAddVoiceTargetChannel(voiceTarget, channel)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function addChannelListener(serverId)
|
||||
-- not in the documentation, but this will return -1 whenever the client isn't in a channel
|
||||
local channel = MumbleGetVoiceChannelFromServerId(serverId)
|
||||
if channel ~= -1 then
|
||||
MumbleAddVoiceChannelListen(channel)
|
||||
logger.verbose("Adding %s to listen table", serverId)
|
||||
end
|
||||
listeners[serverId] = channel ~= -1
|
||||
end
|
||||
|
||||
function removeChannelListener(serverId)
|
||||
if listeners[serverId] then
|
||||
local channel = MumbleGetVoiceChannelFromServerId(serverId)
|
||||
if channel ~= -1 then
|
||||
MumbleRemoveVoiceChannelListen(channel)
|
||||
end
|
||||
logger.verbose("Removing %s from listen table", serverId)
|
||||
end
|
||||
-- remove the listener if they exist
|
||||
listeners[serverId] = nil
|
||||
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
|
||||
addChannelListener(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
|
||||
removeChannelListener(serverId)
|
||||
::skip_loop::
|
||||
end
|
||||
|
||||
-- cleanup table if we stop listening
|
||||
listeners = {}
|
||||
end
|
||||
end
|
||||
|
||||
function tryListeningToFailedListeners()
|
||||
for src, isListening in pairs(listeners) do
|
||||
-- if we failed to listen before we'll be set to false
|
||||
if not isListening then
|
||||
addChannelListener(src)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RegisterNetEvent('onPlayerJoining', function(serverId)
|
||||
if isListenerEnabled then
|
||||
addChannelListener(serverId)
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterNetEvent('onPlayerDropped', function(serverId)
|
||||
if isListenerEnabled then
|
||||
removeChannelListener(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', 'Mutes the player with the specified id', {
|
||||
{ name = "player id", help = "the player to toggle mute" },
|
||||
{ name = "duration", help = "(opt) the duration the mute in seconds (default: 900)" }
|
||||
})
|
||||
while true do
|
||||
-- wait for mumble to reconnect
|
||||
while not MumbleIsConnected() or not isInitialized 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
|
||||
tryListeningToFailedListeners()
|
||||
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[mode], false)
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end)
|
||||
Reference in New Issue
Block a user