local K=game:GetService("\083\111\117\110\100\083\101\114\118\105\099\101")local M=require(script.Parent.t)local D=require(script.Parent.Promise)local b={}local a=1 local U=Instance.new("\083\111\117\110\100\071\114\111\117\112",K)U.Name="\069\102\102\101\099\116\115"local Z=M.union(M.string,M.number)local function A(K,D,b)assert(M.string(K))assert((M.optional(M.number))(D))assert((M.optional(M.Vector3))(b))D=D or 1 local U=Instance.new("\083\111\117\110\100")U.SoundId=K U.Volume=D*a return U end local function m(K)if type(K)=="\115\116\114\105\110\103"then if K:match("\094\114\098\120\097\115\115\101\116\105\100\058\047\047")or K:match("\094\114\098\120\097\115\115\101\116\058\047\047\115\111\117\110\100\115\047")then return K else error("\073\110\118\097\108\105\100 \105\100\058 "..tostring(K))end elseif type(K)=="\110\117\109\098\101\114"then return"\114\098\120\097\115\115\101\116\105\100\058\047\047"..K else error(tostring(K).."\105\115 \110\111\116 \097 \118\097\108\105\100 \105\100")end end local function k(K)return function(M,...)local b={...}return D.new(function(a,U)D.spawn(function()local D,Z=pcall(K,M,unpack(b))if D then a(Z)else U(Z)end end)end)end end local y={}local function J(K)assert(M.string(K))assert(K:match("\094\114\098\120\097\115\115\101\116\105\100\058\047\047")or K:match("\094\114\098\120\097\115\115\101\116\058\047\047\115\111\117\110\100\115\047"))for M,D in next,y do if D.SoundId==K and not D.IsPlaying then return D end end local D=A(K)D.Name="\083\111\117\110\100"..tostring(#y+1)table.insert(y,D)return D end local x=M.tuple(Z,M.optional(M.number))function b.PlayEffect(b,M,D)assert(x(M,D))local a=J(m(M))a.SoundGroup=U a.Name=M a.Parent=K a:Play()a.Ended:Wait()end b.PlayEffectAsync=k(b.PlayEffect)local u=M.tuple(Z,M.Vector3,M.optional(M.number))function b.PlayEffectAtPosition(b,K,M,D)assert(u(K,M,D))local a=Instance.new("\080\097\114\116")a.Name="\083\102\120\051\100\080\108\097\121\101\114"a.Transparency=1 a.Anchored=true a.CFrame=CFrame.new(M)local U=A(m(K),D,M)U.Parent=a U:Play()U.Ended:Wait()U:Destroy()a:Destroy()end b.PlayEffectAtPositionAsync=k(b.PlayEffectAtPosition)return b
--[[
	Lib Sfx
	Sound Effect library for WorldEngine

	namespace SoundEffects
		PlayEffect( effectId: string | number, volume?: number )
		PlayEffectAtPosition( effectId: string | number, position: Vector3, volume?: number )


]]
local SoundService = game:GetService("SoundService")

local t = require(script.Parent.t)
local Promise = require(script.Parent.Promise)
local SoundEffects = {}
local masterVolume = 1

local EffectSoundGroup = Instance.new("SoundGroup", SoundService)
EffectSoundGroup.Name = "Effects"

local t_identifier = t.union(t.string, t.number)

local function new(soundId, volume, vec3)
	assert(t.string(soundId))
	assert(t.optional(t.number)(volume))
	assert(t.optional(t.Vector3)(vec3))

	volume = volume or 1
	local sound = Instance.new("Sound")
	sound.SoundId = soundId
	sound.Volume = volume * masterVolume
	return sound
end

local function getId(value)
	if type(value) == "string" then
		if value:match("^rbxassetid://") or value:match("^rbxasset://sounds/") then
			return value
		else
			error("Invalid id: " .. tostring(value))
		end
	elseif type(value) == "number" then
		return "rbxassetid://" .. value
	else
		error(tostring(value) .. "is not a valid id")
	end
end

local function asyncWrap(f)
	return function(self, ...)
		local args = {...}
		return Promise.new(
			function(resolve, reject)
				Promise.spawn(
					function()
						local success, result = pcall(f, self, unpack(args))
						if success then
							resolve(result)
						else
							reject(result)
						end
					end
				)
			end
		)
	end
end

local soundPool = {}
local function getSoundObject(assetUri)
	assert(t.string(assetUri))
	assert(assetUri:match("^rbxassetid://") or assetUri:match("^rbxasset://sounds/"))
	for _, sound in next, soundPool do
		if sound.SoundId == assetUri and not sound.IsPlaying then
			return sound
		end
	end

	local sound = new(assetUri)
	sound.Name = "Sound" .. tostring(#soundPool + 1)
	table.insert(soundPool, sound)
	return sound
end

local PlayEffect_ArgTypes = t.tuple(t_identifier, t.optional(t.number))
function SoundEffects:PlayEffect(effectId, volume)
	assert(PlayEffect_ArgTypes(effectId, volume))

	local effect = getSoundObject(getId(effectId))
	effect.SoundGroup = EffectSoundGroup
	effect.Name = effectId
	effect.Parent = SoundService

	effect:Play()
	effect.Ended:Wait()
end
SoundEffects.PlayEffectAsync = asyncWrap(SoundEffects.PlayEffect)

local PlayEffectAtPosition_ArgTypes = t.tuple(t_identifier, t.Vector3, t.optional(t.number))
function SoundEffects:PlayEffectAtPosition(effectId, position, volume)
	assert(PlayEffectAtPosition_ArgTypes(effectId, position, volume))

	local part = Instance.new("Part")
	part.Name = "Sfx3dPlayer"
	part.Transparency = 1
	part.Anchored = true
	part.CFrame = CFrame.new(position)

	local effect = new(getId(effectId), volume, position)
	effect.Parent = part
	effect:Play()
	effect.Ended:Wait()
	effect:Destroy()
	part:Destroy()
end
SoundEffects.PlayEffectAtPositionAsync = asyncWrap(SoundEffects.PlayEffectAtPosition)

return SoundEffects
