Animation Cache System

Hello, i need feedback on my Animation Cache System so i can see what needs to improve/change thanks.

AnimationService.__index = AnimationService
local Players = game:GetService("Players")
AnimationService._cache = setmetatable({}, {__mode="k"})
AnimationService._globalCache = {}

AnimationService.Debug = true

local TrackWrapper = {}
TrackWrapper.__index = TrackWrapper

local function debugLog(...)
	if AnimationService.Debug then
		print("[AnimationService]", ...)
	end
end

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
		debugLog("Animation stopped:", animId, "for", character.Name)
	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)
	if self._track then
		self._track:Stop(fadeTime or 0.1)
	end
	self._isPlaying = false
	debugLog(self._animId, "stopped for", self._character.Name, "| Fade:", fadeTime or 0.1)
end

function TrackWrapper:Destroy()
	if self._conn then
		self._conn:Disconnect()
		self._conn = nil
	end
	self._cacheTable[self._animId] = nil
	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 or not AnimationInstance then return 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(FadeTime or 0.1)
				return
			end
		end
	end
end


function AnimationService.StopAll(Character, FadeTime)
	if not Character then return end
	
	local charCache = AnimationService._cache[Character]
	if charCache then
		for _, wrapper in pairs(charCache) do
			wrapper:Stop(FadeTime or 0.1)
		end
	end
	local Animator = GetAnimator(Character)
	if Animator then
		for _, track in ipairs(Animator:GetPlayingAnimationTracks()) do
			track:Stop(FadeTime)
		end
	end
end

Players.PlayerRemoving:Connect(function(player)
	local char = player.Character
	if char then
		local charCache = AnimationService._cache[char]
		if charCache then
			for _, wrapper in pairs(charCache) do 
				wrapper:Destroy() 
			end
		end

		AnimationService._cache[char] = nil
	end
end)

workspace.ChildRemoved:Connect(function(child)
	local charCache = AnimationService._cache[child]
	if charCache then
		for _, wrapper in pairs(charCache) do 
			wrapper:Destroy()
		end

		AnimationService._cache[child] = nil
	end
end)
return AnimationService

Can you please stop spamming same exact post across every category? Hello?