SaltyChat in FiveM integrieren + GCPhone

In diesem Tutorial erkläre ich wie man SaltyChat in FiveM integriert und das GCPhone umstellt.In dieser Anleitung wird Schritt für Schritt erklärt, wie man SaltyChat in FiveM integriert und das GCPhone entsprechend umstellt.

Diese Anleitung wird auf der Installation aufgebaut die hier zu finden ist: FiveM Server unter Debian 10 installieren inkl. txAdmin und Template

Hallo Community,

in dieser Schritt für Schritt Anleitung werde ich so gut wie möglich erklären wie man SaltyChat in FiveM integriert, das GCPhone entsprechend umstellt und Mumble-VoIP aus dem Template entfernt.

Bei Fragen dazu könnt ihr gerne jederzeit ein Thread im Forum eröffnen oder ein Ticket schreiben. Dort wird euch dann weiter geholfen.

Vorraussetzungen

Bevor es los geht müsst ihr bereits ein paar Dinge auf euren FiveM Server herunterladen damit das ganze funktioniert.

Optional kann man SaltyNUI installieren um einen Bildschirm zu bekommen, wenn man nicht mit dem Teamspeak verbunden ist.

Als Funksystem kann man SaltyRadio nehmen welches direkt mit SaltyChat kompatibel ist.

Das GCPhone ist bereits im Template installiert, weshalb ich davon keinen Link habe.

Es ist in folgendem Ordner zu finden: resources/[esx]/

  • esx_addons_gcphone
  • gcphone

Außerdem benötigen wir noch ein Programm welches wir herunter laden müssen um SaltyChat zu konfigurieren bevor wir dieses auf den FiveM Server hochladen.

Wir benötigen für die Einrichtung auch gleich das SaltyChat Plugin für den Teamspeak welches direkt installiert werden sollte.

SaltyChat installieren

Als erstes Laden wir uns SaltyChat für FiveM herunter. Laden dieses aber noch nicht auf den FiveM Server hoch da wir das noch mit Visual Studio Community 2019 bearbeiten müssen.

Wenn wir das Programm installiert haben, gehen wir in den SaltyChat Ordner und öffnen dort folgende Datei mit Visual Studio Community 2019.

  • SaltyChat-FiveM.sln

Wenn ihr das nun gestartet habt, solltet ihr nun folgendes vor euch sehen. Dabei ist zu beachten, dass bei euch Debug und Any CPU ausgewählt ist wie im Bild ROT markiert habe.

Nun gehen wir rechts in der Leiste mit Rechtsklick auf SaltyClient und dann im Menü auf Erstellen.

Wir bekommen unten in der Konsole dann eine Meldung , dass dies erfolgreich war.Code

Erstellen gestartet...
1>------ Erstellen gestartet: Projekt: SaltyClient, Konfiguration: Debug Any CPU ------
1>  SaltyClient -> H:\Server Leitung Einstellungen\FiveM Server\[SaltyChat]\[saltychat]\saltychat-fivem-master\saltychat-fivem-master\saltychat\SaltyClient\bin\Debug\SaltyClient.net.dll
========== Erstellen: 1 erfolgreich, 0 fehlerhaft, 0 aktuell, 0 übersprungen ==========

Das selbe wiederholen wir nun mit SaltyServer, Rechtsklick und Erstellen und sollten dann ebenfalls eine Meldung bekommen, dass dies erfolgreich war.Code

Erstellen gestartet...
1>------ Erstellen gestartet: Projekt: SaltyServer, Konfiguration: Debug Any CPU ------
1>H:\Server Leitung Einstellungen\FiveM Server\[SaltyChat]\[saltychat]\saltychat-fivem-master\saltychat-fivem-master\saltychat\SaltyServer\VoiceManager.cs(47,68,47,86): warning CS0612: "VoiceManager.EstablishCall(int, int)" ist veraltet.
1>H:\Server Leitung Einstellungen\FiveM Server\[SaltyChat]\[saltychat]\saltychat-fivem-master\saltychat-fivem-master\saltychat\SaltyServer\VoiceManager.cs(48,62,48,74): warning CS0612: "VoiceManager.EndCall(int, int)" ist veraltet.
1>SaltyServer -> H:\Server Leitung Einstellungen\FiveM Server\[SaltyChat]\[saltychat]\saltychat-fivem-master\saltychat-fivem-master\saltychat\SaltyServer\bin\Debug\netstandard2.0\SaltyServer.net.dll
1>Erstellen des Projekts SaltyServer.csproj beendet.
========== Erstellen: 1 erfolgreich, 0 fehlerhaft, 0 aktuell, 0 übersprungen ==========

