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

[Question] Random Fires only with dispatch system and starting fire from another script? #39

Open
Ma-Ko-dev opened this issue Jun 13, 2024 · 3 comments
Labels
enhancement New feature or request good first issue Good for newcomers question Further information is requested

Comments

@Ma-Ko-dev
Copy link

Hi!

first i want to say i like this firescript, i especially like the spreading feature!
My first question is about the random fires. I read that random fires will only spawn if i activate the build in dispatch system. Is this right or did i misunderstood something there?

I am currently using Emergency Dispatch and of course i want to use this instead of another Dispatch system to alarm my players :D

My second question is pretty simple. Is it possible to start a fire from another script? If so - how?

@gimicze
Copy link
Owner

gimicze commented Jun 13, 2024

Hey,

As the code is right now, you need to use the dispatch system. However, if you're not afraid of a bit of coding, you could easily modify the following code section so that it only uses method Dispatch:addFirefighter() instead of Dispatch:subscribe(). I now see that I could have written it in a way that basically wouldn't require players to be sent the dispatch notifications, etc. but too late I guess 😄

firescript/server/main.lua

Lines 576 to 650 in e7f25ee

--================================--
-- AUTO-SUBSCRIBE --
--================================--
if Config.Dispatch.enabled then
local allowedJobs = {}
local firefighterJobs = {}
if Config.Dispatch.enableFramework then
if type(Config.Dispatch.jobs) == "table" then
for k, v in pairs(Config.Dispatch.jobs) do
allowedJobs[v] = true
end
else
allowedJobs[Config.Dispatch.jobs] = true
end
firefighterJobs = Config.Fire.spawner.firefighterJobs or allowedJobs
end
if Config.Dispatch.enableFramework == 1 then
ESX = exports["es_extended"]:getSharedObject()
AddEventHandler(
"esx:setJob",
function(source)
local xPlayer = ESX.GetPlayerFromId(source)
if allowedJobs[xPlayer.job.name] then
Dispatch:subscribe(source, firefighterJobs[xPlayer.job.name])
else
Dispatch:unsubscribe(source)
end
end
)
AddEventHandler(
"esx:playerLoaded",
function(source, xPlayer)
if allowedJobs[xPlayer.job.name] then
Dispatch:subscribe(source, firefighterJobs[xPlayer.job.name])
else
Dispatch:unsubscribe(source)
end
end
)
elseif Config.Dispatch.enableFramework == 2 then
AddEventHandler(
'QBCore:Server:PlayerLoaded',
function(Player)
if Player.PlayerData.job.onduty and allowedJobs[Player.PlayerData.job.name] then
Dispatch:subscribe(Player.PlayerData.source, firefighterJobs[Player.PlayerData.job.name])
end
end
)
AddEventHandler(
'QBCore:Server:OnJobUpdate',
function(source, job)
if allowedJobs[job.name] and job.onduty then
Dispatch:subscribe(source, firefighterJobs[job.name])
else
Dispatch:unsubscribe(source)
end
end
)
AddEventHandler(
'QBCore:Server:OnPlayerUnload',
function(source)
Dispatch:unsubscribe(source)
end
)
end
end

Using the Dispatch:addFirefighter() function will not send any dispatch notifications to the specified player but will count them towards the spawner criteria (see this part of code, notice it uses Dispatch:firefighters() which simply returns number of players registered as firefighters).

It is possible to start a fire from another script - though I haven't written much events nor provide any exports to use, you could use the ExecuteCommand native. The list of things you could achieve with this approach will probably be limited - one major problem with this is you will not have access to list of scenarios, etc. You could bypass this by creating a function similar to getSharedObject from ESX, which would pass the Fire class, and then exporting this function and using the Fire class in any resource.

In case you need to know hot certain commands work, they should all be defined here:

firescript/server/main.lua

Lines 55 to 459 in e7f25ee

