Make Animation in Client Distinct to in Server

It’s possible to make an animation that is running in the client distinct than the other running in the server? Like I want to make two different animations, however one shows only for the local player and the other shows for all players except the local player.

1 Like

Any animation played on the client will replicate to the server. I think you could get around this by removing the Animator from the humanoid and creating a new one locally, however this would only allow you to play animations on the client.

Therefore, achieving this effect is impossible?

This is entirely possible, you would first have to delete an Animator (if it exists) inside the Humanoid and replace it from the client. This way the animation won’t be replicated to the server.

And how about the other where it’d be played for the server? I’ve wanted like one playing only for the client player, and another distinct one playing for all players except the localplayer.

Playing for the server is the easiest, you just have to make sure an Animator exists in the server. After that any animation played (regardless if it is a client script or server script) will be replicated to all.

local EquipAnimTrackServer = Humanoid:LoadAnimation(EquipAnimServer)
local Animator = Humanoid:FindFirstChild("Animator")
if Animator then
	Animator:Destroy()
end

local NewAnimator = Instance.new("Animator", Humanoid)

local EquipAnimTrack = NewAnimator:LoadAnimation(EquipAnim)
local SnipeAnimTrack = NewAnimator:LoadAnimation(SnipeAnim)

...
EquipAnimTrack:Play()	
EquipAnimTrackServer:Play()
...

Only the client can see the animation now.

I see that you are attempting the destruction and creation of the Animator at the same server / local script.

  1. If you want it to be replicated to the client you have to delete the Animator from the server and create it from the client.
  2. If you want it to be replicated to both the server and the client you can simple use :LoadAnimation() on the Animator.
1 Like
local RemoveAnimator = game:GetService("ReplicatedStorage"):WaitForChild("RemoveAnimator")
RemoveAnimator:FireServer()

local NewAnimator = Instance.new("Animator", Humanoid)

local EquipAnimTrackServer = Humanoid:LoadAnimation(EquipAnimServer)
local EquipAnimTrack = NewAnimator:LoadAnimation(EquipAnim)
local SnipeAnimTrack = NewAnimator:LoadAnimation(SnipeAnim)

..
EquipAnimTrackServer:Play()
EquipAnimTrack:Play()
..

Same thing again.

I quickly made these scripts and it seems to work fine for me, make sure you are correctly waiting until the players character fully loads in.

Server script:

game.ReplicatedStorage.asd.OnServerEvent:Connect(function(player)
	local character = player.Character
	character:FindFirstChild("Humanoid"):FindFirstChildOfClass("Animator"):Destroy()
end)

Local script:

local event = game.ReplicatedStorage:WaitForChild("asd")

local player = game.Players.LocalPlayer
repeat task.wait() until player.Character
local char = player.Character

event:FireServer()

local Animator = Instance.new("Animator", char:WaitForChild("Humanoid"))

local anim = Instance.new("Animation")
anim.AnimationId = "rbxassetid://180426354"

while task.wait() do
	local Animation = Animator:LoadAnimation(anim)
	Animation:Play()
	Animation.Ended:Wait()
end

No… You didn’t understand what I want. I’ve wanted like two different animations, one playing in the client (localplayer only) and other playing for the server (all players, they are different)

Ah so 2 animations at the same character except one is replicated locally and the other one is replicated to the server without being replicated to the client? I am not sure if this is possible but I will let you know if so.

1 Like

Its possible but you would have to work around how Animator works. Animator replicates all animations played on client to the server, meaning if you delete it from either the server or the client, client will stop replicating all animations to the server. You could create your own replication system but it wouldn’t be easy.

I believe if you play animations on the player from the server, the client itself wont see the animation being played on them, but other players should be able to see it. You could use this for the server part of the animation, however the moment you play animation on the client it will play over the one you played on the server (you could maybe get around this with animation priorities).

One hacky solution that comes to mind is to listen to new animations being played on the server and if you detect the animation you want only played on the client, you can just stop it:

local clientAnimationId = "rbxassetid://YOUR_ANIM_ID"
local serverAnimation = path.to.server.animation

--when character is added get their animator
local humanoid = character:WaitForChild("Humanoid")
local animator = humanoid:WaitForChild("Animator")

--from the server you can play animation for other players
local serverAnim = animator:LoadAnimation(serverAnimation)
serverAnim:Play()

