Is it possible to wait for an instance to be added to a table?


Elaboration

I want to add a Animation Instance to a table inside a script; then be able to read the keyframes of the animation to fire a function at a certain point of the animation.

My issue is, every time I try this; the connection comes back nil on the first attempt. This makes the entire function break.

That’s the code that creates and successfully adds the animation instance to a table with its own name.

This is the function that i’m trying to run;

This is the connection I’m speaking of; on the first attempt to connect to this instance, it comes up nil.


Local Script

Here’s the function that keeps breaking.

							Connections["Animations"]["FT-Slapshot"].KeyframeReached:Connect(function(keyframeName)
								warn(keyframeName)
								if string.lower(keyframeName) == string.lower("Pow") then
									game.ReplicatedStorage.Events.MovementListener:FireServer("Shoot",TableOfInfo)
									warn("Fired Puck!")
									Debounces["Movement Debounces"].MouseButton1 = false
									--Module.ClearAnimations(humanoid)
								end
							end)

Well, yeah;

repeat
    task.wait()
until Connections["Animations"]["FT-Slapshot"]

But I don’t see how this is running before you even load the animations? When are you loading them in the script?

When the event Variables.RemoteEvents.CommunicatorEvent:FireServer("Server Animation Finder","With Puck","PowerStop",false), it calls to the server to get the AnimationId, name and so on; then fires the same event to the Client to play the Animation on the client side. That’s what the Client Animation Player is for.

It plays the Animation, and adds the instance to the table.

But why don’t you load the animations on the client instead of asking the server? That just sounds overcomplicated.

I am, however I store all the Animation Info on the Server; including its speed, which type of Character Rig, etc… My issue is, I have to add the instances to a table on the local script for me to be able to pause them, and play them properly; but when i try to connect to these instances after they’re added; they don’t connect.

But why? Can’t you just have the client know all the information about the animation by having it in ReplicatedStorage or something? This type of programming just introduces annoying race conditions like this.

Yes, however I’d like to prevent exploiters from messing with the Module Script and editing… as I have the speeds stored on the Module… if they edit that; it will effect all players as it would be visible to all clients.

With this, I still have to add the instance to a table either way to show the animation loaded.

But they can’t replicate to anything that can’t be physically simulated, i.e. they can’t edit animations, values, server-scripts, workspace properties etc.

This type of visual stuff should be visible to the client directly, to prevent input lag etc.

I have to reference Humanoid.Animator:LoadAnimation(NewAnimation) for whatever animation i’m trying to edit, so that way I’m able to pause, and stop an animation; in a different function , or argument.

A good example of this would be, if you want someone to hold a sword up in an animation and hold it while their mouse button 1 is held down, then when the mouse button is released; you have to send that load animation info to the InputEnded function to break the other animation, and play another/ or continue the animation to strike the enemy.

The issue with this is, the game I’m working on is to be competitive. So if the person has an animation speed of .1 for shooting a Hockey Puck, that’ll give them an advantage; which will likely disinterest people from playing the game.

I may end up putting the Info of the animations on the Client, however I’d still have the same issue.

They already have that advantage? The client is still the one telling the server when the hockey puck should actually hit the puck and fling it, it would be no different in that specific example.

You shouldn’t be tying core gameplay features to animations on the client in a competitive game, if it’s so competitive then the server should be the one monitoring the animation and the client should just be loading it in and playing it for the looks.

I’m not sure what you’re trying to say here, but you can just call :Stop.

None of this is improving your game’s security, it just opens up avenues for race conditions (which I guarantee will create more bugs down the line), and input lag for the normal player.

I highly recommend you look at how animations work and how to actually secure your game.

I tried that, it's very redundant. Read more
if inputState == true then
	local AnimTrack = character.Humanoid.Animator:LoadAnimation("AnimationHere")
	AnimTrack:Play()
elseif inputState == false then
	AnimTrack:Stop()
	Debounces["Movement Debounces"].Right = false
