diff --git a/server-data/resources/[phone]/pma-voice/.github/CHANGELOG.md b/server-data/resources/[phone]/pma-voice/.github/CHANGELOG.md deleted file mode 100644 index 12f660a9c..000000000 --- a/server-data/resources/[phone]/pma-voice/.github/CHANGELOG.md +++ /dev/null @@ -1,13 +0,0 @@ -# Changelog - - - - - - -1. [voice-ui/pnpm-lock.yaml]: chore: (deps-dev) bump url-parse + bump minimatch + bump terser @bitpredator -2. [client/module/phone.lua]: fix(phone): fix getting re-added to radios if perfectly hit -3. [client/init/main.lua]: fix(radio): fix oversight with function call -4. [workflows/dependency-review.yml]: chore(deps): bump actions/checkout from 3 to 4 -5. [voice-ui/pnpm-lock.yaml]: chore(deps-dev): bump follow-redirects in /voice-ui -6. [voice-ui/pnpm-lock.yaml]: chore(deps-dev): bump browserify-sign from 4.2.1 to 4.2.2 in /voice-ui \ No newline at end of file diff --git a/server-data/resources/[phone]/pma-voice/.github/ISSUE_TEMPLATE/bug_report.md b/server-data/resources/[phone]/pma-voice/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 7ce3d661e..000000000 --- a/server-data/resources/[phone]/pma-voice/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -**Did you read the README?**: There's a lot of information in the README, if you ask a question that is answered in the README, you will be told to "Read the README" - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See an error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Server Info:** - - Server Version: [e.g. 3456] -- Client Version: [e.g. production|canary] -- Client Build: [e.g. b1604|b2060|b2189|b2372] -- Game: [e.g. FiveM|RedM] - -**Additional context** -Add any other context about the problem here. diff --git a/server-data/resources/[phone]/pma-voice/.github/dependabot.yml b/server-data/resources/[phone]/pma-voice/.github/dependabot.yml deleted file mode 100644 index 3e89607de..000000000 --- a/server-data/resources/[phone]/pma-voice/.github/dependabot.yml +++ /dev/null @@ -1,20 +0,0 @@ -version: 2 -updates: - - package-ecosystem: github-actions - directory: '/' - schedule: - interval: daily - open-pull-requests-limit: 99 - labels: - - 'dependencies' - - # Dependencies npm - - package-ecosystem: 'npm' - directory: '/' - schedule: - interval: 'daily' - # Disable version updates for npm dependencies - # https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/configuring-dependabot-security-updates#overriding-the-default-behavior-with-a-configuration-file - open-pull-requests-limit: 99 - labels: - - 'dependencies' diff --git a/server-data/resources/[phone]/pma-voice/.github/stale.yml b/server-data/resources/[phone]/pma-voice/.github/stale.yml deleted file mode 100644 index aaf506716..000000000 --- a/server-data/resources/[phone]/pma-voice/.github/stale.yml +++ /dev/null @@ -1,18 +0,0 @@ -# Number of days of inactivity before an issue becomes stale -daysUntilStale: 30 -# Number of days of inactivity before a stale issue is closed -daysUntilClose: 7 -# Issues with these labels will never be considered stale -exemptLabels: - - pinned - - security - - todo -# Label to use when marking an issue as stale -staleLabel: wontfix -# Comment to post when marking an issue as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. -# Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false diff --git a/server-data/resources/[phone]/pma-voice/.github/workflows/dependency-review.yml b/server-data/resources/[phone]/pma-voice/.github/workflows/dependency-review.yml deleted file mode 100644 index 0d4a01360..000000000 --- a/server-data/resources/[phone]/pma-voice/.github/workflows/dependency-review.yml +++ /dev/null @@ -1,20 +0,0 @@ -# Dependency Review Action -# -# This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. -# -# Source repository: https://github.com/actions/dependency-review-action -# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement -name: 'Dependency Review' -on: [pull_request] - -permissions: - contents: read - -jobs: - dependency-review: - runs-on: ubuntu-latest - steps: - - name: 'Checkout Repository' - uses: actions/checkout@v4 - - name: 'Dependency Review' - uses: actions/dependency-review-action@v4 diff --git a/server-data/resources/[phone]/pma-voice/.gitignore b/server-data/resources/[phone]/pma-voice/.gitignore deleted file mode 100644 index 2e2d6d210..000000000 --- a/server-data/resources/[phone]/pma-voice/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.idea -.vscode \ No newline at end of file diff --git a/server-data/resources/[phone]/pma-voice/LICENSE b/server-data/resources/[phone]/pma-voice/LICENSE deleted file mode 100644 index ad5aece80..000000000 --- a/server-data/resources/[phone]/pma-voice/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 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. diff --git a/server-data/resources/[phone]/pma-voice/README.md b/server-data/resources/[phone]/pma-voice/README.md deleted file mode 100644 index 2e130d725..000000000 --- a/server-data/resources/[phone]/pma-voice/README.md +++ /dev/null @@ -1,201 +0,0 @@ -## 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 | diff --git a/server-data/resources/[phone]/pma-voice/TODO.md b/server-data/resources/[phone]/pma-voice/TODO.md deleted file mode 100644 index 0371ce297..000000000 --- a/server-data/resources/[phone]/pma-voice/TODO.md +++ /dev/null @@ -1,10 +0,0 @@ -## TODO -- [ ] Ability to display radio members on the client. -- [ ] Use commands to define voiceModes in shared.lua and only leave debug logs in shared.lua. -- [ ] Convert the UI to React. -- [ ] Multiple radio channels. - -## DONE -- [ x ] Implement a easy way to get the players current radio channel on the server. -- [ x ] Add the ability to override proximity with exports. -- [ x ] Rename everything that uses 'phone' to 'call' for consistency. diff --git a/server-data/resources/[phone]/pma-voice/client/commands.lua b/server-data/resources/[phone]/pma-voice/client/commands.lua deleted file mode 100644 index 79713c88d..000000000 --- a/server-data/resources/[phone]/pma-voice/client/commands.lua +++ /dev/null @@ -1,83 +0,0 @@ -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 diff --git a/server-data/resources/[phone]/pma-voice/client/events.lua b/server-data/resources/[phone]/pma-voice/client/events.lua deleted file mode 100644 index 918673db2..000000000 --- a/server-data/resources/[phone]/pma-voice/client/events.lua +++ /dev/null @@ -1,44 +0,0 @@ -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) diff --git a/server-data/resources/[phone]/pma-voice/client/init/init.lua b/server-data/resources/[phone]/pma-voice/client/init/init.lua deleted file mode 100644 index 8653445cf..000000000 --- a/server-data/resources/[phone]/pma-voice/client/init/init.lua +++ /dev/null @@ -1,49 +0,0 @@ -AddEventHandler('onClientResourceStart', function(resource) - if resource ~= GetCurrentResourceName() then - return - end - print('Starting script initialization') - - -- Some people modify pma-voice and mess up the resource Kvp, which means that if someone - -- joins another server that has pma-voice, it will error out, this will catch and fix the kvp. - local success = pcall(function() - local micClicksKvp = GetResourceKvpString('pma-voice_enableMicClicks') - if not micClicksKvp then - SetResourceKvp('pma-voice_enableMicClicks', "true") - else - if micClicksKvp ~= 'true' and micClicksKvp ~= 'false' then - error('Invalid Kvp, throwing error for automatic fix') - end - micClicks = micClicksKvp - end - end) - - if not success then - logger.warn( - 'Failed to load resource Kvp, likely was inappropriately modified by another server, resetting the Kvp.') - SetResourceKvp('pma-voice_enableMicClicks', "true") - micClicks = 'true' - end - sendUIMessage({ - uiEnabled = GetConvarInt("voice_enableUi", 1) == 1, - voiceModes = json.encode(Cfg.voiceModes), - voiceMode = mode - 1 - }) - - local radioChannel = LocalPlayer.state.radioChannel or 0 - local callChannel = LocalPlayer.state.callChannel or 0 - - -- Reinitialize channels if they're set. - if radioChannel ~= 0 then - setRadioChannel(radioChannel) - end - - if callChannel ~= 0 then - setCallChannel(callChannel) - end - if not LocalPlayer.state.disableRadio then - LocalPlayer.state:set("disableRadio", 0, true) - end - - print('Script initialization finished.') -end) diff --git a/server-data/resources/[phone]/pma-voice/client/init/main.lua b/server-data/resources/[phone]/pma-voice/client/init/main.lua deleted file mode 100644 index e17d09c10..000000000 --- a/server-data/resources/[phone]/pma-voice/client/init/main.lua +++ /dev/null @@ -1,324 +0,0 @@ -local mutedPlayers = {} - --- we can't use GetConvarInt because its not a integer, and theres no way to get a float... so use a hacky way it is! -local volumes = { - -- people are setting this to 1 instead of 1.0 and expecting it to work. - ['radio'] = GetConvarInt('voice_defaultRadioVolume', 60) / 100, - ['call'] = GetConvarInt('voice_defaultCallVolume', 60) / 100, - ['click_on'] = GetConvarInt('voice_onClickVolume', 10) / 100, - ['click_off'] = GetConvarInt('voice_offClickVolume', 3) / 100, -} - -radioEnabled, radioPressed, mode = true, false, GetConvarInt('voice_defaultVoiceMode', 2) -radioData = {} -callData = {} -submixIndicies = {} ---- function setVolume ---- Toggles the players volume ----@param volume number between 0 and 100 ----@param volumeType string the volume type (currently radio & call) to set the volume of (opt) -function setVolume(volume, volumeType) - type_check({ volume, "number" }) - local volumeFraction = volume / 100 - - if volumeType then - local volumeTbl = volumes[volumeType] - if volumeTbl then - LocalPlayer.state:set(volumeType, volume, true) - volumes[volumeType] = volumeFraction - resyncVolume(volumeType, volumeFraction) - else - error(('setVolume got a invalid volume type %s'):format(volumeType)) - end - else - for volumeType, _ in pairs(volumes) do - volumes[volumeType] = volumeFraction - LocalPlayer.state:set(volumeType, volume, true) - end - resyncVolume("all", volumeFraction) - end -end - -exports('setRadioVolume', function(vol) - setVolume(vol, 'radio') -end) -exports('getRadioVolume', function() - return volumes['radio'] * 100 -end) -exports("setCallVolume", function(vol) - setVolume(vol, 'call') -end) -exports('getCallVolume', function() - return volumes['call'] * 100 -end) - - --- default submix incase people want to fiddle with it. --- freq_low = 389.0 --- freq_hi = 3248.0 --- fudge = 0.0 --- rm_mod_freq = 0.0 --- rm_mix = 0.16 --- o_freq_lo = 348.0 --- o_freq_hi = 4900.0 - -local radioEffectId = CreateAudioSubmix('Radio') -SetAudioSubmixEffectRadioFx(radioEffectId, 0) --- This is a GetHashKey on purpose, backticks break treesitter in nvim :| -SetAudioSubmixEffectParamInt(radioEffectId, 0, GetHashKey('default'), 1) -SetAudioSubmixOutputVolumes( - radioEffectId, - 0, - 1.0 --[[ frontLeftVolume ]], - 0.25 --[[ frontRightVolume ]], - 0.0 --[[ rearLeftVolume ]], - 0.0 --[[ rearRightVolume ]], - 1.0 --[[ channel5Volume ]], - 1.0 --[[ channel6Volume ]] -) -AddAudioSubmixOutput(radioEffectId, 0) -submixIndicies['radio'] = radioEffectId - -local callEffectId = CreateAudioSubmix('Call') -SetAudioSubmixOutputVolumes( - callEffectId, - 1, - 0.10 --[[ frontLeftVolume ]], - 0.50 --[[ frontRightVolume ]], - 0.0 --[[ rearLeftVolume ]], - 0.0 --[[ rearRightVolume ]], - 1.0 --[[ channel5Volume ]], - 1.0 --[[ channel6Volume ]] -) -AddAudioSubmixOutput(callEffectId, 1) -submixIndicies['call'] = callEffectId - --- Callback is expected to return data in an array, this is for compatibility sake with js, index 0 should be the name and index 1 should be the submixId --- the callback is sent the effectSlot it can register to, not sure if this is needed, but its here for safety -exports("registerCustomSubmix", function(callback) - local submixTable = callback() - type_check({ submixTable, "table" }) - local submixName, submixId = submixTable[1], submixTable[2] - type_check({ submixName, "string" }, { submixId, "number" }) - logger.info("Creating submix %s with submixId %s", submixName, submixId) - submixIndicies[submixName] = submixId -end) -TriggerEvent("pma-voice:registerCustomSubmixes") - ---- export setEffectSubmix ---- Sets a user defined audio submix for radio and phonecall effects ----@param type string either "call" or "radio" ----@param effectId number submix id returned from CREATE_AUDIO_SUBMIX -exports("setEffectSubmix", function(type, effectId) - type_check({ type, "string" }, { effectId, "number" }) - if submixIndicies[type] then - submixIndicies[type] = effectId - end -end) - -function restoreDefaultSubmix(plyServerId) - local submix = Player(plyServerId).state.submix - local submixEffect = submixIndicies[submix] - if not submix or not submixEffect then - MumbleSetSubmixForServerId(plyServerId, -1) - return - end - MumbleSetSubmixForServerId(plyServerId, submixEffect) -end - --- used to prevent a race condition if they talk again afterwards, which would lead to their voice going to default. -local disableSubmixReset = {} ---- function toggleVoice ---- Toggles the players voice ----@param plySource number the players server id to override the volume for ----@param enabled boolean if the players voice is getting activated or deactivated ----@param moduleType string the volume & submix to use for the voice. -function toggleVoice(plySource, enabled, moduleType) - if mutedPlayers[plySource] then return end - logger.verbose('[main] Updating %s to talking: %s with submix %s', plySource, enabled, moduleType) - local distance = currentTargets[plySource] - if enabled and (not distance or distance > 4.0) then - print(volumes[moduleType]) - MumbleSetVolumeOverrideByServerId(plySource, enabled and volumes[moduleType]) - if GetConvarInt('voice_enableSubmix', 1) == 1 then - if moduleType then - disableSubmixReset[plySource] = true - if submixIndicies[moduleType] then - MumbleSetSubmixForServerId(plySource, submixIndicies[moduleType]) - end - else - restoreDefaultSubmix(plySource) - end - end - elseif not enabled then - if GetConvarInt('voice_enableSubmix', 1) == 1 then - -- garbage collect it - disableSubmixReset[plySource] = nil - SetTimeout(250, function() - if not disableSubmixReset[plySource] then - restoreDefaultSubmix(plySource) - end - end) - end - MumbleSetVolumeOverrideByServerId(plySource, -1.0) - end -end - -local function updateVolumes(voiceTable, override) - for serverId, talking in pairs(voiceTable) do - if serverId == playerServerId then goto skip_iter end - MumbleSetVolumeOverrideByServerId(serverId, talking and override or -1.0) - ::skip_iter:: - end -end - ---- resyncs the call/radio/etc volume to the new volume ----@param volumeType any -function resyncVolume(volumeType, newVolume) - if volumeType == "all" then - resyncVolume("radio", newVolume) - resyncVolume("call", newVolume) - elseif volumeType == "radio" then - updateVolumes(radioData, newVolume) - elseif volumeType == "call" then - updateVolumes(callData, newVolume) - end -end - ----Adds players voices to the local players listen channels allowing them to ----communicate at long range, ignoring proximity range. ---- ----@diagnostic disable-next-line: undefined-doc-param ----@param targets table expects multiple tables to be sent over -function addVoiceTargets(...) - local targets = { ... } - local addedPlayers = { - [playerServerId] = true - } - - for i = 1, #targets do - for id, _ in pairs(targets[i]) do - -- we don't want to log ourself, or listen to ourself - if addedPlayers[id] and id ~= playerServerId then - logger.verbose('[main] %s is already target don\'t re-add', id) - goto skip_loop - end - if not addedPlayers[id] then - logger.verbose('[main] Adding %s as a voice target', id) - addedPlayers[id] = true - MumbleAddVoiceTargetPlayerByServerId(voiceTarget, id) - end - ::skip_loop:: - end - end -end - ---- function playMicClicks ----plays the mic click if the player has them enabled. ----@param clickType boolean whether to play the 'on' or 'off' click. -function playMicClicks(clickType) - if micClicks ~= 'true' then return logger.verbose("Not playing mic clicks because client has them disabled") end - -- TODO: Add customizable radio click volumes - sendUIMessage({ - sound = (clickType and "audio_on" or "audio_off"), - volume = (clickType and volumes['click_on'] or volumes['click_off']) - }) -end - ---- check if player is muted -exports('isPlayerMuted', function(source) - return mutedPlayers[source] -end) - ---- getter for mutedPlayers -exports('getMutedPlayers', function() - return mutedPlayers -end) - ---- toggles the targeted player muted ----@param source number the player to mute -function toggleMutePlayer(source) - if mutedPlayers[source] then - mutedPlayers[source] = nil - MumbleSetVolumeOverrideByServerId(source, -1.0) - else - mutedPlayers[source] = true - MumbleSetVolumeOverrideByServerId(source, 0.0) - end -end - -exports('toggleMutePlayer', toggleMutePlayer) - ---- function setVoiceProperty ---- sets the specified voice property ----@param type string what voice property you want to change (only takes 'radioEnabled' and 'micClicks') ----@param value any the value to set the type to. -function setVoiceProperty(type, value) - if type == "radioEnabled" then - radioEnabled = value - handleRadioEnabledChanged(value) - sendUIMessage({ - radioEnabled = value - }) - elseif type == "micClicks" then - local val = tostring(value) - micClicks = val - SetResourceKvp('pma-voice_enableMicClicks', val) - end -end - -exports('setVoiceProperty', setVoiceProperty) --- compatibility -exports('SetMumbleProperty', setVoiceProperty) -exports('SetTokoProperty', setVoiceProperty) - - --- cache their external servers so if it changes in runtime we can reconnect the client. -local externalAddress = '' -local externalPort = 0 -CreateThread(function() - while true do - Wait(500) - -- only change if what we have doesn't match the cache - if GetConvar('voice_externalAddress', '') ~= externalAddress or GetConvarInt('voice_externalPort', 0) ~= externalPort then - externalAddress = GetConvar('voice_externalAddress', '') - externalPort = GetConvarInt('voice_externalPort', 0) - MumbleSetServerAddress(GetConvar('voice_externalAddress', ''), GetConvarInt('voice_externalPort', 0)) - end - end -end) - - -if gameVersion == 'redm' then - CreateThread(function() - while true do - if IsControlJustPressed(0, 0xA5BDCD3C --[[ Right Bracket ]]) then - ExecuteCommand('cycleproximity') - end - if IsControlJustPressed(0, 0x430593AA --[[ Left Bracket ]]) then - ExecuteCommand('+radiotalk') - elseif IsControlJustReleased(0, 0x430593AA --[[ Left Bracket ]]) then - ExecuteCommand('-radiotalk') - end - - Wait(0) - end - end) -end - ---- handles initializiation for whenever radio or call data changes ---- calls should always be last because they're assumed to always be enabled so ---- theres no delay in talking. -function handleRadioAndCallInit() - for tgt, enabled in pairs(radioData) do - if tgt ~= playerServerId then - toggleVoice(tgt, enabled, 'radio') - end - end - - for tgt, enabled in pairs(callData) do - if tgt ~= playerServerId then - toggleVoice(tgt, true, 'call') - end - end -end diff --git a/server-data/resources/[phone]/pma-voice/client/init/proximity.lua b/server-data/resources/[phone]/pma-voice/client/init/proximity.lua deleted file mode 100644 index 5a627f76a..000000000 --- a/server-data/resources/[phone]/pma-voice/client/init/proximity.lua +++ /dev/null @@ -1,212 +0,0 @@ --- 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(LocalPlayer.state.assignedChannel) - MumbleAddVoiceTargetChannel(voiceTarget, LocalPlayer.state.assignedChannel) - - for source, _ in pairs(callData) do - if source ~= playerServerId then - MumbleAddVoiceTargetChannel(voiceTarget, MumbleGetVoiceChannelFromServerId(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, MumbleGetVoiceChannelFromServerId(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(MumbleGetVoiceChannelFromServerId(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(MumbleGetVoiceChannelFromServerId(serverId)) - ::skip_loop:: - end - end -end - -RegisterNetEvent('onPlayerJoining', function(serverId) - if isListenerEnabled then - MumbleAddVoiceChannelListen(MumbleGetVoiceChannelFromServerId(serverId)) - logger.verbose("Adding %s to listen table", serverId) - end -end) - -RegisterNetEvent('onPlayerDropped', function(serverId) - if isListenerEnabled then - MumbleRemoveVoiceChannelListen(MumbleGetVoiceChannelFromServerId(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', '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() 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[mode], false) - end - return true - end - end - - return false -end) diff --git a/server-data/resources/[phone]/pma-voice/client/init/submix.lua b/server-data/resources/[phone]/pma-voice/client/init/submix.lua deleted file mode 100644 index a8235d422..000000000 --- a/server-data/resources/[phone]/pma-voice/client/init/submix.lua +++ /dev/null @@ -1,19 +0,0 @@ -AddStateBagChangeHandler("submix", "", function(bagName, _, value) - local tgtId = tonumber(bagName:gsub('player:', ''), 10) - if not tgtId then return end - -- We got an invalid submix, discard we don't care about it - if value and not submixIndicies[value] then - return logger.warn("Player %s applied submix %s but it isn't valid", - tgtId, value) - end - -- we don't want to reset submix if the player is talking on the radio - if not value then - if not radioData[tgtId] and not callData[tgtId] then - logger.info("Resetting submix for player %s", tgtId) - MumbleSetSubmixForServerId(tgtId, -1) - end - return - end - logger.info("%s had their submix set to %s", tgtId, value) - MumbleSetSubmixForServerId(tgtId, submixIndicies[value]) -end) diff --git a/server-data/resources/[phone]/pma-voice/client/module/phone.lua b/server-data/resources/[phone]/pma-voice/client/module/phone.lua deleted file mode 100644 index 97f3a51f3..000000000 --- a/server-data/resources/[phone]/pma-voice/client/module/phone.lua +++ /dev/null @@ -1,58 +0,0 @@ -local callChannel = 0 - -RegisterNetEvent('pma-voice:syncCallData', function(callTable, channel) - callData = callTable - handleRadioAndCallInit() -end) - -RegisterNetEvent('pma-voice:addPlayerToCall', function(plySource) - toggleVoice(plySource, true, 'call') - callData[plySource] = true -end) - -RegisterNetEvent('pma-voice:removePlayerFromCall', function(plySource) - if plySource == playerServerId then - for tgt, _ in pairs(callData) do - if tgt ~= playerServerId then - toggleVoice(tgt, false, 'call') - end - end - callData = {} - MumbleClearVoiceTargetPlayers(voiceTarget) - addVoiceTargets((radioPressed and isRadioEnabled()) and radioData or {}, callData) - else - callData[plySource] = nil - toggleVoice(plySource, radioData[plySource], 'call') - if MumbleIsPlayerTalking(PlayerId()) then - MumbleClearVoiceTargetPlayers(voiceTarget) - addVoiceTargets((radioPressed and isRadioEnabled()) and radioData or {}, callData) - end - end -end) - -function setCallChannel(channel) - if GetConvarInt('voice_enableCalls', 1) ~= 1 then return end - TriggerServerEvent('pma-voice:setPlayerCall', channel) - callChannel = channel - sendUIMessage({ - callInfo = channel - }) -end - -exports('setCallChannel', setCallChannel) -exports('SetCallChannel', setCallChannel) - -exports('addPlayerToCall', function(_call) - local call = tonumber(_call) - if call then - setCallChannel(call) - end -end) -exports('removePlayerFromCall', function() - setCallChannel(0) -end) - -RegisterNetEvent('pma-voice:clSetPlayerCall', function(_callChannel) - if GetConvarInt('voice_enableCalls', 1) ~= 1 then return end - callChannel = _callChannel -end) diff --git a/server-data/resources/[phone]/pma-voice/client/module/radio.lua b/server-data/resources/[phone]/pma-voice/client/module/radio.lua deleted file mode 100644 index 25f076cc4..000000000 --- a/server-data/resources/[phone]/pma-voice/client/module/radio.lua +++ /dev/null @@ -1,293 +0,0 @@ -local radioChannel = 0 -local radioNames = {} -local disableRadioAnim = false - ----@return boolean isEnabled if radioEnabled is true and LocalPlayer.state.disableRadio is 0 (no bits set) -function isRadioEnabled() - return radioEnabled and LocalPlayer.state.disableRadio == 0 -end - ---- event syncRadioData ---- syncs the current players on the radio to the client ----@param radioTable table the table of the current players on the radio ----@param localPlyRadioName string the local players name -function syncRadioData(radioTable, localPlyRadioName) - radioData = radioTable - logger.info('[radio] Syncing radio table.') - if GetConvarInt('voice_debugMode', 0) >= 4 then - print('-------- RADIO TABLE --------') - tPrint(radioData) - print('-----------------------------') - end - - local isEnabled = isRadioEnabled() - - if isEnabled then - handleRadioAndCallInit() - end - - sendUIMessage({ - radioChannel = radioChannel, - radioEnabled = isEnabled - }) - if GetConvarInt("voice_syncPlayerNames", 0) == 1 then - radioNames[playerServerId] = localPlyRadioName - end -end - -RegisterNetEvent('pma-voice:syncRadioData', syncRadioData) - ---- event setTalkingOnRadio ---- sets the players talking status, triggered when a player starts/stops talking. ----@param plySource number the players server id. ----@param enabled boolean whether the player is talking or not. -function setTalkingOnRadio(plySource, enabled) - radioData[plySource] = enabled - - if not isRadioEnabled() then return logger.info("[radio] Ignoring setTalkingOnRadio. radioEnabled: %s disableRadio: %s", radioEnabled, LocalPlayer.state.disableRadio) end - -- If we're on a call we don't want to toggle their voice disabled this will break calls. - local enabled = enabled or callData[plySource] - toggleVoice(plySource, enabled, 'radio') - playMicClicks(enabled) -end -RegisterNetEvent('pma-voice:setTalkingOnRadio', setTalkingOnRadio) - ---- event addPlayerToRadio ---- adds a player onto the radio. ----@param plySource number the players server id to add to the radio. -function addPlayerToRadio(plySource, plyRadioName) - radioData[plySource] = false - if GetConvarInt("voice_syncPlayerNames", 0) == 1 then - radioNames[plySource] = plyRadioName - end - logger.info('[radio] %s joined radio %s %s', plySource, radioChannel, - radioPressed and " while we were talking, adding them to targets" or "") - if radioPressed then - addVoiceTargets(radioData, callData) - end -end -RegisterNetEvent('pma-voice:addPlayerToRadio', addPlayerToRadio) - ---- event removePlayerFromRadio ---- removes the player (or self) from the radio ----@param plySource number the players server id to remove from the radio. -function removePlayerFromRadio(plySource) - if plySource == playerServerId then - logger.info('[radio] Left radio %s, cleaning up.', radioChannel) - for tgt, _ in pairs(radioData) do - if tgt ~= playerServerId then - toggleVoice(tgt, false, 'radio') - end - end - sendUIMessage({ - radioChannel = 0, - radioEnabled = radioEnabled - }) - radioNames = {} - radioData = {} - addVoiceTargets(callData) - else - toggleVoice(plySource, false, 'radio') - if radioPressed then - logger.info('[radio] %s left radio %s while we were talking, updating targets.', plySource, radioChannel) - addVoiceTargets(radioData, callData) - else - logger.info('[radio] %s has left radio %s', plySource, radioChannel) - end - radioData[plySource] = nil - if GetConvarInt("voice_syncPlayerNames", 0) == 1 then - radioNames[plySource] = nil - end - end -end - -RegisterNetEvent('pma-voice:removePlayerFromRadio', removePlayerFromRadio) - -RegisterNetEvent('pma-voice:radioChangeRejected', function() - logger.info("The server rejected your radio change.") - radioChannel = 0 -end) - ---- function setRadioChannel ---- sets the local players current radio channel and updates the server ----@param channel number the channel to set the player to, or 0 to remove them. -function setRadioChannel(channel) - if GetConvarInt('voice_enableRadios', 1) ~= 1 then return end - type_check({ channel, "number" }) - TriggerServerEvent('pma-voice:setPlayerRadio', channel) - radioChannel = channel -end - ---- exports setRadioChannel ---- sets the local players current radio channel and updates the server -exports('setRadioChannel', setRadioChannel) --- mumble-voip compatability -exports('SetRadioChannel', setRadioChannel) - ---- exports removePlayerFromRadio ---- sets the local players current radio channel and updates the server -exports('removePlayerFromRadio', function() - setRadioChannel(0) -end) - ---- exports addPlayerToRadio ---- sets the local players current radio channel and updates the server ----@param _radio number the channel to set the player to, or 0 to remove them. -exports('addPlayerToRadio', function(_radio) - local radio = tonumber(_radio) - if radio then - setRadioChannel(radio) - end -end) - ---- exports toggleRadioAnim ---- toggles whether the client should play radio anim or not, if the animation should be played or notvaliddance -exports('toggleRadioAnim', function() - disableRadioAnim = not disableRadioAnim - TriggerEvent('pma-voice:toggleRadioAnim', disableRadioAnim) -end) - -exports("setDisableRadioAnim", function(shouldDisable) - disableRadioAnim = shouldDisable -end) - --- exports disableRadioAnim ---- returns whether the client is undercover or not -exports('getRadioAnimState', function() - return disableRadioAnim -end) - ---- check if the player is dead ---- seperating this so if people use different methods they can customize ---- it to their need as this will likely never be changed ---- but you can integrate the below state bag to your death resources. ---- LocalPlayer.state:set('isDead', true or false, false) -function isDead() - if LocalPlayer.state.isDead then - return true - elseif IsPlayerDead(PlayerId()) then - return true - end - return false -end - -function isRadioAnimEnabled() - if - GetConvarInt('voice_enableRadioAnim', 1) == 1 - and not (GetConvarInt('voice_disableVehicleRadioAnim', 0) == 1 - and IsPedInAnyVehicle(PlayerPedId(), false)) - and not disableRadioAnim then - return true - end - return false -end - -RegisterCommand('+radiotalk', function() - if GetConvarInt('voice_enableRadios', 1) ~= 1 then return end - if isDead() then return end - if not isRadioEnabled() then return end - if not radioPressed then - if radioChannel > 0 then - logger.info('[radio] Start broadcasting, update targets and notify server.') - addVoiceTargets(radioData, callData) - TriggerServerEvent('pma-voice:setTalkingOnRadio', true) - radioPressed = true - local shouldPlayAnimation = isRadioAnimEnabled() - playMicClicks(true) - if shouldPlayAnimation then - RequestAnimDict('random@arrests') - end - CreateThread(function() - TriggerEvent("pma-voice:radioActive", true) - LocalPlayer.state:set("radioActive", true, true); - local checkFailed = false - while radioPressed do - if radioChannel < 0 or isDead() or not isRadioEnabled() then - checkFailed = true - break - end - if shouldPlayAnimation and HasAnimDictLoaded("random@arrests") then - if not IsEntityPlayingAnim(PlayerPedId(), "random@arrests", "generic_radio_enter", 3) then - TaskPlayAnim(PlayerPedId(), "random@arrests", "generic_radio_enter", 8.0, 2.0, -1, 50, 2.0, false, - false, - false) - end - end - SetControlNormal(0, 249, 1.0) - SetControlNormal(1, 249, 1.0) - SetControlNormal(2, 249, 1.0) - Wait(0) - end - - - if checkFailed then - logger.info("Canceling radio talking as the checks have failed.") - ExecuteCommand("-radiotalk") - end - if shouldPlayAnimation then - RemoveAnimDict('random@arrests') - end - end) - else - logger.info("Player tried to talk but was not on a radio channel") - end - end -end, false) - -RegisterCommand('-radiotalk', function() - if radioChannel > 0 and radioPressed then - radioPressed = false - MumbleClearVoiceTargetPlayers(voiceTarget) - addVoiceTargets(callData) - TriggerEvent("pma-voice:radioActive", false) - LocalPlayer.state:set("radioActive", false, true); - playMicClicks(false) - if GetConvarInt('voice_enableRadioAnim', 1) == 1 then - StopAnimTask(PlayerPedId(), "random@arrests", "generic_radio_enter", -4.0) - end - TriggerServerEvent('pma-voice:setTalkingOnRadio', false) - end -end, false) -if gameVersion == 'fivem' then - RegisterKeyMapping('+radiotalk', 'Talk over Radio', 'keyboard', GetConvar('voice_defaultRadio', 'LMENU')) -end - ---- event syncRadio ---- syncs the players radio, only happens if the radio was set server side. ----@param _radioChannel number the radio channel to set the player to. -function syncRadio(_radioChannel) - if GetConvarInt('voice_enableRadios', 1) ~= 1 then return end - logger.info('[radio] radio set serverside update to radio %s', radioChannel) - radioChannel = _radioChannel -end -RegisterNetEvent('pma-voice:clSetPlayerRadio', syncRadio) - - ---- handles "radioEnabled" changing ----@param wasRadioEnabled boolean whether radio is enabled or not -function handleRadioEnabledChanged(wasRadioEnabled) - if wasRadioEnabled then - syncRadioData(radioData, "") - else - removePlayerFromRadio(playerServerId) - end -end - ---- adds the bit to the disableRadio bits ----@param bit number the bit to add -local function addRadioDisableBit(bit) - local curVal = LocalPlayer.state.disableRadio or 0 - curVal = curVal | bit - LocalPlayer.state:set("disableRadio", curVal, true) -end -exports("addRadioDisableBit", addRadioDisableBit) - ---- removes the bit from disableRadio ----@param bit number the bit to remove -local function removeRadioDisableBit(bit) - local curVal = LocalPlayer.state.disableRadio or 0 - curVal = curVal & (~bit) - LocalPlayer.state:set("disableRadio", curVal, true) -end -exports("removeRadioDisableBit", removeRadioDisableBit) - diff --git a/server-data/resources/[phone]/pma-voice/client/utils/Nui.lua b/server-data/resources/[phone]/pma-voice/client/utils/Nui.lua deleted file mode 100644 index dd9e914fa..000000000 --- a/server-data/resources/[phone]/pma-voice/client/utils/Nui.lua +++ /dev/null @@ -1,11 +0,0 @@ -local uiReady = promise.new() -function sendUIMessage(message) - Citizen.Await(uiReady) - SendNUIMessage(message) -end - -RegisterNUICallback("uiReady", function(data, cb) - uiReady:resolve(true) - - cb('ok') -end) diff --git a/server-data/resources/[phone]/pma-voice/docs/_config.yml b/server-data/resources/[phone]/pma-voice/docs/_config.yml deleted file mode 100644 index 18854876c..000000000 --- a/server-data/resources/[phone]/pma-voice/docs/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-midnight \ No newline at end of file diff --git a/server-data/resources/[phone]/pma-voice/docs/client-getters/events.md b/server-data/resources/[phone]/pma-voice/docs/client-getters/events.md deleted file mode 100644 index 961243709..000000000 --- a/server-data/resources/[phone]/pma-voice/docs/client-getters/events.md +++ /dev/null @@ -1,27 +0,0 @@ -## setTalkingMode | settingsCallback | radioACtive - -## Description - -These event is designed to allow third part applications (like a hud) use the current voice mode of the player, radio state, etc. - -```lua --- default voice mode is 2 -local voiceMode = 2 -local voiceModes = {} -local usingRadio = false --- sets the current radio state boolean -AddEventHandler("pma-voice:radioActive", function(radioTalking) usingRadio = radioTalking end) --- changes the current voice range index -AddEventHandler('pma-voice:setTalkingMode', function(newTalkingRange) voiceMode = newTalkingRange end) --- returns registered voice modes from shared.lua's `Cfg.voiceModes` -TriggerEvent("pma-voice:settingsCallback", function(voiceSettings) - local voiceTable = voiceSettings.voiceModes - - -- loop through all voice modes and add them to the table - -- the percentage is used for the voice mode slider if this was an actual UI - for i = 1, #voiceTable do - local distance = math.ceil(((i/#voiceTable) * 100)) - voiceModes[i] = ("%s"):format(distance) - end -end) -``` \ No newline at end of file diff --git a/server-data/resources/[phone]/pma-voice/docs/client-setters/removePlayerFromCall.md b/server-data/resources/[phone]/pma-voice/docs/client-setters/removePlayerFromCall.md deleted file mode 100644 index 638728def..000000000 --- a/server-data/resources/[phone]/pma-voice/docs/client-setters/removePlayerFromCall.md +++ /dev/null @@ -1,12 +0,0 @@ -## removePlayerFromCall - -## Description - -Removes the player from the call - -## NOTE: This is just syntactic sugar for `setCallChannel(0)` - -```lua --- Removes the player from the call channel -exports['pma-voice']:removePlayerFromCall() -``` \ No newline at end of file diff --git a/server-data/resources/[phone]/pma-voice/docs/client-setters/removePlayerFromRadio.md b/server-data/resources/[phone]/pma-voice/docs/client-setters/removePlayerFromRadio.md deleted file mode 100644 index a15fd7a14..000000000 --- a/server-data/resources/[phone]/pma-voice/docs/client-setters/removePlayerFromRadio.md +++ /dev/null @@ -1,12 +0,0 @@ -## removePlayerFromRadio - -## Description - -Removes the player from the radio - -## NOTE: This is just syntactic sugar for `setRadioChannel(0)` - -```lua --- Removes the player from the radio channel -exports['pma-voice']:removePlayerFromRadio() -``` \ No newline at end of file diff --git a/server-data/resources/[phone]/pma-voice/docs/client-setters/setCallChannel.md b/server-data/resources/[phone]/pma-voice/docs/client-setters/setCallChannel.md deleted file mode 100644 index e2d98c428..000000000 --- a/server-data/resources/[phone]/pma-voice/docs/client-setters/setCallChannel.md +++ /dev/null @@ -1,25 +0,0 @@ -## setCallChannel | addPlayerToCall | SetCallChannel - -## Description - -Sets the local players call channel. - -## Parameters - -* **callChannel**: the call channel to join - - -```lua --- Joins call channel 1 -exports['pma-voice']:setCallChannel(1) - --- This will remove them from the call channel -exports['pma-voice']:setCallChannel(0) -``` - -addPlayerToCall is provided as a 'easier to read' version of setCallChannel. - -```lua --- Joins call channel 1 -exports['pma-voice']:addPlayerToCall(1) -``` \ No newline at end of file diff --git a/server-data/resources/[phone]/pma-voice/docs/client-setters/setCallVolume.md b/server-data/resources/[phone]/pma-voice/docs/client-setters/setCallVolume.md deleted file mode 100644 index 93509b9a6..000000000 --- a/server-data/resources/[phone]/pma-voice/docs/client-setters/setCallVolume.md +++ /dev/null @@ -1,14 +0,0 @@ -## setCallVolume - -## Description - -Sets the local players call channel volume - -## Parameters - -* **callVolume**: the call volume to set to between 0 - 100 percent - -```lua --- set the call volume to 50 percent -exports['pma-voice']:setCallVolume(50) -``` \ No newline at end of file diff --git a/server-data/resources/[phone]/pma-voice/docs/client-setters/setRadioChannel.md b/server-data/resources/[phone]/pma-voice/docs/client-setters/setRadioChannel.md deleted file mode 100644 index ee0ea376f..000000000 --- a/server-data/resources/[phone]/pma-voice/docs/client-setters/setRadioChannel.md +++ /dev/null @@ -1,26 +0,0 @@ -## setRadioChannel | addPlayerToRadio | SetCallChannel - -## Description - -Sets the local players radio channel. - -## Parameters - -* **radioChannel**: the radio channel to join - -## NOTE: If the player fails the server side radio channel check they will be reset to no channel. - -```lua --- Joins radio channel 1 -exports['pma-voice']:setRadioChannel(1) - --- This will remove the player from all radio channels -exports ['pma-voice']:setRadioChannel(0) -``` - -addPlayerToRadio is provided as a 'easier to read' alternative to setRadioChannel. - -```lua --- Joins radio channel 1 -exports['pma-voice']:addPlayerToRadio(1) -``` diff --git a/server-data/resources/[phone]/pma-voice/docs/client-setters/setRadioVolume.md b/server-data/resources/[phone]/pma-voice/docs/client-setters/setRadioVolume.md deleted file mode 100644 index 4f093cf45..000000000 --- a/server-data/resources/[phone]/pma-voice/docs/client-setters/setRadioVolume.md +++ /dev/null @@ -1,14 +0,0 @@ -## setRadioVolume - -## Description - -Sets the local players radio channel volume - -## Parameters - -* **radioVolume**: the radio volume to set to between 0 - 100 percent - -```lua --- sets the radio volume to 50 percent -exports['pma-voice']:setRadioVolume(50) -``` \ No newline at end of file diff --git a/server-data/resources/[phone]/pma-voice/docs/client-setters/setVoiceProperty.md b/server-data/resources/[phone]/pma-voice/docs/client-setters/setVoiceProperty.md deleted file mode 100644 index 737e961e8..000000000 --- a/server-data/resources/[phone]/pma-voice/docs/client-setters/setVoiceProperty.md +++ /dev/null @@ -1,17 +0,0 @@ -## setVoiceProperty | SetMumbleProperty | SetTokoProperty - -## Description - -Sets the voice property, currently the only use is to enable/disable radios and radio clicks. - -## Parameters - -* **property**: The property to set -* **value**: The value to set the property to - -```lua --- Enable the radio -exports['pma-voice']:setVoiceProperty('radioEnabled', true) --- Disable radio clicks -exports['pma-voice']:setVoiceProperty('micClicks', false) -``` \ No newline at end of file diff --git a/server-data/resources/[phone]/pma-voice/docs/routingBuckets.md b/server-data/resources/[phone]/pma-voice/docs/routingBuckets.md deleted file mode 100644 index f9e42292f..000000000 --- a/server-data/resources/[phone]/pma-voice/docs/routingBuckets.md +++ /dev/null @@ -1,3 +0,0 @@ -## Routing Buckets - -pma-voice natively supports routing buckets. \ No newline at end of file diff --git a/server-data/resources/[phone]/pma-voice/docs/server-getters/getPlayersInRadioChannel.md b/server-data/resources/[phone]/pma-voice/docs/server-getters/getPlayersInRadioChannel.md deleted file mode 100644 index e0f9bb05c..000000000 --- a/server-data/resources/[phone]/pma-voice/docs/server-getters/getPlayersInRadioChannel.md +++ /dev/null @@ -1,21 +0,0 @@ -## getPlayersInRadioChannel - -## Description - -Gets a list of all of the players in the specified radio channel. - -## Parameters - -* **radioChannel**: The channel to get all the members of - -## Returns - -Returns a table of all of the players in the specified radio channel - -```lua --- this will return all of the current players in radio channel 1 -local players = exports['pma-voice']:getPlayersInRadioChannel(1) -for source, isTalking in pairs(players) do - print(('%s is in radio channel 1, isTalking: %s'):format(GetPlayerName(source), isTalking)) -end -``` diff --git a/server-data/resources/[phone]/pma-voice/docs/server-setters/addChannelCheck.md b/server-data/resources/[phone]/pma-voice/docs/server-setters/addChannelCheck.md deleted file mode 100644 index 59e396e90..000000000 --- a/server-data/resources/[phone]/pma-voice/docs/server-setters/addChannelCheck.md +++ /dev/null @@ -1,22 +0,0 @@ -## addChannelCheck - -## Description - -Adds a channel check to radio channels. - -## Parameters - -* **channel**: The channel to add the check to. -* **function**: the function to call when the check is triggered, which should return a boolean of if the player is allowed to join the channel.. - - -```lua --- Example for addChannelCheck --- this always has to return true/false -exports['pma-voice']:addChannelCheck(1, function(source) - if IsPlayerAceAllowed(source, 'radio.police') then - return true - end - return false -end) -``` \ No newline at end of file diff --git a/server-data/resources/[phone]/pma-voice/docs/server-setters/setPlayerCall.md b/server-data/resources/[phone]/pma-voice/docs/server-setters/setPlayerCall.md deleted file mode 100644 index db5ae7ec4..000000000 --- a/server-data/resources/[phone]/pma-voice/docs/server-setters/setPlayerCall.md +++ /dev/null @@ -1,14 +0,0 @@ -## setPlayerCall - -## Description - -Sets the players call channel. - -## Parameters - -* **source**: The player to set the radio channel of -* **callChannel**: the radio channel to set the player to - -```lua -exports['pma-voice']:setPlayerCall(source, 1) -``` \ No newline at end of file diff --git a/server-data/resources/[phone]/pma-voice/docs/server-setters/setPlayerRadio.md b/server-data/resources/[phone]/pma-voice/docs/server-setters/setPlayerRadio.md deleted file mode 100644 index 11c8db29c..000000000 --- a/server-data/resources/[phone]/pma-voice/docs/server-setters/setPlayerRadio.md +++ /dev/null @@ -1,14 +0,0 @@ -## setPlayerRadio - -## Description - -Sets the players radio channel. - -## Parameters - -* **source**: The player to set the radio channel of -* **radioChannel**: the radio channel to set the player to - -```lua -exports['pma-voice']:setPlayerRadio(source, 1) -``` \ No newline at end of file diff --git a/server-data/resources/[phone]/pma-voice/docs/state-getters/stateBagGetters.md b/server-data/resources/[phone]/pma-voice/docs/state-getters/stateBagGetters.md deleted file mode 100644 index c21e87847..000000000 --- a/server-data/resources/[phone]/pma-voice/docs/state-getters/stateBagGetters.md +++ /dev/null @@ -1,17 +0,0 @@ -## State Bag Getters/Setters - -## Description - -State bag getters are a little bit simpler, they just return the current value that is set in the state bag. - -#### Note: If you're on the client and only using it on the current player, you can replace Player(source) with LocalPlayer - -## Example for Proximity - -```lua -local plyState = Player(source).state -local proximity = plyState.proximity -print(proximity.index) -- prints the index of the proximity as seen in Cfg.voiceModes -print(proximity.distance) -- prints the distance of the proximity -print(proximity.mode) -- prints the mode name of the proximity -``` \ No newline at end of file diff --git a/server-data/resources/[phone]/pma-voice/fxmanifest.lua b/server-data/resources/[phone]/pma-voice/fxmanifest.lua deleted file mode 100644 index 4a4d73abe..000000000 --- a/server-data/resources/[phone]/pma-voice/fxmanifest.lua +++ /dev/null @@ -1,70 +0,0 @@ -game 'common' - -fx_version 'cerulean' -author 'AvarianKnight' -description 'VOIP built using FiveM\'s built in mumble.' - -dependencies { - '/onesync', -} - -lua54 'yes' - -shared_script 'shared.lua' - -client_scripts { - 'client/utils/*', - 'client/init/proximity.lua', - 'client/init/init.lua', - 'client/init/main.lua', - 'client/init/submix.lua', - 'client/module/*.lua', - 'client/*.lua', -} - -server_scripts { - 'server/**/*.lua', - 'server/**/*.js' -} - -files { - 'ui/*.ogg', - 'ui/css/*.css', - 'ui/js/*.js', - 'ui/index.html', -} - -ui_page 'ui/index.html' - -provides { - 'mumble-voip', - 'tokovoip', - 'toko-voip', - 'tokovoip_script' -} - -convar_category 'PMA-Voice' { - "PMA-Voice Configuration Options", - { - { "Use native audio", "$voice_useNativeAudio", "CV_BOOL", "false" }, - { "Use 2D audio", "$voice_use2dAudio", "CV_BOOL", "false" }, - { "Use sending range only", "$voice_useSendingRangeOnly", "CV_BOOL", "false" }, - { "Enable UI", "$voice_enableUi", "CV_INT", "1" }, - { "Enable F11 proximity key", "$voice_enableProximityCycle", "CV_INT", "1" }, - { "Proximity cycle key", "$voice_defaultCycle", "CV_STRING", "F11" }, - { "Voice radio volume", "$voice_defaultRadioVolume", "CV_INT", "30" }, - { "Voice call volume", "$voice_defaultCallVolume", "CV_INT", "60" }, - { "Enable radios", "$voice_enableRadios", "CV_INT", "1" }, - { "Enable calls", "$voice_enableCalls", "CV_INT", "1" }, - { "Enable submix", "$voice_enableSubmix", "CV_INT", "1" }, - { "Enable radio animation", "$voice_enableRadioAnim", "CV_INT", "0" }, - { "Radio key", "$voice_defaultRadio", "CV_STRING", "LMENU" }, - { "UI refresh rate", "$voice_uiRefreshRate", "CV_INT", "200" }, - { "Allow players to set audio intent", "$voice_allowSetIntent", "CV_INT", "1" }, - { "External mumble server address", "$voice_externalAddress", "CV_STRING", "" }, - { "External mumble server port", "$voice_externalPort", "CV_INT", "0" }, - { "Voice debug mode", "$voice_debugMode", "CV_INT", "0" }, - { "Disable players being allowed to join", "$voice_externalDisallowJoin", "CV_INT", "0" }, - { "Hide server endpoints in logs", "$voice_hideEndpoints", "CV_INT", "1" }, - } -} diff --git a/server-data/resources/[phone]/pma-voice/server/main.lua b/server-data/resources/[phone]/pma-voice/server/main.lua deleted file mode 100644 index be4c96333..000000000 --- a/server-data/resources/[phone]/pma-voice/server/main.lua +++ /dev/null @@ -1,157 +0,0 @@ -voiceData = {} -radioData = {} -callData = {} - -local mappedChannels = {} -function firstFreeChannel() - for i = 1, 2048 do - if not mappedChannels[i] then - return i - end - end - - return 0 -end - -function defaultTable(source) - handleStateBagInitilization(source) - return { - radio = 0, - call = 0, - lastRadio = 0, - lastCall = 0 - } -end - -function handleStateBagInitilization(source) - local plyState = Player(source).state - if not plyState.pmaVoiceInit then - plyState:set('radio', GetConvarInt('voice_defaultRadioVolume', 30), true) - plyState:set('call', GetConvarInt('voice_defaultCallVolume', 60), true) - plyState:set('submix', nil, true) - plyState:set('proximity', {}, true) - plyState:set('callChannel', 0, true) - plyState:set('radioChannel', 0, true) - plyState:set('voiceIntent', 'speech', true) - -- We want to save voice inits because we'll automatically reinitalize calls and channels - plyState:set('pmaVoiceInit', true, false) - end - - local assignedChannel = firstFreeChannel() - plyState:set('assignedChannel', assignedChannel, true) - if assignedChannel ~= 0 then - mappedChannels[assignedChannel] = source - logger.verbose('[reuse] Assigned %s to channel %s', source, assignedChannel) - else - logger.error('[reuse] Failed to find a free channel for %s', source) - end -end - -CreateThread(function() - local plyTbl = GetPlayers() - for i = 1, #plyTbl do - local ply = tonumber(plyTbl[i]) - voiceData[ply] = defaultTable(plyTbl[i]) - end - - Wait(5000) - - local nativeAudio = GetConvar('voice_useNativeAudio', 'not-set') - local _3dAudio = GetConvar('voice_use3dAudio', 'not-set') - local _2dAudio = GetConvar('voice_use2dAudio', 'not-set') - local sendingRangeOnly = GetConvar('voice_useSendingRangeOnly', 'not-set') - local gameVersion = GetConvar('gamename', 'fivem') - - -- handle no convars being set (default drag n' drop) - if - nativeAudio == 'not-set' - and _3dAudio == 'not-set' - and _2dAudio == 'not-set' - then - SetConvarReplicated('voice_useNativeAudio', 'true') - if sendingRangeOnly == 'not-set' then - SetConvarReplicated('voice_useSendingRangeOnly', 'true') - logger.info( - 'No convars detected for voice mode, defaulting to \'setr voice_useNativeAudio true\' and \'setr voice_useSendingRangeOnly true\'') - else - logger.info('No voice mod detected, defaulting to \'setr voice_useNativeAudio true\'') - end - elseif sendingRangeOnly == 'not-set' then - logger.warn( - "It's recommended to have 'voice_useSendingRangeOnly' set to true, you can do that with 'setr voice_useSendingRangeOnly true', this prevents players who directly join the mumble server from broadcasting to players.") - end - - local radioVolume = GetConvarInt("voice_defaultRadioVolume", 30) - local callVolume = GetConvarInt("voice_defaultCallVolume", 60) - - -- When casted to an integer these get set to 0 or 1, so warn on these values that they don't work - if - radioVolume == 0 or radioVolume == 1 or - callVolume == 0 or callVolume == 1 - then - SetConvarReplicated("voice_defaultRadioVolume", 30) - SetConvarReplicated("voice_defaultCallVolume", 60) - for i = 1, 5 do - Wait(5000) - logger.warn( - "`voice_defaultRadioVolume` or `voice_defaultCallVolume` have their value set as a float, this is going to automatically be fixed but please update your convars.") - end - end -end) - -AddEventHandler('playerJoining', function() - if not voiceData[source] then - voiceData[source] = defaultTable(source) - end -end) - -AddEventHandler("playerDropped", function() - local source = source - local mappedChannel = Player(source).state.assignedChannel - - if voiceData[source] then - local plyData = voiceData[source] - - if plyData.radio ~= 0 then - removePlayerFromRadio(source, plyData.radio) - end - - if plyData.call ~= 0 then - removePlayerFromCall(source, plyData.call) - end - - voiceData[source] = nil - end - - if mappedChannel then - mappedChannels[mappedChannel] = nil - logger.verbose('[reuse] Unassigned %s from channel %s', source, mappedChannel) - end -end) - -if GetConvarInt('voice_externalDisallowJoin', 0) == 1 then - AddEventHandler('playerConnecting', function(_, _, deferral) - deferral.defer() - Wait(0) - deferral.done('This server is not accepting connections.') - end) -end - --- only meant for internal use so no documentation -function isValidPlayer(source) - return voiceData[source] -end - -exports('isValidPlayer', isValidPlayer) - -function getPlayersInRadioChannel(channel) - local returnChannel = radioData[channel] - if returnChannel then - return returnChannel - end - -- channel doesnt exist - return {} -end - -exports('getPlayersInRadioChannel', getPlayersInRadioChannel) -exports('GetPlayersInRadioChannel', getPlayersInRadioChannel) diff --git a/server-data/resources/[phone]/pma-voice/server/module/phone.lua b/server-data/resources/[phone]/pma-voice/server/module/phone.lua deleted file mode 100644 index ac6412137..000000000 --- a/server-data/resources/[phone]/pma-voice/server/module/phone.lua +++ /dev/null @@ -1,76 +0,0 @@ ---- removes a player from the call for everyone in the call. ----@param source number the player to remove from the call ----@param callChannel number the call channel to remove them from -function removePlayerFromCall(source, callChannel) - logger.verbose('[call] Removed %s from call %s', source, callChannel) - - callData[callChannel] = callData[callChannel] or {} - for player, _ in pairs(callData[callChannel]) do - TriggerClientEvent('pma-voice:removePlayerFromCall', player, source) - end - callData[callChannel][source] = nil - voiceData[source] = voiceData[source] or defaultTable(source) - voiceData[source].call = 0 -end - ---- adds a player to a call ----@param source number the player to add to the call ----@param callChannel number the call channel to add them to -function addPlayerToCall(source, callChannel) - logger.verbose('[call] Added %s to call %s', source, callChannel) - -- check if the channel exists, if it does set the varaible to it - -- if not create it (basically if not callData make callData) - callData[callChannel] = callData[callChannel] or {} - for player, _ in pairs(callData[callChannel]) do - -- don't need to send to the source because they're about to get sync'd! - if player ~= source then - TriggerClientEvent('pma-voice:addPlayerToCall', player, source) - end - end - callData[callChannel][source] = true - voiceData[source] = voiceData[source] or defaultTable(source) - voiceData[source].call = callChannel - TriggerClientEvent('pma-voice:syncCallData', source, callData[callChannel]) -end - ---- set the players call channel ----@param source number the player to set the call off ----@param _callChannel number the channel to set the player to (or 0 to remove them from any call channel) -function setPlayerCall(source, _callChannel) - if GetConvarInt('voice_enableCalls', 1) ~= 1 then return end - voiceData[source] = voiceData[source] or defaultTable(source) - local isResource = GetInvokingResource() - local plyVoice = voiceData[source] - local callChannel = tonumber(_callChannel) - if not callChannel then - -- only full error if its sent from another server-side resource - if isResource then - error(("'callChannel' expected 'number', got: %s"):format(type(_callChannel))) - else - return logger.warn("%s sent a invalid call, 'callChannel' expected 'number', got: %s", source, - type(_callChannel)) - end - end - if isResource then - -- got set in a export, need to update the client to tell them that their call - -- changed - TriggerClientEvent('pma-voice:clSetPlayerCall', source, callChannel) - end - - Player(source).state.callChannel = callChannel - - if callChannel ~= 0 and plyVoice.call == 0 then - addPlayerToCall(source, callChannel) - elseif callChannel == 0 then - removePlayerFromCall(source, plyVoice.call) - elseif plyVoice.call > 0 then - removePlayerFromCall(source, plyVoice.call) - addPlayerToCall(source, callChannel) - end -end - -exports('setPlayerCall', setPlayerCall) - -RegisterNetEvent('pma-voice:setPlayerCall', function(callChannel) - setPlayerCall(source, callChannel) -end) diff --git a/server-data/resources/[phone]/pma-voice/server/module/radio.lua b/server-data/resources/[phone]/pma-voice/server/module/radio.lua deleted file mode 100644 index 576c170cb..000000000 --- a/server-data/resources/[phone]/pma-voice/server/module/radio.lua +++ /dev/null @@ -1,178 +0,0 @@ -local radioChecks = {} - ---- checks if the player can join the channel specified ---- @param source number the source of the player ---- @param radioChannel number the channel they're trying to join ---- @return boolean if the user can join the channel -function canJoinChannel(source, radioChannel) - if radioChecks[radioChannel] then - return radioChecks[radioChannel](source) - end - return true -end - ---- adds a check to the channel, function is expected to return a boolean of true or false ----@param channel number the channel to add a check to ----@param cb function the function to execute the check on -function addChannelCheck(channel, cb) - local channelType = type(channel) - local cbType = type(cb) - if channelType ~= "number" then - error(("'channel' expected 'number' got '%s'"):format(channelType)) - end - if cbType ~= 'table' or not cb.__cfx_functionReference then - error(("'cb' expected 'function' got '%s'"):format(cbType)) - end - radioChecks[channel] = cb - logger.info("%s added a check to channel %s", GetInvokingResource(), channel) -end - -exports('addChannelCheck', addChannelCheck) - -local function radioNameGetter_orig(source) - return GetPlayerName(source) -end -local radioNameGetter = radioNameGetter_orig - ---- adds a check to the channel, function is expected to return a boolean of true or false ----@param cb function the function to execute the check on -function overrideRadioNameGetter(channel, cb) - local cbType = type(cb) - if cbType == 'table' and not cb.__cfx_functionReference then - error(("'cb' expected 'function' got '%s'"):format(cbType)) - end - radioNameGetter = cb - logger.info("%s added a check to channel %s", GetInvokingResource(), channel) -end - -exports('overrideRadioNameGetter', overrideRadioNameGetter) - ---- adds a player to the specified radion channel ----@param source number the player to add to the channel ----@param radioChannel number the channel to set them to ----@return boolean wasAdded if the player was successfuly added to the radio channel, or if it failed. -function addPlayerToRadio(source, radioChannel) - if not canJoinChannel(source, radioChannel) then - -- remove the player from the radio client side - TriggerClientEvent("pma-voice:radioChangeRejected", source) - TriggerClientEvent('pma-voice:removePlayerFromRadio', source, source) - return false - end - logger.verbose('[radio] Added %s to radio %s', source, radioChannel) - - -- check if the channel exists, if it does set the varaible to it - -- if not create it (basically if not radiodata make radiodata) - radioData[radioChannel] = radioData[radioChannel] or {} - local plyName = radioNameGetter(source) - for player, _ in pairs(radioData[radioChannel]) do - TriggerClientEvent('pma-voice:addPlayerToRadio', player, source, plyName) - end - voiceData[source] = voiceData[source] or defaultTable(source) - voiceData[source].radio = radioChannel - radioData[radioChannel][source] = false - TriggerClientEvent('pma-voice:syncRadioData', source, radioData[radioChannel], - GetConvarInt("voice_syncPlayerNames", 0) == 1 and plyName) - return true -end - ---- removes a player from the specified channel ----@param source number the player to remove ----@param radioChannel number the current channel to remove them from -function removePlayerFromRadio(source, radioChannel) - logger.verbose('[radio] Removed %s from radio %s', source, radioChannel) - radioData[radioChannel] = radioData[radioChannel] or {} - for player, _ in pairs(radioData[radioChannel]) do - TriggerClientEvent('pma-voice:removePlayerFromRadio', player, source) - end - radioData[radioChannel][source] = nil - voiceData[source] = voiceData[source] or defaultTable(source) - voiceData[source].radio = 0 -end - --- TODO: Implement this in a way that allows players to be on multiple channels ---- sets the players current radio channel ----@param source number the player to set the channel of ----@param _radioChannel number the radio channel to set them to (or 0 to remove them from radios) -function setPlayerRadio(source, _radioChannel) - if GetConvarInt('voice_enableRadios', 1) ~= 1 then return end - voiceData[source] = voiceData[source] or defaultTable(source) - local isResource = GetInvokingResource() - local plyVoice = voiceData[source] - local radioChannel = tonumber(_radioChannel) - if not radioChannel then - -- only full error if its sent from another server-side resource - if isResource then - error(("'radioChannel' expected 'number', got: %s"):format(type(_radioChannel))) - else - return logger.warn("%s sent a invalid radio, 'radioChannel' expected 'number', got: %s", source, - type(_radioChannel)) - end - end - if isResource then - -- got set in a export, need to update the client to tell them that their radio - -- changed - TriggerClientEvent('pma-voice:clSetPlayerRadio', source, radioChannel) - end - if radioChannel ~= 0 then - if plyVoice.radio > 0 then - removePlayerFromRadio(source, plyVoice.radio) - end - local wasAdded = addPlayerToRadio(source, radioChannel) - Player(source).state.radioChannel = wasAdded and radioChannel or 0 - elseif radioChannel == 0 then - removePlayerFromRadio(source, plyVoice.radio) - Player(source).state.radioChannel = 0 - end -end - -exports('setPlayerRadio', setPlayerRadio) - -RegisterNetEvent('pma-voice:setPlayerRadio', function(radioChannel) - setPlayerRadio(source, radioChannel) -end) - ---- syncs the player talking across all radio members ----@param talking boolean sets if the palyer is talking. -function setTalkingOnRadio(talking) - if GetConvarInt('voice_enableRadios', 1) ~= 1 then return end - voiceData[source] = voiceData[source] or defaultTable(source) - local plyVoice = voiceData[source] - local radioTbl = radioData[plyVoice.radio] - if radioTbl then - radioTbl[source] = talking - logger.verbose('[radio] Set %s to talking: %s on radio %s', source, talking, plyVoice.radio) - for player, _ in pairs(radioTbl) do - if player ~= source then - TriggerClientEvent('pma-voice:setTalkingOnRadio', player, source, talking) - logger.verbose('[radio] Sync %s to let them know %s is %s', player, source, - talking and 'talking' or 'not talking') - end - end - end -end - -RegisterNetEvent('pma-voice:setTalkingOnRadio', setTalkingOnRadio) - -AddEventHandler("onResourceStop", function(resource) - for channel, cfxFunctionRef in pairs(radioChecks) do - local functionRef = cfxFunctionRef.__cfx_functionReference - local functionResource = string.match(functionRef, resource) - if functionResource then - radioChecks[channel] = nil - logger.warn('Channel %s had its radio check removed because the resource that gave the checks stopped', - channel) - end - end - - if type(radioNameGetter) == "table" then - local radioRef = radioNameGetter.__cfx_functionReference - if radioRef then - local isResource = string.match(radioRef, resource) - if isResource then - radioNameGetter = radioNameGetter_orig - logger.warn( - 'Radio name getter is resetting to default because the resource that gave the cb got turned off') - end - end - end -end) diff --git a/server-data/resources/[phone]/pma-voice/server/mute.js b/server-data/resources/[phone]/pma-voice/server/mute.js deleted file mode 100644 index 61b45ffed..000000000 --- a/server-data/resources/[phone]/pma-voice/server/mute.js +++ /dev/null @@ -1,26 +0,0 @@ -let mutedPlayers = {} -// this is implemented in JS due to Lua's lack of a ClearTimeout -// muteply instead of mute because mute conflicts with rp-radio -RegisterCommand('muteply', (source, args) => { - const mutePly = parseInt(args[0]) - const duration = parseInt(args[1]) || 900 - if (mutePly && exports[GetCurrentResourceName()].isValidPlayer(mutePly)) { - const isMuted = !MumbleIsPlayerMuted(mutePly); - Player(mutePly).state.muted = isMuted; - MumbleSetPlayerMuted(mutePly, isMuted); - emit('pma-voice:playerMuted', mutePly, source, isMuted, duration); - // since this is a toggle, if theres a mutedPlayers entry it can be assumed - // that they're currently muted, so we'll clear the timeout and unmute - if (mutedPlayers[mutePly]) { - clearTimeout(mutedPlayers[mutePly]); - MumbleSetPlayerMuted(mutePly, isMuted) - Player(mutePly).state.muted = isMuted; - return; - } - mutedPlayers[mutePly] = setTimeout(() => { - MumbleSetPlayerMuted(mutePly, !isMuted) - Player(mutePly).state.muted = !isMuted; - delete mutedPlayers[mutePly] - }, duration * 1000) - } -}, true) diff --git a/server-data/resources/[phone]/pma-voice/shared.lua b/server-data/resources/[phone]/pma-voice/shared.lua deleted file mode 100644 index a81d5d78d..000000000 --- a/server-data/resources/[phone]/pma-voice/shared.lua +++ /dev/null @@ -1,127 +0,0 @@ -Cfg = {} - -voiceTarget = 1 - -gameVersion = GetGameName() - --- these are just here to satisfy linting -if not IsDuplicityVersion() then - LocalPlayer = LocalPlayer - playerServerId = GetPlayerServerId(PlayerId()) - - if gameVersion == "redm" then - function CreateAudioSubmix(name) - return Citizen.InvokeNative(0x658d2bc8, name, Citizen.ResultAsInteger()) - end - - function AddAudioSubmixOutput(submixId, outputSubmixId) - Citizen.InvokeNative(0xAC6E290D, submixId, outputSubmixId) - end - - function MumbleSetSubmixForServerId(serverId, submixId) - Citizen.InvokeNative(0xFE3A3054, serverId, submixId) - end - - function SetAudioSubmixEffectParamFloat(submixId, effectSlot, paramIndex, paramValue) - Citizen.InvokeNative(0x9A209B3C, submixId, effectSlot, paramIndex, paramValue) - end - - function SetAudioSubmixEffectParamInt(submixId, effectSlot, paramIndex, paramValue) - Citizen.InvokeNative(0x77FAE2B8, submixId, effectSlot, paramIndex, paramValue) - end - - function SetAudioSubmixEffectRadioFx(submixId, effectSlot) - Citizen.InvokeNative(0xAAA94D53, submixId, effectSlot) - end - - function SetAudioSubmixOutputVolumes(submixId, outputSlot, frontLeftVolume, frontRightVolume, rearLeftVolume, - rearRightVolume, channel5Volume, channel6Volume) - Citizen.InvokeNative(0x825DC0D1, submixId, outputSlot, frontLeftVolume, frontRightVolume, rearLeftVolume, - rearRightVolume, channel5Volume, channel6Volume) - end - end -end -Player = Player -Entity = Entity - -if GetConvar('voice_useNativeAudio', 'false') == 'true' then - -- native audio distance seems to be larger then regular gta units - Cfg.voiceModes = { - { 1.5, "Whisper" }, -- Whisper speech distance in gta distance units - { 3.0, "Normal" }, -- Normal speech distance in gta distance units - { 6.0, "Shouting" } -- Shout speech distance in gta distance units - } -else - Cfg.voiceModes = { - { 3.0, "Whisper" }, -- Whisper speech distance in gta distance units - { 7.0, "Normal" }, -- Normal speech distance in gta distance units - { 15.0, "Shouting" } -- Shout speech distance in gta distance units - } -end - -logger = { - log = function(message, ...) - print((message):format(...)) - end, - info = function(message, ...) - if GetConvarInt('voice_debugMode', 0) >= 1 then - print(('[info] ' .. message):format(...)) - end - end, - warn = function(message, ...) - print(('[^1WARNING^7] ' .. message):format(...)) - end, - error = function(message, ...) - error((message):format(...)) - end, - verbose = function(message, ...) - if GetConvarInt('voice_debugMode', 0) >= 4 then - print(('[verbose] ' .. message):format(...)) - end - end, -} - - -function tPrint(tbl, indent) - indent = indent or 0 - for k, v in pairs(tbl) do - local tblType = type(v) - local formatting = string.rep(" ", indent) .. k .. ": " - - if tblType == "table" then - print(formatting) - tPrint(v, indent + 1) - elseif tblType == 'boolean' then - print(formatting .. tostring(v)) - elseif tblType == "function" then - print(formatting .. tostring(v)) - else - print(formatting .. v) - end - end -end - -local function types(args) - local argType = type(args[1]) - for i = 2, #args do - local arg = args[i] - if argType == arg then - return true, argType - end - end - return false, argType -end - ---- does a type check and errors if an invalid type is sent ----@param ... table a table with the variable being the first argument and the expected type being the second -function type_check(...) - local vars = { ... } - for i = 1, #vars do - local var = vars[i] - local matchesType, varType = types(var) - if not matchesType then - table.remove(var, 1) - error(("Invalid type sent to argument #%s, expected %s, got %s"):format(i, table.concat(var, "|"), varType)) - end - end -end diff --git a/server-data/resources/[phone]/pma-voice/ui/css/app.css b/server-data/resources/[phone]/pma-voice/ui/css/app.css deleted file mode 100644 index 1a0b3a0c7..000000000 --- a/server-data/resources/[phone]/pma-voice/ui/css/app.css +++ /dev/null @@ -1 +0,0 @@ -.voiceInfo{font-family:Avenir,Helvetica,Arial,sans-serif;position:fixed;text-align:right;bottom:5px;padding:0;right:5px;font-size:12px;font-weight:700;color:#949697;text-shadow:1.25px 0 0 #000,0 -1.25px 0 #000,0 1.25px 0 #000,-1.25px 0 0 #000}.talking{color:hsla(0,0%,100%,.822)}p{margin:0} \ No newline at end of file diff --git a/server-data/resources/[phone]/pma-voice/ui/index.html b/server-data/resources/[phone]/pma-voice/ui/index.html deleted file mode 100644 index bd213b624..000000000 --- a/server-data/resources/[phone]/pma-voice/ui/index.html +++ /dev/null @@ -1 +0,0 @@ -
\r\n\t\t\t\t[Call]\r\n\t\t\t
\r\n\t\t\t\r\n\t\t\t\t{{ voice.radioChannel }} Mhz [Radio]\r\n\t\t\t
\r\n\t\t\t\r\n\t\t\t\t{{ voice.voiceModes[voice.voiceMode][1] }} [Range]\r\n\t\t\t
\r\n\t\tf?q(e,s,c,!0,!1,p):F(t,n,r,s,c,i,l,u,p)},$=(e,t,n,r,s,c,i,l,u)=>{let a=0;const f=t.length;let p=e.length-1,d=f-1;while(a<=p&&a<=d){const o=e[a],r=t[a]=u?Yn(t[a]):Qn(t[a]);if(!$n(o,r))break;g(o,r,n,null,s,c,i,l,u),a++}while(a<=p&&a<=d){const o=e[p],r=t[d]=u?Yn(t[d]):Qn(t[d]);if(!$n(o,r))break;g(o,r,n,null,s,c,i,l,u),p--,d--}if(a>p){if(a<=d){const e=d+1,o=e