Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dispatch Client Update -> 1.5.7, along with various bug fixes #280

Open
wants to merge 8 commits into
base: next
Choose a base branch
from
2 changes: 2 additions & 0 deletions fivem_script/tokovoip_script/c_config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ TokoVoipConfig = {
keySwitchChannelsSecondary = Keys["LEFTSHIFT"], -- If set, both the keySwitchChannels and keySwitchChannelsSecondary keybinds must be pressed to switch the radio channels
keyProximity = Keys["Z"], -- Keybind used to switch the proximity mode
radioClickMaxChannel = 100, -- Set the max amount of radio channels that will have local radio clicks enabled
enableDispatch = false, -- change to true to enable support for the dispatch client
dispatchRadioMaxChannel = 10, -- Set the max channel for the dispatch client, only matters if enableDispatch is set to true
radioAnim = true, -- Enable or disable the radio animation
radioEnabled = true, -- Enable or disable using the radio
wsServer = "ip:port", -- Address of the websocket server
Expand Down
14 changes: 14 additions & 0 deletions fivem_script/tokovoip_script/nui/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,12 @@ function receivedClientCall (event) {
} else if (eventName == 'toggleLatency') {
displayLatency = !displayLatency;
document.querySelector('#latency').style.display = (displayLatency) ? 'block' : 'none';
} else if (eventName == 'lChannel') {
leaveChannel(payload);
} else if (eventName == 'jChannel') {
joinChannel(payload);
} else if (eventName == 'talkStatusDS') {
websocket.send(`42${JSON.stringify(['talkingStatus', { status: payload }])}`);
}
}

Expand All @@ -221,6 +227,14 @@ function receivedClientCall (event) {
updateTokovoipInfo();
}

function leaveChannel (data) {
websocket.send(`42${JSON.stringify(['channels', { type: 1, channel: data.channel, uuid: data.uuid }])}`);
}

function joinChannel (data) {
websocket.send(`42${JSON.stringify(['channels', { type: 0, channel: data.channel, uuid: data.uuid }])}`);
}

