Mastering Event-Driven Architecture
Let’s talk about some good patterns for bug-free programming.
Imagine that you have Inventory in your game mode.
You should store player items on the server-side/database to avoid hacking.
Now let’s look at the example code below:
Inventory = { }
function Inventory.ConsumeFood()
TriggerServerEvent('gamemode:consumeFood') -- We should check if a player has enough food etc.
end
AddEventHandler('gamemode:onFoodConsumed', function(consume)
if not consume then return end -- 'consume' is a boolean flag which indicates if a player can actually consume food
Inventory.DoConsumeFood() -- Actual stuff like restoring player health etc.
end)
This code has a few potential issues.
Let’s fix it step by step.
This code allows to consume food multiple times at once.
The fix is really easy - just use a boolean flag to check if the consuming process is already in progress.
Inventory.IsConsumingFood = false
function Inventory.ConsumeFood()
if Inventory.IsConsumingFood then
return false
end
Inventory.IsConsumingFood = true
TriggerServerEvent('gamemode:consumeFood')
return true -- You could even return a boolean to check if it was actually triggered
end
But what if a player has died while we’re waiting for the server result?
You should always think about events and any functions with Citizen.Wait(ms)
call in asynchronous way.
As for this problem, you should not forget to reset your consuming boolean flag at appropriate place.
AddEventHandler('playerSpawned', function()
Inventory.CancelConsuming()
end)
-- It is better to use a helper function for future items like Bandages, Drinks etc.
function Inventory.CancelConsuming()
Inventory.IsConsumingFood = false
end
AddEventHandler('gamemode:onFoodConsumed', function(consume)
if not consume or not Inventory.IsConsumingFood then return end
Inventory.DoConsumeFood()
end)
It would be also a good idea to actually cancel consuming on the server-side.
function Inventory.CancelConsuming()
if Inventory.IsConsumingFood then
TriggerServerEvent('gamemode:cancelConsumingFood')
end
Inventory.IsConsumingFood = false
end
And yes - that is all for now.
Please leave comments so I could add more detailed information or even write another tutorial.
Thank you for your attention!