Files
red-valley/cache/files/xsound/resource.rpf

1745 lines
66 KiB
Plaintext
Raw Normal View History

2026-03-29 21:41:17 +03:00
RPF2<00><00>$ <00><00>"<00>"<00><00><00><00><00><00><00><00>+08<00>I<00>lHw<00><00><00><00><00>@<00>8<00>R<00>am@m X <00><00>`<00><00>6h6<00>_
x_
<00>Y<00>Y<00><00><00>f<00>f<00><00><00><00>
<00>
/addoncrewphoneclientclient.luaclientcommands.luaeffectsmain.luaemulatorinteract_soundclient.luaevents.luaexportsevents.luainfo.luamanipulation.luaplay.luamain.luaconfig.luafxmanifest.luahtmlindex.htmlscriptsSoundPlayer.jsfunctions.jslistener.jsif config.AddonList.crewPhone then
local calanMuzikler = {}
local musicOn = false
local ESX = nil
CreateThread(function()
xpcall(function()
ESX = exports['es_extended']['getSharedObject']()
end, function(error)
while ESX == nil do
Wait(50)
TriggerEvent('esx:getSharedObject', function(obj)
ESX = obj
end)
end
end)
end)
-- Müzik çalma
exports('Cal', function(link, mp3)
local ped = PlayerPedId()
local pos = GetEntityCoords(ped)
local serverId = GetPlayerServerId(PlayerId())
local muzikAdi = tostring(serverId)
if musicOn then
TriggerServerEvent("muzik-durdur", muzikAdi)
musicOn = false
end
if #calanMuzikler <= 99 then
if mp3 then
TriggerServerEvent("muzik-cal", pos, muzikAdi, "phone-ring/" .. link, serverId, true)
else
TriggerServerEvent("muzik-cal", pos, muzikAdi, "https://www.youtube.com/watch?v=" .. link, serverId, false)
end
musicOn = true
else
ESX.ShowNotification("Fazla kişi youtube uygulamasını kullandığı için açtığınız videonun sesini yakındaki kişiler duyamıyor", "error")
end
end)
RegisterNetEvent('client-muzik-cal')
AddEventHandler('client-muzik-cal', function(pos, muzikAdi, link, serverId, mp3)
if tostring(GetPlayerServerId(PlayerId())) ~= muzikAdi then
calanMuzikler[muzikAdi] = {}
calanMuzikler[muzikAdi]["duraklat"] = false
calanMuzikler[muzikAdi]["serverId"] = serverId
calanMuzikler[muzikAdi]["mp3"] = mp3
if mp3 then
PlayUrlPos(muzikAdi, link, 0.1, pos)
setVolumeMax(muzikAdi, 0.1)
Distance(muzikAdi, 10)
else
PlayUrlPos(muzikAdi, link, 0.15, pos)
setVolumeMax(muzikAdi, 0.15)
Distance(muzikAdi, 15)
end
end
end)
-- Müzik durdurma
exports('Durdur', function(link)
if musicOn then
musicOn = false
TriggerServerEvent("muzik-durdur", tostring(GetPlayerServerId(PlayerId())))
end
end)
RegisterNetEvent('client-muzik-durdur')
AddEventHandler('client-muzik-durdur', function(muzikAdi)
if GetPlayerServerId(PlayerId()) ~= muzikAdi then
calanMuzikler[muzikAdi] = nil
Destroy(muzikAdi)
end
end)
-- Müzik duraklatma
exports('Duraklat', function(link)
local myId = tostring(GetPlayerServerId(PlayerId()))
TriggerServerEvent("muzik-duraklat", myId)
end)
RegisterNetEvent('client-muzik-duraklat')
AddEventHandler('client-muzik-duraklat', function(muzikAdi)
if tostring(GetPlayerServerId(PlayerId())) ~= muzikAdi then
if calanMuzikler[muzikAdi]["duraklat"] == false then
calanMuzikler[muzikAdi]["duraklat"] = true
Pause(muzikAdi)
end
end
end)
-- Müzik duraklatma
exports('Devamet', function(link)
local myId = tostring(GetPlayerServerId(PlayerId()))
TriggerServerEvent("muzik-devamet", myId)
end)
RegisterNetEvent('client-muzik-devamet')
AddEventHandler('client-muzik-devamet', function(muzikAdi)
if tostring(GetPlayerServerId(PlayerId())) ~= muzikAdi then
if calanMuzikler[muzikAdi]["duraklat"] == true then
calanMuzikler[muzikAdi]["duraklat"] = false
Resume(muzikAdi)
end
end
end)
-- Müzik Konum güncelleme
local time = 100
Citizen.CreateThread(function()
while true do
Citizen.Wait(time)
for x, y in pairs(calanMuzikler) do
local player = GetPlayerFromServerId(calanMuzikler[x]["serverId"])
if player ~= -1 then
local ped = GetPlayerPed(player)
local kordinat = GetEntityCoords(ped)
local benimKordinat = GetEntityCoords(PlayerPedId())
local mesafe = #(benimKordinat - kordinat)
if mesafe < 200 then
time = 100
Position(x, kordinat)
if calanMuzikler[x]["mp3"] then
if IsPedInAnyVehicle(ped, true) == 1 then
local vehicle = GetVehiclePedIsIn(ped, false)
if GetEntitySpeed(vehicle) * 3.6 > 200.0 then
Distance(x, 140)
elseif GetEntitySpeed(vehicle) * 3.6 > 150.0 then
Distance(x, 125)
elseif GetEntitySpeed(vehicle) * 3.6 > 110.0 then
Distance(x, 100)
elseif GetEntitySpeed(vehicle) * 3.6 > 90.0 then
Distance(x, 80)
elseif GetEntitySpeed(vehicle) * 3.6 > 60.0 then
Distance(x, 65)
elseif GetEntitySpeed(vehicle) * 3.6 > 30.0 then
Distance(x, 40)
else
Distance(x, 25)
end
else
Distance(x, 10)
end
else
if IsPedInAnyVehicle(ped, true) == 1 then
local vehicle = GetVehiclePedIsIn(ped, false)
if GetEntitySpeed(vehicle) * 3.6 > 200.0 then
Distance(x, 140)
elseif GetEntitySpeed(vehicle) * 3.6 > 150.0 then
Distance(x, 125)
elseif GetEntitySpeed(vehicle) * 3.6 > 110.0 then
Distance(x, 100)
elseif GetEntitySpeed(vehicle) * 3.6 > 90.0 then
Distance(x, 80)
elseif GetEntitySpeed(vehicle) * 3.6 > 60.0 then
Distance(x, 65)
elseif GetEntitySpeed(vehicle) * 3.6 > 30.0 then
Distance(x, 40)
else
Distance(x, 25)
end
else
Distance(x, 15)
end
end
else
time = 2000
Position(x, kordinat)
end
else
local muzikAdi = tostring(calanMuzikler[x]["serverId"])
calanMuzikler[muzikAdi] = nil
Destroy(muzikAdi)
end
end
end
end)
end-- i recommend to NOT change the command name. it will make easier for people to use this command
-- when ever is this library.. so please keep this command name on "streamermode" command
RegisterCommand("streamermode", function(source, args, rawCommand)
disableMusic = not disableMusic
TriggerEvent("xsound:streamerMode", disableMusic)
if disableMusic then
TriggerEvent('chat:addMessage', { args = { "^1[xSound]", config.Messages["streamer_on"] } })
else
TriggerEvent('chat:addMessage', { args = { "^1[xSound]", config.Messages["streamer_off"] } })
end
end, false)
AddEventHandler("xsound:streamerMode", function(status)
if status then
for k, v in pairs(soundInfo) do
Destroy(v.id)
end
end
end)function fadeIn(name, time, volume_)
if soundExists(name) then
volumeType(name, 0)
local addVolume = (volume_ / time) * 100
local called = 0
local volume = volume_
while true do
volume = volume - addVolume
if volume < 0 then volume = 0 end
if volume == 0 then break end
called = called + 1
end
volume = getVolume(name)
while true do
Citizen.Wait(time / called)
volume = volume + addVolume
if volume > volume_ then
volume = volume_
volumeType(name, volume)
break
end
volumeType(name, volume)
end
end
end
exports('fadeIn', fadeIn)
function fadeOut(name, time)
if soundExists(name) then
local volume = getVolume(name)
local addVolume = (volume / time) * 100
local called = 0
while true do
volume = volume - addVolume
if volume < 0 then volume = 0 end
if volume == 0 then break end
called = called + 1
end
volume = getVolume(name)
while true do
Citizen.Wait(time / called)
volume = volume - addVolume
if volume < 0 then
volume = 0
volumeType(name, volume)
break
end
volumeType(name, volume)
end
end
end
exports('fadeOut', fadeOut)
function volumeType(name, volume)
if isDynamic(name) then
setVolumeMax(name,volume)
setVolume(name,volume)
else
setVolume(name,volume)
end
endif config.interact_sound_enable then
RegisterNetEvent('InteractSound_CL:PlayOnOne')
AddEventHandler('InteractSound_CL:PlayOnOne', function(soundFile, soundVolume)
PlayUrl("./sounds/" .. soundFile, "./sounds/" .. soundFile .. "." .. config.interact_sound_file, soundVolume)
end)
RegisterNetEvent('InteractSound_CL:PlayOnAll')
AddEventHandler('InteractSound_CL:PlayOnAll', function(soundFile, soundVolume)
PlayUrl("./sounds/" .. soundFile, "./sounds/" .. soundFile .. "." .. config.interact_sound_file, soundVolume)
end)
RegisterNetEvent('InteractSound_CL:PlayWithinDistance')
AddEventHandler('InteractSound_CL:PlayWithinDistance', function(playerNetId, maxDistance, soundFile, soundVolume)
if GetPlayerFromServerId(playerNetId) ~= -1 then
local eCoords = GetEntityCoords(GetPlayerPed(GetPlayerFromServerId(playerNetId)))
PlayUrlPos("./sounds/" .. soundFile, "./sounds/" .. soundFile .. "." .. config.interact_sound_file, soundVolume, eCoords)
Distance("./sounds/" .. soundFile, maxDistance)
end
end)
end
RegisterNUICallback("init", function(data, cb)
SendNUIMessage({
status = "init",
time = config.RefreshTime,
})
if cb then
cb('ok')
end
end)
RegisterNUICallback("data_status", function(data, cb)
if soundInfo[data.id] ~= nil then
if data.type == "finished" then
if not soundInfo[data.id].loop then
soundInfo[data.id].playing = false
end
TriggerEvent("xSound:songStopPlaying", data.id)
end
if data.type == "maxDuration" then
soundInfo[data.id].hasMaxTime = true
soundInfo[data.id].maxDuration = data.time
end
end
if cb then
cb('ok')
end
end)
RegisterNUICallback("events", function(data, cb)
local id = data.id
local type = data.type
if type == "resetTimeStamp" then
if soundInfo[id] then
soundInfo[id].timeStamp = 0
soundInfo[id].maxDuration = data.time
soundInfo[id].playing = true
end
end
if type == "onPlay" then
if globalOptionsCache[id] then
if globalOptionsCache[id].onPlayStartSilent then
globalOptionsCache[id].onPlayStartSilent(getInfo(id))
end
if globalOptionsCache[id].onPlayStart and not soundInfo[id].SkipEvents then
globalOptionsCache[id].onPlayStart(getInfo(id))
end
soundInfo[id].SkipEvents = nil
end
end
if type == "onEnd" then
if globalOptionsCache[id] then
if globalOptionsCache[id].onPlayEnd then
globalOptionsCache[id].onPlayEnd(getInfo(id))
end
end
if soundInfo[id] then
if soundInfo[id].loop then
soundInfo[id].timeStamp = 0
end
if soundInfo[id].destroyOnFinish and not soundInfo[id].loop then
Destroy(id)
end
end
end
if type == "onLoading" then
if globalOptionsCache[id] then
if globalOptionsCache[id].onLoading then
globalOptionsCache[id].onLoading(getInfo(id))
end
end
end
if cb then
cb('ok')
end
end)
RegisterNetEvent("xsound:stateSound", function(state, data)
local soundId = data.soundId
if state == "destroyOnFinish" then
if soundExists(soundId) then
destroyOnFinish(soundId, data.value)
end
end
if state == "timestamp" then
if soundExists(soundId) then
setTimeStamp(soundId, data.time)
end
end
if state == "play" then
PlayUrl(soundId, data.url, data.volume, data.loop or false)
end
if state == "playpos" then
PlayUrlPos(soundId, data.url, data.volume, data.position, data.loop or false)
end
if state == "position" then
if soundExists(soundId) then
Position(soundId, data.position)
end
end
if state == "distance" then
if soundExists(soundId) then
Distance(soundId, data.distance)
end
end
if state == "destroy" then
if soundExists(soundId) then
Destroy(soundId)
end
end
if state == "pause" then
if soundExists(soundId) then
Pause(soundId)
end
end
if state == "resume" then
if soundExists(soundId) then
Resume(soundId)
end
end
if state == "volume" then
if soundExists(soundId) then
if isDynamic(soundId) then
setVolumeMax(soundId, data.volume)
else
setVolume(soundId, data.volume)
end
end
end
end)
function onPlayStart(name, delegate)
globalOptionsCache[name].onPlayStart = delegate
end
exports('onPlayStart', onPlayStart)
function onPlayEnd(name, delegate)
globalOptionsCache[name].onPlayEnd = delegate
end
exports('onPlayEnd', onPlayEnd)
function onLoading(name, delegate)
globalOptionsCache[name].onLoading = delegate
end
exports('onLoading', onLoading)
function onPlayPause(name, delegate)
globalOptionsCache[name].onPlayPause = delegate
end
exports('onPlayPause', onPlayPause)
function onPlayResume(name, delegate)
globalOptionsCache[name].onPlayResume = delegate
end
exports('onPlayResume', onPlayResume)
function onPlayStartSilent(name, delegate)
globalOptionsCache[name].onPlayStartSilent = delegate
endsoundInfo = {}
function getLink(name_)
return soundInfo[name_].url
end
exports('getLink', getLink)
function getPosition(name_)
return soundInfo[name_].position
end
exports('getPosition', getPosition)
function isLooped(name_)
return soundInfo[name_].loop
end
exports('isLooped', isLooped)
function getInfo(name_)
return soundInfo[name_]
end
exports('getInfo', getInfo)
function soundExists(name_)
if soundInfo[name_] == nil then
return false
end
return true
end
exports('soundExists', soundExists)
function isPlaying(name_)
return soundInfo[name_].playing
end
exports('isPlaying', isPlaying)
function isPaused(name_)
return soundInfo[name_].paused
end
exports('isPaused', isPaused)
function getDistance(name_)
return soundInfo[name_].distance
end
exports('getDistance', getDistance)
function getVolume(name_)
return soundInfo[name_].volume
end
exports('getVolume', getVolume)
function isDynamic(name_)
return soundInfo[name_].isDynamic
end
exports('isDynamic', isDynamic)
function getTimeStamp(name_)
return soundInfo[name_].timeStamp or -1
end
exports('getTimeStamp', getTimeStamp)
function getMaxDuration(name_)
return soundInfo[name_].maxDuration or -1
end
exports('getMaxDuration', getMaxDuration)
function isPlayerInStreamerMode()
return disableMusic
end
exports('isPlayerInStreamerMode', isPlayerInStreamerMode)
function getAllAudioInfo()
return soundInfo
end
exports('getAllAudioInfo', getAllAudioInfo)
function isPlayerCloseToAnySound()
return isPlayerCloseToMusic
end
exports('isPlayerCloseToAnySound', isPlayerCloseToAnySound)function Distance(name_, distance_)
SendNUIMessage({
status = "distance",
name = name_,
distance = distance_,
})
soundInfo[name_].distance = distance_
end
exports('Distance', Distance)
function Position(name_, pos)
SendNUIMessage({
status = "soundPosition",
name = name_,
x = pos.x,
y = pos.y,
z = pos.z,
})
soundInfo[name_].position = pos
soundInfo[name_].id = name_
end
exports('Position', Position)
function Destroy(name_)
SendNUIMessage({
status = "delete",
name = name_
})
soundInfo[name_] = nil
if globalOptionsCache[name_] ~= nil and globalOptionsCache[name_].onPlayEnd ~= nil then
globalOptionsCache[name_].onPlayEnd(getInfo(name_))
end
globalOptionsCache[name_] = nil
end
function DestroySilent(name)
SendNUIMessage({
status = "delete",
name = name
})
end
exports('Destroy', Destroy)
function Resume(name_)
SendNUIMessage({
status = "resume",
name = name_
})
soundInfo[name_].playing = true
soundInfo[name_].paused = false
if globalOptionsCache[name_] ~= nil and globalOptionsCache[name_].onPlayResume ~= nil then
globalOptionsCache[name_].onPlayResume(getInfo(name_))
end
end
exports('Resume', Resume)
function Pause(name_)
SendNUIMessage({
status = "pause",
name = name_
})
soundInfo[name_].playing = false
soundInfo[name_].paused = true
if globalOptionsCache[name_] ~= nil and globalOptionsCache[name_].onPlayPause ~= nil then
globalOptionsCache[name_].onPlayPause(getInfo(name_))
end
end
exports('Pause', Pause)
function setVolume(name_, vol)
SendNUIMessage({
status = "volume",
volume = vol,
name = name_,
})
soundInfo[name_].volume = vol
end
exports('setVolume', setVolume)
function setVolumeMax(name_, vol)
SendNUIMessage({
status = "max_volume",
volume = vol,
name = name_,
})
soundInfo[name_].volume = vol
end
exports('setVolumeMax', setVolumeMax)
function setTimeStamp(name_, timestamp)
getInfo(name_).timeStamp = timestamp
SendNUIMessage({
name = name_,
status = "timestamp",
timestamp = timestamp,
})
end
exports('setTimeStamp', setTimeStamp)
function destroyOnFinish(id, bool)
soundInfo[id].destroyOnFinish = bool
end
exports('destroyOnFinish', destroyOnFinish)
function setSoundLoop(name, value)
SendNUIMessage({
status = "loop",
name = name,
loop = value,
})
soundInfo[name].loop = value
end
exports('setSoundLoop', setSoundLoop)
function repeatSound(name)
if soundExists(name) then
SendNUIMessage({
status = "repeat",
name = name,
})
end
end
exports('repeatSound', repeatSound)
function setSoundDynamic(name, bool)
if soundExists(name) then
soundInfo[name].isDynamic = bool
SendNUIMessage({
status = "changedynamic",
name = name,
bool = bool,
})
end
end
exports('setSoundDynamic', setSoundDynamic)
function setSoundURL(name, url)
if soundExists(name) then
soundInfo[name].url = url
SendNUIMessage({
status = "changeurl",
hasMaxTime = false,
name = name,
url = url,
})
end
end
exports('setSoundURL', setSoundURL)function PlayUrl(name_, url_, volume_, loop_, options)
if disableMusic then return end
if soundInfo[name_] == nil then soundInfo[name_] = getDefaultInfo() end
soundInfo[name_].volume = volume_
soundInfo[name_].url = url_
soundInfo[name_].id = name_
soundInfo[name_].playing = true
soundInfo[name_].loop = loop_ or false
soundInfo[name_].isDynamic = false
soundInfo[name_].hasMaxTime = false
globalOptionsCache[name_] = options or { }
if loop_ then
soundInfo[name_].destroyOnFinish = false
else
soundInfo[name_].destroyOnFinish = true
end
CheckForCloseMusic()
UpdatePlayerPositionInNUI()
SendNUIMessage({ status = "unmuteAll" })
SendNUIMessage({
status = "url",
name = name_,
url = url_,
x = 0,
y = 0,
z = 0,
dynamic = false,
hasMaxTime = false,
volume = volume_,
loop = loop_ or false,
})
end
exports('PlayUrl', PlayUrl)
function PlayUrlPos(name_, url_, volume_, pos, loop_, options)
if disableMusic then return end
if soundInfo[name_] == nil then soundInfo[name_] = getDefaultInfo() end
soundInfo[name_].volume = volume_
soundInfo[name_].url = url_
soundInfo[name_].position = pos
soundInfo[name_].id = name_
soundInfo[name_].playing = true
soundInfo[name_].loop = loop_ or false
soundInfo[name_].isDynamic = true
soundInfo[name_].hasMaxTime = false
globalOptionsCache[name_] = options or { }
CheckForCloseMusic()
if #(GetEntityCoords(PlayerPedId()) - pos) < 10.0 + config.distanceBeforeUpdatingPos then
UpdatePlayerPositionInNUI()
SendNUIMessage({ status = "unmuteAll" })
end
SendNUIMessage({
status = "url",
name = name_,
url = url_,
x = pos.x,
y = pos.y,
z = pos.z,
dynamic = true,
hasMaxTime = false,
volume = volume_,
loop = loop_ or false,
})
if loop_ then
soundInfo[name_].destroyOnFinish = false
else
soundInfo[name_].destroyOnFinish = true
end
end
exports('PlayUrlPos', PlayUrlPos)
function PlayUrlPosSilent(name_, url_, volume_, pos, loop_)
if disableMusic then return end
SendNUIMessage({
status = "url",
name = name_,
url = url_,
x = pos.x,
y = pos.y,
z = pos.z,
hasMaxTime = soundInfo[name_].hasMaxTime or false,
dynamic = true,
volume = volume_,
loop = loop_ or false,
})
endglobalOptionsCache = {}
isPlayerCloseToMusic = false
disableMusic = false
function getDefaultInfo()
return {
volume = 1.0,
url = "",
id = "",
position = nil,
distance = 10,
playing = false,
paused = false,
loop = false,
isDynamic = false,
timeStamp = 0,
maxDuration = 0,
destroyOnFinish = true,
}
end
function UpdatePlayerPositionInNUI()
local ped = PlayerPedId()
local pos = GetEntityCoords(ped)
SendNUIMessage({
status = "position",
x = pos.x,
y = pos.y,
z = pos.z
})
end
function CheckForCloseMusic()
local ped = PlayerPedId()
local playerPos = GetEntityCoords(ped)
isPlayerCloseToMusic = false
for k, v in pairs(soundInfo) do
if v.position ~= nil and v.isDynamic then
if #(v.position - playerPos) < v.distance + config.distanceBeforeUpdatingPos then
isPlayerCloseToMusic = true
break
end
end
end
end
-- updating position on html side so we can count how much volume the sound needs.
CreateThread(function()
local refresh = config.RefreshTime
local ped = PlayerPedId()
local pos = GetEntityCoords(ped)
local lastPos = pos
local changedPosition = false
while true do
Wait(refresh)
if not disableMusic and isPlayerCloseToMusic then
ped = PlayerPedId()
pos = GetEntityCoords(ped)
-- we will update position only when player have moved
if #(lastPos - pos) >= 0.1 then
lastPos = pos
UpdatePlayerPositionInNUI()
end
if changedPosition then
UpdatePlayerPositionInNUI()
SendNUIMessage({ status = "unmuteAll" })
end
changedPosition = false
else
if not changedPosition then
changedPosition = true
SendNUIMessage({ status = "position", x = -900000, y = -900000, z = -900000 })
SendNUIMessage({ status = "muteAll" })
end
Wait(1000)
end
end
end)
-- checking if player is close to sound so we can switch bool value to true.
CreateThread(function()
while true do
Wait(500)
CheckForCloseMusic()
end
end)
-- updating timeStamp
CreateThread(function()
Wait(1100)
while true do
Wait(1000)
for k, v in pairs(soundInfo) do
if v.playing or v.wasSilented then
if getInfo(v.id).timeStamp ~= nil and getInfo(v.id).maxDuration ~= nil then
if getInfo(v.id).timeStamp < getInfo(v.id).maxDuration then
getInfo(v.id).timeStamp = getInfo(v.id).timeStamp + 1
end
end
end
end
end
end)
function PlayMusicFromCache(data)
local musicCache = soundInfo[data.id]
if musicCache then
musicCache.SkipEvents = true
PlayUrlPosSilent(data.id, data.url, data.volume, data.position, data.loop)
onPlayStartSilent(data.id, function()
if getInfo(data.id).maxDuration then
setTimeStamp(data.id, data.timeStamp or 0)
end
Distance(data.id, data.distance)
end)
end
end
-- If player is far away from music we will just delete it.
CreateThread(function()
local ped = PlayerPedId()
local playerPos = GetEntityCoords(ped)
local destroyedMusicList = {}
while true do
Wait(500)
ped = PlayerPedId()
playerPos = GetEntityCoords(ped)
for k, v in pairs(soundInfo) do
if v.position ~= nil and v.isDynamic then
if #(v.position - playerPos) < (v.distance + config.distanceBeforeUpdatingPos) then
if destroyedMusicList[v.id] then
destroyedMusicList[v.id] = nil
v.wasSilented = true
PlayMusicFromCache(v)
end
else
if not destroyedMusicList[v.id] then
destroyedMusicList[v.id] = true
v.wasSilented = false
DestroySilent(v.id)
end
end
end
end
end
end)config = {}
-- How much ofter the player position is updated ?
config.RefreshTime = 300
-- default sound format for interact
config.interact_sound_file = "ogg"
-- is emulator enabled ?
config.interact_sound_enable = false
-- how much close player has to be to the sound before starting updating position ?
config.distanceBeforeUpdatingPos = 40
-- Message list
config.Messages = {
["streamer_on"] = "Streamer mode is on. From now you will not hear any music/sound.",
["streamer_off"] = "Streamer mode is off. From now you will be able to listen to music that players might play.",
["no_permission"] = "You cant use this command, you dont have permissions for it!",
}
-- Addon list
-- True/False enabled/disabled
config.AddonList = {
crewPhone = false,
}fx_version 'cerulean'
games { 'gta5', 'rdr3' }
rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.'
--[[ Resource Information ]]--
name 'xsound'
version '1.5.0'
client_scripts {
"config.lua",
"client/main.lua",
"client/events.lua",
"client/commands.lua",
"client/exports/info.lua",
"client/exports/play.lua",
"client/exports/manipulation.lua",
"client/exports/events.lua",
"client/effects/main.lua",
"client/emulator/interact_sound/client.lua",
"addon/**/client/*.lua",
}
server_scripts {
"config.lua",
"server/exports/play.lua",
"server/exports/manipulation.lua",
"server/emulator/interact_sound/server.lua",
"addon/**/server/*.lua",
}
ui_page "html/index.html"
files {
"html/index.html",
"html/scripts/listener.js",
"html/scripts/SoundPlayer.js",
"html/scripts/functions.js",
"html/sounds/*.ogg",
"html/sounds/*.mp3",
}
<html>
<head>
<title>xSound</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.1.1/howler.min.js" type="text/javascript"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.2.3/purify.js"></script>
<script src="https://s.ytimg.com/yts/jsbin/www-widgetapi-vflJJaNgk/www-widgetapi.js"></script>
<script src="https://www.youtube.com/iframe_api"></script>
</head>
<body>
<div id ="trash"></div>
<script src="./scripts/config.js" type="text/javascript"></script>
<script src="./scripts/functions.js" type="text/javascript"></script>
<script src="./scripts/SoundPlayer.js" type="text/javascript"></script>
<script src="./scripts/listener.js" type="text/javascript"></script>
</body>
</html>
let identifierCounterVariable = 0;
class SoundPlayer {
static yPlayer = null;
youtubePlayerReady = false;
constructor() {
this.url = "test";
this.name = "";
this.dynamic = false;
this.distance = 10;
this.volume = 1.0;
this.pos = [ 0.0, 0.0, 0.0 ];
this.max_volume = -1.0;
this.div_id = "myAudio_" + identifierCounterVariable++;
this.loop = false;
this.isYoutube = false;
this.load = false;
this.isMuted_ = false;
this.audioPlayer = null;
}
setYoutubePlayerReady(result) {
this.youtubePlayerReady = result;
}
isYoutubePlayerReady() {
return this.youtubePlayerReady;
}
isAudioYoutubePlayer() {
return this.isYoutube;
}
getDistance() {
return this.distance;
}
getLocation() {
return this.pos;
}
getVolume() {
return this.volume;
}
getMaxVolume() {
return this.max_volume;
}
getUrlSound() {
return this.url;
}
isDynamic() {
return this.dynamic;
}
getDivId() {
return this.div_id;
}
isLoop() {
return this.loop;
}
getName() {
return this.name;
}
loaded() {
return this.load;
}
getAudioPlayer() {
return this.audioPlayer;
}
getYoutubePlayer() {
return this.yPlayer;
}
getAudioCurrentTime() {
if (this.isAudioYoutubePlayer()) {
return this.getYoutubePlayer().getDuration();
}
return this.getAudioPlayer()._duration;
}
setLoaded(result) {
this.load = result;
}
setName(result) {
this.name = result;
}
setDistance(result) {
this.distance = result;
}
setDynamic(result) {
this.dynamic = result;
}
setLocation(x_, y_, z_) {
this.pos = [ x_, y_, z_ ];
}
setSoundUrl(result) {
this.url = sanitizeURL(result);
}
setLoop(result) {
if (!this.isAudioYoutubePlayer()) {
if (this.audioPlayer != null) {
this.audioPlayer.loop(result);
}
}
this.loop = result;
}
setMaxVolume(result) {
this.max_volume = result;
}
setVolume(result) {
this.volume = result;
if (this.max_volume == -1) this.max_volume = result;
if (this.max_volume > (this.volume - 0.01)) this.volume = this.max_volume;
let volume = result;
if (this.isDynamic() && (this.isMuted() || IsAllMuted)) volume = 0;
if (this.isAudioYoutubePlayer() && this.yPlayer && this.isYoutubePlayerReady()) {
this.yPlayer.setVolume(volume * 100);
} else if (this.audioPlayer) {
this.audioPlayer.volume(volume);
}
}
create() {
const link = getYoutubeUrlId(this.getUrlSound());
if (link === "") {
this.isYoutube = false;
this.audioPlayer = new Howl({
src: [ this.getUrlSound() ],
loop: false,
html5: true,
autoplay: false,
volume: 0.00,
format: [ 'mp3' ],
onload: () => {
$.post('https://xsound/events', JSON.stringify({ type: "onLoading", id: this.getName() }));
},
onend: () => {
ended(this.getName());
},
onplay: () => {
isReady(this.getName());
},
});
$("#" + this.div_id).remove();
} else {
this.isYoutube = true;
this.setYoutubePlayerReady(false);
$("#" + this.div_id).remove();
$("body").append("<div id='" + this.div_id + "'></div>");
this.yPlayer = new YT.Player(this.div_id, {
startSeconds: Number,
videoId: link,
origin: window.location.href,
enablejsapi: 1,
width: "0",
height: "0",
playerVars: {
autoplay: 0,
controls: 0,
quality: 'auto',
},
events: {
'onReady': (event) => {
event.target.unMute();
event.target.setVolume(0);
event.target.playVideo();
isReady(this.getName());
$.post('https://xsound/events', JSON.stringify({ type: "onLoading", id: this.getName() }));
},
'onStateChange': (event) => {
if (event.data == YT.PlayerState.ENDED) {
ended(this.getName());
}
}
}
});
}
}
destroyYoutubeApi() {
if (this.yPlayer) {
if (typeof this.yPlayer.stopVideo === "function" && typeof this.yPlayer.destroy === "function") {
this.yPlayer.stopVideo();
this.yPlayer.destroy();
this.youtubePlayerReady = false;
this.yPlayer = null;
}
}
}
delete() {
if (this.audioPlayer != null) {
this.audioPlayer.pause();
this.audioPlayer.stop();
this.audioPlayer.unload();
}
this.audioPlayer = null;
$("#" + this.div_id).remove();
}
updateVolume(dd, maxd) {
const d_max = maxd;
const d_now = dd;
let vol = 0;
let distance = (d_now / d_max);
if (distance < 1) {
distance = distance * 100;
const far_away = 100 - distance;
vol = (this.max_volume / 100) * far_away;
this.setVolume(vol);
this.isMuted_ = false;
} else {
this.setVolume(0);
this.isMuted_ = true;
}
}
play() {
if (!this.isAudioYoutubePlayer()) {
if (this.audioPlayer != null) {
this.audioPlayer.play();
}
} else {
if (this.isYoutubePlayerReady()) {
this.yPlayer.playVideo();
}
}
}
pause() {
if (!this.isAudioYoutubePlayer()) {
if (this.audioPlayer != null) this.audioPlayer.pause();
} else {
if (this.isYoutubePlayerReady()) this.yPlayer.pauseVideo();
}
}
resume() {
if (!this.isAudioYoutubePlayer()) {
if (this.audioPlayer != null) this.audioPlayer.play();
} else {
if (this.isYoutubePlayerReady()) this.yPlayer.playVideo();
}
}
isMuted() {
return this.isMuted_;
}
mute() {
this.isMuted_ = true;
this.setVolume(0)
}
unmute() {
this.isMuted_ = false;
this.setVolume(this.getVolume())
}
unmuteSilent() {
this.isMuted_ = false;
}
setTimeStamp(time) {
if (!this.isAudioYoutubePlayer()) {
this.audioPlayer.seek(time);
} else {
this.yPlayer.seekTo(time);
}
}
isPlaying() {
if (this.isAudioYoutubePlayer()) return this.isYoutubePlayerReady() && this.yPlayer.getPlayerState() == 1;
else return this.audioPlayer != null && this.audioPlayer.playing();
}
}
function sanitizeURL(url) {
url = DOMPurify.sanitize(url);
return url.replace(/<[^>]*>?/gm, '');
}
function getYoutubeUrlId(url) {
let videoId = "";
if (url.indexOf("youtube") !== -1) {
let urlParts = url.split("?v=");
videoId = urlParts[1].substring(0, 11);
}
if (url.indexOf("youtu.be") !== -1) {
let urlParts = url.replace("//", "").split("/");
videoId = urlParts[1].substring(0, 11);
}
return videoId;
}
function isYoutubeURL(url) {
return getYoutubeUrlId(url) !== "";
}
function getDurationOfMusicFromURL(url, timeStamp) {
url = sanitizeURL(url);
if (isYoutubeURL(url)) {
let ytPlayer = new YT.Player("trash", {
height: '0',
width: '0',
videoId: getYoutubeUrlId(url),
events: {
'onReady': function (event) {
timeStamp(event.target.getDuration());
ytPlayer.stopVideo();
ytPlayer.destroy();
ytPlayer = null;
},
'onError': function (event) {
timeStamp(null);
ytPlayer.destroy();
ytPlayer = null;
},
}
});
} else {
let audioPlayer = new Howl({
src: [ url ],
loop: false,
html5: true,
autoplay: false,
volume: 0.00,
format: [ 'mp3' ],
onload: () => {
timeStamp(audioPlayer.duration());
audioPlayer.unload();
audioPlayer = null;
},
onloaderror: (id, error) => {
timeStamp(null);
audioPlayer.unload();
audioPlayer = null;
},
});
}
}
function isReady(soundName) {
const sound = soundList[soundName];
if (sound == null) {
return;
}
if (sound.loaded() == false) {
sound.setLoaded(true);
$.post('https://xsound/events', JSON.stringify({
type: "onPlay",
id: sound.getName(),
}));
if (sound.isAudioYoutubePlayer()) {
sound.setYoutubePlayerReady(true);
}
if (sound.isDynamic()) {
addToCache();
updateVolumeSounds();
} else {
sound.setVolume(sound.getVolume())
}
}
}
function ended(soundName) {
const sound = soundList[soundName];
if (sound == null) {
return;
}
if (!sound.isPlaying()) {
if (sound.isLoop()) {
const time = sound.getAudioCurrentTime();
sound.setTimeStamp(0);
sound.play();
$.post('https://xsound/events', JSON.stringify({
type: "resetTimeStamp",
id: sound.getName(),
time: time,
}));
}
$.post('https://xsound/data_status', JSON.stringify({
type: "finished",
id: soundName
}));
$.post('https://xsound/events', JSON.stringify({
type: "onEnd",
id: sound.getName(),
}));
}
}
function sendMaxDurationToClient(item) {
if (!item.hasMaxTime || !item.dynamic) {
getDurationOfMusicFromURL(item.url, function (time) {
if (time) {
$.post('https://xsound/data_status', JSON.stringify({
time: time,
type: "maxDuration",
id: item.name,
}));
}
});
}
}const soundList = [];
let closeToPlayer = [];
var IsAllMuted = false;
let updateVolumeSoundTimer;
let updateCacheTimer;
let playerPos = [ -90000, -90000, -90000 ];
let refreshTime = 300;
$(function () {
$.post('https://xsound/init');
window.addEventListener('message', function (event) {
const item = event.data;
let sound;
let sd;
switch (item.status) {
case "init":
refreshTime = item.time;
break;
case "position":
playerPos = [ item.x, item.y, item.z ];
break;
case "volume":
sound = soundList[item.name];
if (sound != null) {
sound.setVolume(item.volume);
sound.setMaxVolume(item.volume);
}
break;
case "timestamp":
sound = soundList[item.name];
if (sound != null) {
sound.setTimeStamp(item.timestamp);
}
break;
case "max_volume":
sound = soundList[item.name];
if (sound != null) {
sound.setMaxVolume(item.volume);
}
break;
case "url":
sound = soundList[item.name];
if (sound != null) {
sound.destroyYoutubeApi();
sound.delete();
sound = null;
}
sd = new SoundPlayer();
sendMaxDurationToClient(item);
sd.setName(item.name);
sd.setSoundUrl(item.url);
sd.setDynamic(item.dynamic);
sd.setLocation(item.x, item.y, item.z);
sd.setLoop(item.loop)
sd.create();
sd.setVolume(item.volume);
sd.play();
soundList[item.name] = sd;
break;
case "distance":
sound = soundList[item.name];
if (sound != null) {
sound.setDistance(item.distance);
}
break;
case "play":
sound = soundList[item.name];
if (sound != null) {
sound.delete();
sound.create();
sound.setVolume(item.volume);
sound.setDynamic(item.dynamic);
sound.setLocation(item.x, item.y, item.z);
sound.play();
}
break;
case "soundPosition":
sound = soundList[item.name];
if (sound != null) {
sound.setLocation(item.x, item.y, item.z);
}
break;
case "resume":
sound = soundList[item.name];
if (sound != null) {
sound.resume();
}
break;
case"pause":
sound = soundList[item.name];
if (sound != null) {
sound.pause();
}
break;
case "delete":
sound = soundList[item.name];
if (sound != null) {
sound.destroyYoutubeApi();
sound.delete();
delete soundList[item.name];
}
break;
case "repeat":
sound = soundList[item.name];
if (sound != null) {
sound.setTimeStamp(0);
sound.play();
}
break;
case "changedynamic":
sound = soundList[item.name];
if (sound != null) {
sound.unmute()
sound.setDynamic(item.bool);
sound.setVolume(sound.getMaxVolume());
}
break;
case "changeurl":
sound = soundList[item.name];
if (sound != null) {
sound.destroyYoutubeApi();
sound.delete();
sendMaxDurationToClient(item);
sound.setSoundUrl(item.url);
sound.setLoaded(false);
sound.create();
sound.play();
}
break;
case "loop":
sound = soundList[item.name];
if (sound != null) {
sound.setLoop(item.loop);
}
break;
case "unmuteAll":
IsAllMuted = false;
for (let soundName in soundList) {
sound = soundList[soundName];
if (sound.isDynamic()) {
sound.unmuteSilent();
}
}
updateVolumeSounds();
if (!updateVolumeSoundTimer) {
updateVolumeSoundTimer = setInterval(addToCache, 1000);
}
if (!updateCacheTimer) {
updateCacheTimer = setInterval(updateVolumeSounds, refreshTime);
}
break;
case "muteAll":
IsAllMuted = true;
for (let soundName in soundList) {
sound = soundList[soundName];
if (sound.isDynamic()) {
sound.mute();
}
}
clearInterval(updateVolumeSoundTimer);
clearInterval(updateCacheTimer);
updateVolumeSoundTimer = null;
updateCacheTimer = null;
break;
}
})
});
function between(loc1, loc2) {
const deltaX = loc1[0] - loc2[0];
const deltaY = loc1[1] - loc2[1];
const deltaZ = loc1[2] - loc2[2];
return Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ);
}
function addToCache() {
if (!IsAllMuted) {
closeToPlayer = [];
let sound = null;
for (const soundName in soundList) {
sound = soundList[soundName];
if (sound.isDynamic()) {
const distance = between(playerPos, sound.getLocation());
const distance_max = sound.getDistance();
if (distance < distance_max + 40) {
closeToPlayer.push(sound);
} else {
if (sound.loaded()) {
sound.mute();
}
}
}
}
}
}
function updateVolumeSounds() {
if (!IsAllMuted) {
for (let sound of closeToPlayer) {
if (sound && sound.isDynamic()) {
const distance = between(playerPos, sound.getLocation());
const distance_max = sound.getDistance();
if (distance < distance_max) {
sound.updateVolume(distance, distance_max);
} else {
sound.mute();
}
}
}
}
}