I am trying to let players stream out when out of streaming distance.
However, from time to time, players stream in correctly, but animations that were playing while the player was loading in don’t get “replicated” correctly.
Checking the animator instance inside their humanoid and looking into GetPlayingAnimationTracks, it seems that the animations seem to be “suspended”, where the AnimationTracks are playing (IsPlaying is set to true), but the TimeLength is 0 (even if their TimePosition can be above 0), indicating it hasn’t loaded for some reason, even though it should be playing. The client is aware of these animations but hasn’t “applied” them to the humanoid as if they haven’t loaded yet.
Yes, the game has access to the animations, as it plays them just fine when the player has not streamed out yet.
I tried to make the game just reload the animation, but that means the other player is no longer in “control” of that AnimationTrack and it just plays independently, and doesn’t start/stop as it should.
Any ideas?
edit: clarification about the state of the animationtracks
Messing around I kind of found a “hack” for that. Can’t say it’s full proof however only used it once.
You can try setting the Parent of the Animator to nil and back to the Humanoid to force a refresh of the animator subsystem.
Well, the animation system doesn’t automatically re-sync or re-apply the animation timeline state.
A reload can correct that, but the sync is pretty touchy. I am a noob when it comes to this, even though I understand the problem with what’s happening. I can write you a minimal sample code for such a server/client sync system for animations, but I’m sure someone else can do it better.
I needed to strip out a few things here, for an example.
This is one I was working on but gave up and went to no streaming.
Server
in ServerScriptService
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local AnimEvent = Instance.new("RemoteEvent", ReplicatedStorage)
AnimEvent.Name = "AnimEvent"
local animations = {
Wave = Instance.new("Animation"),
Dance = Instance.new("Animation"),
}
animations.Wave.AnimationId = "rbxassetid://WAVE_ANIMATION_ID"
animations.Dance.AnimationId = "rbxassetid://DANCE_ANIMATION_ID"
local players = game:GetService("Players")
local playerTracks = {}
players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(char)
playerTracks[player] = {}
AnimEvent:FireClient(player, "StopAll")
end)
end)
function playAnim(player, animName)
if not playerTracks[player] then playerTracks[player] = {} end
if playerTracks[player][animName] then return end
playerTracks[player][animName] = true
AnimEvent:FireClient(player, "Play", animName, animations[animName].AnimationId)
end
function stopAnim(player, animName)
if playerTracks[player] then
playerTracks[player][animName] = nil
AnimEvent:FireClient(player, "Stop", animName)
end
end
-- Example:
players.PlayerAdded:Connect(function(player)
wait(5) playAnim(player, "Wave")
wait(10) stopAnim(player, "Wave")
end)
Client
in StarterPlayerScripts
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local AnimEvent = ReplicatedStorage:WaitForChild("AnimEvent")
local players = game:GetService("Players")
local player = players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local humanoid = char:WaitForChild("Humanoid")
local animator = humanoid:WaitForChild("Animator")
local tracks = {}
AnimEvent.OnClientEvent:Connect(function(action, animName, animId)
if action == "Play" then
if tracks[animName] then return end
local anim = Instance.new("Animation")
anim.AnimationId = animId
local track = animator:LoadAnimation(anim)
tracks[animName] = track
track:Play()
elseif action == "Stop" then
if tracks[animName] then
tracks[animName]:Stop()
tracks[animName]:Destroy()
tracks[animName] = nil
end
elseif action == "StopAll" then
for _, track in pairs(tracks) do
track:Stop()
track:Destroy()
end
tracks = {}
end
end)
player.CharacterAdded:Connect(function(c)
char = c
humanoid = char:WaitForChild("Humanoid")
animator = humanoid:WaitForChild("Animator")
for _, track in pairs(tracks) do
track:Stop()
track:Destroy()
end
tracks = {}
end)