--================================--
-- COMMANDS --
--================================--
RegisterNetEvent('fireManager:command:startfire')
AddEventHandler(
'fireManager:command:startfire',
function(coords, maxSpread, chance, triggerDispatch, dispatchMessage)
if not Whitelist:isWhitelisted(source, "firescript.start") then
sendMessage(source, "Insufficient permissions.")
return
end
local _source = source
local maxSpread = (maxSpread ~= nil and tonumber(maxSpread) ~= nil) and tonumber(maxSpread) or Config.Fire.maximumSpreads
local chance = (chance ~= nil and tonumber(chance) ~= nil) and tonumber(chance) or Config.Fire.fireSpreadChance
local fireIndex = Fire:create(coords, maxSpread, chance)
sendMessage(source, "Spawned fire #" .. fireIndex)
if triggerDispatch then
if Config.Dispatch.toneSources and type(Config.Dispatch.toneSources) == "table" then
TriggerClientEvent('fireClient:playTone', -1)
end
Citizen.SetTimeout(
Config.Dispatch.timeout,
function()
if Config.Dispatch.enabled and not Config.Dispatch.disableCalls then
if dispatchMessage then
Dispatch:create(dispatchMessage, coords)
else
Dispatch.expectingInfo[_source] = true
TriggerClientEvent('fd:dispatch', _source, coords)
end
end
end
)
end
end
)
RegisterNetEvent('fireManager:command:registerscenario')
AddEventHandler(
'fireManager:command:registerscenario',
function(coords)
if not Whitelist:isWhitelisted(source, "firescript.manage") then
sendMessage(source, "Insufficient permissions.")
return
end
local scenarioID = Fire:register(coords)
sendMessage(source, "Created scenario #" .. scenarioID)
end
)
RegisterNetEvent('fireManager:command:addflame')
AddEventHandler(
'fireManager:command:addflame',
function(scenarioID, coords, spread, chance)
if not Whitelist:isWhitelisted(source, "firescript.manage") then
sendMessage(source, "Insufficient permissions.")
return
end
local scenarioID = tonumber(scenarioID)
local spread = tonumber(spread)
local chance = tonumber(chance)
if not (coords and scenarioID and spread and chance) then
return
end
local flameID = Fire:addFlame(scenarioID, coords, spread, chance)
if not flameID then
sendMessage(source, "No such scenario.")
return
end
sendMessage(source, "Added flame #" .. flameID)
end
)
RegisterCommand(
'stopfire',
function(source, args, rawCommand)
if not Whitelist:isWhitelisted(source, "firescript.stop") then
sendMessage(source, "Insufficient permissions.")
return
end
local fireIndex = tonumber(args[1])
if not fireIndex then
return
end
if Fire:remove(fireIndex) then
sendMessage(source, "Stopping fire #" .. fireIndex)
TriggerClientEvent("pNotify:SendNotification", source, {
text = "Fire " .. fireIndex .. " going out...",
type = "info",
timeout = 5000,
layout = "centerRight",
queue = "fire"
})
end
end,
false
)
RegisterCommand(
'stopallfires',
function(source, args, rawCommand)
if not Whitelist:isWhitelisted(source, "firescript.stop") then
sendMessage(source, "Insufficient permissions.")
return
end
Fire:removeAll()
sendMessage(source, "Stopping fires")
TriggerClientEvent("pNotify:SendNotification", source, {
text = "Fires going out...",
type = "info",
timeout = 5000,
layout = "centerRight",
queue = "fire"
})
end,
false
)
RegisterCommand(
'removeflame',
function(source, args, rawCommand)
if not Whitelist:isWhitelisted(source, "firescript.manage") then
sendMessage(source, "Insufficient permissions.")
return
end
local scenarioID = tonumber(args[1])
local flameID = tonumber(args[2])
if not (scenarioID and flameID) then
return
end
local success = Fire:deleteFlame(scenarioID, flameID)
if not success then
sendMessage(source, "No such fire or flame registered.")
return
end
sendMessage(source, "Removed flame #" .. flameID)
end,
false
)
RegisterCommand(
'removescenario',
function(source, args, rawCommand)
if not Whitelist:isWhitelisted(source, "firescript.manage") then
sendMessage(source, "Insufficient permissions.")
return
end
local scenarioID = tonumber(args[1])
if not scenarioID then
return
end
local success = Fire:deleteScenario(scenarioID)
if not success then
sendMessage(source, "No such scenario.")
return
end
sendMessage(source, "Removed scenario #" .. scenarioID)
end,
false
)
RegisterCommand(
'startscenario',
function(source, args, rawCommand)
if not Whitelist:isWhitelisted(source, "firescript.start") then
sendMessage(source, "Insufficient permissions.")
return
end
local scenarioID = tonumber(args[1])
local triggerDispatch = args[2] == "true"
if not scenarioID then
return
end
local success = Fire:startScenario(scenarioID, triggerDispatch, source)
if not success then
sendMessage(source, "No such scenario.")
return
end
sendMessage(source, "Started scenario #" .. scenarioID)
end,
false
)
RegisterCommand(
'stopscenario',
function(source, args, rawCommand)
if not Whitelist:isWhitelisted(source, "firescript.stop") then
sendMessage(source, "Insufficient permissions.")
return
end
local _source = source
local scenarioID = tonumber(args[1])
if not scenarioID then
return
end
local success = Fire:stopScenario(scenarioID)
if not success then
sendMessage(source, "No such scenario active.")
return
end
sendMessage(source, "Stopping scenario #" .. scenarioID)
TriggerClientEvent("pNotify:SendNotification", source, {
text = "Fire going out...",
type = "info",
timeout = 5000,
layout = "centerRight",
queue = "fire"
})
end,
false
)
RegisterCommand(
'firewl',
function(source, args, rawCommand)
local action = args[1]
local serverId = tonumber(args[2])
if not (action and serverId) or serverId < 1 then
return
end
local identifier = GetPlayerIdentifier(serverId, 0)
if not identifier then
sendMessage(source, "Player not online.")
return
end
if action == "add" then
Whitelist:addPlayer(serverId, identifier)
sendMessage(source, ("Added %s to the whitelist."):format(GetPlayerName(serverId)))
elseif action == "remove" then
Whitelist:removePlayer(serverId, identifier)
sendMessage(source, ("Removed %s from the whitelist."):format(GetPlayerName(serverId)))
else
sendMessage(source, "Invalid action.")
end
end,
true
)
RegisterCommand(
'firewlreload',
function(source, args, rawCommand)
Whitelist:load()
sendMessage(source, "Reloaded whitelist from config.")
end,
true
)
RegisterCommand(
'firewlsave',
function(source, args, rawCommand)
Whitelist:save()
sendMessage(source, "Saved whitelist.")
end,
true
)
RegisterCommand(
'firedispatch',
function(source, args, rawCommand)
local action = args[1]
local serverId = tonumber(args[2])
if not (action and serverId) or serverId < 1 then
return
end
if action == "scenario" then
if not Fire.scenario[serverId] then
sendMessage(source, "The specified scenario hasn't been found.")
return
end
table.remove(args, 1)
table.remove(args, 1)
Fire.scenario[serverId].message = next(args) and table.concat(args, " ") or nil
Fire:saveScenarios()
sendMessage(source, ("Changed scenario's (#%s) dispatch message."):format(serverId))
else
local identifier = GetPlayerIdentifier(serverId, 0)
if not identifier then
sendMessage(source, "Player not online.")
return
end
if action == "add" then
Dispatch:subscribe(serverId, (not args[3] or args[3] ~= "false"))
sendMessage(source, ("Subscribed %s to dispatch."):format(GetPlayerName(serverId)))
elseif action == "remove" then
Dispatch:unsubscribe(serverId, identifier)
sendMessage(source, ("Unsubscribed %s from the dispatch."):format(GetPlayerName(serverId)))
else
sendMessage(source, "Invalid action.")
end
end
end,
true
)
RegisterCommand(
'randomfires',
function(source, args, rawCommand)
if not Whitelist:isWhitelisted(source, "firescript.manage") then
sendMessage(source, "Insufficient permissions.")
return
end
local _source = source
local action = args[1]
local scenarioID = tonumber(args[2])
if not action then
return
end
if action == "add" then
if not scenarioID then
sendMessage(source, "Invalid argument (2).")
return
end
Fire:setRandom(scenarioID, true)
sendMessage(source, ("Set scenario #%s to start randomly."):format(scenarioID))
elseif action == "remove" then
if not scenarioID then
sendMessage(source, "Invalid argument (2).")
return
end
Fire:setRandom(scenarioID, false)
sendMessage(source, ("Set scenario #%s not to start randomly."):format(scenarioID))
elseif action == "disable" then
Fire:stopSpawner()
sendMessage(source, "Disabled random fire spawn.")
elseif action == "enable" then
Fire:startSpawner()
sendMessage(source, "Enabled random fire spawn.")
else
sendMessage(source, "Invalid action.")
end
end,
false
)
RegisterCommand(
'setscenariodifficulty',
function(source, args, rawCommand)
if not Whitelist:isWhitelisted(source, "firescript.manage") then
sendMessage(source, "Insufficient permissions.")
return
end
local scenarioID = tonumber(args[1])
local difficulty = tonumber(args[2])
if not scenarioID or not difficulty or difficulty < 0 then
sendMessage(source, "Invalid argument")
return
end
local message = Fire:setScenarioDifficulty(scenarioID, difficulty) and ("Scenario #%s set to difficulty %s"):format(scenarioID, difficulty) or ("Scenario #%s doesn't exist"):format(scenarioID)
sendMessage(source, message)
end
)