Wir können nun nochmal überprüfen ob diese beiden Dinge wirklich erfolgreich waren!

Dafür gehen wir oben in der Leiste auf Erstellen und dann auf Projektmappe erstellen. Wir bekommen nun unten in der Konsole die Bestätigung.

Erstellen gestartet...
========== Erstellen: 0 erfolgreich, 0 fehlerhaft, 2 aktuell, 0 übersprungen ==========

Sollte dies bei euch auch der Fall sein, habt ihr alles korrekt gemacht und könnt das Programm, Visual Studio Community 2019, nun schließen.

SaltyChat mit Teamspeak verbinden

Wir haben nun den ersten Schritt erfolgreich geschafft und müssen SaltyChat nun mitteilen welchen Teamspeak Server und welchen Channel für den Voice genutzt wird.

Wir öffnen nun die config.json im saltychat Ordner und verbinden uns mit dem Teamspeak Server den wir nutzen möchten.

Bitte unbedingt nun das SaltyChat Plugin für TeamSpeak installieren bevor Teamspeak gestartet wird denn sonst können die folgenden Schritte nicht durchgeführt werden!

In der config.json haben wir nun schon einige configs drin die wir nun teilweise ersetzen müssen. Die Standard Config sieht folgendermaßen aus:Code

{
  "VoiceEnabled": true,
  "ServerUniqueIdentifier": "2sxEmKMsR5W37/dKhIDsI+LLJ0s=",
  "MinimumPluginVersion": "2.3.0",
  "SoundPack": "default",
  "IngameChannelId": 6,
  "IngameChannelPassword": "5V88FWWME615",
  "SwissChannelIds": [ 61, 62 ],
  "VoiceRanges": [ 3.5, 8, 15, 32 ],
  "EnableVoiceRangeNotification": true,
  "VoiceRangeNotification": "New voice range is {voicerange} metres.",
  "RadioType": 4,
  "EnableRadioHardcoreMode": true,
  "UltraShortRangeDistance": 1800.0,
  "ShortRangeDistance": 3000.0,
  "LongRangeDistace": 8000.0,
  "MegaphoneRange": 120.0,
  "VariablePhoneDistortion": true,
  "NamePattern": "[{serverid}] {guid}",
  "RequestTalkStates": true,
  "RequestRadioTrafficStates": false,
  "ToggleRange": "F1",
  "TalkPrimary": "N",
  "TalkSecondary": "CAPITAL",
  "TalkMegaphone": "B"
}

Wir gucken nun auf unserem Teamspeak Server wie die Server UID lautet und tragen diese bei ServerUniqueIdentifier ein.

In meinem Fall mit einem Tutorial Test Server sieht dies so aus:

"ServerUniqueIdentifier": 2sxEmKMsR5W37/dKhIDsI+LLJ0s=",

Nun erstellen wir einen Ingame Channel mit Passwort und tragen die Daten ebenfalls in die config.json ein.

"IngameChannelId": 6,
"IngameChannelPassword": "DeinChannelPasswort",

Wenn wir nun Support Channel, etc. haben und das SaltyChat Voice auch funktionieren soll muss bei SwissChannelIds ebenfalls die entsprechenden IDs eingetragen werden.

Ansonsten ändert dies einfach folgendermaßen ab:Code

"SwissChannelIds": [  ],

Wir können nun die Notification noch auf Deutsch übersetzen wenn wir das möchten.Code

"VoiceRangeNotification": "Neue Sprachreichte {voicerange} Meter.",

Den Rest können wir im Prinzip so lassen, da die Tastenbelegung jeder selbst Ingame einstellen kann wie er/sie das möchte.

Also speichern wir das ganze ab und sind mit der Einrichtung von SaltyChat und Teamspeak nun fertig!

Der saltychat Ordner muss jetzt nur noch hochgeladen werden und am besten in die extra.cfg eingetragen werden während wir mumble-voip auskommentieren.

Das rp-radio kommentieren wir ebenfalls aus, da dieses für mumble-voip geschrieben ist und wir für SaltyChat ein anderes benötigen wie z.b. saltyradio.Code

