@quenty/ragdoll 9.1.0 → 9.1.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/package.json +3 -3
- package/src/Client/Classes/RagdollClient.lua +2 -0
- package/src/Server/Classes/Ragdollable.lua +4 -0
- package/src/Server/RagdollService.lua +4 -0
- package/src/Shared/Rigging/RagdollMotorUtils.lua +219 -140
- package/src/Shared/Rigging/RxRagdollUtils.lua +29 -10
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
|
+
## [9.1.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/ragdoll@9.1.0...@quenty/ragdoll@9.1.1) (2022-10-16)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **perf:** Make Ragdoll performance better ([566d2bb](https://github.com/Quenty/NevermoreEngine/commit/566d2bb1045d62fd08f16c9042d68c328c5c307d))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
# [9.1.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/ragdoll@9.0.0...@quenty/ragdoll@9.1.0) (2022-10-11)
|
|
7
18
|
|
|
8
19
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/ragdoll",
|
|
3
|
-
"version": "9.1.
|
|
3
|
+
"version": "9.1.1",
|
|
4
4
|
"description": "Quenty's Ragdoll system for Roblox - Floppy fun ragdolls",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@quenty/baseobject": "^6.0.0",
|
|
30
30
|
"@quenty/binder": "^8.1.0",
|
|
31
31
|
"@quenty/brio": "^8.1.0",
|
|
32
|
-
"@quenty/camera": "^9.1.
|
|
32
|
+
"@quenty/camera": "^9.1.1",
|
|
33
33
|
"@quenty/cancellabledelay": "^3.3.0",
|
|
34
34
|
"@quenty/characterutils": "^6.0.0",
|
|
35
35
|
"@quenty/draw": "^4.2.0",
|
|
@@ -54,5 +54,5 @@
|
|
|
54
54
|
"publishConfig": {
|
|
55
55
|
"access": "public"
|
|
56
56
|
},
|
|
57
|
-
"gitHead": "
|
|
57
|
+
"gitHead": "5fc8df6d4a62c0c774ebc78b275898f7f383935b"
|
|
58
58
|
}
|
|
@@ -60,6 +60,7 @@ function RagdollClient:_setupCameraShake(impulseCamera)
|
|
|
60
60
|
|
|
61
61
|
local lastVelocity = head.Velocity
|
|
62
62
|
self._maid:GiveTask(RunService.Heartbeat:Connect(function()
|
|
63
|
+
debug.profilebegin("ragdollcamerashake")
|
|
63
64
|
local cameraCFrame = Workspace.CurrentCamera.CFrame
|
|
64
65
|
|
|
65
66
|
local velocity = head.Velocity
|
|
@@ -71,6 +72,7 @@ function RagdollClient:_setupCameraShake(impulseCamera)
|
|
|
71
72
|
end
|
|
72
73
|
|
|
73
74
|
lastVelocity = velocity
|
|
75
|
+
debug.profileend()
|
|
74
76
|
end))
|
|
75
77
|
end
|
|
76
78
|
|
|
@@ -15,6 +15,7 @@ local RagdollAdditionalAttachmentUtils = require("RagdollAdditionalAttachmentUti
|
|
|
15
15
|
local RagdollCollisionUtils = require("RagdollCollisionUtils")
|
|
16
16
|
local RagdollBallSocketUtils = require("RagdollBallSocketUtils")
|
|
17
17
|
local Motor6DBindersServer = require("Motor6DBindersServer")
|
|
18
|
+
local RagdollMotorUtils = require("RagdollMotorUtils")
|
|
18
19
|
|
|
19
20
|
local Ragdollable = setmetatable({}, BaseObject)
|
|
20
21
|
Ragdollable.ClassName = "Ragdollable"
|
|
@@ -48,6 +49,9 @@ function Ragdollable.new(humanoid, serviceBag)
|
|
|
48
49
|
maid:GiveTask(RagdollBallSocketUtils.ensureBallSockets(state.character, state.rigType))
|
|
49
50
|
maid:GiveTask(RagdollCollisionUtils.ensureNoCollides(state.character, state.rigType))
|
|
50
51
|
|
|
52
|
+
-- Not super guarded against race conditions but it should be fine, as this is for debugging.
|
|
53
|
+
RagdollMotorUtils.initMotorAttributes(state.character, state.rigType)
|
|
54
|
+
|
|
51
55
|
self._maid._configure = maid
|
|
52
56
|
else
|
|
53
57
|
self._maid._configure = nil
|
|
@@ -21,6 +21,10 @@ function RagdollService:Init(serviceBag)
|
|
|
21
21
|
|
|
22
22
|
-- Internal
|
|
23
23
|
self._binders = self._serviceBag:GetService(require("RagdollBindersServer"))
|
|
24
|
+
|
|
25
|
+
self._binders.RagdollHumanoidOnFall:SetAutomaticTagging(false)
|
|
26
|
+
self._binders.RagdollHumanoidOnDeath:SetAutomaticTagging(false)
|
|
27
|
+
self._binders.UnragdollAutomatically:SetAutomaticTagging(false)
|
|
24
28
|
end
|
|
25
29
|
|
|
26
30
|
--[=[
|
|
@@ -26,6 +26,9 @@ local Rx = require("Rx")
|
|
|
26
26
|
|
|
27
27
|
local RagdollMotorUtils = {}
|
|
28
28
|
|
|
29
|
+
-- For easier debugging
|
|
30
|
+
local DEFAULT_SPRING_SPEED = 20
|
|
31
|
+
|
|
29
32
|
local R6_MOTORS = {
|
|
30
33
|
{
|
|
31
34
|
partName = "Torso";
|
|
@@ -118,6 +121,23 @@ local R15_MOTORS = {
|
|
|
118
121
|
};
|
|
119
122
|
}
|
|
120
123
|
|
|
124
|
+
local ROOT_JOINT_CACHE = {}
|
|
125
|
+
|
|
126
|
+
function RagdollMotorUtils.getFirstRootJointData(rigType)
|
|
127
|
+
if ROOT_JOINT_CACHE[rigType] then
|
|
128
|
+
return ROOT_JOINT_CACHE[rigType]
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
for _, item in pairs(RagdollMotorUtils.getMotorData(rigType)) do
|
|
132
|
+
if item.isRootJoint then
|
|
133
|
+
ROOT_JOINT_CACHE[rigType] = item
|
|
134
|
+
return item
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
error("Could not find root joint data")
|
|
139
|
+
end
|
|
140
|
+
|
|
121
141
|
function RagdollMotorUtils.getMotorData(rigType)
|
|
122
142
|
if rigType == Enum.HumanoidRigType.R15 then
|
|
123
143
|
return R15_MOTORS
|
|
@@ -128,158 +148,217 @@ function RagdollMotorUtils.getMotorData(rigType)
|
|
|
128
148
|
end
|
|
129
149
|
end
|
|
130
150
|
|
|
131
|
-
function RagdollMotorUtils.
|
|
151
|
+
function RagdollMotorUtils.initMotorAttributes(character, rigType)
|
|
132
152
|
assert(typeof(character) == "Instance" and character:IsA("Model"), "Bad character")
|
|
133
153
|
assert(EnumUtils.isOfType(Enum.HumanoidRigType, rigType), "Bad rigType")
|
|
134
154
|
|
|
155
|
+
for _, data in pairs(RagdollMotorUtils.getMotorData(rigType)) do
|
|
156
|
+
local motor = R15Utils.getRigMotor(character, data.partName, data.motorName)
|
|
157
|
+
if motor then
|
|
158
|
+
AttributeUtils.initAttribute(motor, RagdollConstants.IS_MOTOR_ANIMATED_ATTRIBUTE, false)
|
|
159
|
+
AttributeUtils.initAttribute(motor, RagdollConstants.RETURN_SPRING_SPEED_ATTRIBUTE, DEFAULT_SPRING_SPEED)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
function RagdollMotorUtils.setupAnimatedMotor(character, part)
|
|
165
|
+
local maid = Maid.new()
|
|
166
|
+
|
|
167
|
+
-- make this stuff not physics collide with our own rig
|
|
168
|
+
-- O(n^2)
|
|
169
|
+
maid:GiveTask(RagdollCollisionUtils.preventCollisionAmongOthers(character, part))
|
|
170
|
+
|
|
171
|
+
return maid
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
function RagdollMotorUtils.setupRagdollRootPartMotor(motor, part0, part1)
|
|
175
|
+
local maid = Maid.new()
|
|
176
|
+
|
|
177
|
+
local lastTransformSpring = Spring.new(QFrame.fromCFrameClosestTo(motor.Transform, QFrame.new()))
|
|
178
|
+
lastTransformSpring.t = QFrame.new()
|
|
179
|
+
|
|
180
|
+
-- replacing this weld ensures interpolation for some reason
|
|
181
|
+
local weldContainer = Instance.new("Camera")
|
|
182
|
+
weldContainer.Name = "TempWeldContainer"
|
|
183
|
+
weldContainer.Parent = part0
|
|
184
|
+
maid:GiveTask(weldContainer)
|
|
185
|
+
|
|
186
|
+
local function setupWeld(weldType)
|
|
187
|
+
local weldMaid = Maid.new()
|
|
188
|
+
|
|
189
|
+
local weld = Instance.new(weldType)
|
|
190
|
+
weld.Name = "TempRagdollWeld"
|
|
191
|
+
weld.Part0 = part0
|
|
192
|
+
weld.Part1 = part1
|
|
193
|
+
weldMaid:GiveTask(weld)
|
|
194
|
+
|
|
195
|
+
-- Inserted C1/C0 here
|
|
196
|
+
weldMaid:GiveTask(Rx.combineLatest({
|
|
197
|
+
C0 = RxInstanceUtils.observeProperty(motor, "C0");
|
|
198
|
+
Transform = RxInstanceUtils.observeProperty(motor, "Transform");
|
|
199
|
+
}):Subscribe(function(innerState)
|
|
200
|
+
weld.C0 = innerState.C0 * innerState.Transform
|
|
201
|
+
end))
|
|
202
|
+
weldMaid:GiveTask(RxInstanceUtils.observeProperty(motor, "C1"):Subscribe(function(c1)
|
|
203
|
+
weld.C1 = c1
|
|
204
|
+
end))
|
|
205
|
+
weld.Parent = weldContainer
|
|
206
|
+
|
|
207
|
+
return weldMaid
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
if CharacterUtils.getPlayerFromCharacter(part0) then
|
|
211
|
+
-- Swap from choppy to interpolation
|
|
212
|
+
maid._weld = setupWeld("Motor6D")
|
|
213
|
+
maid:GiveTask(task.delay(0.25, function()
|
|
214
|
+
maid._weld = setupWeld("Weld")
|
|
215
|
+
end))
|
|
216
|
+
else
|
|
217
|
+
-- Smooth all the way! (Probably NPC)
|
|
218
|
+
maid._weld = setupWeld("Weld")
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
maid:GiveTask(RxAttributeUtils.observeAttribute(motor, RagdollConstants.RETURN_SPRING_SPEED_ATTRIBUTE, DEFAULT_SPRING_SPEED)
|
|
222
|
+
:Subscribe(function(speed)
|
|
223
|
+
lastTransformSpring.s = speed
|
|
224
|
+
end))
|
|
225
|
+
|
|
226
|
+
-- Lerp smoothly to 0 to avoid jarring camera.
|
|
227
|
+
maid:GiveTask(RunService.Stepped:Connect(function()
|
|
228
|
+
local target = QFrame.toCFrame(lastTransformSpring.p)
|
|
229
|
+
if target then
|
|
230
|
+
motor.Transform = target
|
|
231
|
+
end
|
|
232
|
+
end))
|
|
233
|
+
|
|
234
|
+
motor.Enabled = false
|
|
235
|
+
|
|
236
|
+
maid:GiveTask(function()
|
|
237
|
+
motor.Enabled = true
|
|
238
|
+
end)
|
|
239
|
+
|
|
240
|
+
return maid
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
function RagdollMotorUtils.setupRagdollMotor(motor, part0, part1)
|
|
244
|
+
local maid = Maid.new()
|
|
245
|
+
|
|
246
|
+
motor.Enabled = false
|
|
247
|
+
maid:GiveTask(function()
|
|
248
|
+
local implemention = Motor6DStackInterface:FindFirstImplementation(motor)
|
|
249
|
+
if implemention then
|
|
250
|
+
local initialTransform = (part0.CFrame * motor.C0):toObjectSpace(part1.CFrame * motor.C1)
|
|
251
|
+
local speed = AttributeUtils.getAttribute(motor, RagdollConstants.RETURN_SPRING_SPEED_ATTRIBUTE, DEFAULT_SPRING_SPEED)
|
|
252
|
+
|
|
253
|
+
implemention:TransformFromCFrame(initialTransform, speed)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
motor.Enabled = true
|
|
257
|
+
end)
|
|
258
|
+
|
|
259
|
+
maid:GiveTask(RunService.Stepped:Connect(function()
|
|
260
|
+
motor.Transform = CFrame.new()
|
|
261
|
+
end))
|
|
262
|
+
|
|
263
|
+
return maid
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
function RagdollMotorUtils.suppressJustRootPart(character, rigType)
|
|
267
|
+
local data = RagdollMotorUtils.getFirstRootJointData(rigType)
|
|
268
|
+
|
|
269
|
+
local observable = RxR15Utils.observeRigMotorBrio(character, data.partName, data.motorName):Pipe({
|
|
270
|
+
RxBrioUtils.switchMapBrio(function(motor)
|
|
271
|
+
return RxBrioUtils.flatCombineLatest({
|
|
272
|
+
motor = motor;
|
|
273
|
+
part0 = RxInstanceUtils.observeProperty(motor, "Part0");
|
|
274
|
+
part1 = RxInstanceUtils.observeProperty(motor, "Part1");
|
|
275
|
+
isAnimated = RxAttributeUtils.observeAttribute(motor, RagdollConstants.IS_MOTOR_ANIMATED_ATTRIBUTE, false);
|
|
276
|
+
})
|
|
277
|
+
end);
|
|
278
|
+
})
|
|
279
|
+
|
|
135
280
|
local topMaid = Maid.new()
|
|
136
281
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
part0 = observable:Pipe({
|
|
142
|
-
RxBrioUtils.switchMapBrio(function(motor)
|
|
143
|
-
return RxInstanceUtils.observeProperty(motor, "Part0");
|
|
144
|
-
end);
|
|
145
|
-
});
|
|
146
|
-
part1 = observable:Pipe({
|
|
147
|
-
RxBrioUtils.switchMapBrio(function(motor)
|
|
148
|
-
return RxInstanceUtils.observeProperty(motor, "Part1");
|
|
149
|
-
end);
|
|
150
|
-
});
|
|
151
|
-
}):Subscribe(function(state)
|
|
152
|
-
if state.motor and state.part0 and state.part1 then
|
|
153
|
-
local motorMaid = Maid.new()
|
|
154
|
-
local motor = state.motor
|
|
155
|
-
|
|
156
|
-
-- For easier debugging
|
|
157
|
-
local DEFAULT_SPEED = 20
|
|
158
|
-
AttributeUtils.initAttribute(motor, RagdollConstants.IS_MOTOR_ANIMATED_ATTRIBUTE, false)
|
|
159
|
-
AttributeUtils.initAttribute(motor, RagdollConstants.RETURN_SPRING_SPEED_ATTRIBUTE, DEFAULT_SPEED)
|
|
160
|
-
|
|
161
|
-
motorMaid:GiveTask(RxAttributeUtils.observeAttribute(motor, RagdollConstants.IS_MOTOR_ANIMATED_ATTRIBUTE, false):Subscribe(function(isAnimated)
|
|
162
|
-
if isAnimated then
|
|
163
|
-
local lockMaid = Maid.new()
|
|
164
|
-
|
|
165
|
-
-- make this stuff not physics collide with our own rig
|
|
166
|
-
lockMaid:GiveTask(RagdollCollisionUtils.preventCollisionAmongOthers(character, state.part1))
|
|
167
|
-
|
|
168
|
-
motorMaid._lock = lockMaid
|
|
169
|
-
else
|
|
170
|
-
local lockMaid = Maid.new()
|
|
171
|
-
|
|
172
|
-
if data.isRootJoint then
|
|
173
|
-
local lastTransformSpring = Spring.new(QFrame.fromCFrameClosestTo(motor.Transform, QFrame.new()))
|
|
174
|
-
lastTransformSpring.t = QFrame.new()
|
|
175
|
-
|
|
176
|
-
-- replacing this weld ensures interpolation for some reason
|
|
177
|
-
local weldContainer = Instance.new("Camera")
|
|
178
|
-
weldContainer.Name = "TempWeldContainer"
|
|
179
|
-
weldContainer.Parent = state.part0
|
|
180
|
-
lockMaid:GiveTask(weldContainer)
|
|
181
|
-
|
|
182
|
-
local function setupWeld(weldType)
|
|
183
|
-
local weldMaid = Maid.new()
|
|
184
|
-
|
|
185
|
-
local weld = Instance.new(weldType)
|
|
186
|
-
weld.Name = "TempRagdollWeld"
|
|
187
|
-
weld.Part0 = state.part0
|
|
188
|
-
weld.Part1 = state.part1
|
|
189
|
-
weldMaid:GiveTask(weld)
|
|
190
|
-
|
|
191
|
-
-- Inserted C1/C0 here
|
|
192
|
-
weldMaid:GiveTask(Rx.combineLatest({
|
|
193
|
-
C0 = RxInstanceUtils.observeProperty(motor, "C0");
|
|
194
|
-
Transform = RxInstanceUtils.observeProperty(motor, "Transform");
|
|
195
|
-
}):Subscribe(function(innerState)
|
|
196
|
-
weld.C0 = innerState.C0 * innerState.Transform
|
|
197
|
-
end))
|
|
198
|
-
weldMaid:GiveTask(RxInstanceUtils.observeProperty(motor, "C1"):Subscribe(function(c1)
|
|
199
|
-
weld.C1 = c1
|
|
200
|
-
end))
|
|
201
|
-
weld.Parent = weldContainer
|
|
202
|
-
|
|
203
|
-
return weldMaid
|
|
204
|
-
end
|
|
282
|
+
topMaid:GiveTask(observable:Subscribe(function(brio)
|
|
283
|
+
if brio:IsDead() then
|
|
284
|
+
return
|
|
285
|
+
end
|
|
205
286
|
|
|
287
|
+
local state = brio:GetValue()
|
|
288
|
+
local motorMaid = brio:ToMaid()
|
|
206
289
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
lockMaid:GiveTask(task.delay(0.25, function()
|
|
211
|
-
lockMaid._weld = setupWeld("Weld")
|
|
212
|
-
end))
|
|
213
|
-
else
|
|
214
|
-
-- Smooth all the way! (Probably NPC)
|
|
215
|
-
lockMaid._weld = setupWeld("Weld")
|
|
216
|
-
end
|
|
290
|
+
if not (state.motor and state.part0 and state.part1) then
|
|
291
|
+
return
|
|
292
|
+
end
|
|
217
293
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
lockMaid:GiveTask(RunService.Stepped:Connect(function()
|
|
225
|
-
local target = QFrame.toCFrame(lastTransformSpring.p)
|
|
226
|
-
if target then
|
|
227
|
-
motor.Transform = target
|
|
228
|
-
end
|
|
229
|
-
end))
|
|
230
|
-
|
|
231
|
-
motor.Enabled = false
|
|
232
|
-
|
|
233
|
-
lockMaid:GiveTask(function()
|
|
234
|
-
motor.Enabled = true
|
|
235
|
-
end)
|
|
236
|
-
else
|
|
237
|
-
motor.Enabled = false
|
|
238
|
-
|
|
239
|
-
lockMaid:GiveTask(function()
|
|
240
|
-
local implemention = Motor6DStackInterface:FindFirstImplementation(state.motor)
|
|
241
|
-
if implemention then
|
|
242
|
-
local initialTransform = (state.part0.CFrame * motor.C0):toObjectSpace(state.part1.CFrame * motor.C1)
|
|
243
|
-
local speed = AttributeUtils.getAttribute(state.motor, RagdollConstants.RETURN_SPRING_SPEED_ATTRIBUTE, DEFAULT_SPEED)
|
|
244
|
-
|
|
245
|
-
implemention:TransformFromCFrame(initialTransform, speed)
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
motor.Enabled = true
|
|
249
|
-
end)
|
|
250
|
-
|
|
251
|
-
lockMaid:GiveTask(RunService.Stepped:Connect(function()
|
|
252
|
-
motor.Transform = CFrame.new()
|
|
253
|
-
end))
|
|
254
|
-
end
|
|
294
|
+
if state.isAnimated then
|
|
295
|
+
motorMaid._current = RagdollMotorUtils.setupAnimatedMotor(character, state.part1)
|
|
296
|
+
else
|
|
297
|
+
motorMaid._current = RagdollMotorUtils.setupRagdollRootPartMotor(state.motor, state.part0, state.part1)
|
|
298
|
+
end
|
|
299
|
+
end))
|
|
255
300
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if passed <= 0.1 then
|
|
263
|
-
local rotVelocity = velocityReadings.rotation[data]
|
|
264
|
-
if rotVelocity then
|
|
265
|
-
state.part1.RotVelocity += rotVelocity
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
local velocity = velocityReadings.linear[data]
|
|
269
|
-
if velocity then
|
|
270
|
-
state.part1.Velocity += velocity
|
|
271
|
-
end
|
|
272
|
-
end
|
|
273
|
-
end
|
|
274
|
-
end)
|
|
301
|
+
return topMaid
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
function RagdollMotorUtils.suppressMotors(character, rigType, velocityReadings)
|
|
305
|
+
assert(typeof(character) == "Instance" and character:IsA("Model"), "Bad character")
|
|
306
|
+
assert(EnumUtils.isOfType(Enum.HumanoidRigType, rigType), "Bad rigType")
|
|
275
307
|
|
|
276
|
-
|
|
277
|
-
end
|
|
278
|
-
end))
|
|
308
|
+
local topMaid = Maid.new()
|
|
279
309
|
|
|
280
|
-
|
|
310
|
+
for _, data in pairs(RagdollMotorUtils.getMotorData(rigType)) do
|
|
311
|
+
local observable = RxR15Utils.observeRigMotorBrio(character, data.partName, data.motorName):Pipe({
|
|
312
|
+
RxBrioUtils.switchMapBrio(function(motor)
|
|
313
|
+
return RxBrioUtils.flatCombineLatest({
|
|
314
|
+
motor = motor;
|
|
315
|
+
part0 = RxInstanceUtils.observeProperty(motor, "Part0");
|
|
316
|
+
part1 = RxInstanceUtils.observeProperty(motor, "Part1");
|
|
317
|
+
isAnimated = RxAttributeUtils.observeAttribute(motor, RagdollConstants.IS_MOTOR_ANIMATED_ATTRIBUTE, false);
|
|
318
|
+
})
|
|
319
|
+
end);
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
topMaid:GiveTask(observable:Subscribe(function(brio)
|
|
323
|
+
if brio:IsDead() then
|
|
324
|
+
return
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
local state = brio:GetValue()
|
|
328
|
+
local motorMaid = brio:ToMaid()
|
|
329
|
+
|
|
330
|
+
if not (state.motor and state.part0 and state.part1) then
|
|
331
|
+
return
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
if state.isAnimated then
|
|
335
|
+
motorMaid._current = RagdollMotorUtils.setupAnimatedMotor(character, state.part1)
|
|
281
336
|
else
|
|
282
|
-
|
|
337
|
+
if data.isRootJoint then
|
|
338
|
+
motorMaid._current = RagdollMotorUtils.setupRagdollRootPartMotor(state.motor, state.part0, state.part1)
|
|
339
|
+
else
|
|
340
|
+
motorMaid._current = RagdollMotorUtils.setupRagdollMotor(state.motor, state.part0, state.part1)
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
-- Note animator:ApplyJointVelocities fails. Do this manually.
|
|
344
|
+
-- We only want to do this on the network owner.
|
|
345
|
+
if RagdollMotorUtils.guessIfNetworkOwner(state.part1) then
|
|
346
|
+
task.defer(function()
|
|
347
|
+
-- use physics time
|
|
348
|
+
local passed = time() - velocityReadings.readingTimePhysics
|
|
349
|
+
if passed <= 0.1 then
|
|
350
|
+
local rotVelocity = velocityReadings.rotation[data]
|
|
351
|
+
if rotVelocity then
|
|
352
|
+
state.part1.RotVelocity += rotVelocity
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
local velocity = velocityReadings.linear[data]
|
|
356
|
+
if velocity then
|
|
357
|
+
state.part1.Velocity += velocity
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
end)
|
|
361
|
+
end
|
|
283
362
|
end
|
|
284
363
|
end))
|
|
285
364
|
end
|
|
@@ -6,11 +6,15 @@
|
|
|
6
6
|
|
|
7
7
|
local require = require(script.Parent.loader).load(script)
|
|
8
8
|
|
|
9
|
+
local Players = game:GetService("Players")
|
|
10
|
+
local RunService = game:GetService("RunService")
|
|
11
|
+
|
|
9
12
|
local Maid = require("Maid")
|
|
10
13
|
local RxBrioUtils = require("RxBrioUtils")
|
|
11
14
|
local RxInstanceUtils = require("RxInstanceUtils")
|
|
12
15
|
local RxR15Utils = require("RxR15Utils")
|
|
13
16
|
local RagdollMotorUtils = require("RagdollMotorUtils")
|
|
17
|
+
local CharacterUtils = require("CharacterUtils")
|
|
14
18
|
|
|
15
19
|
local RxRagdollUtils = {}
|
|
16
20
|
|
|
@@ -94,19 +98,34 @@ function RxRagdollUtils.runLocal(humanoid)
|
|
|
94
98
|
|
|
95
99
|
local maid = Maid.new()
|
|
96
100
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
+
local player = CharacterUtils.getPlayerFromCharacter(humanoid)
|
|
102
|
+
-- This velocity work only really needs to occur on the network owner and on the server
|
|
103
|
+
-- since the server will replicate all changes over to the client.
|
|
104
|
+
if RunService:IsServer() or player == Players.LocalPlayer then
|
|
105
|
+
maid:GivePromise(RagdollMotorUtils.promiseVelocityRecordings(character, rigType))
|
|
106
|
+
:Then(function(velocityReadings)
|
|
107
|
+
debug.profilebegin("initragdoll")
|
|
108
|
+
|
|
109
|
+
maid:GiveTask(RxRagdollUtils.suppressRootPartCollision(character, rigType))
|
|
110
|
+
maid:GiveTask(RxRagdollUtils.enforceHeadCollision(character))
|
|
111
|
+
|
|
112
|
+
-- Do motors
|
|
113
|
+
maid:GiveTask(RagdollMotorUtils.suppressMotors(character, rigType, velocityReadings))
|
|
101
114
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
115
|
+
humanoid:ChangeState(Enum.HumanoidStateType.Physics)
|
|
116
|
+
maid:GiveTask(function()
|
|
117
|
+
humanoid:ChangeState(Enum.HumanoidStateType.GettingUp)
|
|
118
|
+
end)
|
|
119
|
+
|
|
120
|
+
debug.profileend()
|
|
105
121
|
end)
|
|
122
|
+
else
|
|
123
|
+
debug.profilebegin("initragdoll_nonowner")
|
|
124
|
+
|
|
125
|
+
maid:GiveTask(RagdollMotorUtils.suppressJustRootPart(character, rigType))
|
|
106
126
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
end)
|
|
127
|
+
debug.profileend()
|
|
128
|
+
end
|
|
110
129
|
|
|
111
130
|
topMaid._current = maid
|
|
112
131
|
else
|