Refer to the wiki page as well, but it is dated and it probably isn't written very clearly. Hopefully this will help you - there is a lot of areas in which the script could and maybe even should be improved, but I don't have the time to do so (feel free to track your changes here on GitHub and publish a pull request :-).

@gimicze gimicze added enhancement New feature or request good first issue Good for newcomers question Further information is requested labels Jun 13, 2024
@Ma-Ko-dev
Copy link
Author

Thank you for the helpful reply!

So far, i tested some things on my local server.

Interestingly, i do get fires when i set

Config.Dispatch = {
    enabled = false
    ...
}

Of course i need some scenarios for that, but i do get random fires without the dispatch set to true. I also found out that i can use a pre-created scenario when i want to start a fire from another script (with ExecuteCommand() just like you mentioned, i saw it in the release page a bit later :D). This is of course not 100% ideal, but good enough for the moment.

So what i probably will do is continue some tests locally and later online (if my admin is okay with that :D) before i start to change some stuff (the chat messages for example) and the way players get notified.

I am also thinking of not adding any player or job to the whitelist, since i dont want to allow every firefighter to use the start/stop fire commands, or create scenarios. That would be, in theory, not a problem when i set "players = 0" :D Maybe if we got different "tiers" of whitelist with different things they can do. But thats more of an idea for a new feature and should not be the topic here. Its just a safety thing. Players will abuse that 100% :D

