Ragdoll system: joint spesific ragdolling and more

This looks very very nice, it would be nice if u made an example place that utilizes rocket launchers and what not to play around with the ragdoll and act as a learning example to utilize the module and to showcase what u can do with it.

3 Likes

Wow this is extremely detailed and impressive, the amount of features and effort is exceptional. This is one of the best ragdoll system to exist in my opinion. Quick question though, is it possible to sort of play animations and be ragdolled, i saw a RagdollFadeToAnimation module but not sure what it does. What im trying to do is sort of have an euphoria ragdoll imitation by lets say the player gets shot by a gun, and i play an animation that sort of has the player touch the limb to see if its okay, aka inspecting the hurt limb. I want to ragdoll blended with the animation. Is there anyway to do this? Or is there anything in this ragdoll system that allows me to do this?

2 Likes

The RagdollFadeToAnimation module is used to make the transition non-instant when unragdolling (unstun or unparalyze). It won’t work for the purpose you are describing and doesn’t make a realistic transition.

If I understood correctly, you want the character to be in an active ragdoll state where it has no humanoid physics or rigid joints and needs to keep its balance by adjusting joint rotations as necessary while also following animations as much as possible.

This is something that I don’t know how to do. I think AlignOrientations together with BallSocketConstraints could be used for rotating the joints in a way that respects physics. However, the problem is that I don’t know how I should calculate the target rotations.

3 Likes

Nice Work man, and thanks for sharing it!. :pray:

2 Likes

Any effort put into fixing the known errors?

1 Like

Some of the problems are ones that I don’t know how to fix. However, since you asked this, I decided to do something about two problems and give more information about the unsolved problems.

Partially solved problems

In a live game, ragdolling is laggy

Causes of the problem and different things I tried:

Apparently, for the network owner client, the problem was caused by detaching HumanoidRootPart from the rest of the character. I noticed that this caused the engine to give the network ownership of the rest of the character to the server while the HumanoidRootPart’s network owner was still the client. The reason for the HumanoidRootPart being detached was that my “RagdollRootConstraint” object used an AlignPosition with ReactionForceEnabled false in order to have the HumanoidRootPart follow the torso without affecting the physics of the ragdoll. It also uses an AlignOrientation to have the HumanoidRootPart face the direction that I considered the front direction of the ragdoll. This determines the look direction of the character after unragdolling.

I thought I might be able to solve this by setting the network owner of the LowerTorso to be the same as the network owner of the HumanoidRootPart. This was set every frame on Hearbeat while the RagdollRootConstraint was enabled. This fixed the problem for the network owner but not for other players. For other players, the HumanoidRootPart moved as it should but the rest of the character teleported with a delay.

I think the cause of the problem for other clients is that when the character is split from one assembly into multiple assemblies, the original assembly’s root part, which is HumanoidRootPart, will continue having its CFrame replicated but the replication for the new assemblies begins later for some reason.

I also tried if using a BallSocketConstraint instead of an AlignPosition would solve the problem, but it didn’t. The reason why I didn’t originally use a BallSocketConstraint is that then the HumanoidRootPart affects the ragdoll physics which I consider undesirable. However, I mitigated this by using an anti-gravity force on the HumanoidRootPart and giving it a low density during ragdolling. Another thing I tried was keeping the Root Motor6D enabled but that just made the LowerTorso move with the HumanoidRootPart while the rest of the character still had the teleport problem.

Finally, I decided to move the rest of the character on each client other than the network owner every frame such that it follows the HumanoidRootPart.

This local updating wasn't as easy as I thought.

Apparently updating the CFrames with lua code caused replicated CFrame updates that arrived to the client soon after that to be discarded which meant that the offsets of the bodyparts from each other never updated. This meant that the visible bodyparts did move with the HumanoidRootPart but they didn’t rotate relative to each other so the character remained in a fixed pose on each client other than the network owner until unragdolling. I solved this by having the server see when the first CFrame update from the network owner comes and then tell the other clients to stop the lua code updates so that future CFrame updates would work.

