Hello, i made a Animation Cache System about 2 months ago and there was been issues happening weeks later and when i play Animations Using the Cache system Sometimes it dosent not play at all, then it plays the second time and so on. And sometimes the Animation glitches First time play but when i first made it i didnt encounter such issues and Yes i preloaded and played the animations on a dummy and stopped it. I would appreciate the Help Thanks!
AnimationService.__index = AnimationService
AnimationService._cache = setmetatable({}, {__mode="k"})
AnimationService._globalCache = {}
AnimationService.Debug = true
local TrackWrapper = {}
TrackWrapper.__index = TrackWrapper
function TrackWrapper.new(track, character, animId, cacheTable)
local self = setmetatable({}, TrackWrapper)
self._track = track
self._character = character
self._animId = animId
self._cacheTable = cacheTable
self._priority = track.Priority
self._isPlaying = false
self._conn = track.Stopped:Connect(function()
self._isPlaying = false
end)
return self
end
function TrackWrapper:Play(fadeTime, weight, speed)
fadeTime = fadeTime or 0.1
weight = weight or 1
speed = speed or 1
self._track.Priority = self._priority
self._track:AdjustSpeed(speed)
self._track:Play(fadeTime)
self._track:AdjustWeight(weight, fadeTime)
self._isPlaying = true
if AnimationService.Debug then
print(string.format("[DEBUG][Play] %s playing for %s | Speed: %.2f | Weight: %.2f | Fade: %.2f",
self._animId, self._character.Name, speed, weight, fadeTime))
end
end
function TrackWrapper:Stop(fadeTime)
fadeTime = fadeTime or 0
if self._track then
self._track:Stop(fadeTime)
end
self:Destroy()
self._isPlaying = false
if AnimationService.Debug then
print(string.format("[DEBUG][Stop] %s stopped for %s | Fade: %.2f",
self._animId, self._character.Name, fadeTime))
end
end
function TrackWrapper:Destroy()
if self._conn then
self._conn:Disconnect()
self._conn = nil
end
if self._cacheTable then
self._cacheTable[self._animId] = nil
end
if self._track then
self._track:Destroy()
self._track = nil
end
self._isPlaying = false
if AnimationService.Debug then
print("[DEBUG][Destroy] Wrapper destroyed for", self._animId)
end
end
function TrackWrapper:__index(key)
local track = rawget(self, "_track")
if TrackWrapper[key] then
return TrackWrapper[key]
end
if track and typeof(track[key]) == "function" then
return function(_, ...)
return track[key](track, ...)
end
end
if track and track[key] ~= nil then
return track[key]
end
return rawget(TrackWrapper, key)
end
local function GetAnimator(Character)
if not Character then return nil end
local Humanoid = Character:FindFirstChildOfClass("Humanoid")
if Humanoid then
local Animator = Humanoid:FindFirstChildOfClass("Animator")
if not Animator then
Animator = Instance.new("Animator")
Animator.Parent = Humanoid
end
return Animator
end
local AnimationController = Character:FindFirstChildOfClass("AnimationController")
if AnimationController then
local Animator = AnimationController:FindFirstChildOfClass("Animator")
if not Animator then
Animator = Instance.new("Animator")
Animator.Parent = AnimationController
end
return Animator
end
return nil
end
local function GetTrack(animId, Animator, AnimationInstance)
if not AnimationService._globalCache[animId] then
AnimationService._globalCache[animId] = {
instance = AnimationInstance,
_lastUsed = os.clock(),
}
if AnimationService.Debug then
print("[DEBUG][GlobalCache] Added animation:", animId)
end
else
AnimationService._globalCache[animId]._lastUsed = os.clock()
if AnimationService.Debug then
print("[DEBUG][GlobalCache] Reusing animation:", animId)
end
end
return Animator:LoadAnimation(AnimationService._globalCache[animId].instance)
end
local function countKeys(tbl)
local count = 0
for _ in pairs(tbl) do
count += 1
end
return count
end
task.spawn(function()
while task.wait(600) do
local now = os.clock()
local keys = {}
for animId in pairs(AnimationService._globalCache) do
table.insert(keys, animId)
end
local BATCH_SIZE = 20
for i = 1, #keys, BATCH_SIZE do
for j = i, math.min(i + BATCH_SIZE - 1, #keys) do
local animId = keys[j]
local data = AnimationService._globalCache[animId]
if data._lastUsed and (now - data._lastUsed > 1200) then
AnimationService._globalCache[animId] = nil
if AnimationService.Debug then
print("[DEBUG][GlobalCache] Removed unused animation:", animId)
end
end
end
task.wait(0.05)
end
end
end)
function AnimationService.new(Character, AnimationInstance, Priority, Looped, Speed, FadeTime)
if not Character or not AnimationInstance then return end
local Animator = GetAnimator(Character)
if not Animator then return end
local animId = AnimationInstance.AnimationId
AnimationService._cache[Character] = AnimationService._cache[Character] or {}
local charCache = AnimationService._cache[Character]
local Wrapper = charCache[animId]
if not Wrapper then
local Track = GetTrack(animId, Animator, AnimationInstance)
if Looped ~= nil then Track.Looped = Looped end
Wrapper = TrackWrapper.new(Track, Character, animId, charCache)
charCache[animId] = Wrapper
if AnimationService.Debug then
print("[DEBUG][CharacterCache] Added track for character:", Character.Name, animId)
end
else
if Priority then
Wrapper._priority = Priority
end
if AnimationService.Debug then
print("[DEBUG][CharacterCache] Reusing track for character:", Character.Name, animId)
end
end
Wrapper:Play(FadeTime, nil, Speed)
if AnimationService.Debug then
print(string.format("[DEBUG] Player '%s' animation cache size: %d | Global cache size: %d",
Character.Name,
countKeys(charCache),
countKeys(AnimationService._globalCache)))
end
return Wrapper
end
function AnimationService.StopAnimation(Character, AnimationInstance, FadeTime)
if not Character then
warn("Wheres the characr")
end
local animId = AnimationInstance.AnimationId
local charCache = AnimationService._cache[Character]
if charCache and charCache[animId] then
charCache[animId]:Stop(FadeTime)
else
local Animator = GetAnimator(Character)
if not Animator then return end
for _, track in ipairs(Animator:GetPlayingAnimationTracks()) do
if track.Animation == AnimationInstance then
track:Stop()
return
end
end
end
end
function AnimationService.StopFolderAnimations(Character, Folder, FadeTime)
local charCache = AnimationService._cache[Character]
if charCache then
for animId, wrapper in pairs(charCache) do
if wrapper._track.Animation:IsDescendantOf(Folder) then
wrapper:Stop(FadeTime)
end
end
end
local Animator = GetAnimator(Character)
if Animator then
for _, track in ipairs(Animator:GetPlayingAnimationTracks()) do
if track.Animation:IsDescendantOf(Folder) then
track:Stop(FadeTime or 0.1)
end
end
end
end
function AnimationService.StopAll(Character, FadeTime)
if not Character then return end
local charCache = AnimationService._cache[Character]
if charCache then
for animId, wrapper in pairs(charCache) do
wrapper:Stop(FadeTime)
end
end
local Animator = GetAnimator(Character)
if Animator then
for _, track in ipairs(Animator:GetPlayingAnimationTracks()) do
track:Stop(FadeTime or 0.1)
end
end
AnimationService._cache[Character] = nil
end
local Players = game:GetService("Players")
Players.PlayerRemoving:Connect(function(player)
local char = player.Character
if char then
AnimationService._cache[char] = nil
end
end)
game:GetService("Workspace").ChildRemoved:Connect(function(child)
if AnimationService._cache[child] then
AnimationService._cache[child] = nil
end
end)
return AnimationService```