--you also connect to the AnimationPlayed event to detect when new animations are played
animator.AnimationPlayed:Connect(function(newAnim)
	if newAnim.Animation.AnimationId ~= clientAnimationId then return end
	newAnim:Stop() --only stop the animation if it has the Id of the client animation
end)

This is probably not the best way to do this (mostly because AnimationPlayed will detect any new animation played), but it should give you the idea of how this works.

There is a little issue with your script, the original animator which is inside the Humanoid is replicated to the server aswell meaning any action you do will also be replicated to the server.

I have managed to rewire @realmile 's method to fit your needs.

Local script:


local player = game.Players.LocalPlayer
repeat task.wait() until player.Character
local char = player.Character
local Animator = char:WaitForChild("Humanoid"):WaitForChild("Animator")

local anim = Instance.new("Animation")
local animationId = "rbxassetid://180426354"
anim.AnimationId = animationId

Animator.AnimationPlayed:Connect(function(anim)
	if anim.Animation.AnimationId ~= animationId then
		anim:Stop()
	end
end)

while task.wait() do
	local Animation = Animator:LoadAnimation(anim)
	Animation:Play()
	Animation.Ended:Wait()
end

Server:

game.Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(character)
		local Animator = character:WaitForChild("Humanoid"):WaitForChild("Animator")
		local anim = Instance.new("Animation")
		local animationId = "rbxassetid://125750702"
		anim.AnimationId = animationId
		Animator.AnimationPlayed:Connect(function(anim)
			if anim.Animation.AnimationId ~= animationId then
				anim:Stop()
			end
		end)
		while task.wait() do
			local Animation = Animator:LoadAnimation(anim)
			Animation:Play()
			Animation.Ended:Wait()
		end
	end)
end)

Realmile should get the credit here. The old method can still be used as this method will constantly try to stop the animation instead of destroying it on the client however I have found this method more effective than mine.

Thats why we use AnimationPlayed to detect when new animations are being played, if its the animation we only want played on the client, we simply stop it from the server. This should cancel the animation for other players, while not stopping it for the client who played it.

But it outputs:

 Cannot load the AnimationClipProvider Service.  -  Client - Animate:260
  15:45:06.364  Stack Begin  -  Studio
  15:45:06.365  Script 'Workspace.Rapture_TY.Animate', Line 260 - function playAnimation  -  Studio - Animate:260
  15:45:06.365  Script 'Workspace.Rapture_TY.Animate', Line 356 - function onRunning  -  Studio - Animate:356
  15:45:06.365  Stack End  -  Studio

Can you please provide me with the script?

Sure
LocalScript:

local event = game.ReplicatedStorage:WaitForChild("asd")

local ClientFolder = script.Client
local EquipAnim = ClientFolder.EquipAnim
local Tool = script.Parent
local LocalPlayer = game.Players.LocalPlayer
repeat task.wait() until LocalPlayer.Character
local Character = LocalPlayer.Character
local Humanoid = LocalPlayer.Character:WaitForChild("Humanoid")
local DefaultCameraMaxZoom = StarterPlayer.CameraMaxZoomDistance

local Animator = Instance.new("Animator", Humanoid)

Character:WaitForChild("Humanoid").ChildAdded:Connect(function(instance)
	if instance:IsA("Animator") then
		instance:Destroy()
	end
end)

local isEquipped = false

local EquipAnimation = Animator:LoadAnimation(EquipAnim)

Tool.Equipped:Connect(function()
	isEquipped = true
	...
	event:FireServer(true)
	while task.wait() and isEquipped do
		EquipAnimation:Play()
		EquipAnimation.Ended:Wait()
	end
end)

Tool.Unequipped:Connect(function()
	isEquipped = false
       ...
	if CurrentCamera then
                ...
		EquipAnimation:Stop()
		event:FireServer(false)	
               ...
	end
end)

Server:

game.ReplicatedStorage.asd.OnServerEvent:Connect(function(player, active)
	local character = player.Character
	character:FindFirstChild("Humanoid"):FindFirstChildOfClass("Animator"):Destroy()
	task.wait()
	local newAnimator = Instance.new("Animator", character:WaitForChild("Humanoid"))

	local EquipAnimation = newAnimator:LoadAnimation(script.EquipAnim)
	
	while task.wait() and active do
		EquipAnimation:Play()
		EquipAnimation.Ended:Wait()
	end
	if not active then
		EquipAnimation:Stop()
	end
end)

(I know I need to store the animation task for each player, it’s just a test now)

I think the issue is that the Animator gets destroyed.
image

1 Like