The end result for player characters was that, when the player kept the characters network ownership during ragdolling, ragdolling was smooth for the network owner client and I managed to mitigate the teleportation problem for other clients. However, the character still stayed in a fixed pose on the other clients until they began getting CFrame updates from the network owner. If the server was set as the Network owner of the player character at the moment of ragdolling, then every client had a delay but it wasn’t as big as the delay when a player was the network owner. So, for player characters, there were two options:

  1. no delay for network owner and somewhat big delay for others
  2. a delay for everyone, but it is smaller than the delay of others in option 1.

I added a setting setServerAsNetworkOwnerOnEnable for RagdollRootConstraint so that users could easily choose between these options. However, I noticed that for characters that are constantly owned by the server, there was still a teleport issue.

My last attempt to fix the teleport issue is by temporarily using a client-only clone of the character. This clone is recreated when the RigAttachment properties of the RagdollRootConstraint are changed, when bodyparts are added to or removed from the RagdollStructure, or when the user calls the :recreateChoppinessFixClone() method of a RagdollRootConstraint object. The clone is invisible when it’s not needed.

When RagdollRootConstraint is enabled on a client other than the network owner, the clone is made visible and the original character is made invisible. The clone’s HumanoidRootPart’s CFrame is updated every frame on RunService.PreRender to be equal to the CFrame of the original character’s HumanoidRootPart. When the client starts getting CFrame updates for the other parts, it begins to interpolate the rotation offsets between the clone’s parts towards the offset of the corresponding parts in the original character. There’s a RagdollRootConstraint setting for the duration of this interpolation. After this interpolation ends, the clone is made invisible and the original character is made visible.

Here are some problems with the current clone solution (some also apply to the earlier solutions):

  • The character stays in a fixed pose on the clients other than the network owner until they begin getting CFrame updates from the server.
  • The fix only works for clients to which the RagdollStructure object is replicated.
  • If the network owner is changed at the moment of ragdolling, there’s a short back and forth movement for the clients. With the earlier solution, I think I only saw such a movement happen for the original network owner, but I’m not sure.
  • Cloning is obviously more expensive for a character with more instances (but I did add a RagdollRootConstraint setting for not using this choppiness fix / teleportation fix).

Neither the earlier solution involving a remote event nor the new one involving a local clone feels elegant but I’m out of ideas. I don’t know of any solution that would work well in all cases. Of course, there could be an easy solution that I haven’t thought of or found by googling.

Layered clothing that becomes irrelevant when breaking a joint isn’t removed which sometimes causes weird looking results.
I have now added code for removing layered clothing items for which none of the remaining bodyparts are considered to be relevant. The removing doesn’t mean destroying but instead just moving it to the detached RagdollStructure. When it shouldn’t be removed, it’s kept in the original structure and a clone is created for the detached structure. Previously I gave the detached structure a clone instead of the original item regardless of whether the item is relevant to the original structure so the clothing item in original structure remained there even if it became irrelevant.

I also added code for moving layered clothing from a structure that is being merged to the structure it is being merged to if

  • the structure being merged contains all bodyparts that are considered relevant and
  • the structure it is being merged to doesn’t already contain an item of that type.

However, the code that determines which items a RagdollStructure should or shouldn’t have doesn’t give correct results in all cases. The problem is that I’m pretty sure there’s no way to find out which bodyparts are relevant to a spesific layered clothing item. This means that I need to make some assumptions based on the AccessoryType (shoe/jacket/shirt etc.). These assumptions are not necessarily correct. There is variation between items of the same category. For example, some pants only cover legs while some also cover torso and arms. Some shoes only cover the feet while boots cover more. There are also shoes that were put in the pants category and a fluffy pen held in hand which is in the jackets category.

Before the new functionality mentioned in this post, I already used this kind of assumptions for determining which layered clothing items should be cloned to a detached structure. However, now I also changed my definitions of which bodyparts each type of layered clothing is considered to be relevant to. For example, jackets were previously considered to be relevant to head but aren’t anymore. I believe these new bodypart lists will work better in most situations although there are some situations in which the old ones would work better (such as aura jackets). The problem with considering jacket relevant to head was that, in the case of jackets that don’t have anything around the head, if the head was detached, the jacket was just a weird rectangle in the bottom of the detached head.

Unsolved problems

Chat bubble vertical positioning breaks after breaking and merging joints on an R6 character.
I don’t know why this happens or how to fix it.

Paralyzed bodyparts cause undesired behavior when jumping.
In the case of character rotating slightly around its z-axis when a limb on one side is paralyzed, I believe the reason is that the paralyzed parts pull the rest of the character down when jumping as they are in separate assemblies (the mass of the assemblies of these parts resists the velocity change caused by the jump). I’m not sure about this, though. I also don’t know how to fix this. Sometimes paralyzed bodyparts also cause the character to quickly move a long distance in some direction. I don’t have a fix for this either. Replacing BallSocketConstraint with AlignPosition would prevent the paralyzed parts from pulling the other parts but this approach would have problems. There could be situations where the detached bodyparts are unable to get to the correct position, and not using a BallSocketConstraint would also remove rotation limits.

Ragdolls sometimes shake.
I believe this might have something to do with rotations exceeding BallSocketConstraint limits for whatever reason, but I’m not sure. Changing the rotation limits might help.

When resetting (Reset character button or the keybind), the character either doesn’t die on the server, dies on the server many seconds late or dies when something collides with the character.
Setting both BreakJointsOnDeath and RequiresNeck to true seems to fix this (and that’s the default value of these properties). However, RequiresNeck being true prevents making living ragdolls so I’m not going to do this.

I assume resetting could be fixed by firing a RemoteEvent when the player resets and having the server do the server side killing when it’s fired. The API mentioned in the announcement below could be used for this. However, I consider that out of scope for this ragdoll system, and having the ragdoll system use the API might interfere with other code using the same API. I also haven’t tested if this works.

Layered clothing doesn’t always look very good when breaking joints.
I don’t think I can make all layered clothing look good when breaking joints. Simple shirts and pants should look reasonably good while something more unusual may not.

4 Likes
  18:46:55.585  Stack Begin  -  Studio
  18:46:55.585  Script 'ReplicatedStorage.Modules.Shared.RagdollSystemPackage.ExternalDependencies.RagdollExternalDependencyReferences', Line 54  -  Studio -

doesn’t work anymore?
edit: it’s due to the RemoteEventSystem package not being included with the script. I was able to get the GeneralUtilityPackage because it’s public, how do you expect us to use this module if you’re not even going to include the dependencies and gatekeep them?

Sorry about that mistake. RemoteEventSystem isn’t meant to be gatekept. I’ll make a free model version of RemoteEventSystem when I’m on my laptop next time. I may also later replace the current RemoteEventSystem with a new one because although RemoteEventSystem was supposed to make RemoteEvent communication easier, it ironically just made it more difficult.

The reason why GeneralUtility and RemoteEventSystem aren’t included as nested packages anymore is that I don’t want there to potentially be multiple copies of them in the same game.

Edit: RemoteEventSystem is now available as a free model.

2 Likes

Thank you very much! Apologizes if I came off passive aggressive :sweat_smile::sweat_smile:

Annnnd it errored.

ReplicatedStorage.RagdollSystemPackage.Structures.SetupCode.RagdollClientCopyConstructionSentDataUtility:20: table index is nil  -  Client -

This is the line it errored at:

		connectedBodypartNodesAndConnectingMotor6DsForBodypartNodes[bodypartNode] = {}

Did you get this error in studio or in a live server? And what kind of character were you using? Today, I tested this in a live server with one client and in studio in a local server with three clients. I didn’t get that error. I have now updated RagdollSystem and added some new checks with errors to help pinpoint the issue. I also fixed an unrelated issue that I happened to find (more about this issue in the change log).

1 Like

For some reason it was just the place file that had the error, i transferred the dependencies and ragdoll engine over, it doesn’t error but it just doesn’t do anything when i call stun character.

Edit: Odd, it works in a live server but not a studio. Oh well, it’ll just be harder to debug but i guess it’ll work.

The studio command bar has a different Luau environment than scripts and localscripts. Thus, testing RagdollSystem in the command bar would require doing all the initialization related things in the command bar. I also noticed that I’ve written my CharacterEvents.doesPlayerCharacterHaveEverything (which is used by RagdollEaseOfUse) in a way that relies on the CharacterEvents.characterHasEverything event. Thus, doesPlayerCharacterHaveEverything will never return true for characters that spawned before than GeneralUtility was required in the environment in which doesPlayerCharacterHaveEverything is called.