#[voice]
#start mumble-voip
#start rp-radio
start saltychat
start saltyNUI
start saltyradio #Funk System falls vorhanden ansonsten ein # davor setzen

GCPhone auf SaltyChat umstellen

Wir müssen nun noch das GCPhone von Mumble-Voip auf SaltyChat umstellen. Dies machen wir wie folgt.

Wir gehen nun in den Ordner vom gcphone in resources/[esx]/. Wir müssen hier clientseitig und serverseitig ein wenig ändern damit das ganze funktioniert.

Wir gehen dafür zu erst in gcphone/client/client.lua in Zeile 378 und ändern dort folgende Dinge!

Folgenden alten Code ersetzen:

RegisterNetEvent("gcPhone:acceptCall")
AddEventHandler("gcPhone:acceptCall", function(infoCall, initiator)
  if inCall == false and USE_RTC == false then
    inCall = true
    exports["mumble-voip"]:SetCallChannel(infoCall.id+1)
    --NetworkSetVoiceChannel(infoCall.id + 1)
    --NetworkSetTalkerProximity(0.0)
  end
  if menuIsOpen == false then 
    TooglePhone()
  end
  PhonePlayCall()
  SendNUIMessage({event = 'acceptCall', infoCall = infoCall, initiator = initiator})
end)

RegisterNetEvent("gcPhone:rejectCall")
AddEventHandler("gcPhone:rejectCall", function(infoCall)
  if inCall == true then
    inCall = false
    exports["mumble-voip"]:SetCallChannel(0)
    --Citizen.InvokeNative(0xE036A705F989E049)
    --NetworkSetTalkerProximity(2.5)
  end
  PhonePlayText()
  SendNUIMessage({event = 'rejectCall', infoCall = infoCall})
end)

Durch diesen Code:

RegisterNetEvent("gcPhone:acceptCall")
AddEventHandler("gcPhone:acceptCall", function(infoCall, initiator)
  if inCall == false and USE_RTC == false then
    inCall = true
    --exports["mumble-voip"]:SetCallChannel(infoCall.id+1)
    NetworkSetVoiceChannel(infoCall.id + 1)
    NetworkSetTalkerProximity(0.0)
  end
  if menuIsOpen == false then 
    TooglePhone()
  end
  PhonePlayCall()
  SendNUIMessage({event = 'acceptCall', infoCall = infoCall, initiator = initiator})
end)

RegisterNetEvent("gcPhone:rejectCall")
AddEventHandler("gcPhone:rejectCall", function(infoCall)
  if inCall == true then
    inCall = false
    --exports["mumble-voip"]:SetCallChannel(0)
    Citizen.InvokeNative(0xE036A705F989E049)
    NetworkSetTalkerProximity(2.5)
  end
  PhonePlayText()
  SendNUIMessage({event = 'rejectCall', infoCall = infoCall})
end)

Nun gehen wir in gcphone/server/server.lua und ändern auch hier den Code ab.

Folgenden alten Code ersetzen:

RegisterServerEvent('gcPhone:acceptCall')
AddEventHandler('gcPhone:acceptCall', function(infoCall, rtcAnswer)
    local id = infoCall.id
    if AppelsEnCours[id] ~= nil then
        if PhoneFixeInfo[id] ~= nil then
            onAcceptFixePhone(source, infoCall, rtcAnswer)
            return
        end
        AppelsEnCours[id].receiver_src = infoCall.receiver_src or AppelsEnCours[id].receiver_src
        if AppelsEnCours[id].transmitter_src ~= nil and AppelsEnCours[id].receiver_src~= nil then
            AppelsEnCours[id].is_accepts = true
            AppelsEnCours[id].rtcAnswer = rtcAnswer
            TriggerClientEvent('gcPhone:acceptCall', AppelsEnCours[id].transmitter_src, AppelsEnCours[id], true)
        SetTimeout(2000, function() -- change to +1000, if necessary.
               TriggerClientEvent('gcPhone:acceptCall', AppelsEnCours[id].receiver_src, AppelsEnCours[id], false)
        end)
            saveAppels(AppelsEnCours[id])
        end
    end
end)

