Help with cleaning and fixing emote system

So i have an emote system, And this emote system has been alot of trouble, And i have made a few posts needing help with it before, But im hoping this is the last post i have to make about it.

So currently, On the client, Upon pressing G, It fires a remote event, And the server handles it, by requiring a module script, and telling it to emote, Then it makes your character emote.

Problem 1
The client has a cooldown, and sometimes assumes that they stopped emoting, even if the remote event fire hasn’t reached the server, So sometimes when you try to stop emoting too quickly, You won’t stop, since the cooldown on the server hasn’t finished, Therefore, you have to reset or rejoin.

Problem 2
Possible memory leak, When you tell the server to emote, Then it will save that animation instance inside a table, and a bool value in a different table for cooldown checking (isnt an instance, just True or False), When you stop emoting, It checks for the animation in the table, and then stops it, But also checks if you are on cooldown. Now, the problem is that if you’re character is removed, or you leave the game, Your animation AND bool stay in their tables, So the table can just fill up.

Here is the code.
Client:

game:GetService("UserInputService").InputBegan:Connect(function(input, isTyping)
	if input.KeyCode == Enum.KeyCode.G and not onemotecooldown then
		if not playinganemote and char.IsEmoting.Value == false then
			if onemotecooldown then return end
			if not playinganemote then
				onemotecooldown = true
				EmoteRE:FireServer(true, emotename, char)
				playinganemote = true
				task.wait(2)
				onemotecooldown = false
			end
		end
		if playinganemote and not onemotecooldown then
			onemotecooldown = true
			EmoteRE:FireServer(false, nil, char)
			playinganemote = false
			task.wait(2)
			onemotecooldown = false
		end
	end
end)

Server:


EmoteRE.OnServerEvent:Connect(function(plr, startemote, emotename, character)
	if character == nil or startemote == nil then return end
	if startemote == true then
		if emotename ~= nil then
			emotemodule.Emote(emotemodule, startemote, emotename, character)
		end
	elseif startemote == false then
		emotemodule.Emote(emotemodule, startemote, emotename, character)
	end
end)

Module script:

local animtable = {}
local oncooldowntable = {}
function module:Emote(startemote, emotename, character)
	if character and not oncooldowntable[character] then
		if startemote == true and emotename ~= nil then
			oncooldowntable[character] = true
			local emote = --get emote object
			animtable[character] = character:WaitForChild("Humanoid"):LoadAnimation(emote)
			task.wait(2)
			oncooldowntable[character] = false
		end
		if startemote == false and animtable[character] ~= nil then
			oncooldowntable[character] = true
			animtable[character]:Stop()

			task.wait(2)
			oncooldowntable[character] = false
		end
	end
end

Animations loaded via localscripts will replicate to all clients so there is not much of a need to use remote events.

When it comes to cooldowns, etc. I’d just create a local debounce. You could go with your approach and insert the animation in a table and whenever G is pressed check if either debounce is true or there is a instance in the table.

When handling stop emoting, you could insert the animation into a table and when stopping emoting you could loop through the table and call stop on the emote, or you could create a global variable which whenever you emote, you could set the global variable to the animation and when you want to stop you could just use the global variable to stop emoting.

Emotes have music, And sometimes props, So yes, The remote event is needed.

Players could just use exploits to remove that cooldown, so they could just spam emotes.

Bumping because i still need help.

And bumping again, Still not sure how to fix this