Your current script is very vulnerable. You are relying on the client for crucial game data (which is very bad), and you are doing no validation of data server side. Never trust the client for anything.
If you are using a tool for this, you can detect an activation of the tool and find the closest field the player is in. You could add attributes, names, etc. to each field of different flower types and raycast downwards from the player when you suspect a field change, or just use a .Touched
event for a BasePart
.
As for the events themselves, I would recommend making your own class similar to RBXScriptSignal
for event changing things. It’d be better than bindables.
local CustomEvent = {}
CustomEvent.__index = CustomEvent
--current events
CustomEvent.Events = {}
--class constructor
function CustomEvent.new(name: string): Event
local self = setmetatable({}, CustomEvent)
--set data about the event
self.Callbacks = {}
self.Fired = false
--add to the module of events
CustomEvent.Events[name] = self
--return the new event
return self
end
--waiting for a signal to exist
function CustomEvent:WaitForEvent(name: string): Event?
local Signal
local attempt = 0
repeat
Signal = self.Events[name]
attempt += 1
task.wait(1)
if attempt == 5 then
warn("Yielded for signal 5+ seconds")
end
until
Signal or attempt == 60
return Signal
end
--replicating RBXScriptSignal's :Connect function
function CustomEvent:Connect(callback: (any?) -> (nil)): nil --the given callback should not return a value
--add an asynchronous version of the given callback to be run
table.insert(self.Callbacks, callback)
end
--to fire your custom event
function CustomEvent:Fire(...:any?): nil -- '...' is data to be sent to the connected callbacks
local extraData = {...} --get extra data into a table
--run each callback
for _, callback: (any?) -> (nil) in next, self.Callbacks, nil do
--an asynchronous version of the callback was added so we can just run it normally
task.spawn(callback, table.unpack(extraData))
end
end
--type for custom event
--I didn't include inherited things that won't be used
export type Event = {
["Connect"]: (self: Event, (any?) -> (nil),
["Fire"]: (self: Event, any?) -> (nil),
["Callbacks"]: {(any?) -> (nil)}
["Fired"]: boolean
}
return CustomEvent
An example use for your game:
local players = game:GetService("Players")
local Event = require(game:GetService("ServerScriptService")["FinishWithYourPathHere"])
--create a new event for when a player enters a new field
local FieldEvent = Event.new("PlayerFieldChanged")
local fields = {}
--now, every time a player changes field, you can store it
--example use in a player's raycast using suggestions I mentioned earlier:
--'fields' holds the current field of each player
local function checkNewField(field:string, hit:BasePart)
local player = players:GetPlayerFromCharacter(hit.Parent)
if player and fields[player.Name] ~= field then
fields[player.Name] = field
FieldEvent:Fire(player, field)
end
end
for _, field in next, fields, nil do
field.Touched:Connect(function(hit)
checkNewField(field.Name, hit)
end)
end
Another script can receive this:
local Event = require(game:GetService("ServerScriptService")["FinishWithYourPathHere"])
local function onFieldChanged(player: Player, newField: string)
print(`@{player.Name} entered field: {newField}`)
end
event.Events.PlayerFieldChanged:Connect(onFieldChanged)
Another example use for listening for a player collecting pollen:
local players = game:GetService("Players")
local Event = require(game:GetService("ServerScriptService")["FinishWithYourPathHere"])
local CollectEvent = Event.new("PlayerCollectPollen")
players.PlayerAdded:Connect(function(player: Player)
local char = player.Character or player.CharacterAdded:Wait()
local backpack = player.Backpack
local tool = backpack:WaitForChild("ToolName", 5) or char:WaitForChild("ToolName", 5)
tool.Activated:Connect(function()
CollectEvent:Fire(player) --custom event saves a lot of scripts holding memory references to the tool
end)
end)
Event.Events.PlayerCollectPollen:Connect(function(player: Player)
print("Player @"..player.Name.." requested to collect pollen.")
end)
This structure could be applied to the things you mentioned you wanted to do.