What Is The Optimal Way to Handle Animations that use GetMarkerReachedSignal to trigger Remotes?

Hey developers, sorry if this in the wrong category. So I’ve been working with animations and their GetMarkerReachedSignal events, and I’ve been using remotes to replicate effects when certain markers are reached in animations. However, I’ve been struggling with trying to get some effects sync up with the animations that replicate to the server automatically from the client, and I’m wondering I should refactor parts of my code to be more consistent. The problem is this: When I run an animation on the client and then display some sort of particle, sound, or other effect based on a marker being hit, the effect operates how it should be. The effect is shown by firing a RemoteEvent at the marker, which then replicates the effect to the rest of the clients in the game (but not the server). However, when other clients see someone perform an animation with an effect, the effect is “desynced,” and looks like it triggers before the animation reaches it’s particular marker. Here’s an example of a taunt animation for my game:

This is what my client sees when I taunt. The sparkle and trail effect are normal!

However, when another client views someone taunting, you can see that the sparkle sometimes pops in too early and the trail stops early.

And to just to clarify, here’s what the server sees. It doesn’t see any of these effects because they don’t replicate to the server.

Now, I’ve tried not replicating these effects to the clients and just doing them on the server, but the same problem still arises, so that idea was scratched. I believe what is happening is that because the server animations are typically never in sync with what the client sees (the replicated server animations lag behind the client animation), when the client hits it’s specific marker to trigger effects, the effects display still without considering the server animations.

To show what I’m doing in the code, here’s the section that deals with the taunt effect:

tauntTrack:GetMarkerReachedSignal("Trail"):Connect(function(enabled)
	if enabled == "true" then
		replicatedWorkerModule.enableEffectObjects({object = swordTrail, state = true})	
		replicatedWorkerModule.playSound(rootPart, "199145204", 0.5, 0.9)
	else
		replicatedWorkerModule.enableEffectObjects({object = swordTrail, state = false}, 
													{object = sparkle, emit = 1},
													{object = wave, emit = 1},
													{object = flare, emit = 1})	
		replicatedWorkerModule.playSound(rootPart, "4108911043", 0.8, 1, 0.5)
	end
end)

My overall goal is to remove the “delay” between the replicated server animation and the effect and make the replicated server animation be in sync with the effect. Would it be a wise idea to add GetMarkerReachedSignal events server-sided as well and then use the RemoteEvent from there? And if that’s the case, would it be better to just have the majority of the animations run server-sided? Or would it be better to have each client render every other client’s animations, and simply don’t trust the server replicated animations? I’m kind of stuck at a crossroads right now, and I don’t want to continue ahead until I have a definitive answer on what I should do (I don’t want to refactor the code again lol). Any suggestion is helpful! Thanks for reading.

7 Likes

What I would do is to check locally for when someone’s Humanoid plays an animation by connecting to the Humanoid.AnimationPlayed (also has a good example on the API page) event for each character then see if the animationTrack name equals a specific name like the taunt animation name and connect a function with the effects to the animationTrack.KeyframeReached event to sync it locally for each client.

Doing this you won’t have to deal with networking.

9 Likes

Personally, I would just do it all on the server–tell the server when a player is taunting and have both the animation and effects be run from there. You’ll still get a tiny bit of latency since you’re using a remote, but I’m fairly certain that the animation and effects will be in sync with one another across all clients if they’re both run from the server.

I would propose this if doing so wouldn’t feel unresponsive for the person who fires it due to the delay. ‘Responsiveness’ > ‘server-client synchronization’ especially for these kind of animations where it doesn’t affect any object nor player by doing so. My method was entirely focused on responsiveness.

1 Like

My bad, didn’t mean to reply to your post (actually, I hadn’t even read yours when I made my response). Your idea’s definitely better in terms of responsiveness, which is probably what @Kyles45678 is shooting for anyways, especially since these are solely cosmetics :+1:

I just went ahead and tested this by creating a local script for every player, and when a player detects when someone’s humanoid plays an animation with Humanoid.AnimationPlayed, there were some interesting results.

With Humanoid.AnimationPlayed, a client will be able to tell what animation tracks are playing on their character. However, if another client tries to read another player’s humanoid’s animations played, the returning animation track sent though is simply named “Animation” and that’s it. There’s no way to differentiate between what animations are playing. I think it’s because the animation track itself isn’t replicated across client to server. I also testing doing Humanoid.AnimationPlayed on a server script as well and the same results occurred.

I fear what I’m going to have to do instead is play animations locally on the requesting player, and then tell other clients to replicate the animation manually with remote events (something I really don’t want to do because I want to take advantage of Roblox’s automatic client to server animation replication).

I’m trying stray away from using AnimationTrack.KeyframeReached just because GetMarkerReachedSignal superseded it and KeyframeReached is basically deprecated as far as I know.

And yeah, to clarify, responsiveness comes first. I tried the idea @ChefJustice proposed in an earlier build, but I figured the delay between input and move was far to great for a fighting game like this.

Oh, yes I actually did mean :GetMarkerReachedSignal - I switched tabs a lot when I wrote the post and might’ve confused the two with each other. You could, however, use :GetMarkerReachedSignal on all played animations as it won’t make a change unless the corresponding Marker is reached.

3 Likes

I just tested it and surprisingly markers still activate! This is helpful, as I could now just tell other clients to wait for animations to be played and do effects when they see a certain marker get triggered on another player’s animation! It seems kind of wacky though that we can still see the markers but not the actual name of the animation on other clients. Thanks for the help!