Detect when a Player Emotes (works with R6 & R15)

I wanted a script that detects when a Player emotes. I couldn’t find any solutions for this, so I made my own.

Server Script:

local Players = game:GetService("Players")

-- we only use this array for R15 avatars, because R6 avatars do not store these
local defaultDances = {
	"cheer",
	"dance",
	"dance2",
	"dance3",
	"laugh",
	"point",
	"wave"
}

local function urlToId(animationId: string): string
	animationId = string.gsub(animationId, "http://www%.roblox%.com/asset/%?id=", "")
	animationId = string.gsub(animationId, "rbxassetid://", "")
	return animationId
end

local function isGivenAnimation(animationHolder: StringValue, animationId: string): boolean
	for _, animation: Animation in animationHolder:GetChildren() do
		if urlToId(animation.AnimationId) == animationId then
			return true
		end
	end

	return false
end

local function isDancing(character: model, animationTrack: AnimationTrack): boolean
	--[[
	afiak, it isn't possible to obtain animationIds of player Emotes efficiently
	HumanoidDescription:GetEmotes() returns the Asset IDs of emotes, which is not what we want
	instead, this function does a process of elimination to determine if the animationId is a dance animation or not
	
	because everything in defaultDances are not descendants of R6 characters:
	this function will return true if the player does any "/e" emote in R6, such as "/e cheer"
	--]]

	local animationId = urlToId(animationTrack.Animation.AnimationId)
	local isR15 = character.Humanoid.RigType == Enum.HumanoidRigType.R15
	
	-- emotes from the emote wheel are not children of the Animate script,
	-- so we can do a process of elimation to determine if it's an emote
	for _, animationHolder: StringValue in character.Animate:GetChildren() do
		local sharesAnimationId = isGivenAnimation(animationHolder, animationId)
		
		if isR15 then
			local isDance = sharesAnimationId and table.find(defaultDances, animationHolder.Name)
			-- the given animationId is from a default /e emote
			if isDance then
				return true
			end
		end

		if sharesAnimationId then
			-- this is just a normal character animation
			return false
		end
	end
	
	-- the given AnimationId was not a descendant of the Animate script, so it must be an emote
	return true
end

local function onCharacterAdded(character: Model)
	local humanoid: Humanoid = character.Humanoid
	local animator: Animator = humanoid.Animator

	animator.AnimationPlayed:Connect(function(animationTrack)
		print(isDancing(character, animationTrack)) --> boolean
	end)
end

local function onPlayerAdded(player: Player)
	player.CharacterAdded:Connect(onCharacterAdded)
end

for _, player: Player in Players:GetPlayers() do
	task.spawn(onPlayerAdded, player)
end

Players.PlayerAdded:Connect(onPlayerAdded)

This is my first Community Resource. If you have any feedback, let me know.

5 Likes