RegisterServerEvent('gcPhone:rejectCall')
AddEventHandler('gcPhone:rejectCall', function (infoCall)
    local id = infoCall.id
    if AppelsEnCours[id] ~= nil then
        if PhoneFixeInfo[id] ~= nil then
            onRejectFixePhone(source, infoCall)
            return
        end
        if AppelsEnCours[id].transmitter_src ~= nil then
            TriggerClientEvent('gcPhone:rejectCall', AppelsEnCours[id].transmitter_src)
        end
        if AppelsEnCours[id].receiver_src ~= nil then
            TriggerClientEvent('gcPhone:rejectCall', AppelsEnCours[id].receiver_src)
        end

        if AppelsEnCours[id].is_accepts == false then 
            saveAppels(AppelsEnCours[id])
        end
        TriggerEvent('gcPhone:removeCall', AppelsEnCours)
        AppelsEnCours[id] = nil
    end
end)

Alles anzeigen

In diesen Code hier:

RegisterServerEvent('gcPhone:acceptCall')
AddEventHandler('gcPhone:acceptCall', function(infoCall, rtcAnswer)
    local id = infoCall.id
    if AppelsEnCours[id] ~= nil then
        if PhoneFixeInfo[id] ~= nil then
            onAcceptFixePhone(source, infoCall, rtcAnswer)
            return
        end
        AppelsEnCours[id].receiver_src = infoCall.receiver_src or AppelsEnCours[id].receiver_src
        if AppelsEnCours[id].transmitter_src ~= nil and AppelsEnCours[id].receiver_src~= nil then
            AppelsEnCours[id].is_accepts = true
            AppelsEnCours[id].rtcAnswer = rtcAnswer
            TriggerClientEvent('gcPhone:acceptCall', AppelsEnCours[id].transmitter_src, AppelsEnCours[id], true)
        SetTimeout(2000, function() -- change to +1000, if necessary.
               TriggerClientEvent('gcPhone:acceptCall', AppelsEnCours[id].receiver_src, AppelsEnCours[id], false)
        end)
            saveAppels(AppelsEnCours[id])

            exports['saltychat']:EstablishCall(ApplesEnCours[id].receiver_src, ApplesEncours[id].transmitter_src)
            exports['saltychat']:EstablishCall(ApplesEnCours[id].transmitter_src, ApplesEncours[id].receiver_src)
        end
    end
end)

RegisterServerEvent('gcPhone:rejectCall')
AddEventHandler('gcPhone:rejectCall', function (infoCall)
    local id = infoCall.id
    if AppelsEnCours[id] ~= nil then
        if PhoneFixeInfo[id] ~= nil then
            onRejectFixePhone(source, infoCall)
            return
        end
        if AppelsEnCours[id].transmitter_src ~= nil then
            TriggerClientEvent('gcPhone:rejectCall', AppelsEnCours[id].transmitter_src)
            exports['saltychat']:EstablishCall(ApplesEnCours[id].receiver_src, ApplesEncours[id].transmitter_src)
            exports['saltychat']:EstablishCall(ApplesEnCours[id].transmitter_src, ApplesEncours[id].receiver_src)
        end
        if AppelsEnCours[id].receiver_src ~= nil then
            TriggerClientEvent('gcPhone:rejectCall', AppelsEnCours[id].receiver_src)
            exports['saltychat']:EstablishCall(ApplesEnCours[id].receiver_src, ApplesEncours[id].transmitter_src)
            exports['saltychat']:EstablishCall(ApplesEnCours[id].transmitter_src, ApplesEncours[id].receiver_src)
        end

        if AppelsEnCours[id].is_accepts == false then 
            saveAppels(AppelsEnCours[id])
        end
        TriggerEvent('gcPhone:removeCall', AppelsEnCours)
        AppelsEnCours[id] = nil
    end
end)

Alles anzeigen

Beides nun abspeichern und damit wäre SaltyChat in das GCPhone integriert.

Wer nun noch das SaltyNUI möchte kann sich das ebenfalls runterladen. In der extra.cfg ist es schon eingetragen wer dies weiter oben bereits getan hat. Außerdem sollte hier die Anleitung dazu beachtet werden. Ansonsten spinnt SaltyNUI. https://github.com/EgoPvP/SaltyNUI

Ich hoffe dieses Tutorial hat euch geholfen und ihr habt alles verstanden.

Bei weiteren Fragen könnt ihr gerne hier im Forum ein Thread eröffnen oder ein Ticket schreiben, dann wird euch bestmöglich vom Team geholfen.