@quenty/ragdoll 9.22.0 → 9.23.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 +17 -0
- package/package.json +13 -12
- package/src/Client/Classes/RagdollClient.lua +50 -17
- package/src/Client/RagdollServiceClient.lua +1 -0
- package/src/Server/Classes/RagdollHumanoidOnFall.lua +17 -3
- package/src/Server/Classes/UnragdollAutomatically.lua +31 -4
- package/src/Shared/Classes/BindableRagdollHumanoidOnFall.lua +18 -2
- package/src/Shared/Rigging/RagdollBallSocketUtils.lua +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,23 @@
|
|
|
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
|
+
# [9.23.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/ragdoll@9.22.0...@quenty/ragdoll@9.23.0) (2023-05-08)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* Ragdoll initializes CameraStackService ([814f327](https://github.com/Quenty/NevermoreEngine/commit/814f327beb53ab3665428a6357ca4293a7fdd9be))
|
|
12
|
+
* Will not try to unragdoll automatically while falling ([ac3c062](https://github.com/Quenty/NevermoreEngine/commit/ac3c06200f6dd6a09ee53ed0f3a726bcc4a3105e))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* Reduce friction torqueon ragdoll head ([cfd1535](https://github.com/Quenty/NevermoreEngine/commit/cfd153587f199da77edce185c49a957aa23aee6b))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
6
23
|
# [9.22.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/ragdoll@9.21.0...@quenty/ragdoll@9.22.0) (2023-04-20)
|
|
7
24
|
|
|
8
25
|
**Note:** Version bump only for package @quenty/ragdoll
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/ragdoll",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.23.0",
|
|
4
4
|
"description": "Quenty's Ragdoll system for Roblox - Floppy fun ragdolls",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -25,33 +25,34 @@
|
|
|
25
25
|
"Quenty"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@quenty/attributeutils": "^8.
|
|
28
|
+
"@quenty/attributeutils": "^8.14.0",
|
|
29
29
|
"@quenty/baseobject": "^6.2.1",
|
|
30
|
-
"@quenty/binder": "^8.
|
|
31
|
-
"@quenty/brio": "^8.
|
|
32
|
-
"@quenty/camera": "^9.
|
|
30
|
+
"@quenty/binder": "^8.15.0",
|
|
31
|
+
"@quenty/brio": "^8.12.0",
|
|
32
|
+
"@quenty/camera": "^9.12.0",
|
|
33
33
|
"@quenty/cancellabledelay": "^3.4.0",
|
|
34
|
-
"@quenty/characterutils": "^6.
|
|
34
|
+
"@quenty/characterutils": "^6.6.0",
|
|
35
35
|
"@quenty/draw": "^4.2.0",
|
|
36
36
|
"@quenty/enumutils": "^3.1.0",
|
|
37
37
|
"@quenty/hapticfeedbackutils": "^3.1.0",
|
|
38
|
-
"@quenty/instanceutils": "^7.
|
|
38
|
+
"@quenty/instanceutils": "^7.13.0",
|
|
39
39
|
"@quenty/loader": "^6.2.1",
|
|
40
40
|
"@quenty/maid": "^2.5.0",
|
|
41
|
-
"@quenty/motor6d": "^1.
|
|
42
|
-
"@quenty/playerhumanoidbinder": "^8.
|
|
41
|
+
"@quenty/motor6d": "^1.21.0",
|
|
42
|
+
"@quenty/playerhumanoidbinder": "^8.15.0",
|
|
43
43
|
"@quenty/promise": "^6.5.0",
|
|
44
44
|
"@quenty/qframe": "^6.6.0",
|
|
45
|
-
"@quenty/r15utils": "^7.
|
|
45
|
+
"@quenty/r15utils": "^7.14.0",
|
|
46
46
|
"@quenty/remoting": "^6.5.0",
|
|
47
47
|
"@quenty/rx": "^7.10.0",
|
|
48
|
+
"@quenty/rxbinderutils": "^8.16.0",
|
|
48
49
|
"@quenty/spring": "^6.2.1",
|
|
49
50
|
"@quenty/steputils": "^3.2.0",
|
|
50
51
|
"@quenty/table": "^3.2.0",
|
|
51
|
-
"@quenty/valuebaseutils": "^7.
|
|
52
|
+
"@quenty/valuebaseutils": "^7.13.0"
|
|
52
53
|
},
|
|
53
54
|
"publishConfig": {
|
|
54
55
|
"access": "public"
|
|
55
56
|
},
|
|
56
|
-
"gitHead": "
|
|
57
|
+
"gitHead": "2ad8cea7dd3ad79a39afd7d7b785b489b90553fd"
|
|
57
58
|
}
|
|
@@ -19,6 +19,9 @@ local CharacterUtils = require("CharacterUtils")
|
|
|
19
19
|
local HapticFeedbackUtils = require("HapticFeedbackUtils")
|
|
20
20
|
local RagdollServiceClient = require("RagdollServiceClient")
|
|
21
21
|
local RagdollMotorUtils = require("RagdollMotorUtils")
|
|
22
|
+
local RxR15Utils = require("RxR15Utils")
|
|
23
|
+
local RxBrioUtils = require("RxBrioUtils")
|
|
24
|
+
local RxInstanceUtils = require("RxInstanceUtils")
|
|
22
25
|
|
|
23
26
|
local RagdollClient = setmetatable({}, BaseObject)
|
|
24
27
|
RagdollClient.ClassName = "RagdollClient"
|
|
@@ -51,28 +54,58 @@ function RagdollClient.new(humanoid, serviceBag)
|
|
|
51
54
|
return self
|
|
52
55
|
end
|
|
53
56
|
|
|
54
|
-
-- TODO: Move out of this open source module
|
|
55
57
|
function RagdollClient:_setupCameraShake(impulseCamera)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
-- TODO: Move out of this open source module
|
|
59
|
+
|
|
60
|
+
-- Use the upper torso instead of the head because the upper torso shakes a lot less so
|
|
61
|
+
-- we get a stronger response to full character movement.
|
|
62
|
+
|
|
63
|
+
self._maid:GiveTask(RxInstanceUtils.observePropertyBrio(self._obj, "Parent", function(character)
|
|
64
|
+
return character ~= nil
|
|
65
|
+
end):Pipe({
|
|
66
|
+
RxBrioUtils.switchMapBrio(function(character)
|
|
67
|
+
return RxBrioUtils.flatCombineLatestBrio({
|
|
68
|
+
upperTorso = RxR15Utils.observeCharacterPartBrio(character, "UpperTorso");
|
|
69
|
+
head = RxR15Utils.observeCharacterPartBrio(character, "Head")
|
|
70
|
+
}, function(state)
|
|
71
|
+
return state.upperTorso and state.head
|
|
72
|
+
end)
|
|
73
|
+
end);
|
|
74
|
+
}):Subscribe(function(brio)
|
|
75
|
+
if brio:IsDead() then
|
|
76
|
+
return
|
|
77
|
+
end
|
|
60
78
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
debug.profilebegin("ragdollcamerashake")
|
|
64
|
-
local cameraCFrame = Workspace.CurrentCamera.CFrame
|
|
79
|
+
local maid = brio:ToMaid()
|
|
80
|
+
local state = brio:GetValue()
|
|
65
81
|
|
|
66
|
-
local
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
local function getEstimatedVelocityFromUpperTorso()
|
|
83
|
+
-- TODO: Consider neck attachments
|
|
84
|
+
local headOffset = state.upperTorso.Size*Vector3.new(0, 0.5, 0)
|
|
85
|
+
+ state.head.Size*Vector3.new(0, 0.5, 0)
|
|
86
|
+
local headPosition = state.upperTorso.CFrame:PointToWorldSpace(headOffset)
|
|
87
|
+
|
|
88
|
+
return state.upperTorso:GetVelocityAtPosition(headPosition)
|
|
72
89
|
end
|
|
73
90
|
|
|
74
|
-
lastVelocity =
|
|
75
|
-
|
|
91
|
+
local lastVelocity = getEstimatedVelocityFromUpperTorso()
|
|
92
|
+
maid:GiveTask(RunService.Heartbeat:Connect(function()
|
|
93
|
+
|
|
94
|
+
debug.profilebegin("ragdollcamerashake")
|
|
95
|
+
|
|
96
|
+
local cameraCFrame = Workspace.CurrentCamera.CFrame
|
|
97
|
+
|
|
98
|
+
local velocity = getEstimatedVelocityFromUpperTorso()
|
|
99
|
+
local dVelocity = velocity - lastVelocity
|
|
100
|
+
if dVelocity.magnitude >= 0 then
|
|
101
|
+
if self._ragdollServiceClient:GetScreenShakeEnabled() then
|
|
102
|
+
impulseCamera:Impulse(cameraCFrame:vectorToObjectSpace(-0.1*cameraCFrame.lookVector:Cross(dVelocity)))
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
lastVelocity = velocity
|
|
107
|
+
debug.profileend()
|
|
108
|
+
end))
|
|
76
109
|
end))
|
|
77
110
|
end
|
|
78
111
|
|
|
@@ -23,6 +23,7 @@ function RagdollServiceClient:Init(serviceBag)
|
|
|
23
23
|
|
|
24
24
|
-- External
|
|
25
25
|
self._serviceBag:GetService(require("Motor6DServiceClient"))
|
|
26
|
+
self._serviceBag:GetService(require("CameraStackService"))
|
|
26
27
|
|
|
27
28
|
-- Internal
|
|
28
29
|
self._serviceBag:GetService(require("RagdollBindersClient"))
|
|
@@ -43,10 +43,8 @@ function RagdollHumanoidOnFall.new(humanoid, serviceBag)
|
|
|
43
43
|
self:_handleServerEvent(...)
|
|
44
44
|
end))
|
|
45
45
|
else
|
|
46
|
-
self._ragdollLogic = BindableRagdollHumanoidOnFall.new(self._obj, self._ragdollBinder)
|
|
47
|
-
self._maid:GiveTask(self._ragdollLogic)
|
|
48
46
|
|
|
49
|
-
self._maid:GiveTask(self.
|
|
47
|
+
self._maid:GiveTask(self:_getOrCreateRagdollLogic().ShouldRagdoll.Changed:Connect(function()
|
|
50
48
|
self:_update()
|
|
51
49
|
end))
|
|
52
50
|
end
|
|
@@ -54,6 +52,22 @@ function RagdollHumanoidOnFall.new(humanoid, serviceBag)
|
|
|
54
52
|
return self
|
|
55
53
|
end
|
|
56
54
|
|
|
55
|
+
function RagdollHumanoidOnFall:ObserveIsFalling()
|
|
56
|
+
-- TODO: Remove logic if nothing is observing it
|
|
57
|
+
return self:_getOrCreateRagdollLogic():ObserveIsFalling()
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
function RagdollHumanoidOnFall:_getOrCreateRagdollLogic()
|
|
61
|
+
if self._ragdollLogic then
|
|
62
|
+
return self._ragdollLogic
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
self._ragdollLogic = BindableRagdollHumanoidOnFall.new(self._obj, self._ragdollBinder)
|
|
66
|
+
self._maid:GiveTask(self._ragdollLogic)
|
|
67
|
+
|
|
68
|
+
return self._ragdollLogic
|
|
69
|
+
end
|
|
70
|
+
|
|
57
71
|
function RagdollHumanoidOnFall:_handleServerEvent(player, value)
|
|
58
72
|
assert(player == self._player, "Bad player")
|
|
59
73
|
assert(typeof(value) == "boolean", "Bad value")
|
|
@@ -16,6 +16,8 @@ local cancellableDelay = require("cancellableDelay")
|
|
|
16
16
|
local Observable = require("Observable")
|
|
17
17
|
local Rx = require("Rx")
|
|
18
18
|
local RxInstanceUtils = require("RxInstanceUtils")
|
|
19
|
+
local RxBrioUtils = require("RxBrioUtils")
|
|
20
|
+
local RxBinderUtils = require("RxBinderUtils")
|
|
19
21
|
|
|
20
22
|
local UnragdollAutomatically = setmetatable({}, BaseObject)
|
|
21
23
|
UnragdollAutomatically.ClassName = "UnragdollAutomatically"
|
|
@@ -83,14 +85,27 @@ function UnragdollAutomatically:_observeCanUnragdollTimer()
|
|
|
83
85
|
isReady.Value = false
|
|
84
86
|
maid:GiveTask(isReady)
|
|
85
87
|
|
|
86
|
-
maid:GiveTask(
|
|
87
|
-
|
|
88
|
+
maid:GiveTask(RxBrioUtils.flatCombineLatest({
|
|
89
|
+
canUnragdoll = RxBrioUtils.flatCombineLatest({
|
|
90
|
+
enabled = self._unragdollAutomatically:Observe();
|
|
91
|
+
isFallingRagdoll = self:_observeIsFallingRagdoll();
|
|
92
|
+
}):Pipe({
|
|
93
|
+
Rx.map(function(state)
|
|
94
|
+
return state.enabled and not state.isFallingRagdoll
|
|
95
|
+
end);
|
|
96
|
+
Rx.distinct();
|
|
97
|
+
Rx.tap(function(canUnragdoll)
|
|
98
|
+
-- Ensure we reset timer if we change state
|
|
99
|
+
if canUnragdoll then
|
|
100
|
+
startTime = os.clock()
|
|
101
|
+
end
|
|
102
|
+
end);
|
|
103
|
+
});
|
|
88
104
|
time = self._unragdollAutomaticTime:Observe();
|
|
89
105
|
}):Subscribe(function(state)
|
|
90
|
-
if state.
|
|
106
|
+
if state.canUnragdoll then
|
|
91
107
|
maid._deferred = nil
|
|
92
108
|
|
|
93
|
-
|
|
94
109
|
local timeElapsed = os.clock() - startTime
|
|
95
110
|
local remainingTime = state.time - timeElapsed
|
|
96
111
|
if remainingTime <= 0 then
|
|
@@ -102,6 +117,7 @@ function UnragdollAutomatically:_observeCanUnragdollTimer()
|
|
|
102
117
|
end)
|
|
103
118
|
end
|
|
104
119
|
else
|
|
120
|
+
|
|
105
121
|
isReady.Value = false
|
|
106
122
|
maid._deferred = nil
|
|
107
123
|
end
|
|
@@ -116,4 +132,15 @@ function UnragdollAutomatically:_observeCanUnragdollTimer()
|
|
|
116
132
|
end)
|
|
117
133
|
end
|
|
118
134
|
|
|
135
|
+
function UnragdollAutomatically:_observeIsFallingRagdoll()
|
|
136
|
+
return RxBinderUtils.observeBoundClassBrio(self._ragdollBindersServer.RagdollHumanoidOnFall, self._obj)
|
|
137
|
+
:Pipe({
|
|
138
|
+
RxBrioUtils.switchMapBrio(function(ragdollHumanoidOnFall)
|
|
139
|
+
return ragdollHumanoidOnFall:ObserveIsFalling()
|
|
140
|
+
end);
|
|
141
|
+
RxBrioUtils.emitOnDeath(false);
|
|
142
|
+
Rx.distinct();
|
|
143
|
+
})
|
|
144
|
+
end
|
|
145
|
+
|
|
119
146
|
return UnragdollAutomatically
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
local require = require(script.Parent.loader).load(script)
|
|
7
7
|
|
|
8
8
|
local BaseObject = require("BaseObject")
|
|
9
|
+
local RxInstanceUtils = require("RxInstanceUtils")
|
|
9
10
|
|
|
10
11
|
local FRAMES_TO_EXAMINE = 8
|
|
11
12
|
local FRAME_TIME = 0.1
|
|
@@ -31,6 +32,10 @@ function BindableRagdollHumanoidOnFall.new(humanoid, ragdollBinder)
|
|
|
31
32
|
self.ShouldRagdoll.Value = false
|
|
32
33
|
self._maid:GiveTask(self.ShouldRagdoll)
|
|
33
34
|
|
|
35
|
+
self._isFalling = Instance.new("BoolValue")
|
|
36
|
+
self._isFalling.Value = false
|
|
37
|
+
self._maid:GiveTask(self._isFalling)
|
|
38
|
+
|
|
34
39
|
-- Setup Ragdoll
|
|
35
40
|
self:_initLastVelocityRecords()
|
|
36
41
|
self._lastRagDollTime = 0
|
|
@@ -50,7 +55,7 @@ function BindableRagdollHumanoidOnFall.new(humanoid, ragdollBinder)
|
|
|
50
55
|
|
|
51
56
|
self._maid:GiveTask(self._ragdollBinder:ObserveInstance(self._obj, function(class)
|
|
52
57
|
if not class then
|
|
53
|
-
self._lastRagDollTime =
|
|
58
|
+
self._lastRagDollTime = os.clock()
|
|
54
59
|
self.ShouldRagdoll.Value = false
|
|
55
60
|
end
|
|
56
61
|
end))
|
|
@@ -58,6 +63,10 @@ function BindableRagdollHumanoidOnFall.new(humanoid, ragdollBinder)
|
|
|
58
63
|
return self
|
|
59
64
|
end
|
|
60
65
|
|
|
66
|
+
function BindableRagdollHumanoidOnFall:ObserveIsFalling()
|
|
67
|
+
return RxInstanceUtils.observeProperty(self._isFalling, "Value")
|
|
68
|
+
end
|
|
69
|
+
|
|
61
70
|
function BindableRagdollHumanoidOnFall:_initLastVelocityRecords()
|
|
62
71
|
self._lastVelocityRecords = {}
|
|
63
72
|
for _ = 1, FRAMES_TO_EXAMINE + 1 do -- Add an extra frame because we remove before inserting
|
|
@@ -103,6 +112,7 @@ function BindableRagdollHumanoidOnFall:_updateVelocity()
|
|
|
103
112
|
|
|
104
113
|
local rootPart = self._obj.RootPart
|
|
105
114
|
if not rootPart then
|
|
115
|
+
self._isFalling.Value = false
|
|
106
116
|
table.insert(self._lastVelocityRecords, Vector3.new())
|
|
107
117
|
return
|
|
108
118
|
end
|
|
@@ -125,13 +135,18 @@ function BindableRagdollHumanoidOnFall:_updateVelocity()
|
|
|
125
135
|
table.insert(self._lastVelocityRecords, currentVelocity)
|
|
126
136
|
|
|
127
137
|
if not fellForAllFrames then
|
|
138
|
+
self._isFalling.Value = false
|
|
128
139
|
return
|
|
129
140
|
end
|
|
130
141
|
|
|
131
142
|
if mostNegativeVelocityY >= REQUIRED_MAX_FALL_VELOCITY then
|
|
143
|
+
self._isFalling.Value = false
|
|
132
144
|
return
|
|
133
145
|
end
|
|
134
146
|
|
|
147
|
+
-- Write that we're falling (candidate for ragdoll)
|
|
148
|
+
self._isFalling.Value = true
|
|
149
|
+
|
|
135
150
|
-- print("currentVelocity.magnitude, mostNegativeVelocityY", currentVelocity.magnitude, mostNegativeVelocityY)
|
|
136
151
|
|
|
137
152
|
if self._obj.Health <= 0 then
|
|
@@ -148,7 +163,8 @@ function BindableRagdollHumanoidOnFall:_updateVelocity()
|
|
|
148
163
|
return
|
|
149
164
|
end
|
|
150
165
|
|
|
151
|
-
|
|
166
|
+
|
|
167
|
+
if (os.clock() - self._lastRagDollTime) <= RAGDOLL_DEBOUNCE_TIME then
|
|
152
168
|
return
|
|
153
169
|
end
|
|
154
170
|
|