@quenty/soundgroup 1.26.0 → 1.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/LICENSE.md +1 -1
- package/package.json +9 -5
- package/src/Client/SoundGroupServiceClient.lua +4 -0
- package/src/Server/SoundGroupService.lua +4 -0
- package/src/Shared/SoundEffectService.lua +88 -14
- package/src/Shared/Volume/SoundGroupVolume.lua +65 -0
- package/src/Shared/Volume/SoundGroupVolumeInterface.lua +12 -0
- package/src/Shared/Volume/SoundGroupVolumeProperties.lua +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.26.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/soundgroup@1.26.0...@quenty/soundgroup@1.26.1) (2026-01-05)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* Update the sound group package to include sound volume multipliers ([bf9591f](https://github.com/Quenty/NevermoreEngine/commit/bf9591fe2d08dbefae47f8c449b7bbf20c01fdfe))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
# [1.26.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/soundgroup@1.25.8...@quenty/soundgroup@1.26.0) (2026-01-04)
|
|
7
18
|
|
|
8
19
|
**Note:** Version bump only for package @quenty/soundgroup
|
package/LICENSE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2014-
|
|
3
|
+
Copyright (c) 2014-2026 James Onnen (Quenty)
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/soundgroup",
|
|
3
|
-
"version": "1.26.
|
|
3
|
+
"version": "1.26.1",
|
|
4
4
|
"description": "Service and utility methods to working with sound groups and sounds in Roblox",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -26,20 +26,24 @@
|
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@quenty/baseobject": "^10.9.1",
|
|
29
|
+
"@quenty/binder": "^14.26.1",
|
|
29
30
|
"@quenty/brio": "^14.21.0",
|
|
30
|
-
"@quenty/counter": "^7.22.
|
|
31
|
+
"@quenty/counter": "^7.22.1",
|
|
31
32
|
"@quenty/instanceutils": "^13.21.0",
|
|
32
33
|
"@quenty/loader": "^10.9.1",
|
|
33
34
|
"@quenty/maid": "^3.5.1",
|
|
34
|
-
"@quenty/observablecollection": "^12.25.
|
|
35
|
+
"@quenty/observablecollection": "^12.25.1",
|
|
36
|
+
"@quenty/promise": "^10.12.4",
|
|
37
|
+
"@quenty/rogue-properties": "^11.31.1",
|
|
35
38
|
"@quenty/rx": "^13.21.0",
|
|
36
39
|
"@quenty/servicebag": "^11.13.4",
|
|
37
40
|
"@quenty/signal": "^7.11.3",
|
|
38
41
|
"@quenty/table": "^3.9.0",
|
|
39
|
-
"@quenty/
|
|
42
|
+
"@quenty/tie": "^10.27.1",
|
|
43
|
+
"@quenty/valueobject": "^13.22.1"
|
|
40
44
|
},
|
|
41
45
|
"publishConfig": {
|
|
42
46
|
"access": "public"
|
|
43
47
|
},
|
|
44
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "5232cd2c58ca0dcdf591dd8ae78995211da2f3e2"
|
|
45
49
|
}
|
|
@@ -16,6 +16,10 @@ function SoundGroupServiceClient:Init(serviceBag: ServiceBag.ServiceBag)
|
|
|
16
16
|
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
17
17
|
self._maid = Maid.new()
|
|
18
18
|
|
|
19
|
+
-- External
|
|
20
|
+
self._serviceBag:GetService(require("TieRealmService"))
|
|
21
|
+
self._serviceBag:GetService(require("RoguePropertyService"))
|
|
22
|
+
|
|
19
23
|
-- Internal
|
|
20
24
|
self._serviceBag:GetService(require("SoundEffectService"))
|
|
21
25
|
end
|
|
@@ -17,6 +17,10 @@ function SoundGroupService:Init(serviceBag: ServiceBag.ServiceBag)
|
|
|
17
17
|
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
18
18
|
self._maid = Maid.new()
|
|
19
19
|
|
|
20
|
+
-- External
|
|
21
|
+
self._serviceBag:GetService(require("TieRealmService"))
|
|
22
|
+
self._serviceBag:GetService(require("RoguePropertyService"))
|
|
23
|
+
|
|
20
24
|
-- Internal
|
|
21
25
|
self._soundEffectService = self._serviceBag:GetService(require("SoundEffectService"))
|
|
22
26
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
--!
|
|
1
|
+
--!strict
|
|
2
2
|
--[=[
|
|
3
3
|
Handles applying global volume and effects to specific sounds in a group based upon a path.
|
|
4
4
|
|
|
@@ -11,25 +11,46 @@ local RunService = game:GetService("RunService")
|
|
|
11
11
|
local SoundService = game:GetService("SoundService")
|
|
12
12
|
|
|
13
13
|
local Maid = require("Maid")
|
|
14
|
+
local Promise = require("Promise")
|
|
14
15
|
local ServiceBag = require("ServiceBag")
|
|
16
|
+
local SoundEffectsList = require("SoundEffectsList")
|
|
15
17
|
local SoundEffectsRegistry = require("SoundEffectsRegistry")
|
|
16
18
|
local SoundGroupPathUtils = require("SoundGroupPathUtils")
|
|
17
19
|
local SoundGroupTracker = require("SoundGroupTracker")
|
|
20
|
+
local SoundGroupVolume = require("SoundGroupVolume")
|
|
18
21
|
local WellKnownSoundGroups = require("WellKnownSoundGroups")
|
|
19
22
|
|
|
20
23
|
local SoundEffectService = {}
|
|
21
24
|
SoundEffectService.ServiceName = "SoundEffectService"
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
export type SoundEffectService = typeof(setmetatable(
|
|
27
|
+
{} :: {
|
|
28
|
+
_serviceBag: ServiceBag.ServiceBag,
|
|
29
|
+
_maid: Maid.Maid,
|
|
30
|
+
_soundEffectsRegister: any, -- SoundEffectsRegistry.SoundEffectsRegistry,
|
|
31
|
+
_tracker: any, -- SoundGroupTracker.SoundGroupTracker,
|
|
32
|
+
},
|
|
33
|
+
{} :: typeof({ __index = SoundEffectService })
|
|
34
|
+
))
|
|
35
|
+
|
|
36
|
+
function SoundEffectService.Init(self: SoundEffectService, serviceBag: ServiceBag.ServiceBag)
|
|
37
|
+
assert(not (self :: any)._serviceBag, "Already initialized")
|
|
25
38
|
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
26
39
|
self._maid = Maid.new()
|
|
27
40
|
|
|
41
|
+
-- External
|
|
42
|
+
self._serviceBag:GetService(require("TieRealmService"))
|
|
43
|
+
self._serviceBag:GetService(require("RoguePropertyService"))
|
|
44
|
+
|
|
45
|
+
-- State
|
|
28
46
|
self._soundEffectsRegister = self._maid:Add(SoundEffectsRegistry.new())
|
|
29
47
|
self._tracker = self._maid:Add(SoundGroupTracker.new(SoundService))
|
|
48
|
+
|
|
49
|
+
-- Binders
|
|
50
|
+
self._serviceBag:GetService(require("SoundGroupVolume"))
|
|
30
51
|
end
|
|
31
52
|
|
|
32
|
-
function SoundEffectService
|
|
53
|
+
function SoundEffectService.Start(self: SoundEffectService): ()
|
|
33
54
|
self:_setupEffectApplication()
|
|
34
55
|
end
|
|
35
56
|
|
|
@@ -38,14 +59,42 @@ end
|
|
|
38
59
|
@param sound Sound
|
|
39
60
|
@param soundGroupPath string? -- Optional
|
|
40
61
|
]=]
|
|
41
|
-
function SoundEffectService
|
|
62
|
+
function SoundEffectService.RegisterSFX(self: SoundEffectService, sound: Sound, soundGroupPath: string): ()
|
|
42
63
|
assert(typeof(sound) == "Instance" and sound:IsA("Sound"), "Bad sound")
|
|
43
64
|
assert(SoundGroupPathUtils.isSoundGroupPath(soundGroupPath) or soundGroupPath == nil, "Bad soundGroupPath")
|
|
44
65
|
|
|
45
66
|
sound.SoundGroup = self:GetOrCreateSoundGroup(soundGroupPath or WellKnownSoundGroups.SFX)
|
|
46
67
|
end
|
|
47
68
|
|
|
48
|
-
|
|
69
|
+
--[=[
|
|
70
|
+
Creates a NumberValue multiplier for the given sound group path.
|
|
71
|
+
|
|
72
|
+
Destroy (or unparent) the returned NumberValue to remove the multiplier.
|
|
73
|
+
|
|
74
|
+
@param soundGroupPath string
|
|
75
|
+
@return Promise<NumberValue>
|
|
76
|
+
]=]
|
|
77
|
+
function SoundEffectService:PromiseCreateVolumeMultiplier(soundGroupPath: string): Promise.Promise<NumberValue>
|
|
78
|
+
local soundGroup = self:GetOrCreateSoundGroup(soundGroupPath)
|
|
79
|
+
if soundGroup == nil then
|
|
80
|
+
return Promise.rejected("Failed to get or create sound group for path: " .. soundGroupPath)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
local soundGroupVolumeBinder = self._serviceBag:GetService(require("SoundGroupVolume"))
|
|
84
|
+
soundGroupVolumeBinder:Tag(soundGroup)
|
|
85
|
+
|
|
86
|
+
return soundGroupVolumeBinder:Promise(soundGroup):Then(function(soundGroupVolume)
|
|
87
|
+
return soundGroupVolume:CreateMultiplier()
|
|
88
|
+
end)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
--[=[
|
|
92
|
+
Returns the SoundGroup for the given path, creating it if it does not exist.
|
|
93
|
+
|
|
94
|
+
@param soundGroupPath string
|
|
95
|
+
@return SoundGroup
|
|
96
|
+
]=]
|
|
97
|
+
function SoundEffectService.GetOrCreateSoundGroup(self: SoundEffectService, soundGroupPath: string): SoundGroup
|
|
49
98
|
assert(SoundGroupPathUtils.isSoundGroupPath(soundGroupPath), "Bad soundGroupPath")
|
|
50
99
|
|
|
51
100
|
local found = self:GetSoundGroup(soundGroupPath)
|
|
@@ -54,10 +103,21 @@ function SoundEffectService:GetOrCreateSoundGroup(soundGroupPath: string): Sound
|
|
|
54
103
|
end
|
|
55
104
|
|
|
56
105
|
-- Handle deferred mode
|
|
57
|
-
|
|
106
|
+
found = SoundGroupPathUtils.findOrCreateSoundGroup(soundGroupPath)
|
|
107
|
+
assert(found, "Failed to create sound group for path")
|
|
108
|
+
|
|
109
|
+
SoundGroupVolume:Tag(found)
|
|
110
|
+
|
|
111
|
+
return found
|
|
58
112
|
end
|
|
59
113
|
|
|
60
|
-
|
|
114
|
+
--[=[
|
|
115
|
+
Returns the SoundGroup for the given path, or nil if it does not exist.
|
|
116
|
+
|
|
117
|
+
@param soundGroupPath string
|
|
118
|
+
@return SoundGroup
|
|
119
|
+
]=]
|
|
120
|
+
function SoundEffectService.GetSoundGroup(self: SoundEffectService, soundGroupPath: string): SoundGroup?
|
|
61
121
|
assert(SoundGroupPathUtils.isSoundGroupPath(soundGroupPath), "Bad soundGroupPath")
|
|
62
122
|
|
|
63
123
|
if not self._tracker then
|
|
@@ -71,27 +131,41 @@ function SoundEffectService:GetSoundGroup(soundGroupPath: string): SoundGroup
|
|
|
71
131
|
|
|
72
132
|
local found = self._tracker:GetFirstSoundGroup(soundGroupPath)
|
|
73
133
|
if found then
|
|
134
|
+
SoundGroupVolume:Tag(found)
|
|
74
135
|
return found
|
|
75
136
|
end
|
|
76
137
|
|
|
77
|
-
|
|
138
|
+
found = SoundGroupPathUtils.findSoundGroup(soundGroupPath)
|
|
139
|
+
if found then
|
|
140
|
+
SoundGroupVolume:Tag(found)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
return found
|
|
78
144
|
end
|
|
79
145
|
|
|
80
|
-
function SoundEffectService
|
|
146
|
+
function SoundEffectService.PushEffect(
|
|
147
|
+
self: SoundEffectService,
|
|
148
|
+
soundGroupPath: string,
|
|
149
|
+
effect: SoundEffectsList.SoundEffectApplier
|
|
150
|
+
): ()
|
|
81
151
|
assert(SoundGroupPathUtils.isSoundGroupPath(soundGroupPath), "Bad soundGroupPath")
|
|
82
152
|
assert(type(effect) == "function", "Bad effect")
|
|
83
153
|
|
|
84
154
|
return self._soundEffectsRegister:PushEffect(soundGroupPath, effect)
|
|
85
155
|
end
|
|
86
156
|
|
|
87
|
-
function SoundEffectService
|
|
157
|
+
function SoundEffectService.ApplyEffects(
|
|
158
|
+
self: SoundEffectService,
|
|
159
|
+
soundGroupPath: string,
|
|
160
|
+
instance: SoundGroup | Sound
|
|
161
|
+
): () -> ()
|
|
88
162
|
assert(SoundGroupPathUtils.isSoundGroupPath(soundGroupPath), "Bad soundGroupPath")
|
|
89
163
|
assert(typeof(instance) == "Instance" and (instance:IsA("SoundGroup") or instance:IsA("Sound")), "Bad instance")
|
|
90
164
|
|
|
91
165
|
return self._soundEffectsRegister:ApplyEffects(soundGroupPath, instance)
|
|
92
166
|
end
|
|
93
167
|
|
|
94
|
-
function SoundEffectService
|
|
168
|
+
function SoundEffectService._setupEffectApplication(self: SoundEffectService): ()
|
|
95
169
|
self._maid:GiveTask(self._tracker:ObserveSoundGroupsBrio():Subscribe(function(brio)
|
|
96
170
|
if brio:IsDead() then
|
|
97
171
|
return
|
|
@@ -102,7 +176,7 @@ function SoundEffectService:_setupEffectApplication()
|
|
|
102
176
|
if soundGroupPath then
|
|
103
177
|
maid._currentEffects = self._soundEffectsRegister:ApplyEffects(soundGroupPath, soundGroup)
|
|
104
178
|
else
|
|
105
|
-
maid._currentEffects = nil
|
|
179
|
+
maid._currentEffects = nil :: any
|
|
106
180
|
end
|
|
107
181
|
end))
|
|
108
182
|
end))
|
|
@@ -122,7 +196,7 @@ function SoundEffectService:_setupEffectApplication()
|
|
|
122
196
|
end))
|
|
123
197
|
end
|
|
124
198
|
|
|
125
|
-
function SoundEffectService
|
|
199
|
+
function SoundEffectService.Destroy(self: SoundEffectService): ()
|
|
126
200
|
self._maid:DoCleaning()
|
|
127
201
|
end
|
|
128
202
|
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
local SoundGroupVolumeInterface = require(script.Parent.SoundGroupVolumeInterface)
|
|
3
|
+
--[=[
|
|
4
|
+
@class SoundGroupVolume
|
|
5
|
+
]=]
|
|
6
|
+
|
|
7
|
+
local require = require(script.Parent.loader).load(script)
|
|
8
|
+
|
|
9
|
+
local BaseObject = require("BaseObject")
|
|
10
|
+
local Binder = require("Binder")
|
|
11
|
+
local ServiceBag = require("ServiceBag")
|
|
12
|
+
local SoundGroupVolumeProperties = require("SoundGroupVolumeProperties")
|
|
13
|
+
local TieRealms = require("TieRealms")
|
|
14
|
+
|
|
15
|
+
local SoundGroupVolume = setmetatable({}, BaseObject)
|
|
16
|
+
SoundGroupVolume.ClassName = "SoundGroupVolume"
|
|
17
|
+
SoundGroupVolume.__index = SoundGroupVolume
|
|
18
|
+
|
|
19
|
+
export type SoundGroupVolume =
|
|
20
|
+
typeof(setmetatable(
|
|
21
|
+
{} :: {
|
|
22
|
+
_obj: SoundGroup,
|
|
23
|
+
_serviceBag: ServiceBag.ServiceBag,
|
|
24
|
+
_tieRealmService: any,
|
|
25
|
+
_properties: any,
|
|
26
|
+
RenderedVolume: any,
|
|
27
|
+
},
|
|
28
|
+
{} :: typeof({ __index = SoundGroupVolume })
|
|
29
|
+
))
|
|
30
|
+
& BaseObject.BaseObject
|
|
31
|
+
|
|
32
|
+
function SoundGroupVolume.new(instance: SoundGroup, serviceBag: ServiceBag.ServiceBag): SoundGroupVolume
|
|
33
|
+
local self: SoundGroupVolume = setmetatable(BaseObject.new(instance) :: any, SoundGroupVolume)
|
|
34
|
+
|
|
35
|
+
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
36
|
+
self._tieRealmService = self._serviceBag:GetService(require("TieRealmService"))
|
|
37
|
+
|
|
38
|
+
self._properties = SoundGroupVolumeProperties:Get(self._serviceBag, self._obj)
|
|
39
|
+
self.RenderedVolume = self._properties.Volume
|
|
40
|
+
|
|
41
|
+
self._maid:GiveTask(SoundGroupVolumeInterface:Implement(self._obj, self, self._tieRealmService:GetTieRealm()))
|
|
42
|
+
|
|
43
|
+
-- Assign our volume to the current volume if we're on the server
|
|
44
|
+
if self._tieRealmService:GetTieRealm() == TieRealms.SERVER then
|
|
45
|
+
self._properties.Volume:SetBaseValue(self._obj.Volume)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
self._maid:GiveTask(self._properties.Volume:Observe():Subscribe(function(volume)
|
|
49
|
+
self._obj.Volume = volume
|
|
50
|
+
end))
|
|
51
|
+
|
|
52
|
+
return self
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
--[=[
|
|
56
|
+
Creates a volume multiplier for this sound group volume.
|
|
57
|
+
|
|
58
|
+
@param amount number?
|
|
59
|
+
@return NumberValue
|
|
60
|
+
]=]
|
|
61
|
+
function SoundGroupVolume.CreateMultiplier(self: SoundGroupVolume, amount: number?): NumberValue
|
|
62
|
+
return self._properties.Volume:CreateMultiplier(amount or 1)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
return Binder.new("SoundGroupVolume", SoundGroupVolume :: any) :: Binder.Binder<SoundGroupVolume>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--[=[
|
|
3
|
+
@class SoundGroupVolumeInterface
|
|
4
|
+
]=]
|
|
5
|
+
|
|
6
|
+
local require = require(script.Parent.loader).load(script)
|
|
7
|
+
|
|
8
|
+
local TieDefinition = require("TieDefinition")
|
|
9
|
+
|
|
10
|
+
return TieDefinition.new("SoundGroupVolume", {
|
|
11
|
+
CreateMultiplier = TieDefinition.Types.METHOD,
|
|
12
|
+
})
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--[=[
|
|
3
|
+
@class SoundGroupVolumeProperties
|
|
4
|
+
]=]
|
|
5
|
+
|
|
6
|
+
local require = require(script.Parent.loader).load(script)
|
|
7
|
+
|
|
8
|
+
local RoguePropertyTableDefinition = require("RoguePropertyTableDefinition")
|
|
9
|
+
|
|
10
|
+
return RoguePropertyTableDefinition.new("SoundGroupVolume", {
|
|
11
|
+
Volume = 1,
|
|
12
|
+
})
|