I’ve created an animation syncing system, but the issue is that it’s hard to prevent stack overflows due to the recursive nature of how these work.
Basically, one player can sync with another, and that player can sync with another, so when the third player does an animation, it will recurse its way down to the third player.
This is my code:
local Animations = {}
local AnimationsTable = require(game:GetService("ReplicatedStorage").Shared.Animations)
local PlayerAnimations = {} -- Dictionary of Animations. Key = Player, Value = AnimationTrack
local Tracks = {} -- Dictionary of AnimationTracks. Key = Player, Value = AnimationTrack
local Synced = {} -- Dictionary of Synced, Key = Player, Value = Array of Players
local ManipulationCache = {}
local AnimationCaches = {}
local function GetNumbers(Str)
local FirstTry = tonumber(Str)
if FirstTry then return FirstTry end
local Cached = table.find(ManipulationCache, Str)
if Cached then return Cached end
local Final = tonumber(Str:match("%d+"))
ManipulationCache[Str] = Final
return Final
end
function GetAnimationIdByName(NameString)
for _, AnimInfo in pairs (AnimationsTable) do
if AnimInfo.Name == NameString then
return AnimInfo.ID
end
end
end
function Animations.GetPlayerTrack(Player)
return Tracks[Player]
end
function Animations.Sync(Player, PlayerToSyncWith)
if not Player or not PlayerToSyncWith then return end
if Animations.IsPlayerSyncingWith(PlayerToSyncWith, Player) then return end
Animations.CompleteUnsync(Player)
if Player == PlayerToSyncWith then
return
end
if not Synced[PlayerToSyncWith] then
Synced[PlayerToSyncWith] = {}
end
table.insert(Synced[PlayerToSyncWith], Player)
local PlayerAnimation = Animations.GetPlayerTrack(PlayerToSyncWith)
if PlayerAnimation then
Animations.PlayAnimation(PlayerToSyncWith, GetNumbers(PlayerAnimation.Animation.AnimationId))
end
end
function Animations.CompleteUnsync(SpecifiedPlayer, Stop)
for Player, PlayersSyncedWithThem in pairs (Synced) do
local Found = table.find(PlayersSyncedWithThem, SpecifiedPlayer)
if Found then
table.remove(PlayersSyncedWithThem, Found)
Synced[Player] = PlayersSyncedWithThem
end
end
if Stop then
Animations.StopAnimation(SpecifiedPlayer)
end
end
function Animations.IsPlayerSyncingWith(PlayerToCheck, HostPlayer)
if not Synced[HostPlayer] then Synced[HostPlayer] = {} end
return table.find(Synced[HostPlayer], PlayerToCheck)
end
function Animations.PlayAnimation(Player, Id, Original)
if Original then
Animations.CompleteUnsync(Player)
end
if Id then
if PlayerAnimations[Player] and Original then
if GetNumbers(PlayerAnimations[Player].AnimationId) == Id then
Animations.StopAnimation(Player)
local SyncedPlayers = Synced[Player]
if SyncedPlayers and #SyncedPlayers > 0 then
for i = 1, #SyncedPlayers do
Animations.StopAnimation(SyncedPlayers[i])
end
end
return true
end
end
Animations.StopAnimation(Player)
local New = Instance.new("Animation")
New.AnimationId = "rbxassetid://" .. Id
local Character = Player.Character
if not Character then return end
local Humanoid = Character:FindFirstChildOfClass("Humanoid")
if not Humanoid then return end
local Animator = Humanoid.Animator
PlayerAnimations[Player] = New
if not AnimationCaches[Player] then
AnimationCaches[Player] = {}
end
local Track = AnimationCaches[Player][Id]
if not Track then
Track = Animator:LoadAnimation(New)
AnimationCaches[Player][Id] = Track
end
Tracks[Player] = Track
Track:Play()
local SyncedPlayers = Synced[Player]
if SyncedPlayers and #SyncedPlayers > 0 then
for i = 1, #SyncedPlayers do
Animations.PlayAnimation(SyncedPlayers[i], Id)
end
end
end
end
function Animations.StopAnimation(Player)
local Track = Tracks[Player]
if Track then Track:Stop() end
PlayerAnimations[Player] = nil
Tracks[Player] = nil
end
function Animations.ClearCachedLoadedAnimations(Player)
AnimationCaches[Player] = nil
end
return Animations
As you can see I have the function Animations.IsPlayerSyncingWith
to use to make sure that a player can’t sync with someone who is syncing with them. However , this boolean isn’t always reliable because the player could be syncing with someone ELSE who is syncing with them, which makes it very hard to detect and abort these cases which will cause stack overflows. As you can see it’s happened before:
I’m looking for the best way to stop these cases. Any help is appreciated.