function checkPluginStatus () {
switch (parseInt(voip.pluginStatus)) {
case -1:
Expand Down
20 changes: 20 additions & 0 deletions fivem_script/tokovoip_script/src/c_TokoVoip.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@ TokoVoip = {};
TokoVoip.__index = TokoVoip;
local lastTalkState = false

function TokoVoip.leaveChannel(self, lChannel, lUuid)
local dat = {};
dat.channel = lChannel;
dat.uuid = lUuid;
self:updatePlugin("lChannel", dat);
end

function TokoVoip.joinChannel(self, lChannel, lUuid)
local dat = {};
dat.channel = lChannel;
dat.uuid = lUuid;
self:updatePlugin("jChannel", dat);
end

function TokoVoip.init(self, config)
local self = setmetatable(config, TokoVoip);
self.config = json.decode(json.encode(config));
Expand Down Expand Up @@ -148,6 +162,9 @@ function TokoVoip.initialize(self)
end
if (not getPlayerData(self.serverId, "radio:talking")) then
setPlayerData(self.serverId, "radio:talking", true, true);
if(self.config.enableDispatch and self.plugin_data.radioChannel <= self.config.dispatchRadioMaxChannel and self.plugin_data.radioChannel > 0) then
self:updatePlugin("talkStatusDS", true);
end
end
self:updateTokoVoipInfo();
if (lastTalkState == false and self.myChannels[self.plugin_data.radioChannel] and self.config.radioAnim) then
Expand All @@ -164,6 +181,9 @@ function TokoVoip.initialize(self)
self.plugin_data.radioTalking = false;
if (getPlayerData(self.serverId, "radio:talking")) then
setPlayerData(self.serverId, "radio:talking", false, true);
if(self.config.enableDispatch and self.plugin_data.radioChannel <= self.config.dispatchRadioMaxChannel and self.plugin_data.radioChannel > 0) then
self:updatePlugin("talkStatusDS", false);
end
end
self:updateTokoVoipInfo();

Expand Down
52 changes: 43 additions & 9 deletions fivem_script/tokovoip_script/src/c_main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,20 @@ local nuiLoaded = false
local function setPlayerTalkingState(player, playerServerId)
local talking = tonumber(getPlayerData(playerServerId, "voip:talking"));
if (animStates[playerServerId] == 0 and talking == 1) then
if not HasAnimDictLoaded("mp_facial") then
RequestAnimDict("mp_facial");
while not HasAnimDictLoaded("mp_facial") do
Citizen.Wait(5)
end
end
PlayFacialAnim(GetPlayerPed(player), "mic_chatter", "mp_facial");
elseif (animStates[playerServerId] == 1 and talking == 0) then
if not HasAnimDictLoaded("facials@gen_male@base") then
RequestAnimDict("facials@gen_male@base");
while not HasAnimDictLoaded("facials@gen_male@base") do
Citizen.Wait(5)
end
end
PlayFacialAnim(GetPlayerPed(player), "mood_normal_1", "facials@gen_male@base");
end
animStates[playerServerId] = talking;
Expand All @@ -44,7 +56,7 @@ local function PlayRedMFacialAnimation(player, animDict, animName)
while not HasAnimDictLoaded(animDict) do
Wait(100)
end
SetFacialIdleAnimOverride(player, animName, animDict)
SetFacialIdleAnimOverride(player, animName, animDict)
end

RegisterNUICallback("updatePluginData", function(data, cb)
Expand All @@ -64,15 +76,39 @@ RegisterNUICallback("setPlayerTalking", function(data, cb)
if (voip.talking == 1) then
setPlayerData(voip.serverId, "voip:talking", 1, true);
if (GetConvar("gametype") == "gta5") then
if not HasAnimDictLoaded("mp_facial") then
RequestAnimDict("mp_facial");
while not HasAnimDictLoaded("mp_facial") do
Citizen.Wait(5)
end
end
PlayFacialAnim(GetPlayerPed(PlayerId()), "mic_chatter", "mp_facial");
elseif (GetConvar("gametype") == "rdr3") then
if not HasAnimDictLoaded("face_human@gen_male@base") then
RequestAnimDict("face_human@gen_male@base");
while not HasAnimDictLoaded("face_human@gen_male@base") do
Citizen.Wait(5)
end
end
PlayRedMFacialAnimation(GetPlayerPed(PlayerId()), "face_human@gen_male@base", "mood_talking_normal");
end
else
setPlayerData(voip.serverId, "voip:talking", 0, true);
if (GetConvar("gametype") == "gta5") then
if not HasAnimDictLoaded("facials@gen_male@base") then
RequestAnimDict("facials@gen_male@base");
while not HasAnimDictLoaded("facials@gen_male@base") do
Citizen.Wait(5)
end
end
PlayFacialAnim(PlayerPedId(), "mood_normal_1", "facials@gen_male@base");
elseif (GetConvar("gametype") == "rdr3") then
if not HasAnimDictLoaded("face_human@gen_male@base") then
RequestAnimDict("face_human@gen_male@base");
while not HasAnimDictLoaded("face_human@gen_male@base") do
Citizen.Wait(5)
end
end
PlayRedMFacialAnimation(PlayerPedId(), "face_human@gen_male@base", "mood_normal");
end
end
Expand Down Expand Up @@ -236,14 +272,6 @@ AddEventHandler("initializeVoip", function()
-- Set targetped (used for spectator mod for admins)
targetPed = GetPlayerPed(-1);

-- Request this stuff here only one time
if (GetConvar("gametype") == "gta5") then
RequestAnimDict("mp_facial");
RequestAnimDict("facials@gen_male@base");
elseif (GetConvar("gametype") == "rdr3") then
RequestAnimDict("face_human@gen_male@base");
end

Citizen.Trace("TokoVoip: Initialized script (" .. scriptVersion .. ")\n");

local response;
Expand Down Expand Up @@ -342,6 +370,9 @@ AddEventHandler("TokoVoip:onPlayerLeaveChannel", function(channelId, playerServe

if (previousChannel ~= voip.plugin_data.radioChannel) then -- Update network data only if we actually changed radio channel
setPlayerData(voip.serverId, "radio:channel", voip.plugin_data.radioChannel, true);
if (voip.config.enableDispatch and voip.config.dispatchRadioMaxChannel >= previousChannel) then
voip:leaveChannel(previousChannel, getPlayerData(voip.serverId, "voip:pluginUUID"));
end
end

-- Remote player left channel we are subscribed to
Expand All @@ -361,6 +392,9 @@ AddEventHandler("TokoVoip:onPlayerJoinChannel", function(channelId, playerServer

if (previousChannel ~= voip.plugin_data.radioChannel) then -- Update network data only if we actually changed radio channel
setPlayerData(voip.serverId, "radio:channel", voip.plugin_data.radioChannel, true);
if (voip.config.enableDispatch and voip.config.dispatchRadioMaxChannel >= voip.plugin_data.radioChannel) then
voip:joinChannel(voip.plugin_data.radioChannel, getPlayerData(voip.serverId, "voip:pluginUUID"));
end
end

-- Remote player joined a channel we are subscribed to
Expand Down
138 changes: 137 additions & 1 deletion ws_server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ require('console-stamp')(console, { pattern: 'dd/mm/yyyy HH:MM:ss.l' });
let masterHeartbeatInterval;
const clients = {};

const channelsubs = {};

const ADS = {};

const handshakes = {};

console.log(chalk`Like {cyan TokoVOIP} ? Consider supporting the development: {hex('#f96854') https://patreon.com/Itokoyamato}`);
Expand Down Expand Up @@ -162,6 +166,22 @@ io.on('connection', async socket => {
});
await registerHandshake(socket);
socket.on('data', data => onIncomingData(socket, data));
socket.on('channels', data => onChannelSub(socket, data));
socket.on('talkingStatus', data => talkStatus(socket, data));
} else if (socket.from === 'ds') {
socketHeartbeat(socket);
socket.on('updateClientIP', data => {
if (!data || !data.ip || !IPv4Regex.test(data.ip) || !clients[socket.uuid]) return;
if (lodash.get(clients, `[${socket.uuid}].fivem.socket`)) clients[socket.uuid].fivem.socket.clientIp = data.ip;
if (lodash.get(clients, `[${socket.uuid}].ts3.socket`)) clients[socket.uuid].ts3.socket.clientIp = data.ip;
});
socket.ds = true;
await registerHandshake(socket);
socket.on('data', data => onIncomingDataDS(socket, data));
socket.on('requestList', data => requestList(socket, data));
socket.on('disconnect', (socket) => {
delete ADS[socket.uuid];
});
}
});

Expand Down Expand Up @@ -192,6 +212,14 @@ async function registerHandshake(socket) {
throw e;
}
}
if(socket.ds) {
ADS[client.uuid] = {
channel: 1,
uuid: client.uuid,
talking: false
}
socket.emit('newDataList', channelsubs);
}
socket.uuid = client.uuid;
client.fivem.socket = socket;
client.fivem.linkedAt = (new Date()).toISOString();
Expand All @@ -205,31 +233,139 @@ function setTS3Data(socket, data) {
if (client.fivem.socket) {
client.fivem.socket.emit('setTS3Data', client.ts3.data);
}
if (data.key === 'talking') {
if(client.fivem.socket && client.fivem.socket.from === 'ds') {
ADS[socket.uuid].talking = data.value;
for (const [key, value] of Object.entries(clients)) {
if(value.uuid != socket.uuid) {
if(!value.fivem.data.Users.find(item => item.uuid === socket.uuid) && value.fivem.data.radioChannel == ADS[socket.uuid].channel) {
value.fivem.data.Users.push({
uuid: socket.uuid,
radioEffect: true,
muted: !ADS[socket.uuid].talking,
radioTalking: ADS[socket.uuid].talking,
radioChannel: ADS[socket.uuid].channel,
volume: 100,
posX: 0,
posY: 0,
posZ: 0
});
client.ts3.socket.emit('processTokovoip', client.fivem.data);
} else if(value.fivem.data.radioChannel === ADS[socket.uuid].channel) {
value.fivem.data.Users.find(item => item.uuid === socket.uuid).radioTalking = ADS[socket.uuid].talking;
client.ts3.socket.emit('processTokovoip', client.fivem.data);
}
} else {
client.ts3.socket.emit('processTokovoip', client.fivem.data);
}
}
}
}
}

function talkStatus(socket, data) {
dsclients = Object.values(clients).filter(item => item.fivem.socket.from === 'ds');
let payload = {
status: data.status,
uuid: socket.uuid,
channel: socket.tokoData.radioChannel
};
for (const [key, value] of Object.entries(dsclients)) {
value.fivem.socket.emit("talkStatusSet", payload);
}
}

function onIncomingData(socket, data) {
const client = clients[socket.uuid];
if (!socket.uuid || !client || !client.ts3.socket || typeof data !== 'object') return;
socket.tokoData = data;
for (const [key, value] of Object.entries(ADS)) {
if(socket.tokoData.radioChannel == value.channel) {
socket.tokoData.Users.push({
uuid: key,
radioEffect: true,
muted: !value.talking,
radioTalking: value.talking,
radioChannel: value.channel,
volume: 0,
posX: 0,
posY: 0,
posZ: 0
});
}
}
client.fivem.data = socket.tokoData;
client.fivem.updatedAt = (new Date()).toISOString();
client.ts3.socket.emit('processTokovoip', client.fivem.data);
}

function onIncomingDataDS(socket, data) {
const client = clients[socket.uuid];
if (!socket.uuid || !client || !client.ts3.socket) return;
socket.tokoData = data;
ADS[socket.uuid].channel = socket.tokoData.radioChannel;
for (const [key, value] of Object.entries(ADS)) {
if(socket.tokoData.radioChannel == value.channel && key !== socket.uuid) {
socket.tokoData.Users.push({
uuid: key,
radioEffect: true,
muted: !value.talking,
radioTalking: value.talking,
radioChannel: value.channel,
volume: 0,
posX: 0,
posY: 0,
posZ: 0
});
}
}
client.fivem.data = socket.tokoData;
client.fivem.updatedAt = (new Date()).toISOString();
client.ts3.socket.emit('processTokovoip', client.fivem.data);
}

function onChannelSub(socket, data) {
const client = clients[socket.uuid];
if (!socket.uuid || !client || !client.ts3.socket) return;
if(data.type == 0) {
channelsubs[data.uuid] = data.channel;
} else {
delete channelsubs[data.uuid];
}
dsclients = Object.values(clients).filter(item => item.fivem.socket.from === 'ds');
for (const [key, value] of Object.entries(dsclients)) {
value.fivem.socket.emit("newDataList", channelsubs);
}
}

function requestList(socket, data) {
socket.emit("newDataList", channelsubs);
}

async function onSocketDisconnect(socket) {
log('log', chalk`{${socket.from === 'ts3' ? 'cyan' : 'yellow'} ${socket.from}} | Connection {red lost} - ${socket.safeIp}`);
if (socket.from === 'fivem') {
if (socket.from === 'fivem' || socket.from === 'ds') {
if (handshakes[socket.clientIp]) delete handshakes[socket.clientIp];
}
if (socket.uuid && clients[socket.uuid]) {
const client = clients[socket.uuid];
delete clients[socket.uuid];
if(channelsubs[socket.uuid]) {
delete channelsubs[socket.uuid];
}
const secondary = (socket.from === 'fivem') ? 'ts3' : 'fivem';
if (client[secondary].socket) {
client[secondary].socket.emit('disconnectMessage', `${socket.from}Disconnected`);
if (secondary === 'ts3') sleep(100) && client[secondary].socket.disconnect(true);
else registerHandshake(client[secondary].socket);
}
if (socket.from === 'ds') {
if (client['ts3'].socket) {
client.ts3.socket.emit("disconnectMessage", "Disconnected");
sleep(100);
client['ts3'].socket.disconnect(true);
}
}
}
}

Expand Down