end

Lets use the above code as an example, if I play the animation track when the Input Begins; you are unable to reference AnimTrack in the InputEnd Function.

Now, lets say you load the AnimationTrack in each function;

if inputState == true then
	local AnimTrack1 = character.Humanoid.Animator:LoadAnimation("AnimationHere")
	AnimTrack1:Play()
elseif inputState == false then
	local AnimTrack1,AnimTrack2 = character.Humanoid.Animator:LoadAnimation("AnimationHere"),character.Humanoid.Animator:LoadAnimation("AnimationHere")
	AnimTrack1:Stop()
	AnimTrack2:Play()
	Debounces["Movement Debounces"].Right = false
end

Now you have an extra line of redundant code that is only needed for one line of code. Why not create a system that could hold these values that you could reference when needed and then they get removed?

You are correct, I’m already in process of this.

You aren’t suppose to use animations like this, Animators have a cap on how many animations can be loaded at once (256).

Edit: The statement about the cap doesn’t actually make any sense now that I look into it, Animators cache the animation data so loading the same animation over and over won’t incur any memory issues or animation limit issues, so my question now is just why you’ve used a local variable, because you’re effectively doing something like this;

if value then
    local mycomplicatedvalue = 123
    doSomething(mycomplicatedvalue)
else
    local mycomplicatedvalue = 123
    doAnotherThing(mycomplicatedvalue)
end

And then saying that there’s no way around it, when you could just do this;

local mycomplicatedvalue = 123

if value then
    doSomething(mycomplicatedvalue)
else
    doAnotherThing(mycomplicatedvalue)
end

You *should* just be doing;
local MyAnim = Humanoid.Animator:LoadAnimation(script.Animation)

if InputState then -- the same as InputState == true
    MyAnim:Play()
else
    MyAnim:Stop()
end

That’s exactly what i’m trying to do though,

Okay so, the connections animation table is meant to store the Instances of these animations being played. That’s why in the Client Animation Table; I add an instance to the Connection Animation table with the Animation Name being the header, and the actual Instance of the LoadAnimation being what the name connects to.

Connections["Animations"][AnimationInfo["Animation Name"]] = AnimTrack does this exact thing. The issue is; when I try to reference this Instance, it comes back nil. Which is impossible because the animation is playing before the function begins.

That’s my problem, I’m going to rework the animations entirely to be fully loaded on the client like you’ve recommended as I do agree; animations should be controlled by the client 98% of the time. However, my issue still occurs sadly.

When you read this, i’ll probably have redone my entire post to match the issue at hand once I go through and update the code a bit.

Also, if you want to know why I’m adding animation instances to the table;

I wanted their to be a way to add any Animation to a table that could be referenced by the entire script at any time. That way; I don’t have to create any extra variables above… the animation player will do that for me.

If you want wait the instance to be added use:

repeat wait() until Connections["Animations"]["FT-Slapshot"] ~= nil

if want wait it to load use:

repeat wait() until Connections["Animations"]["FT-Slapshot"] ~= nil and Connections["Animations"]["FT-Slapshot"].AnimationTrack.Length > 0

If you want do it more fast use task.wait()

Thank you @Judgy_Oreo & @Migu_VT for responding, however it was neither of those issues.

It was simply a Roblox Keyframe issue, more so the fact that they don’t really work.

I had to replace it with a Heartbeat connection that would be timed and run the function when I needed it to run.

What was the error? I thought it was an “attempt to index nil with .KeyframeReached”, so I don’t understand how it’s a keyframe issue if the animation itself just doesn’t exist in the dictionary.

The issue was that the KeyframeReached is a very faulty system; it only works half the time… everything else was working perfectly fine; it was simply that the KeyframeReached isn’t fully operational. To fix it, I had to create a Heartbeat connection once the Animation was fired to wait for a certain amount of time, then fire and break the connection.