Global Spatial Voice Script

EDITED 12/29/23

I decided to recode the entire system. It still works exactly like it did before, but more performant. I’ve upgraded my programming skills. Let me know if anything needs improved.

Before using this, as I said last time. This should still be used with caution. People on Roblox can say whatever they want, whenever they want. And the ban/VC Suspension/Warning isn’t instant! Depending on the game, if you care about the safety of your player base. Don’t use this. It’s a massive safety hazard.

If you want more features. I sort of suggest AsyncMatrix’s VoicechatSDK. I say “sort of” since

  1. It hasn’t been updated in a year.
  2. From when I was using it, for use in a game, it seemed to have problems actually running certain functions the first time. It seemed to have worked if I ran a function not needed once the player joined the game.

Noob version (Explains everything)

--// Variables

local player = game.Players.LocalPlayer --// Get's the LocalPlayer (User running the script)
local RS = game:GetService("RunService")

--// Setting up Fake Character

local Char = Instance.new("Model") --// Create a model to act as our character.
Char.Name = "GlobalVCRoute" --// Name our new Fake Character.
local Humanoid = Instance.new("Humanoid",Char) --// To have it act as a character we need a fake controller.
local Root = Instance.new("Part",Char) --// Here's a Root for our controller.
Root.Name = "HumanoidRootPart" --// This isn't needed but Humanoid usually hooks on to this name.
Char.PrimaryPart = Root --// This just sets the Root as the main part for the controller.

--// Setup for players currently in the server

function SetupPlayer(v:Player)
	--// Anti-Old
	if v:FindFirstChild("GlobalVCRoute") then v:FindFirstChild("GlobalVCRoute"):Destroy() end --// If they already have a VCModel then delete it, we'll recreate it below.
	RS:UnbindFromRenderStep(v.UserId.."_RunFakeCharacter") --// Ensure there is not a BindToRender already. If so, let's just kill it.
	--// Setup Fake Character for Use
	local Chara = Char:Clone() --// Clone our Fake Character
	Chara.Name = v.UserId --// Set it's name to our players userid, so we can find it easily.
	Chara.Parent = v
	--// Binding to Camera Render
	RS:BindToRenderStep(v.UserId.."_RunFakeCharacter",Enum.RenderPriority.Camera,function() --// Create a loop that runs every camera tick. We can unbind it later once the player leaves to save performance.
		if Chara ~= nil then --// Check if our VCRoute exists (Anti-error activity)
			Chara:WaitForChild("HumanoidRootPart").CFrame = game.Workspace.CurrentCamera.CFrame --// Set the Root of our Fake Character, that acts like the VC player, to our Camera CFrame.
		else
			RS:UnbindFromRenderStep(v.UserId.."_RunFakeCharacter") --// If our VCRoute get's deleted unexpectly, we won't want this stuck on.
		end
	end)
	--// Assigning
	v.Character = Chara --// Set the players fake character.
	v.CharacterAdded:Connect(function(char) --// Run every time the player spawns in
		v.Character = Chara --// Set the players fake character every time they spawn in.
	end)
end

for i,v in pairs(game.Players:GetChildren()) do --// Loop through every player already in the game once
	if v ~= player then --// Block the LocalPlayer
		SetupPlayer(v) --// We will use our function above to set them up.
	end
end

--// Setup new Players

game.Players.PlayerAdded:Connect(function(plr) --// Detect when a new player joins the game.
	SetupPlayer(plr) --// We will use our function above to set them up.
end)

--// Detect leaving players

game.Players.PlayerRemoving:Connect(function(plr) --// Detect when a player, already in the server, is leaving.
	RS:UnbindFromRenderStep(plr.UserId.."_RunFakeCharacter") --// Let's unbind our loop to save memory.
end)

Gamer version (No Annoying notes)

--// Variables

local player = game.Players.LocalPlayer
local RS = game:GetService("RunService")

--// Setting up Fake Character

local Char = Instance.new("Model")
Char.Name = "GlobalVCRoute"
local Humanoid = Instance.new("Humanoid",Char)
local Root = Instance.new("Part",Char)
Root.Name = "HumanoidRootPart"
Char.PrimaryPart = Root

--// Setup for players currently in the server

function SetupPlayer(v:Player)
	--// Anti-Old
	if v:FindFirstChild("GlobalVCRoute") then v:FindFirstChild("GlobalVCRoute"):Destroy() end 
	RS:UnbindFromRenderStep(v.UserId.."_RunFakeCharacter")
	--// Setup Fake Character for Use
	local Chara = Char:Clone()
	Chara.Name = v.UserId 
	Chara.Parent = v
	--// Binding to Camera Render
	RS:BindToRenderStep(v.UserId.."_RunFakeCharacter",Enum.RenderPriority.Camera,function() 
		if Chara ~= nil then
			Chara:WaitForChild("HumanoidRootPart").CFrame = game.Workspace.CurrentCamera.CFrame
		else
			RS:UnbindFromRenderStep(v.UserId.."_RunFakeCharacter")
		end
	end)
	--// Assigning
	v.Character = Chara
	v.CharacterAdded:Connect(function(char)
		v.Character = Chara
	end)
end

for i,v in pairs(game.Players:GetChildren()) do
	if v ~= player then
		SetupPlayer(v)
	end
end

--// Setup new Players

game.Players.PlayerAdded:Connect(function(plr)
	SetupPlayer(plr)
end)

--// Detect leaving players

game.Players.PlayerRemoving:Connect(function(plr)
	RS:UnbindFromRenderStep(plr.UserId.."_RunFakeCharacter")
end)

accidentallyposteditinchatinsteadofeditingsonowihavetoputthissoicanevenpostitahhhhh

32 Likes

I have been looking for something like this for ages.

Same. That’s why I started experimenting and figured out how Spatial Voice works.

They actually do Spatial Voice stuff locally! So just setting there player as a part and teleporting it to your camera will allow you to hear people from infinite distances.

2 Likes

Just to confirm, when you say “globally” you mean the server the player is in and not across all servers in a experience?

1 Like

I’d assume so because with voice chat I’m pretty sure it’s only allowed to be used inside servers unlike chats which can be global.

Should’ve explained that.

No. At it’s current state it’s impossible to do that. I mean everyone in the server you are IN can hear you without being next to eachother. I am even making a Module called SpatialVoice++ which will allow toggled Global chat.

This could be used for among us type stuff.

1 Like

This is amazing, this allows for developers to make radio systems with spatial voice

Oh! I was looking up spatial voice and never found anything.

I’ll be sure to look up at that as it seems pretty cool! Has a lot of features. I’m making a core game where there’s a normal TownRP outside and reactor facility inside.

This will probably help me make the rest of the stuff I was dreaming to do about voice chat in my game.

And the next thing we need is a VR radio to actually use this.

This might help with a project I’m working on. I want to make it to where players can have different channels in-game and talk with each other, like walkie talkies. Will try to play around with this code.

Since I know it’s possible (since it’s featured in SCP 3008 game) I will try to figure out how to make Spatial Voice Audio effects. (The audio effects from Roblox)

hopefully that will also help. But don’t get too excited! Not sure if I could do it.

1 Like

I was told by multiple devs that it is possible and isn’t possible. I hope it can be done! Would go good in my project I’m working on.

Sorry for reviving this topic.

This is overall a well put-together script, works flawlessly with a few optimization tweaks & cleanup. Utilizing this for a Flight System I may release for the public, the player in flight near an airport → attach them to ATC team seat where they can hear ATC & vice versa/quick to use chat commands.

2 Likes