is this possible, i want to play emotes on everyone locally so i can use animation events to sync music with it
Yes! You can use a RemoteEvent on the server and use the method :FireAllClients() to receive data and trigger logic on the client. You’d want to send over the emoting character and an identifier to tell every client what emote you want to play.
I presume the way it works is you have a player start an emote on their client, in which case you’d need to trigger another RemoteEvent on the server from that player’s client. Be a little careful here though, you don’t want it to be possible for a hacker to overload/crash players in the server by spamming the event.
On the client, you’ll need a localscript to receive this ReplicateEmote notification. From there, you can load the animation and audio, then perform the emote once both the animation and audio have loaded.
If you’re simply trying to play an animation with audio at the exact same time, theoretically they will only be desynced the first time the emote is used (*dependant on internet speed), as the animation/audio have not been downloaded to memory yet, and one may take longer to load than the other. Once they’re both loaded, they should both play immediately and thus in sync.
Just fire it to the client when you want to cancel it and keep the animation track cached on the client so you can retrieve it when you want to cancel
Client script:
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local syncAnimationRemote = ReplicatedStorage:WaitForChild("SyncAnimation")
local player = Players.LocalPlayer
local cachedAnimationTracks = {} :: { [number]: AnimationTrack } -- {[animationId]: AnimationTrack}
-- replace this with your custom AnimationController system if it works better for you
local function getAnimator(): Animator?
local character = player.Character
local humanoid = if character then character:FindFirstChildOfClass("Humanoid") else nil
local animator = if humanoid then humanoid:FindFirstChildOfClass("Animator") else nil
return animator
end
-- true state means it should play the animation, false means it should stop
local function onSyncAnimationEvent(state: boolean, animationId: number)
local animator = getAnimator()
if not animator then
return
end
local cachedAnimationTrack = cachedAnimationTracks[animationId]
if not cachedAnimationTrack then
local animation = Instance.new("Animation")
animation.AnimationId = `rbxassetid://{animationId}`
local animationTrack = animator:LoadAnimation(animation)
cachedAnimationTracks[animationId] = animationTrack
cachedAnimationTrack = animationTrack
end
if not cachedAnimationTrack then
return
end
if state == true then
animator:PlayAnimation(cachedAnimationTrack)
return
end
if cachedAnimationTrack.IsPlaying then
animator:StopAnimation(cachedAnimationTrack)
end
end
local function resetCachedAnimations()
cachedAnimationTracks = {}
end
syncAnimationRemote.OnClientEvent:Connect(onSyncAnimationEvent)
player.CharacterAdded:Connect(resetCachedAnimations)
player.CharacterRemoving:Connect(resetCachedAnimations)
Server script:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local syncAnimationRemote = ReplicatedStorage:FindFirstChild("SyncAnimation") or Instance.new("RemoteEvent")
syncAnimationRemote.Name = "SyncAnimation"
syncAnimationRemote.Parent = ReplicatedStorage
local function playAnimationForPlayer(player: Player, animationId: number)
if player and player.Character then
syncAnimationRemote:FireClient(player, true, animationId)
end
end
local function stopAnimationForPlayer(player: Player, animationId: number)
if player and player.Character then
syncAnimationRemote:FireClient(player, false, animationId)
end
end
local function playAnimationForAll(animationId: number)
for _, player in Players:GetPlayers() do
playAnimationForPlayer(player, animationId)
end
end
local function stopAnimationForAll(animationId: number)
for _, player in Players:GetPlayers() do
stopAnimationForPlayer(player, animationId)
end
end
local function triggerEmoteWithMusic(animationId: number, duration: number)
playAnimationForAll(animationId)
task.wait(duration)
stopAnimationForAll(animationId)
end
Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
local sampleAnimationId = 1234567890 -- replace with your animation ID
local duration = 4 -- replace with your animation duration
triggerEmoteWithMusic(sampleAnimationId, duration)
end)
end)
Yep I just coded one, check this out!
BUTTON SCRIPT - Put under your TextButton.
local rep = game:GetService('ReplicatedStorage')
local PlayAnimation = rep:WaitForChild('PlayAnimation')
local button = script.Parent
local animationid = "rbxassetid://8463051688"
button.Activated:Connect(function()
PlayAnimation:FireServer(animationid)
end)
SERVER SCRIPT:
local PlayAnimation = game.ReplicatedStorage:WaitForChild('PlayAnimation')
local PlayAnimationToAllClients = game.ReplicatedStorage:WaitForChild('PlayAnimationToAllClients')
PlayAnimation.OnServerEvent:Connect(function(player, animationid)
PlayAnimationToAllClients:FireAllClients(animationid)
end)
StarterCharacterScripts, - AnimationScript
local rep = game:GetService('ReplicatedStorage')
local PlayAnimationToAllClients = rep:WaitForChild('PlayAnimationToAllClients')
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local animator = humanoid:WaitForChild('Animator')
PlayAnimationToAllClients.OnClientEvent:Connect(function(animationid)
local SwingAnimation = Instance.new("Animation")
SwingAnimation.AnimationId = animationid
local SwingAnimationTrack = humanoid:LoadAnimation(SwingAnimation)
SwingAnimationTrack:Play()
SwingAnimationTrack:GetMarkerReachedSignal("SwingEnd"):Connect(function(paramString)
print(paramString)
end)
end)
WORKSPACE
Note, my animation will not work, as in it’s my animation and it’s private. You have to make your own. But hope this helps!
