This repository has been archived by the owner on Dec 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 54
/
client.lua
1124 lines (954 loc) · 33.4 KB
/
client.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
local initialised = false
local playerServerId = GetPlayerServerId(PlayerId())
local unmutedPlayers = {}
local gridTargets = {}
local radioTargets = {}
local callTargets = {}
local speakerTargets = {}
local nearbySpeakerTargets = {}
local resetTargets = false
local playerChunk = nil
local voiceTarget = 2
local vehicleTargets = {}
local wasPlayerInVehicle = false
-- Functions
function SetVoiceData(key, value, target)
TriggerServerEvent("mumble:SetVoiceData", key, value, target)
end
function PlayMicClick(channel, value)
if channel <= mumbleConfig.radioClickMaxChannel then
if mumbleConfig.micClicks then
if (value and mumbleConfig.micClickOn) or (not value and mumbleConfig.micClickOff) then
SendNUIMessage({ sound = (value and "audio_on" or "audio_off"), volume = mumbleConfig.micClickVolume })
end
end
end
end
function SetGridTargets(pos, reset) -- Used to set the players voice targets depending on where they are in the map
local currentChunk = GetCurrentChunk(pos)
local nearbyChunks = GetNearbyChunks(pos)
local nearbyChunksStr = "None"
local targets = {}
local playerData = voiceData[playerServerId]
if not playerData then
playerData = {
mode = 2,
radio = 0,
radioActive = false,
call = 0,
callSpeaker = false,
speakerTargets = {},
radioName = GetRandomPhoneticLetter() .. "-" .. playerServerId
}
end
for i = 1, #nearbyChunks do
if nearbyChunks[i] ~= currentChunk then
targets[nearbyChunks[i]] = true
if gridTargets[nearbyChunks[i]] then
gridTargets[nearbyChunks[i]] = nil
end
if nearbyChunksStr ~= "None" then
nearbyChunksStr = nearbyChunksStr .. ", " .. nearbyChunks[i]
else
nearbyChunksStr = nearbyChunks[i]
end
end
end
local newGridTargets = false
for channel, exists in pairs(gridTargets) do
if exists then
newGridTargets = true
break
end
end
if reset then
NetworkSetTalkerProximity(mumbleConfig.voiceModes[playerData.mode][1] + 0.0) -- Set voice proximity
MumbleClearVoiceTarget(voiceTarget) -- Reset voice target
end
if playerChunk ~= currentChunk or newGridTargets or reset then -- Only reset target channels if the current chunk or any nearby chunks have changed
MumbleClearVoiceTargetChannels(voiceTarget)
MumbleAddVoiceTargetChannel(voiceTarget, currentChunk)
for channel, _ in pairs(targets) do
MumbleAddVoiceTargetChannel(voiceTarget, channel)
end
NetworkSetVoiceChannel(currentChunk)
playerChunk = currentChunk
gridTargets = targets
DebugMsg("Current Chunk: " .. currentChunk .. ", Nearby Chunks: " .. nearbyChunksStr)
if reset then
SetPlayerTargets(callTargets, speakerTargets, vehicleTargets, playerData.radioActive and radioTargets or nil)
resetTargets = false
end
end
end
function SetPlayerTargets(...)
local targets = { ... }
local targetList = ""
local addedTargets = {}
MumbleClearVoiceTargetPlayers(voiceTarget)
for i = 1, #targets do
for id, _ in pairs(targets[i]) do
if not addedTargets[id] then
MumbleAddVoiceTargetPlayerByServerId(voiceTarget, id)
if targetList == "" then
targetList = targetList .. id
else
targetList = targetList .. ", " .. id
end
addedTargets[id] = true
end
end
end
if targetList ~= "" then
DebugMsg("Sending voice to Player " .. targetList)
else
DebugMsg("Sending voice to Nobody")
end
end
function TogglePlayerVoice(serverId, value)
local msg = false
if value then
if not unmutedPlayers[serverId] then
unmutedPlayers[serverId] = true
MumbleSetVolumeOverrideByServerId(serverId, 1.0)
msg = true
end
else
if unmutedPlayers[serverId] then
unmutedPlayers[serverId] = nil
MumbleSetVolumeOverrideByServerId(serverId, -1.0)
msg = true
end
end
if msg then
DebugMsg((value and "Unmuting" or "Muting") .. " Player " .. serverId)
end
end
function SetRadioChannel(channel)
local channel = tonumber(channel)
if channel ~= nil then
SetVoiceData("radio", channel)
if radioData[channel] then -- Check if anyone is talking and unmute if so
for id, _ in pairs(radioData[channel]) do
if id ~= playerServerId then
if not unmutedPlayers[id] then
local playerData = voiceData[id]
if playerData ~= nil then
if playerData.radioActive then
TogglePlayerVoice(id, true)
end
end
end
end
end
end
end
end
function SetCallChannel(channel)
local channel = tonumber(channel)
if channel ~= nil then
SetVoiceData("call", channel)
if callData[channel] then -- Unmute current call participants
for id, _ in pairs(callData[channel]) do
if id ~= playerServerId then
if not unmutedPlayers[id] then
TogglePlayerVoice(id, true)
end
end
end
end
end
end
function CheckVoiceSetting(varName, msg)
local setting = GetConvarInt(varName, -1)
if setting == 0 then
SendNUIMessage({ warningId = varName, warningMsg = msg })
Citizen.CreateThread(function()
local varName = varName
while GetConvarInt(varName, -1) == 0 do
Citizen.Wait(1000)
end
SendNUIMessage({ warningId = varName })
end)
end
DebugMsg("Checking setting: " .. varName .. " = " .. setting)
return setting == 1
end
function CompareChannels(playerData, type, channel)
local match = false
if playerData[type] ~= nil then
if playerData[type] == channel then
match = true
end
end
return match
end
function GetVehiclePassengers(vehicle)
local passengers = {}
local passengerCount = 0
local seatCount = GetVehicleNumberOfPassengers(vehicle)
for seat = -1, seatCount do
if not IsVehicleSeatFree(vehicle, seat) then
passengers[GetPedInVehicleSeat(vehicle, seat)] = true
passengerCount = passengerCount + 1
end
end
return passengerCount, passengers
end
function MuteVehiclePassengers(playerData)
local changed = false
for id, exists in pairs(vehicleTargets) do
if exists then
changed = true
if playerData.radio > 0 and playerData.call > 0 then -- Only mute player if they are not in call or radio channel with client
local remotePlayerData = voiceData[id]
if remotePlayerData ~= nil then
if playerData.radio == remotePlayerData.radio then
if not remotePlayerData.radioActive and playerData.call ~= remotePlayerData.call then
TogglePlayerVoice(id, false)
end
elseif playerData.call ~= remotePlayerData.call then
TogglePlayerVoice(id, false)
end
end
elseif playerData.call > 0 then
local remotePlayerData = voiceData[id]
if remotePlayerData ~= nil then
if playerData.call ~= remotePlayerData.call then
TogglePlayerVoice(id, false)
end
end
elseif playerData.radio > 0 then
local remotePlayerData = voiceData[id]
if remotePlayerData ~= nil then
if playerData.radio == remotePlayerData.radio then
if not remotePlayerData.radioActive then
TogglePlayerVoice(id, false)
end
end
end
else
TogglePlayerVoice(id, false)
end
end
end
return changed
end
-- Events
AddEventHandler("onClientResourceStart", function(resName) -- Initialises the script, sets up voice range, voice targets and request sync with server
if GetCurrentResourceName() ~= resName then
return
end
DebugMsg("Initialising")
Citizen.Wait(1000)
if mumbleConfig.useExternalServer then
MumbleSetServerAddress(mumbleConfig.externalAddress, mumbleConfig.externalPort)
end
CheckVoiceSetting("profile_voiceEnable", "Voice chat disabled")
CheckVoiceSetting("profile_voiceTalkEnabled", "Microphone disabled")
if not MumbleIsConnected() then
SendNUIMessage({ warningId = "mumble_is_connected", warningMsg = "Not connected to mumble" })
while not MumbleIsConnected() do
Citizen.Wait(250)
end
SendNUIMessage({ warningId = "mumble_is_connected" })
end
Citizen.Wait(1000)
MumbleClearVoiceTarget(voiceTarget) -- Reset voice target
MumbleSetVoiceTarget(voiceTarget)
Citizen.Wait(1000)
voiceData[playerServerId] = {
mode = 2,
radio = 0,
radioActive = false,
call = 0,
callSpeaker = false,
speakerTargets = {},
radioName = GetRandomPhoneticLetter() .. "-" .. playerServerId
}
SetGridTargets(GetEntityCoords(PlayerPedId()), true) -- Add voice targets
TriggerServerEvent("mumble:Initialise")
SendNUIMessage({ speakerOption = mumbleConfig.callSpeakerEnabled })
TriggerEvent("mumble:Initialised")
initialised = true
end)
RegisterNetEvent("mumble:SetVoiceData") -- Used to sync players data each time something changes
AddEventHandler("mumble:SetVoiceData", function(player, key, value)
if not voiceData[player] then
voiceData[player] = {
mode = 2,
radio = 0,
radioActive = false,
call = 0,
callSpeaker = false,
speakerTargets = {},
radioName = GetRandomPhoneticLetter() .. "-" .. player
}
end
local radioChannel = voiceData[player]["radio"]
local callChannel = voiceData[player]["call"]
local radioActive = voiceData[player]["radioActive"]
local playerData = voiceData[playerServerId]
if not playerData then
playerData = {
mode = 2,
radio = 0,
radioActive = false,
call = 0,
callSpeaker = false,
speakerTargets = {},
radioName = GetRandomPhoneticLetter() .. "-" .. playerServerId
}
end
if key == "radio" and radioChannel ~= value then -- Check if channel has changed
if radioChannel > 0 then -- Check if player was in a radio channel
if radioData[radioChannel] then -- Remove player from radio channel
if radioData[radioChannel][player] then
DebugMsg("Player " .. player .. " was removed from radio channel " .. radioChannel)
radioData[radioChannel][player] = nil
if CompareChannels(playerData, "radio", radioChannel) then
if playerServerId ~= player then
if unmutedPlayers[player] then
if not vehicleTargets[player] then -- Mute if player is not in client vehicle
if playerData.call > 0 then -- Check if the client is in a call
if not CompareChannels(voiceData[player], "call", playerData.call) then -- Check if the client is in a call with the unmuted player
TogglePlayerVoice(player, false)
end
else
TogglePlayerVoice(player, false) -- mute player on radio channel leave
end
end
end
if radioTargets[player] then
radioTargets[player] = nil
if mumbleConfig.showRadioList then
SendNUIMessage({ radioId = player }) -- Remove player from radio list
end
end
elseif playerServerId == player then
for id, _ in pairs(radioData[radioChannel]) do -- Mute players that aren't supposed to be unmuted
if id ~= playerServerId then
if unmutedPlayers[id] then -- Check if a player isn't muted
if not vehicleTargets[id] then -- Mute if player is not in client vehicle
if playerData.call > 0 then -- Check if the client is in a call
if not CompareChannels(voiceData[id], "call", playerData.call) then -- Check if the client is in a call with the unmuted player
TogglePlayerVoice(id, false)
end
else
TogglePlayerVoice(id, false)
end
end
end
end
end
radioTargets = {} -- Remove all radio targets as client has left the radio channel
if mumbleConfig.showRadioList then
SendNUIMessage({ clearRadioList = true }) -- Clear radio list
end
if playerData.radioActive then
SetPlayerTargets(callTargets, speakerTargets, vehicleTargets) -- Reset active targets if for some reason if the client was talking on the radio when the client left
end
end
end
end
end
end
if value > 0 then
if not radioData[value] then -- Create channel if it does not exist
DebugMsg("Player " .. player .. " is creating channel: " .. value)
radioData[value] = {}
end
DebugMsg("Player " .. player .. " was added to channel: " .. value)
radioData[value][player] = true -- Add player to channel
if CompareChannels(playerData, "radio", value) then
if playerServerId ~= player then
if not radioTargets[player] then
radioTargets[player] = true
if mumbleConfig.showRadioList then
SendNUIMessage({ radioId = player, radioName = voiceData[player].radioName }) -- Add player to radio list
end
if playerData.radioActive then
SetPlayerTargets(callTargets, speakerTargets, vehicleTargets, radioTargets)
end
end
end
end
if playerServerId == player then
if mumbleConfig.showRadioList then
SendNUIMessage({ radioId = playerServerId, radioName = playerData.radioName, self = true }) -- Add client to radio list
end
for id, _ in pairs(radioData[value]) do -- Add radio targets of existing players in channel
if id ~= playerServerId then
if not radioTargets[id] then
radioTargets[id] = true
if mumbleConfig.showRadioList then
if voiceData[id] ~= nil then
if voiceData[id].radioName ~= nil then
SendNUIMessage({ radioId = id, radioName = voiceData[id].radioName }) -- Add player to radio list
end
end
end
end
end
end
end
end
elseif key == "call" and callChannel ~= value then
if callChannel > 0 then -- Check if player was in a call channel
if callData[callChannel] then -- Remove player from call channel
if callData[callChannel][player] then
DebugMsg("Player " .. player .. " was removed from call channel " .. callChannel)
callData[callChannel][player] = nil
if CompareChannels(playerData, "call", callChannel) then
if playerServerId ~= player then
if unmutedPlayers[player] then
if not vehicleTargets[player] then -- Mute if player is not in client vehicle
if playerData.radio > 0 then -- Check if the client is on the radio
if not CompareChannels(voiceData[player], "radio", playerData.radio) then -- Check if the client is in a radio channel with the unmuted player
TogglePlayerVoice(player, false)
else
if voiceData[player] ~= nil then
if not voiceData[player].radioActive then -- Check if the unmuted player isn't talking
TogglePlayerVoice(player, false)
end
else
TogglePlayerVoice(player, false)
end
end
else
TogglePlayerVoice(player, false) -- mute player on radio channel leave
end
end
end
if callTargets[player] then
callTargets[player] = nil
SetPlayerTargets(callTargets, speakerTargets, vehicleTargets, playerData.radioActive and radioTargets or nil)
end
elseif playerServerId == player then
for id, _ in pairs(callData[callChannel]) do -- Mute players that aren't supposed to be unmuted
if id ~= playerServerId then
if unmutedPlayers[id] then -- Check if a player isn't muted
if not vehicleTargets[id] then -- Mute if player is not in client vehicle
if playerData.radio > 0 then -- Check if the client is in a radio channel
if not CompareChannels(voiceData[id], "radio", playerData.radio) then -- Check if the client isn't in the radio channel with the unmuted player
TogglePlayerVoice(id, false)
else -- Client is in the same radio channel with unmuted player
if voiceData[id] ~= nil then
if not voiceData[id].radioActive then -- Check if the unmuted player isn't talking
TogglePlayerVoice(id, false)
end
else
TogglePlayerVoice(id, false)
end
end
else
TogglePlayerVoice(id, false)
end
end
end
end
end
callTargets = {} -- Remove all call targets as client has left the call
SetPlayerTargets(callTargets, speakerTargets, vehicleTargets, playerData.radioActive and radioTargets or nil) -- Reset player targets
end
end
end
end
end
if value > 0 then
if not callData[value] then -- Create call if it does not exist
DebugMsg("Player " .. player .. " is creating call: " .. value)
callData[value] = {}
end
DebugMsg("Player " .. player .. " was added to call: " .. value)
callData[value][player] = true -- Add player to call
if CompareChannels(playerData, "call", value) then
if playerServerId ~= player then
TogglePlayerVoice(player, value)
if not callTargets[player] then
callTargets[player] = true
SetPlayerTargets(callTargets, speakerTargets, vehicleTargets, playerData.radioActive and radioTargets or nil)
end
end
end
if playerServerId == player then
for id, _ in pairs(callData[value]) do
if id ~= playerServerId then
if not unmutedPlayers[id] then
TogglePlayerVoice(id, true)
end
if not callTargets[id] then
callTargets[id] = true
SetPlayerTargets(callTargets, speakerTargets, vehicleTargets, playerData.radioActive and radioTargets or nil)
end
end
end
end
end
elseif key == "radioActive" and radioActive ~= value then
DebugMsg("Player " .. player .. " radio talking state was changed from: " .. tostring(radioActive):upper() .. " to: " .. tostring(value):upper())
if radioChannel > 0 then
if CompareChannels(playerData, "radio", radioChannel) then -- Check if player is in the same radio channel as you
if playerServerId ~= player then
if value then
TogglePlayerVoice(player, true) -- unmute player
else
if not vehicleTargets[player] then -- Mute if player is not in client vehicle
if playerData.call > 0 then -- Check if the client is in a call
if not CompareChannels(voiceData[player], "call", playerData.call) then -- Check if the client is in a call with the unmuted player
TogglePlayerVoice(player, false)
end
else
TogglePlayerVoice(player, false) -- mute player on radio channel leave
end
end
end
PlayMicClick(radioChannel, value) -- play on/off clicks
if mumbleConfig.showRadioList then
SendNUIMessage({ radioId = player, radioTalking = value }) -- Set player talking in radio list
end
end
end
end
elseif key == "speakerTargets" then
local speakerTargetsRemoved = false
local speakerTargetsAdded = {}
for id, _ in pairs(value) do
if voiceData[player] ~= nil then
if voiceData[player][key] ~= nil then
if voiceData[player][key][id] then
voiceData[player][key][id] = nil
else
if playerServerId == id then -- Check if the client is gonna hear a nearby call
TogglePlayerVoice(player, true) -- Unmute
end
if playerServerId == player then -- Check if the client is a paricipant in the phone call whose voice is heard through the speaker
if not speakerTargets[id] then -- Send voice to player
speakerTargets[id] = true
speakerTargetsAdded[#speakerTargetsAdded + 1] = id
end
end
end
end
end
end
if voiceData[player] ~= nil then
if voiceData[player][key] ~= nil then
for id, _ in pairs(voiceData[player][key]) do
if playerServerId == id then -- Check if the client has been removed from a nearby call
if not vehicleTargets[player] then -- Mute if player is not in client vehicle
TogglePlayerVoice(player, false) -- Mute
end
end
if playerServerId == player then -- Check if the client is a paricipant in the phone call whose voice is heard through the speaker
if speakerTargets[id] then -- Stop sending voice to player
speakerTargets[id] = nil
speakerTargetsRemoved = true
end
end
end
end
end
if speakerTargetsRemoved or #speakerTargetsAdded > 0 then
SetPlayerTargets(callTargets, speakerTargets, vehicleTargets, playerData.radioActive and radioTargets or nil)
end
elseif key == "callSpeaker" and not value then
if voiceData[player] ~= nil then
if voiceData[player].call ~= nil then
if voiceData[player].call > 0 then
if callData[voiceData[player].call] ~= nil then -- Check if the call exists
for id, _ in pairs(callData[voiceData[player].call]) do -- Loop through each call participant
if voiceData[id] ~= nil then
if voiceData[id].speakerTargets ~= nil then
local speakerTargetsRemoved = false
for targetId, _ in pairs(voiceData[id].speakerTargets) do -- Loop through each call participants speaker targets
if playerServerId == targetId then -- Check if the client was a target and mute the call
if not vehicleTargets[id] then -- Mute if player is not in client vehicle
TogglePlayerVoice(id, false) -- Mute
end
end
if playerServerId == id then -- Check if the client is a paricipant in the phone call whose voice is heard through the speaker
if speakerTargets[targetId] then -- Stop sending voice to player
speakerTargets[targetId] = nil
speakerTargetsRemoved = true
end
end
end
if speakerTargetsRemoved then
SetPlayerTargets(callTargets, speakerTargets, vehicleTargets, playerData.radioActive and radioTargets or nil)
end
end
end
end
end
end
end
end
end
voiceData[player][key] = value
DebugMsg("Player " .. player .. " changed " .. key .. " to: " .. tostring(value))
end)
RegisterNetEvent("mumble:SyncVoiceData") -- Used to sync players data on initialising
AddEventHandler("mumble:SyncVoiceData", function(voice, radio, call)
voiceData = voice
radioData = radio
callData = call
end)
RegisterNetEvent("mumble:RemoveVoiceData") -- Used to remove redundant data when a player disconnects
AddEventHandler("mumble:RemoveVoiceData", function(player)
if voiceData[player] then
local radioChannel = voiceData[player]["radio"] or 0
local callChannel = voiceData[player]["call"] or 0
if radioChannel > 0 then -- Check if player was in a radio channel
if radioData[radioChannel] then -- Remove player from radio channel
if radioData[radioChannel][player] then
DebugMsg("Player " .. player .. " was removed from radio channel " .. radioChannel)
radioData[radioChannel][player] = nil
end
end
end
if callChannel > 0 then -- Check if player was in a call channel
if callData[callChannel] then -- Remove player from call channel
if callData[callChannel][player] then
DebugMsg("Player " .. player .. " was removed from call channel " .. callChannel)
callData[callChannel][player] = nil
end
end
end
if radioTargets[player] or callTargets[player] or speakerTargets[player] then
local playerData = voiceData[playerServerId]
if not playerData then
playerData = {
mode = 2,
radio = 0,
radioActive = false,
call = 0,
callSpeaker = false,
speakerTargets = {},
radioName = GetRandomPhoneticLetter() .. "-" .. playerServerId
}
end
radioTargets[player] = nil
callTargets[player] = nil
speakerTargets[player] = nil
SetPlayerTargets(callTargets, speakerTargets, vehicleTargets, playerData.radioActive and radioTargets or nil)
end
voiceData[player] = nil
end
end)
-- Simulate PTT when radio is active
Citizen.CreateThread(function()
while true do
Citizen.Wait(0)
if initialised then
local playerData = voiceData[playerServerId]
if not playerData then
playerData = {
mode = 2,
radio = 0,
radioActive = false,
call = 0,
callSpeaker = false,
speakerTargets = {},
}
end
if playerData.radioActive then -- Force PTT enabled
SetControlNormal(0, 249, 1.0)
SetControlNormal(1, 249, 1.0)
SetControlNormal(2, 249, 1.0)
end
if IsControlJustPressed(0, mumbleConfig.controls.proximity.key) then
local secondaryPressed = true
if mumbleConfig.controls.speaker.key ~= mumbleConfig.controls.proximity.key or mumbleConfig.controls.speaker.secondary == nil then
secondaryPressed = false
else
secondaryPressed = IsControlPressed(0, mumbleConfig.controls.speaker.secondary) and (playerData.call > 0)
end
if not secondaryPressed then
local voiceMode = playerData.mode
local newMode = voiceMode + 1
if newMode > #mumbleConfig.voiceModes then
voiceMode = 1
else
voiceMode = newMode
end
NetworkSetTalkerProximity(mumbleConfig.voiceModes[voiceMode][1] + 0.0)
SetVoiceData("mode", voiceMode)
playerData.mode = voiceMode
end
end
if mumbleConfig.radioEnabled then
if not mumbleConfig.controls.radio.pressed then
if IsControlJustPressed(0, mumbleConfig.controls.radio.key) and IsInputDisabled(0) then
if playerData.radio > 0 then
SetVoiceData("radioActive", true)
playerData.radioActive = true
SetPlayerTargets(callTargets, speakerTargets, vehicleTargets, radioTargets) -- Send voice to everyone in the radio and call
PlayMicClick(playerData.radio, true)
if mumbleConfig.showRadioList then
SendNUIMessage({ radioId = playerServerId, radioTalking = true }) -- Set client talking in radio list
end
mumbleConfig.controls.radio.pressed = true
Citizen.CreateThread(function()
while IsControlPressed(0, mumbleConfig.controls.radio.key) and IsInputDisabled(0) do
Citizen.Wait(0)
end
SetVoiceData("radioActive", false)
SetPlayerTargets(callTargets, speakerTargets, vehicleTargets) -- Stop sending voice to everyone in the radio
PlayMicClick(playerData.radio, false)
if mumbleConfig.showRadioList then
SendNUIMessage({ radioId = playerServerId, radioTalking = false }) -- Set client talking in radio list
end
playerData.radioActive = false
mumbleConfig.controls.radio.pressed = false
end)
end
end
end
else
if playerData.radioActive then
SetVoiceData("radioActive", false)
playerData.radioActive = false
end
end
if mumbleConfig.callSpeakerEnabled then
local secondaryPressed = false
if mumbleConfig.controls.speaker.secondary ~= nil then
secondaryPressed = IsControlPressed(0, mumbleConfig.controls.speaker.secondary)
else
secondaryPressed = true
end
if IsControlJustPressed(0, mumbleConfig.controls.speaker.key) and secondaryPressed then
if playerData.call > 0 then
SetVoiceData("callSpeaker", not playerData.callSpeaker)
playerData.callSpeaker = not playerData.callSpeaker
end
end
end
end
end
end)
-- UI
Citizen.CreateThread(function()
while true do
if initialised then
local playerId = PlayerId()
local playerData = voiceData[playerServerId]
local playerTalking = NetworkIsPlayerTalking(playerId)
local playerMode = 2
local playerRadio = 0
local playerRadioActive = false
local playerCall = 0
local playerCallSpeaker = false
if playerData ~= nil then
playerMode = playerData.mode or 2
playerRadio = playerData.radio or 0
playerRadioActive = playerData.radioActive or false
playerCall = playerData.call or 0
playerCallSpeaker = playerData.callSpeaker or false
end
-- Update UI
SendNUIMessage({
talking = playerTalking,
mode = mumbleConfig.voiceModes[playerMode][2],
radio = mumbleConfig.radioChannelNames[playerRadio] ~= nil and mumbleConfig.radioChannelNames[playerRadio] or playerRadio,
radioActive = playerRadioActive,
call = mumbleConfig.callChannelNames[playerCall] ~= nil and mumbleConfig.callChannelNames[playerCall] or playerCall,
speaker = playerCallSpeaker,
})
Citizen.Wait(200)
else
Citizen.Wait(0)
end
end
end)
-- Manage Grid Target Channels
Citizen.CreateThread(function()
while true do
if initialised then
if not MumbleIsConnected() then
SendNUIMessage({ warningId = "mumble_is_connected", warningMsg = "Not connected to mumble" })
while not MumbleIsConnected() do
Citizen.Wait(250)
end
SendNUIMessage({ warningId = "mumble_is_connected" })
resetTargets = true
end
local playerPed = PlayerPedId()
local playerCoords = GetEntityCoords(playerPed)
SetGridTargets(playerCoords, resetTargets)
Citizen.Wait(2500)
else
Citizen.Wait(0)
end
end
end)
-- Manage hearing nearby players on call
Citizen.CreateThread(function()
while true do
if initialised then
if mumbleConfig.callSpeakerEnabled then
local playerData = voiceData[playerServerId]
if not playerData then
playerData = {
mode = 2,
radio = 0,
radioActive = false,
call = 0,
callSpeaker = false,
speakerTargets = {},
}
end
if playerData.call > 0 then -- Check if player is in call
if playerData.callSpeaker then -- Check if they have loud speaker on
local playerId = PlayerId()
local playerPed = PlayerPedId()
local playerPos = GetEntityCoords(playerPed)
local playerList = GetActivePlayers()
local nearbyPlayers = {}
local nearbyPlayerAdded = false
local nearbyPlayerRemoved = false
for i = 1, #playerList do -- Get a list of all players within loud speaker range
local remotePlayerId = playerList[i]
if playerId ~= remotePlayerId then
local remotePlayerServerId = GetPlayerServerId(remotePlayerId)
local remotePlayerPed = GetPlayerPed(remotePlayerId)
local remotePlayerPos = GetEntityCoords(remotePlayerPed)
local distance = #(playerPos - remotePlayerPos)
if distance <= mumbleConfig.speakerRange then
local remotePlayerData = voiceData[remotePlayerServerId]
if remotePlayerData ~= nil then
if remotePlayerData.call ~= nil then
if remotePlayerData.call ~= playerData.call then
nearbyPlayers[remotePlayerServerId] = true
if nearbySpeakerTargets[remotePlayerServerId] then
nearbySpeakerTargets[remotePlayerServerId] = nil
else
nearbyPlayerAdded = true
end
end
end
end
end
end
end
for id, exists in pairs(nearbySpeakerTargets) do
if exists then
nearbyPlayerRemoved = true
end
end
if nearbyPlayerAdded or nearbyPlayerRemoved then -- Check that we don't send an empty list
if callData[playerData.call] ~= nil then -- Check if the call still exists
for id, _ in pairs(callData[playerData.call]) do -- Send a copy of the nearby players to each participant in the call
if playerServerId ~= id then
SetVoiceData("speakerTargets", nearbyPlayers, id)
end
end
end
end