@quenty/inputkeymaputils 14.35.0-canary.643.622f151.0 → 14.35.0
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 +26 -1
- package/package.json +10 -10
- package/src/Shared/HoldableInputModel.lua +217 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,7 +3,32 @@
|
|
|
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
|
-
# [14.35.0
|
|
6
|
+
# [14.35.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/inputkeymaputils@14.34.2...@quenty/inputkeymaputils@14.35.0) (2026-01-26)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* Fix lint ([7c77d1f](https://github.com/Quenty/NevermoreEngine/commit/7c77d1f6d95657072fc756e6f93bed1484646ad9))
|
|
12
|
+
* Remove holding state from input system ([b20d6f8](https://github.com/Quenty/NevermoreEngine/commit/b20d6f88725703864fe8112517dd4a5270274e3a))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* Add Holdable option to InputKeyMapList ([0422fb6](https://github.com/Quenty/NevermoreEngine/commit/0422fb61671d80b110b06c6bf2da00fb293698bb))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
## [14.34.2](https://github.com/Quenty/NevermoreEngine/compare/@quenty/inputkeymaputils@14.34.1...@quenty/inputkeymaputils@14.34.2) (2026-01-23)
|
|
24
|
+
|
|
25
|
+
**Note:** Version bump only for package @quenty/inputkeymaputils
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
## [14.34.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/inputkeymaputils@14.34.0...@quenty/inputkeymaputils@14.34.1) (2026-01-21)
|
|
7
32
|
|
|
8
33
|
**Note:** Version bump only for package @quenty/inputkeymaputils
|
|
9
34
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/inputkeymaputils",
|
|
3
|
-
"version": "14.35.0
|
|
3
|
+
"version": "14.35.0",
|
|
4
4
|
"description": "System to define rebindable key bindings and inputs for Roblox.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -30,25 +30,25 @@
|
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@quenty/baseobject": "10.9.3",
|
|
33
|
-
"@quenty/brio": "14.
|
|
34
|
-
"@quenty/clienttranslator": "14.
|
|
33
|
+
"@quenty/brio": "14.24.1",
|
|
34
|
+
"@quenty/clienttranslator": "14.29.2",
|
|
35
35
|
"@quenty/ducktype": "5.9.3",
|
|
36
36
|
"@quenty/enumutils": "3.4.5",
|
|
37
|
-
"@quenty/inputmode": "13.
|
|
37
|
+
"@quenty/inputmode": "13.27.1",
|
|
38
38
|
"@quenty/loader": "10.9.3",
|
|
39
39
|
"@quenty/maid": "3.5.3",
|
|
40
|
-
"@quenty/observablecollection": "12.
|
|
40
|
+
"@quenty/observablecollection": "12.30.2",
|
|
41
41
|
"@quenty/pseudolocalize": "3.5.2",
|
|
42
|
-
"@quenty/rx": "13.
|
|
42
|
+
"@quenty/rx": "13.23.1",
|
|
43
43
|
"@quenty/servicebag": "11.13.6",
|
|
44
|
-
"@quenty/statestack": "14.
|
|
44
|
+
"@quenty/statestack": "14.26.1",
|
|
45
45
|
"@quenty/string": "3.3.6",
|
|
46
46
|
"@quenty/table": "3.9.2",
|
|
47
|
-
"@quenty/valuebaseutils": "13.
|
|
48
|
-
"@quenty/valueobject": "13.
|
|
47
|
+
"@quenty/valuebaseutils": "13.24.1",
|
|
48
|
+
"@quenty/valueobject": "13.25.1"
|
|
49
49
|
},
|
|
50
50
|
"publishConfig": {
|
|
51
51
|
"access": "public"
|
|
52
52
|
},
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "6fd82c03003b22a03c83d00cac39fe2b2f7f8aa1"
|
|
54
54
|
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--[=[
|
|
3
|
+
Tracks hold state for an input. Handles the timing logic
|
|
4
|
+
and exposes observables for hold progress.
|
|
5
|
+
|
|
6
|
+
```lua
|
|
7
|
+
local holdableInputModel = HoldableInputModel.new(1.5)
|
|
8
|
+
-- Or set it later:
|
|
9
|
+
-- holdableInputModel:SetMaxHoldDuration(1.5)
|
|
10
|
+
|
|
11
|
+
maid:GiveTask(holdableInputModel.HoldReleased:Connect(function(holdPercent)
|
|
12
|
+
print("Released at", holdPercent)
|
|
13
|
+
end))
|
|
14
|
+
|
|
15
|
+
-- When input begins
|
|
16
|
+
holdableInputModel:StartHold()
|
|
17
|
+
|
|
18
|
+
-- When input ends
|
|
19
|
+
holdableInputModel:StopHold()
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
@class HoldableInputModel
|
|
23
|
+
]=]
|
|
24
|
+
|
|
25
|
+
local require = require(script.Parent.loader).load(script)
|
|
26
|
+
|
|
27
|
+
local RunService = game:GetService("RunService")
|
|
28
|
+
|
|
29
|
+
local BaseObject = require("BaseObject")
|
|
30
|
+
local Maid = require("Maid")
|
|
31
|
+
local Observable = require("Observable")
|
|
32
|
+
local Signal = require("Signal")
|
|
33
|
+
local ValueObject = require("ValueObject")
|
|
34
|
+
|
|
35
|
+
local HoldableInputModel = setmetatable({}, BaseObject)
|
|
36
|
+
HoldableInputModel.ClassName = "HoldableInputModel"
|
|
37
|
+
HoldableInputModel.__index = HoldableInputModel
|
|
38
|
+
|
|
39
|
+
export type HoldableInputModel =
|
|
40
|
+
typeof(setmetatable(
|
|
41
|
+
{} :: {
|
|
42
|
+
_maxHoldDuration: ValueObject.ValueObject<number>,
|
|
43
|
+
_holdPercent: ValueObject.ValueObject<number>,
|
|
44
|
+
_isHolding: ValueObject.ValueObject<boolean>,
|
|
45
|
+
HoldStarted: Signal.Signal<()>,
|
|
46
|
+
HoldUpdated: Signal.Signal<number>,
|
|
47
|
+
HoldReleased: Signal.Signal<number>,
|
|
48
|
+
},
|
|
49
|
+
{} :: typeof({ __index = HoldableInputModel })
|
|
50
|
+
))
|
|
51
|
+
& BaseObject.BaseObject
|
|
52
|
+
|
|
53
|
+
--[=[
|
|
54
|
+
Constructs a new HoldableInputModel
|
|
55
|
+
|
|
56
|
+
@param maxHoldDuration number? -- Optional max hold duration in seconds (defaults to 1)
|
|
57
|
+
@return HoldableInputModel
|
|
58
|
+
]=]
|
|
59
|
+
function HoldableInputModel.new(maxHoldDuration: number?): HoldableInputModel
|
|
60
|
+
local self = setmetatable(BaseObject.new() :: any, HoldableInputModel)
|
|
61
|
+
|
|
62
|
+
self._maxHoldDuration = self._maid:Add(ValueObject.new(maxHoldDuration or 1, "number"))
|
|
63
|
+
self._holdPercent = self._maid:Add(ValueObject.new(0, "number"))
|
|
64
|
+
self._isHolding = self._maid:Add(ValueObject.new(false, "boolean"))
|
|
65
|
+
|
|
66
|
+
--[=[
|
|
67
|
+
Fires when a hold begins
|
|
68
|
+
@prop HoldStarted Signal<>
|
|
69
|
+
@within HoldableInputModel
|
|
70
|
+
]=]
|
|
71
|
+
self.HoldStarted = self._maid:Add(Signal.new())
|
|
72
|
+
|
|
73
|
+
--[=[
|
|
74
|
+
Fires when the hold percent updates
|
|
75
|
+
@prop HoldUpdated Signal<number>
|
|
76
|
+
@within HoldableInputModel
|
|
77
|
+
]=]
|
|
78
|
+
self.HoldUpdated = self._maid:Add(Signal.new())
|
|
79
|
+
|
|
80
|
+
--[=[
|
|
81
|
+
Fires when a hold is released with the final hold percent
|
|
82
|
+
@prop HoldReleased Signal<number>
|
|
83
|
+
@within HoldableInputModel
|
|
84
|
+
]=]
|
|
85
|
+
self.HoldReleased = self._maid:Add(Signal.new())
|
|
86
|
+
|
|
87
|
+
return self
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
--[=[
|
|
91
|
+
Sets the maximum hold duration in seconds
|
|
92
|
+
|
|
93
|
+
@param duration number | Observable<number>
|
|
94
|
+
@return MaidTask
|
|
95
|
+
]=]
|
|
96
|
+
function HoldableInputModel.SetMaxHoldDuration(
|
|
97
|
+
self: HoldableInputModel,
|
|
98
|
+
duration: number | Observable.Observable<number>
|
|
99
|
+
)
|
|
100
|
+
return self._maxHoldDuration:Mount(duration)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
--[=[
|
|
104
|
+
Gets the maximum hold duration
|
|
105
|
+
|
|
106
|
+
@return number
|
|
107
|
+
]=]
|
|
108
|
+
function HoldableInputModel.GetMaxHoldDuration(self: HoldableInputModel): number
|
|
109
|
+
return self._maxHoldDuration.Value
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
--[=[
|
|
113
|
+
Observes the maximum hold duration
|
|
114
|
+
|
|
115
|
+
@return Observable<number>
|
|
116
|
+
]=]
|
|
117
|
+
function HoldableInputModel.ObserveMaxHoldDuration(self: HoldableInputModel): Observable.Observable<number>
|
|
118
|
+
return self._maxHoldDuration:Observe()
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
--[=[
|
|
122
|
+
Observes the current hold percent (0-1)
|
|
123
|
+
|
|
124
|
+
@return Observable<number>
|
|
125
|
+
]=]
|
|
126
|
+
function HoldableInputModel.ObserveHoldPercent(self: HoldableInputModel): Observable.Observable<number>
|
|
127
|
+
return self._holdPercent:Observe()
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
--[=[
|
|
131
|
+
Gets the current hold percent (0-1)
|
|
132
|
+
|
|
133
|
+
@return number
|
|
134
|
+
]=]
|
|
135
|
+
function HoldableInputModel.GetHoldPercent(self: HoldableInputModel): number
|
|
136
|
+
return self._holdPercent.Value
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
--[=[
|
|
140
|
+
Observes whether currently holding
|
|
141
|
+
|
|
142
|
+
@return Observable<boolean>
|
|
143
|
+
]=]
|
|
144
|
+
function HoldableInputModel.ObserveIsHolding(self: HoldableInputModel): Observable.Observable<boolean>
|
|
145
|
+
return self._isHolding:Observe()
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
--[=[
|
|
149
|
+
Returns whether currently holding
|
|
150
|
+
|
|
151
|
+
@return boolean
|
|
152
|
+
]=]
|
|
153
|
+
function HoldableInputModel.IsHolding(self: HoldableInputModel): boolean
|
|
154
|
+
return self._isHolding.Value
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
--[=[
|
|
158
|
+
Starts tracking a hold. Call this when input begins.
|
|
159
|
+
]=]
|
|
160
|
+
function HoldableInputModel.StartHold(self: HoldableInputModel): ()
|
|
161
|
+
self._maid._holdMaid = nil
|
|
162
|
+
|
|
163
|
+
local maid = Maid.new()
|
|
164
|
+
local elapsed = 0
|
|
165
|
+
local maxDuration = self._maxHoldDuration.Value or 1
|
|
166
|
+
|
|
167
|
+
self._isHolding.Value = true
|
|
168
|
+
self._holdPercent.Value = 0
|
|
169
|
+
self.HoldStarted:Fire()
|
|
170
|
+
|
|
171
|
+
maid:GiveTask(RunService.Heartbeat:Connect(function(dt)
|
|
172
|
+
elapsed += dt
|
|
173
|
+
local newPercent = math.clamp(elapsed / maxDuration, 0, 1)
|
|
174
|
+
if self._holdPercent.Value ~= newPercent then
|
|
175
|
+
self._holdPercent.Value = newPercent
|
|
176
|
+
self.HoldUpdated:Fire(newPercent)
|
|
177
|
+
end
|
|
178
|
+
end))
|
|
179
|
+
|
|
180
|
+
maid:GiveTask(function()
|
|
181
|
+
local finalPercent = self._holdPercent.Value
|
|
182
|
+
self._holdPercent.Value = 0
|
|
183
|
+
self._isHolding.Value = false
|
|
184
|
+
self.HoldReleased:Fire(finalPercent)
|
|
185
|
+
end)
|
|
186
|
+
|
|
187
|
+
self._maid._holdMaid = maid
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
--[=[
|
|
191
|
+
Stops tracking a hold and fires HoldReleased with the final percent.
|
|
192
|
+
Call this when input ends.
|
|
193
|
+
]=]
|
|
194
|
+
function HoldableInputModel.StopHold(self: HoldableInputModel): ()
|
|
195
|
+
self._maid._holdMaid = nil
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
--[=[
|
|
199
|
+
Cancels a hold without firing HoldReleased.
|
|
200
|
+
Use this when the hold should be aborted (e.g., interrupted by stun).
|
|
201
|
+
]=]
|
|
202
|
+
function HoldableInputModel.CancelHold(self: HoldableInputModel): ()
|
|
203
|
+
if self._maid._holdMaid then
|
|
204
|
+
self._isHolding.Value = false
|
|
205
|
+
self._holdPercent.Value = 0
|
|
206
|
+
-- Clear without triggering cleanup function
|
|
207
|
+
local holdMaid = self._maid._holdMaid
|
|
208
|
+
self._maid._holdMaid = nil
|
|
209
|
+
if holdMaid and holdMaid.Destroy then
|
|
210
|
+
-- Destroy without the cleanup function firing HoldReleased
|
|
211
|
+
holdMaid._tasks = {}
|
|
212
|
+
holdMaid:Destroy()
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
return HoldableInputModel
|