I will give everything a good read when i have more time, even tho i am not very skilled in lua (and i kinda dislike it too :D).
I will probably at least provide some example fire scenarios later for everyone to use :)

@gimicze
Copy link
Owner

gimicze commented Jun 13, 2024

Glad I could help.

I have actually just now found that I was probably thinking of your first question at some point and implemented Config.Dispatch.disableCalls variable, but I completely forgot about it 😄 . So basically, you can enable dispatch in config, add a line under Config.Dispatch which sets disableCalls = true. That way the system will track firefighters according your defined jobs but won't send any dispatch messages. So if you use ESX or QB core, I'd recommend using this approach as it should work as is now.

Config.Dispatch = {
    disableCalls = true,
    enabled = true, -- Set this to false if you don't want to use the default dispatch system
    timeout = 15000, -- The amount of time in ms to delay the dispatch after the fire has been created
    ...

(Example of a few config.lua lines to disable the dispatch messages)

The enabled option actually only enables/disables automatic subscription of players to the dispatch based on their job.

As for whitelist, I didn't want to complicate it. You can bypass the whitelist by using ace permissions, so it might make more sense to utilize them (see this method - it is called at the beginning of every command handler and you can specify the required permission as second argument). The ace permission firescript.all allows the use of every command provided by the script.

The whitelist commands were intended only for situations where you want to let's say temporarily allow non-admin play with the scenarios, etc., thus not for every player (as the spawner would start the fires anyway, so there wouldn't be need for anyone except the admin team to have access to the commands).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request good first issue Good for newcomers question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants