@quenty/ragdoll 5.2.0 → 5.3.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 +19 -0
- package/package.json +13 -13
- package/src/Client/Classes/RagdollClient.lua +7 -2
- package/src/Client/Classes/RagdollableClient.lua +3 -2
- package/src/Client/RagdollServiceClient.lua +49 -0
- package/src/Server/Classes/Ragdollable.lua +2 -2
- package/src/Server/RagdollService.lua +32 -0
- package/src/Shared/RagdollRigging.lua +42 -44
- package/src/Shared/RagdollServiceConstants.lua +11 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
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
|
+
# [5.3.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/ragdoll@5.2.1...@quenty/ragdoll@5.3.0) (2022-01-17)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Add RagdollService and suppress initialization race condition warnings in deferred mode ([480a089](https://github.com/Quenty/NevermoreEngine/commit/480a0892f47fd5acbcb4e846bfb2dd93e207e681))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## [5.2.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/ragdoll@5.2.0...@quenty/ragdoll@5.2.1) (2022-01-16)
|
|
18
|
+
|
|
19
|
+
**Note:** Version bump only for package @quenty/ragdoll
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
6
25
|
# [5.2.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/ragdoll@5.1.2...@quenty/ragdoll@5.2.0) (2022-01-07)
|
|
7
26
|
|
|
8
27
|
**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": "5.
|
|
3
|
+
"version": "5.3.0",
|
|
4
4
|
"description": "Quenty's Ragdoll system for Roblox - Floppy fun ragdolls",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -25,23 +25,23 @@
|
|
|
25
25
|
"Quenty"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@quenty/baseobject": "^3.
|
|
29
|
-
"@quenty/binder": "^4.
|
|
30
|
-
"@quenty/camera": "^5.
|
|
31
|
-
"@quenty/characterutils": "^3.
|
|
28
|
+
"@quenty/baseobject": "^3.5.0",
|
|
29
|
+
"@quenty/binder": "^4.8.0",
|
|
30
|
+
"@quenty/camera": "^5.3.0",
|
|
31
|
+
"@quenty/characterutils": "^3.6.0",
|
|
32
32
|
"@quenty/hapticfeedbackutils": "^2.1.1",
|
|
33
33
|
"@quenty/humanoidanimatorutils": "^2.0.1",
|
|
34
|
-
"@quenty/loader": "^3.
|
|
35
|
-
"@quenty/maid": "^2.0
|
|
36
|
-
"@quenty/playerhumanoidbinder": "^4.
|
|
37
|
-
"@quenty/promise": "^3.
|
|
38
|
-
"@quenty/remoting": "^3.
|
|
39
|
-
"@quenty/rx": "^3.
|
|
34
|
+
"@quenty/loader": "^3.4.0",
|
|
35
|
+
"@quenty/maid": "^2.1.0",
|
|
36
|
+
"@quenty/playerhumanoidbinder": "^4.8.0",
|
|
37
|
+
"@quenty/promise": "^3.6.0",
|
|
38
|
+
"@quenty/remoting": "^3.6.0",
|
|
39
|
+
"@quenty/rx": "^3.8.0",
|
|
40
40
|
"@quenty/table": "^2.1.1",
|
|
41
|
-
"@quenty/valuebaseutils": "^3.
|
|
41
|
+
"@quenty/valuebaseutils": "^3.8.0"
|
|
42
42
|
},
|
|
43
43
|
"publishConfig": {
|
|
44
44
|
"access": "public"
|
|
45
45
|
},
|
|
46
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "c094ba8f4e128cdff08919d89de226d3d65247ce"
|
|
47
47
|
}
|
|
@@ -17,6 +17,7 @@ local BaseObject = require("BaseObject")
|
|
|
17
17
|
local CameraStackService = require("CameraStackService")
|
|
18
18
|
local CharacterUtils = require("CharacterUtils")
|
|
19
19
|
local HapticFeedbackUtils = require("HapticFeedbackUtils")
|
|
20
|
+
local RagdollServiceClient = require("RagdollServiceClient")
|
|
20
21
|
|
|
21
22
|
local RagdollClient = setmetatable({}, BaseObject)
|
|
22
23
|
RagdollClient.ClassName = "RagdollClient"
|
|
@@ -31,7 +32,9 @@ RagdollClient.__index = RagdollClient
|
|
|
31
32
|
function RagdollClient.new(humanoid, serviceBag)
|
|
32
33
|
local self = setmetatable(BaseObject.new(humanoid), RagdollClient)
|
|
33
34
|
|
|
34
|
-
self.
|
|
35
|
+
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
36
|
+
self._ragdollServiceClient = self._serviceBag:GetService(RagdollServiceClient)
|
|
37
|
+
self._cameraStackService = self._serviceBag:GetService(CameraStackService)
|
|
35
38
|
|
|
36
39
|
local player = CharacterUtils.getPlayerFromCharacter(self._obj)
|
|
37
40
|
if player == Players.LocalPlayer then
|
|
@@ -56,7 +59,9 @@ function RagdollClient:_setupCameraShake(impulseCamera)
|
|
|
56
59
|
local velocity = head.Velocity
|
|
57
60
|
local dVelocity = velocity - lastVelocity
|
|
58
61
|
if dVelocity.magnitude >= 0 then
|
|
59
|
-
|
|
62
|
+
if self._ragdollServiceClient:GetScreenShakeEnabled() then
|
|
63
|
+
impulseCamera:Impulse(cameraCFrame:vectorToObjectSpace(-0.1*cameraCFrame.lookVector:Cross(dVelocity)))
|
|
64
|
+
end
|
|
60
65
|
end
|
|
61
66
|
|
|
62
67
|
lastVelocity = velocity
|
|
@@ -83,8 +83,9 @@ function RagdollableClient:_ragdollLocal()
|
|
|
83
83
|
|
|
84
84
|
-- Really hard to infer whether or not we're the network owner, so we just try to do this for every single one.
|
|
85
85
|
|
|
86
|
-
-- Hopefully these are already created. Intent here is to reset friction.
|
|
87
|
-
|
|
86
|
+
-- Hopefully these are already created. Intent here is to reset friction. If not, the friction
|
|
87
|
+
-- should be good.
|
|
88
|
+
RagdollRigging.configureRagdollJoints(false, self._obj.Parent, self._obj.RigType)
|
|
88
89
|
|
|
89
90
|
maid:GiveTask(RagdollUtils.setupState(self._obj))
|
|
90
91
|
maid:GiveTask(RagdollUtils.setupMotors(self._obj))
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
--[=[
|
|
2
|
+
@client
|
|
3
|
+
@class RagdollServiceClient
|
|
4
|
+
]=]
|
|
5
|
+
|
|
6
|
+
local require = require(script.Parent.loader).load(script)
|
|
7
|
+
|
|
8
|
+
local AttributeUtils = require("AttributeUtils")
|
|
9
|
+
local RagdollServiceConstants = require("RagdollServiceConstants")
|
|
10
|
+
|
|
11
|
+
local Players = game:GetService("Players")
|
|
12
|
+
|
|
13
|
+
local RagdollServiceClient = {}
|
|
14
|
+
|
|
15
|
+
--[=[
|
|
16
|
+
Initializes the ragdoll service on the client. Should be done via [ServiceBag].
|
|
17
|
+
@param serviceBag ServiceBag
|
|
18
|
+
]=]
|
|
19
|
+
function RagdollServiceClient:Init(serviceBag)
|
|
20
|
+
assert(not self._serviceBag, "Already initialized")
|
|
21
|
+
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
22
|
+
|
|
23
|
+
self._serviceBag:GetService(require("RagdollBindersClient"))
|
|
24
|
+
|
|
25
|
+
self._screenShakeEnabled = true
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
--[=[
|
|
29
|
+
Sets screen shake enabled for the local player
|
|
30
|
+
@param value boolelan
|
|
31
|
+
]=]
|
|
32
|
+
function RagdollServiceClient:SetScreenShakeEnabled(value)
|
|
33
|
+
assert(type(value) == "boolean", "Bad value")
|
|
34
|
+
Players.LocalPlayer:SetAttribute(RagdollServiceConstants.SCREEN_SHAKE_ENABLED_ATTRIBUTE)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
--[=[
|
|
38
|
+
Returns wheher screenshake is enabled.
|
|
39
|
+
@return boolean
|
|
40
|
+
]=]
|
|
41
|
+
function RagdollServiceClient:GetScreenShakeEnabled()
|
|
42
|
+
assert(self._serviceBag, "Not initialized")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
return AttributeUtils.getAttribute(Players.LocalPlayer, RagdollServiceConstants.SCREEN_SHAKE_ENABLED_ATTRIBUTE, true)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
return RagdollServiceClient
|
|
@@ -32,7 +32,7 @@ function Ragdollable.new(humanoid, serviceBag)
|
|
|
32
32
|
self._ragdollBinder = serviceBag:GetService(RagdollBindersServer).Ragdoll
|
|
33
33
|
|
|
34
34
|
self._obj.BreakJointsOnDeath = false
|
|
35
|
-
RagdollRigging.
|
|
35
|
+
RagdollRigging.configureRagdollJoints(true, self._obj.Parent, humanoid.RigType)
|
|
36
36
|
|
|
37
37
|
local player = CharacterUtils.getPlayerFromCharacter(self._obj)
|
|
38
38
|
if player then
|
|
@@ -97,7 +97,7 @@ function Ragdollable:_enableServer()
|
|
|
97
97
|
local maid = Maid.new()
|
|
98
98
|
|
|
99
99
|
-- This will reset friction too
|
|
100
|
-
RagdollRigging.
|
|
100
|
+
RagdollRigging.configureRagdollJoints(true, self._obj.Parent, self._obj.RigType)
|
|
101
101
|
|
|
102
102
|
maid:GiveTask(RagdollUtils.setupState(self._obj))
|
|
103
103
|
maid:GiveTask(RagdollUtils.setupMotors(self._obj))
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
--[=[
|
|
2
|
+
@server
|
|
3
|
+
@class RagdollService
|
|
4
|
+
]=]
|
|
5
|
+
|
|
6
|
+
local require = require(script.Parent.loader).load(script)
|
|
7
|
+
|
|
8
|
+
local RagdollService = {}
|
|
9
|
+
|
|
10
|
+
--[=[
|
|
11
|
+
Initializes the ragdoll service on the server. Should be done via [ServiceBag].
|
|
12
|
+
@param serviceBag ServiceBag
|
|
13
|
+
]=]
|
|
14
|
+
function RagdollService:Init(serviceBag)
|
|
15
|
+
assert(not self._serviceBag, "Already initialized")
|
|
16
|
+
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
17
|
+
|
|
18
|
+
self._binders = self._serviceBag:GetService(require("RagdollBindersServer"))
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
--[=[
|
|
22
|
+
Sets whether ragdolls should unragdoll automatically.
|
|
23
|
+
@param unragdollAutomatically boolean
|
|
24
|
+
]=]
|
|
25
|
+
function RagdollService:SetUnragdollAutomatically(unragdollAutomatically)
|
|
26
|
+
assert(self._serviceBag, "Not initialized")
|
|
27
|
+
assert(type(unragdollAutomatically) == "boolean", "Bad unragdollAutomatically")
|
|
28
|
+
|
|
29
|
+
self._binders.UnragdollAutomatically:SetAutomaticTagging(unragdollAutomatically)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
return RagdollService
|
|
@@ -243,7 +243,7 @@ local function indexParts(model)
|
|
|
243
243
|
return parts
|
|
244
244
|
end
|
|
245
245
|
|
|
246
|
-
local function
|
|
246
|
+
local function configureRigJoints(create, parts, rig)
|
|
247
247
|
for _, params in ipairs(rig) do
|
|
248
248
|
local part0Name, part1Name, attachmentName, limits = unpack(params)
|
|
249
249
|
local part0 = parts[part0Name]
|
|
@@ -255,35 +255,34 @@ local function createRigJoints(parts, rig)
|
|
|
255
255
|
-- Our rigs only have one joint per part (connecting each part to it's parent part), so
|
|
256
256
|
-- we can re-use it if we have to re-rig that part again.
|
|
257
257
|
local constraint = part1:FindFirstChild(BALL_SOCKET_NAME)
|
|
258
|
-
if
|
|
258
|
+
if constraint == nil and create then
|
|
259
259
|
constraint = Instance.new("BallSocketConstraint")
|
|
260
260
|
constraint.Name = BALL_SOCKET_NAME
|
|
261
|
+
end
|
|
261
262
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
263
|
+
if constraint then
|
|
264
|
+
constraint.Attachment0 = a0
|
|
265
|
+
constraint.Attachment1 = a1
|
|
266
|
+
constraint.LimitsEnabled = true
|
|
267
|
+
constraint.UpperAngle = limits.UpperAngle
|
|
268
|
+
constraint.TwistLimitsEnabled = true
|
|
269
|
+
constraint.TwistLowerAngle = limits.TwistLowerAngle
|
|
270
|
+
constraint.TwistUpperAngle = limits.TwistUpperAngle
|
|
271
|
+
-- Scale constant torque limit for joint friction relative to gravity and the mass of
|
|
272
|
+
-- the body part.
|
|
273
|
+
local gravityScale = workspace.Gravity / REFERENCE_GRAVITY
|
|
274
|
+
local referenceMass = limits.ReferenceMass
|
|
275
|
+
local massScale = referenceMass and (part1:GetMass() / referenceMass) or 1
|
|
276
|
+
local maxTorque = limits.FrictionTorque or DEFAULT_MAX_FRICTION_TORQUE
|
|
277
|
+
constraint.MaxFrictionTorque = maxTorque * massScale * gravityScale
|
|
278
|
+
constraint.Parent = part1
|
|
265
279
|
end
|
|
266
|
-
constraint.Attachment0 = a0
|
|
267
|
-
constraint.Attachment1 = a1
|
|
268
|
-
constraint.LimitsEnabled = true
|
|
269
|
-
constraint.UpperAngle = limits.UpperAngle
|
|
270
|
-
constraint.TwistLimitsEnabled = true
|
|
271
|
-
constraint.TwistLowerAngle = limits.TwistLowerAngle
|
|
272
|
-
constraint.TwistUpperAngle = limits.TwistUpperAngle
|
|
273
|
-
-- Scale constant torque limit for joint friction relative to gravity and the mass of
|
|
274
|
-
-- the body part.
|
|
275
|
-
local gravityScale = workspace.Gravity / REFERENCE_GRAVITY
|
|
276
|
-
local referenceMass = limits.ReferenceMass
|
|
277
|
-
local massScale = referenceMass and (part1:GetMass() / referenceMass) or 1
|
|
278
|
-
local maxTorque = limits.FrictionTorque or DEFAULT_MAX_FRICTION_TORQUE
|
|
279
|
-
constraint.MaxFrictionTorque = maxTorque * massScale * gravityScale
|
|
280
|
-
constraint.Parent = part1
|
|
281
280
|
end
|
|
282
281
|
end
|
|
283
282
|
end
|
|
284
283
|
end
|
|
285
284
|
|
|
286
|
-
local function
|
|
285
|
+
local function configureAdditionalAttachments(create, parts, attachments)
|
|
287
286
|
for _, attachmentParams in ipairs(attachments) do
|
|
288
287
|
local partName, attachmentName, cframe, baseAttachmentName = unpack(attachmentParams)
|
|
289
288
|
local part = parts[partName]
|
|
@@ -299,13 +298,11 @@ local function createAdditionalAttachments(parts, attachments)
|
|
|
299
298
|
end
|
|
300
299
|
-- The attachment names are unique within a part, so we can re-use
|
|
301
300
|
if not attachment then
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
if RunService:IsClient() then
|
|
308
|
-
warn(("[RagdollRigging] - Creating attachment %q"):format(attachmentName))
|
|
301
|
+
if create then
|
|
302
|
+
attachment = Instance.new("Attachment")
|
|
303
|
+
attachment.Name = attachmentName
|
|
304
|
+
attachment.CFrame = cframe
|
|
305
|
+
attachment.Parent = part
|
|
309
306
|
end
|
|
310
307
|
else
|
|
311
308
|
attachment.CFrame = cframe
|
|
@@ -315,7 +312,7 @@ local function createAdditionalAttachments(parts, attachments)
|
|
|
315
312
|
end
|
|
316
313
|
end
|
|
317
314
|
|
|
318
|
-
local function
|
|
315
|
+
local function configureNoCollides(create, parts, noCollides)
|
|
319
316
|
-- This one's trickier to handle for an already rigged character since a part will have multiple
|
|
320
317
|
-- NoCollide children with the same name. Having fewer unique names is better for
|
|
321
318
|
-- replication so we suck it up and deal with the complexity here.
|
|
@@ -363,16 +360,16 @@ local function createNoCollides(parts, noCollides)
|
|
|
363
360
|
local reusables = reusableNoCollides[part1]
|
|
364
361
|
for part0, _ in pairs(neededPart0s) do
|
|
365
362
|
local constraint = table.remove(reusables)
|
|
366
|
-
if
|
|
363
|
+
if constraint == nil and create then
|
|
367
364
|
constraint = Instance.new("NoCollisionConstraint")
|
|
368
|
-
if RunService:IsClient() then
|
|
369
|
-
warn(("[RagdollRigging] - Creating NoCollisionConstraint %q"))
|
|
370
|
-
end
|
|
371
365
|
end
|
|
372
|
-
|
|
373
|
-
constraint
|
|
374
|
-
|
|
375
|
-
|
|
366
|
+
|
|
367
|
+
if constraint then
|
|
368
|
+
constraint.Name = NO_COLLIDE_NAME
|
|
369
|
+
constraint.Part0 = part0
|
|
370
|
+
constraint.Part1 = part1
|
|
371
|
+
constraint.Parent = part1
|
|
372
|
+
end
|
|
376
373
|
end
|
|
377
374
|
end
|
|
378
375
|
end
|
|
@@ -396,19 +393,20 @@ end
|
|
|
396
393
|
|
|
397
394
|
--[=[
|
|
398
395
|
Creates joints on a model for a given rig type.
|
|
396
|
+
@param create boolean -- True if we create the joints, false if we just configure.
|
|
399
397
|
@param model Model
|
|
400
398
|
@param rigType HumanoidRigType
|
|
401
399
|
]=]
|
|
402
|
-
function RagdollRigging.
|
|
400
|
+
function RagdollRigging.configureRagdollJoints(create, model, rigType)
|
|
403
401
|
local parts = indexParts(model)
|
|
404
402
|
if rigType == Enum.HumanoidRigType.R6 then
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
403
|
+
configureAdditionalAttachments(create, parts, R6_ADDITIONAL_ATTACHMENTS)
|
|
404
|
+
configureRigJoints(create, parts, R6_RAGDOLL_RIG)
|
|
405
|
+
configureNoCollides(create, parts, R6_NO_COLLIDES)
|
|
408
406
|
elseif rigType == Enum.HumanoidRigType.R15 then
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
407
|
+
configureAdditionalAttachments(create, parts, R15_ADDITIONAL_ATTACHMENTS)
|
|
408
|
+
configureRigJoints(create, parts, R15_RAGDOLL_RIG)
|
|
409
|
+
configureNoCollides(create, parts, R15_NO_COLLIDES)
|
|
412
410
|
else
|
|
413
411
|
error("unknown rig type", 2)
|
|
414
412
|
end
|