I’m not sure if the developer console command bar has the same environment as server scripts, but if your code worked when you run it in the developer console then perhaps that’s the case.

Anyway, I don’t recommend using the studio command bar when using RagdollSystem. If you want to easily be able to ragdoll or unragdoll at any moment, you can write client code that fires a remote event when the player presses a spesific key and server code that toggles the ragdoll state when that remote event is fired.

1 Like

Ah okay, I didn’t know it used virtual states so I thought it would work inside the command bar.

I seem to have it working, I have a question, would the module work on NPCs? and if it does how would i set it up?

RagdollSystem uses Luau objects to represent the state of the character. The main object is RagdollStructure. If you just want to ragdoll and unragdoll the entire character, the functions in RagdollEaseOfUse should work for NPCs as well. Those functions create a RagdollStructure object for the character if one hasn’t been created for it yet.

However, RagdollEaseOfUse doesn’t have functions for other features such as ragdolling and unragdolling spesific bodyparts or detaching and attaching bodyparts. So if you want to use those features, a RagdollStructure needs to be created with the constructor RagdollStructure.createStructure before you use those features.

With the built-in settings, RagdollStructures are automatically created for player characters when my code considers the character to be fully loaded. The setting that determines whether they should be automatically created is in ragdoll system server settings. For NPCs, you’ll always have to create the RagdollStructure yourself if you want to use the aforementioned features. I recommend creating the RagdollStructure when you spawn the NPC.

One character or one group of connected bodyparts can only have one RagdollStructure. If you try to create a new one when it already has one, an error will be thrown. You can get the existing RagdollStructure by using RagdollStructureCollections.getStructureFromInstance. You can give it the top instance of that character / bodypart group, or any descendant of the top instance.

When you break a joint (using one of the RagdollStructure’s methods for that), the RagdollStructure will be split into two. The original RagdollStructure will represent the parts that are more closely connected to the break hierarchy root bodypart. The new RagdollStructure will represent the other bodyparts. By default, HumanoidRootPart is the break hierarchy root of R6 and R15 characters. For example, if you break the RightShoulder of an R15 character, The BodypartNode objects of RightUpperArm, RightLowerArm and RightHand will be moved to a new RagdollStructure while the BodyPartNodes of the other bodyparts will remain in the original RagdollStructure.

2 Likes

I followed what you said and I have it working, there’s a slight issue though.
I want to remove an NPC’s limb(s) and make it look smooth, but if I give the client network ownership of the NPC, the limbs just phase through the map for some reason.

For whatever reason, when the limb of an R6 character is detached and the server changes the CanCollide to true, Roblox doesn’t seem to replicate the CanCollide change so it’s false on the clients (including the network owner who does the physics simulation). R15 characters don’t have this issue, and in the case of R6, I had missed it in earlier testing because I replicate the player character RagdollStructures (i.e. create and update client copies of the Luau objects) to every client and as a result every client sets the CanCollide to true as well. The issue happened when using a non-replicated RagdollStructure that was network-owned by a player.

I fixed this by adding a new RemoteEvent for telling the clients to which the RagdollStructure is not replicated to change the CanCollide values.

1 Like

Hi, I seem to be receiving this error when I try to load up the EaseOfUse Ragdoll Module, it seems to be that the module is trying to require two other module in ReplicatedStorage that do not exist ("RemoteSystemPackage & “GeneralUtility”), I have searched the folder but I am unable to find these modules, is it possible that you have not included these? Also are you aware of any quick fixes I could apply to make my ragdoll work. Thank you :heart:
image

Although RagdollSystem used to include GeneralUtility and RemoteEventSystem as nested packages, it doesn’t include them anymore. They need to be inserted as siblings of RagdollSystem. The reason why they aren’t included as nested packages anymore is that I don’t want there to be multiple copies of them in the same game if RagdollSystem is not the only thing using them. Now that you asked about this, I added links to the two other packages below the RagdollSystem link so people don’t need to go to my inventory to get them anymore.

1 Like