PlayerHandler
An easy and simple way to not have to deal with race conditions for player events such as PlayerAdded and CharacterAdded.
Source
please note that the Types are not necessary, it is so you know what everything is. Feel free to remove it if you want to.
--!strict
local Players = game:GetService('Players')
local RunService = game:GetService('RunService')
--> Types (Not necessary but so you know what everything is.)
export type PlayerAddedFunction = (player : Player) -> () -> ()
export type PlayerRemovingFunction = (player : Player) -> () -> ()
export type CharacterAddedFunction = (character : Model, player : Player) -> () -> ()
export type LocalCharacterAddedFunction = (character : Model) -> () -> ()
export type PlayerAddedConnections = {[number] : PlayerAddedFunction}
export type PlayerRemovingConnections = {[number] : PlayerRemovingFunction}
export type CharacterAddedConnections = {[number] : CharacterAddedFunction}
export type Connections = {PlayerAdded : PlayerAddedConnections, PlayerRemoving : PlayerRemovingConnections, CharacterAdded : CharacterAddedConnections}
export type LocalConnections = {[number] : LocalCharacterAddedFunction}
export type PlayerAdded = (fn : (player : Player) -> ()) -> ()
export type PlayerRemoving = (fn : (player : Player) -> ()) -> ()
export type CharacterAdded = (fn : (character : Model, player : Player) -> ()) -> ()
export type LocalCharacterAdded = (fn : (character : Model) -> ()) -> ()
export type players = {player : Player?, character : Model?, LocalCharacterAdded : LocalCharacterAdded?, PlayerAdded : PlayerAdded, PlayerRemoving : PlayerRemoving, CharacterAdded : CharacterAdded}
--> Class
local players = {} :: players
--> Connections
local Connections = {
['PlayerAdded'] = {},
['PlayerRemoving'] = {},
['CharacterAdded'] = {},
} :: Connections
local LocalConnections = {} :: LocalConnections
--> Private
Players.PlayerAdded:Connect(function(player : Player)
for i, v in pairs(Connections.PlayerAdded) do
task.defer(v, player)
end
player.CharacterAdded:Connect(function(character : Model)
for i, v in pairs(Connections.CharacterAdded) do
task.defer(v, character, player)
end
end)
end)
Players.PlayerRemoving:Connect(function(player : Player)
for i, v in pairs(Connections.PlayerRemoving) do
task.defer(v, player)
end
end)
--> Client
if RunService:IsClient() then
players.player = Players.LocalPlayer
function players.LocalCharacterAdded(fn : (character : Model) -> ())
table.insert(LocalConnections, fn)
if players.character ~= nil then
task.defer(fn, players.character)
end
return function()
local index = table.find(LocalConnections, fn)
if index ~= nil then
table.remove(LocalConnections, index)
end
end
end
if players.player.Character ~= nil then
players.character = players.player.Character
end
players.player.CharacterAdded:Connect(function(character : Model)
players.character = character
for i, v in pairs(LocalConnections) do
task.defer(v, character)
end
end)
end
--> Public
function players.PlayerAdded(fn : (player : Player) -> ())
table.insert(Connections.PlayerAdded, fn)
for i, v in pairs(Players:GetPlayers()) do
task.defer(fn, v)
end
return function()
local index = table.find(Connections.PlayerAdded, fn)
if index ~= nil then
table.remove(Connections.PlayerAdded, index)
end
end
end
function players.PlayerRemoving(fn : (player : Player) -> ())
table.insert(Connections.PlayerRemoving, fn)
return function()
local index = table.find(Connections.PlayerRemoving, fn)
if index ~= nil then
table.remove(Connections.PlayerRemoving, index)
end
end
end
function players.CharacterAdded(fn : (Character : Model, player : Player) -> ())
table.insert(Connections.CharacterAdded, fn)
for _, player in pairs(Players:GetPlayers()) do
local character = player.Character
if character ~= nil then
task.defer(fn, character, player)
end
end
return function()
local index = table.find(Connections.CharacterAdded, fn)
if index ~= nil then
table.remove(Connections.CharacterAdded, index)
end
end
end
--> return
return players
Examples
Server:
--!strict
local PlayerHandler = require(game:GetService('ReplicatedStorage').PlayerHandler)
PlayerHandler.PlayerAdded(function(player : Player)
local leaderstats = Instance.new('Folder')
leaderstats.Name = 'leaderstats'
local kills = Instance.new('NumberValue')
kills.Name = 'Kills'
local deaths = Instance.new('NumberValue')
deaths.Name = 'Deaths'
kills.Parent = leaderstats
deaths.Parent = leaderstats
leaderstats.Parent = player
end)
PlayerHandler.CharacterAdded(function(character : Model, player : Player)
local humanoid : Humanoid = character:WaitForChild('Humanoid')
local leaderstats = player:FindFirstChild('leaderstats')
local deaths = leaderstats:FindFirstChild('Deaths')
humanoid.Died:Connect(function()
deaths.Value += 1
end)
end)
Client:
--!strict
local PlayerHandler = require(game:GetService('ReplicatedStorage').PlayerHandler)
local Player = PlayerHandler.player
local disconnectLocalCharacterAdded = PlayerHandler.LocalCharacterAdded(function(character : Model)
local Humanoid : Humanoid = character:WaitForChild('Humanoid')
Humanoid.WalkSpeed = 50
end)
task.wait(5)
disconnectLocalCharacterAdded()
All functions will return a function to “Disconnect”.