Skip to content

Commit

Permalink
chore: push pma-voice new version
Browse files Browse the repository at this point in the history
  • Loading branch information
bitpredator committed Aug 18, 2024
1 parent 04f531e commit 773fda1
Show file tree
Hide file tree
Showing 35 changed files with 10,307 additions and 0 deletions.
21 changes: 21 additions & 0 deletions server-data/resources/[phone]/pma-voice/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2021-2024 Dillon Skaggs

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
201 changes: 201 additions & 0 deletions server-data/resources/[phone]/pma-voice/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
## PLEASE NOTE: Currently master branch has some breaking changes

If you previously used `voice_defaultPhoneVolume` you will instead need to use `voice_defaultCallVolume`
If you previously used `voice_enablePhones` you will instead need to use `voice_enableCalls`

If you were previously using the state bag getter `Player(source).state.phone` you will instead need to use `Player(source).state.call`

# pma-voice
A voice system designed around the use of FiveM/RedM internal mumble server.

## Support

Please report any issues you have in the GitHub [Issues](https://github.com/AvarianKnight/pma-voice/issues)

### NOTE: It is expected for servers to be on the latest recommended version, which you can find [here for Windows](https://runtime.fivem.net/artifacts/fivem/build_server_windows/master/) and [here for Linux](https://runtime.fivem.net/artifacts/fivem/build_proot_linux/master/).

# Compatibility Notice:

This script is not compatible with other voice systems (duh), that means if you have vMenus voice chat you will **have** to [disable](https://docs.vespura.com/vmenu/faq/#q-how-do-i-disable-voice-chat) it.

Please do not override `NetworkSetTalkerProximity`, `MumbleSetTalkerProximity`, `MumbleSetAudioInputDistance`, `MumbleSetAudioOutputDistance` or `NetworkSetVoiceActive` in any of your other scripts as there have been cases where it breaks pma-voice.

# Credits

- @Frazzle for mumble-voip (for which the concept came from)
- @pichotm for pVoice (where the grid concept came from)

# FiveM/RedM Config

### NOTE: Only use one of the Audio options (don't enable 3d Audio & Native Audio at the same time), its also recommended to always use voice_useSendingRangeOnly.

You only need to add the convar **if** you're changing the value.

All of the configs here are set using `setr [voice_configOption] [boolean]`

Native audio will not work on RedM, you will have to use 3d audio.

| ConVar | Default | Description | Parameter(s) |
|----------------------------|---------|---------------------------------------------------------------|--------------|
| voice_useNativeAudio | false | Uses the games native audio, will add 3d sound, echo, reverb, and more. **Required for submixs** | boolean |
| voice_use2dAudio | false | Uses 2d audio, will result in same volume sound no matter where they're at until they leave proximity. | boolean
| voice_use3dAudio | false | Uses 3d audio | boolean |
| voice_useSendingRangeOnly | false | Only allows you to hear people within your hear/send range, prevents people from connecting to your mumble server and trolling. | boolean |

# Config

### PLEASE NOTE: Any keybind changes only affect new players, if you want to change your key bind go to Key Bindings -> FiveM -> Look for keybinds under 'pma-voice'.

All of the config is done via ConVars in order to streamline the process.

The ints are used like a boolean to 0 would be false, 1 true.

All of the configs here are set using `setr [voice_configOption] [int]` OR `setr [voice_configOption] "[string]"`

#### Note: If a convar defaults to 1 (true) you don't have set it again unless you want to disable it.

### General Voice Settings

| ConVar | Default | Description | Parameter(s) |
|-------------------------|---------|--------------------------------------------------------------------|--------------|
| voice_enableUi | 1 | Enables the built in user interface | int |
| voice_enableProximityCycle | 1 | Enables the usage of the F11 proximity key, if disabled players are stuck on the first proximity | int |
| voice_defaultCycle | F11 | The default key to cycle the players proximity. You can find a list of valid keys [in the Cfx docs](https://docs.fivem.net/docs/game-references/input-mapper-parameter-ids/keyboard/) | string |
| voice_defaultRadioVolume | 30 | The default volume to set the radio to (has to be between 1 and 100) *NOTE: Only new joins will have the new value, players that already joined will not.* | float |
| voice_defaultCallVolume | 60 | The default volume to set the call to (has to be between 1 and 100) *NOTE: Only new joins will have the new value, players that already joined will not.* | float |
| voice_defaultVoiceMode | 2 | Default proximity voice value when player joins server. (Voice Modes; 1:Whisper, 2:Normal, 3:Shouting) | int |

### Call & Radio

| ConVar | Default | Description | Parameter(s) |
|-------------------------|---------|--------------------------------------------------------------------|--------------|
| voice_enableRadios | 1 | Enables the radio sub-modules | int |
| voice_enableCalls | 1 | Enables the call sub-modules | int |
| voice_enableSubmix | 1 | Enables the submix which adds a radio/call style submix to their voice **NOTE: Submixs require native audio** | int |
| voice_enableRadioAnim | 1 | Enables (grab shoulder mic) animation while talking on the radio. | int |
| voice_defaultRadio | LMENU | The default key to use the radio. You can find a list of valid keys [in the FiveM docs](https://docs.fivem.net/docs/game-references/input-mapper-parameter-ids/keyboard/) | string |

### Sync

| ConVar | Default | Description | Parameter(s) |
|-------------------------|---------|--------------------------------------------------------------------|--------------|
| voice_refreshRate | 200 | How often the UI/Proximity is refreshed | int |

### External Server & Misc.
| ConVar | Default | Description | Parameter(s) |
|-------------------------|---------|--------------------------------------------------------------------|--------------|
| voice_allowSetIntent | 1 | Whether or not to allow players to set their audio intents (you can see more [here](https://docs.fivem.net/natives/?_0x6383526B)) | int |
| voice_externalAddress | none | The external address to use to connect to the mumble server | string |
| voice_externalPort | 0 | The external port to use | int |
| voice_debugMode | 0 | 1 for basic logs, 4 for verbose logs | int |
| voice_externalDisallowJoin | 0 | Disables players being allowed to join the server, should only be used if you're using a FXServer as a external mumble server. | int |
| voice_hideEndpoints | 1 | Hides the mumble address in logs *NOTE: You should only care to hide this for a external server.* | int |



### Aces

pma-voice comes with a built in /muteply (tgtPly) (duration) command, in order to allow your staff to use it you will have to grand them the ace!

Example:
`add_ace group.superadmin command.muteply allow;`

This would only allow the superadmin group to mute players.

### Exports

#### Client

##### Setters

| Export | Description | Parameter(s) |
|---------------------|-----------------------------|--------------|
| [setVoiceProperty](docs/client-setters/setVoiceProperty.md) | Set config options | string, any |
| [setRadioChannel](docs/client-setters/setRadioChannel.md) | Set radio channel | int |
| [setCallChannel](docs/client-setters/setCallChannel.md) | Set call channel | int |
| [setRadioVolume](docs/client-setters/setRadioVolume.md) | Set radio volume for player | int |
| [setCallVolume](docs/client-setters/setCallVolume.md) | Set call volume for player | int |
| [addPlayerToRadio](docs/client-setters/setRadioChannel.md) | Set radio channel | int |
| [addPlayerToCall](docs/client-setters/setCallChannel.md) | Set call channel | int |
| [removePlayerFromRadio](docs/client-setters/removePlayerFromRadio.md) | Remove player from radio | |
| [removePlayerFromCall](docs/client-setters/removePlayerFromCall.md) | Remove player from call | |

##### Toggles

| Export | Description | Parameter(s) |
|---------------------|--------------------------------------------------------|--------------|
| toggleMutePlayer | Toggles the selected player muted for the local client | int |

Supported from mumble-voip / toko-voip

| Export | Description | Parameter(s) |
|-----------------------|--------------------------|--------------|
| [SetMumbleProperty](docs/client-setters/setVoiceProperty.md) | Set config options | string, any |
| [SetTokoProperty](docs/client-setters/setVoiceProperty.md) | Set config options | string, any |
| [SetRadioChannel](docs/client-setters/setRadioChannel.md) | Set radio channel | int |
| [SetCallChannel](docs/client-setters/setCallChannel.md) | Set call channel | int |

#### Getters

The majority of setters are done through player states.


| State Bag | Description | Return Type |
|---------------|--------------------------------------------------------------|--------------|
| [proximity](docs/state-getters/stateBagGetters.md) | Returns a table with the mode index, distance, and mode name | table |
| [radioChannel](docs/state-getters/stateBagGetters.md) | Returns the players current radio channel, or 0 for none | int |
| [callChannel](docs/state-getters/stateBagGetters.md) | Returns the players current call channel, or 0 for none | int |
| [disableRadio](docs/state-getters/stateBagGetters.md) | Returns if the players radio is currently disabled, or 0 if its not. This is expected to be use as a bitwise, do *not* use a bool | int |

#### Events

These are events designed for third-party resource integration. These are emitted only to the current client.

| Event | Description | Event Params |
|--------------------------|--------------------------------------------------------------|----------------|
| [pma-voice:settingsCallback](docs/client-getters/events.md) | When emited it will return the current pma-voice settings. | cb(voiceSettings) |
| [pma-voice:radioActive](docs/client-getters/events.md) | Triggered when the radio is activated / deactivated | boolean |
| [pma-voice:setTalkingMode](docs/client-getters/events.md) | Triggered on proximity mode change with the voice mode id | int |


#### Server

##### Setters

| Export | Description | Parameter(s) |
|----------------------|--------------------------------------|--------------|
| [setPlayerRadio](docs/server-setters/setPlayerRadio.md) | Sets the players radio channel | int, int |
| [setPlayerCall](docs/server-setters/setPlayerCall.md) | Sets the players call channel | int, int |
| [addChannelCheck](docs/server-setters/addChannelCheck.md) | Adds a channel check to the players radio channel | int, function |


##### Getters

###### State Bags
You can access the state with `Player(source).state['state bag here']`

| State Bag | Description | Return Type |
|---------------|--------------------------------------------------------------|--------------|
| [proximity](docs/state-getters/stateBagGetters.md) | Returns a table with the mode index, distance, and mode name | table |
| [radioChannel](docs/state-getters/stateBagGetters.md) | Returns the players current radio channel, or 0 for none | int |
| [callChannel](docs/state-getters/stateBagGetters.md) | Returns the players current call channel, or 0 for none | int |
| [voiceIntent](docs/state-getters/stateBagGetters.md) | Returns the players current voice intent, either 'speech' or 'music' | string |
| [disableRadio](docs/state-getters/stateBagGetters.md) | Returns if the players radio is currently disabled, or 0 if its not. This is expected to be use as a bitwise, do *not* use a bool | int |

```ts
enum DisabledRadioStates {
Enabled = 0,
IsDead = 1,
IsCuffed = 2,
IsPdCuffed = 4,
IsUnderWater = 8,
DoesntHaveItem = 16,
PlayerDisabledRadio = 32,
}
```

###### Exports

| Export | Description | Parameter(s) |
|------------------------------|---------------------------------------------------|------|
| [getPlayersInRadioChannel](docs/server-getters/getPlayersInRadioChannel.md) | Gets the current players in a radio channel | int |
83 changes: 83 additions & 0 deletions server-data/resources/[phone]/pma-voice/client/commands.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
local wasProximityDisabledFromOverride = false
disableProximityCycle = false
RegisterCommand('setvoiceintent', function(source, args)
if GetConvarInt('voice_allowSetIntent', 1) == 1 then
local intent = args[1]
if intent == 'speech' then
MumbleSetAudioInputIntent(`speech`)
elseif intent == 'music' then
MumbleSetAudioInputIntent(`music`)
end
LocalPlayer.state:set('voiceIntent', intent, true)
end
end)
TriggerEvent('chat:addSuggestion', '/setvoiceintent', 'Sets the players voice intent', {
{
name = "intent",
help = "speech is default and enables noise suppression & high pass filter, music disables both of these."
},
})

-- TODO: Better implementation of this?
RegisterCommand('vol', function(_, args)
if not args[1] then return end
setVolume(tonumber(args[1]))
end)
TriggerEvent('chat:addSuggestion', '/vol', 'Sets the radio/phone volume', {
{ name = "volume", help = "A range between 1-100 on how loud you want them to be" },
})

exports('setAllowProximityCycleState', function(state)
type_check({ state, "boolean" })
disableProximityCycle = state
end)

function setProximityState(proximityRange, isCustom)
local voiceModeData = Cfg.voiceModes[mode]
MumbleSetTalkerProximity(proximityRange + 0.0)
LocalPlayer.state:set('proximity', {
index = mode,
distance = proximityRange,
mode = isCustom and "Custom" or voiceModeData[2],
}, true)
sendUIMessage({
-- JS expects this value to be - 1, "custom" voice is on the last index
voiceMode = isCustom and #Cfg.voiceModes or mode - 1
})
end

exports("overrideProximityRange", function(range, disableCycle)
type_check({ range, "number" })
setProximityState(range, true)
if disableCycle then
disableProximityCycle = true
wasProximityDisabledFromOverride = true
end
end)

exports("clearProximityOverride", function()
local voiceModeData = Cfg.voiceModes[mode]
setProximityState(voiceModeData[1], false)
if wasProximityDisabledFromOverride then
disableProximityCycle = false
end
end)

RegisterCommand('cycleproximity', function()
-- Proximity is either disabled, or manually overwritten.
if GetConvarInt('voice_enableProximityCycle', 1) ~= 1 or disableProximityCycle then return end
local newMode = mode + 1

-- If we're within the range of our voice modes, allow the increase, otherwise reset to the first state
if newMode <= #Cfg.voiceModes then
mode = newMode
else
mode = 1
end

setProximityState(Cfg.voiceModes[mode][1], false)
TriggerEvent('pma-voice:setTalkingMode', mode)
end, false)
if gameVersion == 'fivem' then
RegisterKeyMapping('cycleproximity', 'Cycle Proximity', 'keyboard', GetConvar('voice_defaultCycle', 'F11'))
end
44 changes: 44 additions & 0 deletions server-data/resources/[phone]/pma-voice/client/events.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
function handleInitialState()
local voiceModeData = Cfg.voiceModes[mode]
MumbleSetTalkerProximity(voiceModeData[1] + 0.0)
MumbleClearVoiceTarget(voiceTarget)
MumbleSetVoiceTarget(voiceTarget)
MumbleSetVoiceChannel(LocalPlayer.state.assignedChannel)

while MumbleGetVoiceChannelFromServerId(playerServerId) ~= LocalPlayer.state.assignedChannel do
Wait(250)
MumbleSetVoiceChannel(LocalPlayer.state.assignedChannel)
end

MumbleAddVoiceTargetChannel(voiceTarget, LocalPlayer.state.assignedChannel)

addNearbyPlayers()
end

AddEventHandler('mumbleConnected', function(address, isReconnecting)
logger.info('Connected to mumble server with address of %s, is this a reconnect %s',
GetConvarInt('voice_hideEndpoints', 1) == 1 and 'HIDDEN' or address, isReconnecting)

logger.log('Connecting to mumble, setting targets.')
-- don't try to set channel instantly, we're still getting data.
local voiceModeData = Cfg.voiceModes[mode]
LocalPlayer.state:set('proximity', {
index = mode,
distance = voiceModeData[1],
mode = voiceModeData[2],
}, true)

handleInitialState()

logger.log('Finished connection logic')
end)

AddEventHandler('mumbleDisconnected', function(address)
logger.info('Disconnected from mumble server with address of %s',
GetConvarInt('voice_hideEndpoints', 1) == 1 and 'HIDDEN' or address)
end)

-- TODO: Convert the last Cfg to a Convar, while still keeping it simple.
AddEventHandler('pma-voice:settingsCallback', function(cb)
cb(Cfg)
end)
Loading

0 comments on commit 773fda1

Please sign in to comment.