102 lines
3.8 KiB
Lua
102 lines
3.8 KiB
Lua
-- Prevent running in monitor mode
|
|
if not TX_SERVER_MODE then return end
|
|
-- Prevent running if menu is disabled
|
|
if not TX_MENU_ENABLED then return end
|
|
|
|
--- Logic for starting to spectate + authorization + routing buckets
|
|
--- @param targetId number The player id to spectate.
|
|
local function handleSpectatePlayer(targetId)
|
|
local src = source
|
|
-- Sanity as this is still converted tonumber on client side
|
|
if type(targetId) ~= 'string' and type(targetId) ~= 'number' then
|
|
return
|
|
end
|
|
targetId = tonumber(targetId)
|
|
|
|
local allow = PlayerHasTxPermission(src, 'players.spectate')
|
|
|
|
if allow then
|
|
local targetPed = GetPlayerPed(targetId)
|
|
-- Lets exit if the target doesn't exist
|
|
if not targetPed then
|
|
return
|
|
end
|
|
-- checking if spectator and target are on the same routing bucket
|
|
local targetBucket = GetPlayerRoutingBucket(targetId)
|
|
local srcBucket = GetPlayerRoutingBucket(src)
|
|
local sourcePlayerStateBag = Player(src).state
|
|
if srcBucket ~= targetBucket then
|
|
debugPrint(('Target and source buckets differ | src: %s, bkt: %i | tgt: %s, bkt: %i'):format(src, srcBucket, targetId, targetBucket))
|
|
-- if there was a routing bucket set, we shouldn't overwrite it due to the cycle feature
|
|
if sourcePlayerStateBag.__spectateReturnBucket == nil then
|
|
sourcePlayerStateBag.__spectateReturnBucket = srcBucket
|
|
end
|
|
SetPlayerRoutingBucket(src, targetBucket)
|
|
end
|
|
|
|
TriggerClientEvent('txcl:spectate:start', src, targetId, GetEntityCoords(targetPed))
|
|
end
|
|
TriggerEvent('txsv:logger:menuEvent', src, 'spectatePlayer', allow, targetId)
|
|
end
|
|
|
|
RegisterNetEvent('txsv:req:spectate:start', handleSpectatePlayer)
|
|
|
|
|
|
--- Called to get the previous/next player to cycle to
|
|
--- @param currentTargetId number The current target id.
|
|
--- @param isNextPlayer boolean If we should cycle to the next player or not.
|
|
RegisterNetEvent('txsv:req:spectate:cycle', function(currentTargetId, isNextPlayer)
|
|
local src = source
|
|
|
|
local onlinePlayers = GetPlayers()
|
|
-- We don't allow cycling if there are less than two players online.
|
|
if #onlinePlayers <= 2 then
|
|
return TriggerClientEvent('txcl:spectate:cycleFailed', src)
|
|
end
|
|
|
|
-- Filter out the current src from the online players list
|
|
local sourceIndex = tableIndexOf(onlinePlayers, tostring(src))
|
|
table.remove(onlinePlayers, sourceIndex)
|
|
|
|
-- Find next target
|
|
local nextTargetId
|
|
local currentTargetServerIndex = tableIndexOf(onlinePlayers, tostring(currentTargetId))
|
|
if currentTargetServerIndex < 0 then
|
|
debugPrint('Current spectate target id not found for online players, resetting to onlinePlayers[1]')
|
|
nextTargetId = onlinePlayers[1]
|
|
--TODO: the correct thing would be to do a while to find the corect next/rev, based on value and not index
|
|
else
|
|
if isNextPlayer then
|
|
nextTargetId = onlinePlayers[currentTargetServerIndex + 1] or onlinePlayers[1]
|
|
else
|
|
nextTargetId = onlinePlayers[currentTargetServerIndex - 1] or onlinePlayers[#onlinePlayers]
|
|
end
|
|
end
|
|
|
|
-- Replying to client
|
|
debugPrint(('Cycling to %s player | src: %s, curTgtId: %s, nextTgtId: %s'):format(
|
|
isNextPlayer and 'next' or 'prev',
|
|
src,
|
|
currentTargetId,
|
|
nextTargetId
|
|
))
|
|
handleSpectatePlayer(nextTargetId)
|
|
end)
|
|
|
|
RegisterNetEvent('txsv:req:spectate:end', function()
|
|
local src = source
|
|
local allow = PlayerHasTxPermission(src, 'players.spectate')
|
|
if allow then
|
|
local sourcePlayerStateBag = Player(src).state
|
|
-- If this is nil, assume that no routing bucket change is needed,
|
|
-- as it wasn't stored
|
|
local prevRoutBucket = sourcePlayerStateBag.__spectateReturnBucket
|
|
-- Since lua treats 0 as truthy, actually don't need to handle
|
|
-- explicit nil check for int 0
|
|
if prevRoutBucket then
|
|
SetPlayerRoutingBucket(src, prevRoutBucket)
|
|
sourcePlayerStateBag.__spectateReturnBucket = nil
|
|
end
|
|
end
|
|
end)
|