How to implement global sound from local script?

Hey! I believe I’ve bottlenecked myself a little bit when it comes to playing sounds at the beginning of my ability. Of course, it works fine with an animation starting the ability because that gets replicated to everyone but the sound does not. I guess this is sort of a follow up to this post from earlier today: How to make secure cooldown for local script?

To refresh, my ability first gets called from a local script, then it gets sent to a server script for validation and then if the validation is true the information gets passed into a VFX handler for processing. This is mostly well but again, it feels like i’ve bottlenecked myself a little bit when it comes to adding VFX in the MIDDLE of attacks because of the GetMarkerReachedSignal method I am currently using.

To state the current question: I have this animation with a whoosh sound effect that plays at the start.


Which this obviously plays on the local player, but will not replicate to others.

I know the solution is to fit it somewhere into my FireAllClients call but where exactly? What can I rewrite to make this better so I don’t get bottlenecked with how my animations and VFX work?
Ability: (Local Script)

local function hitboxEffects() --Function that creates hitbox and fires server for hit validation
	
	local hrp = pChar:FindFirstChild("HumanoidRootPart")

	local hitbox = Instance.new("Part")
	local hitCharacters = {}
	local parameters = OverlapParams.new()
	hitbox.Shape = Enum.PartType.Ball
	hitbox.CanCollide = false
	hitbox.CanTouch = false
	hitbox.CanQuery = false
	hitbox.Anchored = true
	hitbox.Transparency = 0.5
	
	local pos = hrp.CFrame * CFrame.new(0, 0, 0) --Changes location of hitbox on creation
	local size = Vector3.new(15, 15, 15) --Changes size of hitbox on creation

	hitbox.CFrame = pos
	hitbox.Size = size
	hitbox.Parent = workspace

	local cf = pos
	local size = hitbox.Size

	parameters.FilterDescendantsInstances = {pChar}

	local hitboxPart = workspace:GetPartBoundsInBox(pos, size, parameters)

	local vTable = {}

	for _, hitPart in pairs(hitboxPart) do
		local vHum = hitPart.Parent:FindFirstChild("Humanoid")
		if vHum and not table.find(vTable, hitPart.Parent) then
			table.insert(vTable, hitPart.Parent)
		end
	end

	slamRemote:FireServer(vTable)
	game.Debris:AddItem(hitbox, 0.1)
	
end

--Hitbox is created on the client for WYSIWYG flow. We will need checks on the server side for exploit purposes
UIS.InputBegan:Connect(function(input, gameProcessed)
	
	if gameProcessed then
		return
	end
	
	if input.KeyCode == Enum.KeyCode.Q and canUseAbility then 
		
		canUseAbility = false
		whooshSound:Play() --POST QUESTION: I want this to play to everyone in the game 
		slam:Play()
		
		task.delay(cooldown, function()
			canUseAbility = true
		end)		
	end
end)

slam:GetMarkerReachedSignal("Knockback"):Connect(hitboxEffects)

Ability Validation: (Server Script)

slamRemote.OnServerEvent:Connect(function(plr, vTable)


	local validHit = validationModule.HitValidation(plr, vTable, slamVFX, 3, 20, 360) --Validation is sent to a module script 

	if #validHit >= 1 then

		local pChar = plr.Character
		local pHum = pChar:FindFirstChild("Humanoid")
		local hrp = pChar:FindFirstChild("HumanoidRootPart")
		local pDirection = hrp.CFrame.LookVector

		print(pChar)
		for _, vChar in pairs (validHit) do

			local vrp = vChar:FindFirstChild("HumanoidRootPart")

			task.delay(0, function() --Allows all knockback to be applied at the same time
				knockbackModule.knockbackAttributes(plr, hrp, vChar, vrp, 50, 0, 30, 0) --Knockback attributes of ability
			end)

		end

		print("Hit Validated")
	else
		return
	end
end)

VFX Handler: (Local Script)

slamVFX.OnClientEvent:Connect(function(pChar, hitChars)
	
	local hrp = pChar:FindFirstChild("HumanoidRootPart")
	
	local rocksClone = rocksEffect:Clone()
	local primaryRock = rocksClone.PrimaryPart
	
	slamSound:Play()
	shakeModule.smallShake(pChar, 0.5)
	
	for _, effect in pairs (explosionEffect) do
		local effectClone = effect:Clone()
		effectClone.Parent = primaryRock
	end
	
	local rockTweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Sine, Enum.EasingDirection.Out, 0, false, 0)
	local rockTweenProperties = {
		["CFrame"] = hrp.CFrame + Vector3.new(0,-3,0)
	}
	local rockTween = TS:Create(primaryRock, rockTweenInfo, rockTweenProperties)

	rocksClone:PivotTo(hrp.CFrame + Vector3.new(0,-5,0))
	rocksClone.Parent = workspace
	
	rockTween:Play()
	
	task.delay(1.5, function()
		rocksClone:Destroy()
	end)		

end)

I keep finding one minor issue after another and I don’t know how to remedy them fully on my own. But that’s apart of the scripting process! If there is a better way to write this please let me know and thanks!

Sooo what I’m getting of your question is the following:

You have built a Roblox ‘slam’ ability that (A) starts on the client, (B) fires a hit-validation request to the server, and (C) then plays VFX back on clients when the server says, “hit confirmed.” That flow works fine… except your initial “whoosh” sound is only playing locally (on the player who fired the ability) anddd you want everyone in the game to hear that whoosh as soon as you press Q.

Soooo you’re asking where do you put your Sound:Play() so that it replicates to all players? And is there a cleaner way to structure your ability (animation markers, hitbox, server validation, cooldowns, etc.) so you’re not bottlenecked by one GetMarkerReachedSignal call?

I think you can split it into remote events instead with the following steps

  1. Client presses Q → the client just asks the server “can start slam??” (no sound or animation yet).
  2. The server checks cooldown, and if OK, immediately broadcasts a “play activation VFX” event (or similar) to all clients. Each client then clones and plays the whoosh sound at the attacker’s HumanoidRootPart and starts off the slam animation on that attacker’s Humanoid.
  3. When the slam animation’s “Knockback” marker fires on the attacker’s client, that local client spawns the hit-box and fires a “hasHit” RemoteEvent back to the server for validation.
  4. Once the server confirms hits (and alsoooo applies knockback), it fires a second “play impact VFX” event to all clients. Each client then spawns the rock chunks, impact sound, camera shake, and all that jazz., at the attacker’s position.

Now you have:

  • ActivateAbility [Remote] (client → server),
  • PlayActivationVFX [Remote] (server → all clients),
  • HasHit [Remote] (client → server),
  • PlayHitVFX [Remote] (server → all clients),

no more cramming allatat into the getmarker function ^.^

So is this a situation where I would have 3 different remote functions? I’m trying to do it with 2 currently.

You can just play sound inside workspace on server btw