Hey everyone, i’m currently working on a grip and carry system and it is designed to allow players to interact with other players who are in a “knocked” state.
This system involves two scripts: a ServerScript and a LocalScript.
The ServerScript handles setting a player’s knocked state, handling health restrictions, and listening for the B and C key presses to perform grip or carry actions. The LocalScript complements this by playing animations and sounds on the client side.
The issue here is that the B and C keys, which trigger the grip and carry actions, even after being registered and approved by the server, the animations and sounds aren't firing.
I’ll post the client script, for further clarity. thanks for the help…
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Animations = ReplicatedStorage:WaitForChild("Animations")
local Sounds = ReplicatedStorage:WaitForChild("Sounds")
local GripEvent = ReplicatedStorage.Events:WaitForChild("GripEvent")
local CarryEvent = ReplicatedStorage.Events:WaitForChild("CarryEvent")
local UserInputService = game:GetService("UserInputService")
local Player = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")
local cooldownTime = 1
local lastPressed = 0
local function ensureBodyAttachment(hrp)
if not hrp:FindFirstChild("BodyAttachment") then
Instance.new("Attachment", hrp).Name = "BodyAttachment"
print("BodyAttachment added to", hrp.Parent.Name)
end
end
local playerHRP = Character:WaitForChild("HumanoidRootPart")
ensureBodyAttachment(playerHRP)
local function createAlignPosition(victimHRP, playerHRP)
local alignPosition = Instance.new("AlignPosition")
alignPosition.Attachment0 = playerHRP:FindFirstChild("BodyAttachment")
alignPosition.Attachment1 = victimHRP:FindFirstChild("BodyAttachment")
alignPosition.RigidityEnabled = true
alignPosition.MaxForce = math.huge
alignPosition.MaxVelocity = 20
alignPosition.Parent = victimHRP
print("AlignPosition created for", victimHRP.Parent.Name)
return alignPosition
end
local function playGripAnimation(victim)
print("Playing grip animation for victim:", victim.Name)
local victimHRP = victim:WaitForChild("HumanoidRootPart")
ensureBodyAttachment(victimHRP)
local gripAnimation = Animations:WaitForChild("Grip")
local victimAnimation = Animations:WaitForChild("BeingGripped")
Humanoid:LoadAnimation(gripAnimation):Play()
victim:FindFirstChild("Humanoid"):LoadAnimation(victimAnimation):Play()
print("Grip animations playing.")
task.delay(0.3, function()
Sounds:WaitForChild("Hit"):Play()
print("Grip sound played.")
end)
local alignPosition = createAlignPosition(victimHRP, playerHRP)
task.delay(5, function()
alignPosition:Destroy()
end)
end
local function playCarryAnimation(victim)
print("Playing carry animation for victim:", victim.Name)
local victimHRP = victim:WaitForChild("HumanoidRootPart")
ensureBodyAttachment(victimHRP)
local carryAnimation = Animations:WaitForChild("Carry")
local victimAnimation = Animations:WaitForChild("BeingCarried")
Humanoid:LoadAnimation(carryAnimation):Play()
victim:FindFirstChild("Humanoid"):LoadAnimation(victimAnimation):Play()
print("Carry animations playing.")
task.delay(0.3, function()
Sounds:WaitForChild("Splurge2"):Play()
print("Carry sound played.")
end)
local alignPosition = createAlignPosition(victimHRP, playerHRP)
task.delay(5, function()
alignPosition:Destroy()
end)
end
UserInputService.InputBegan:Connect(function(input, isProcessed)
if isProcessed then return end
local currentTime = tick()
if currentTime - lastPressed < cooldownTime then
return
end
local targetPlayer = nil
for _, otherPlayer in pairs(game.Players:GetPlayers()) do
if otherPlayer ~= Player and otherPlayer.Character and otherPlayer.Character:GetAttribute("IsKnocked") then
targetPlayer = otherPlayer
print("Target player identified for action:", targetPlayer.Name)
break
end
end
if input.KeyCode == Enum.KeyCode.B and targetPlayer then
print("Grip key (B) pressed. Sending request to server.")
lastPressed = currentTime
GripEvent:FireServer(targetPlayer)
end
if input.KeyCode == Enum.KeyCode.C and targetPlayer then
print("Carry key (C) pressed. Sending request to server.")
lastPressed = currentTime
CarryEvent:FireServer(targetPlayer)
end
end)
GripEvent.OnClientEvent:Connect(function(player, victim)
if player == Player then
print("Grip event received for player:", player.Name)
playGripAnimation(victim)
end
end)
CarryEvent.OnClientEvent:Connect(function(player, victim)
if player == Player then
print("Carry event received for player:", player.Name)
playCarryAnimation(victim)
end
end)
Server: The server listens for the event from the client (OnServerEvent), processes the action, and fires a response back to the client (FireClient).
Client: The client listens for key inputs (grip or carry) and sends the request to the server (FireServer). The server processes the request and fires the event back to the client to trigger the animations and sounds.
– Grip Action (B key)
if input.KeyCode == Enum.KeyCode.B and targetPlayer then
print("Grip key (B) pressed. Sending request to server.")
lastPressed = currentTime
GripEvent:FireServer(targetPlayer)
end
– Carry Action (C key)
if input.KeyCode == Enum.KeyCode.C and targetPlayer then
print("Carry key (C) pressed. Sending request to server.")
lastPressed = currentTime
CarryEvent:FireServer(targetPlayer)
end
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Sounds = ReplicatedStorage:WaitForChild("Sounds")
local MIN_HEALTH_THRESHOLD = 1
local KNOCKED_DURATION = 50
local PROXIMITY_RADIUS = 10
local GripEvent = ReplicatedStorage.Events:WaitForChild("GripEvent")
local CarryEvent = ReplicatedStorage.Events:WaitForChild("CarryEvent")
local function stopAllActions(character)
local humanoid = character:FindFirstChild("Humanoid")
if humanoid then
humanoid.PlatformStand = true
humanoid.WalkSpeed = 0
humanoid.JumpPower = 0
print("Stopping all actions for", character.Name)
end
end
local function restoreNormalState(character)
local humanoid = character:FindFirstChild("Humanoid")
if humanoid then
humanoid.PlatformStand = false
humanoid.WalkSpeed = 16
humanoid.JumpPower = 50
print("Restoring normal state for", character.Name)
end
end
local function applyKnockedState(character)
local humanoid = character:FindFirstChild("Humanoid")
if not humanoid then return end
humanoid.Health = MIN_HEALTH_THRESHOLD
stopAllActions(character)
character:SetPrimaryPartCFrame(character.HumanoidRootPart.CFrame * CFrame.new(0, -2, 0))
character:SetAttribute("IsKnocked", true)
Sounds.Splurge:Play()
print("Player knocked:", character.Name)
wait(KNOCKED_DURATION)
restoreNormalState(character)
character:SetAttribute("IsKnocked", false)
print("Knocked state ended for:", character.Name)
end
local function isPlayerCloseEnough(player, victim)
local playerHRP = player.Character and player.Character:FindFirstChild("HumanoidRootPart")
local victimHRP = victim.Character and victim.Character:FindFirstChild("HumanoidRootPart")
if playerHRP and victimHRP then
local distance = (playerHRP.Position - victimHRP.Position).Magnitude
print("Distance between player:", player.Name, "and victim:", victim.Name, "is:", distance)
print("Proximity radius is set to:", PROXIMITY_RADIUS)
return distance <= PROXIMITY_RADIUS
end
print("Error: Could not find HumanoidRootPart for either player or victim")
return false
end
local function preventDeath(humanoid)
humanoid.HealthChanged:Connect(function()
if humanoid.Health < MIN_HEALTH_THRESHOLD then
humanoid.Health = MIN_HEALTH_THRESHOLD
end
end)
end
GripEvent.OnServerEvent:Connect(function(player, targetPlayer)
local character = player.Character
local targetCharacter = targetPlayer.Character
if character and targetCharacter and targetCharacter:GetAttribute("IsKnocked") then
if isPlayerCloseEnough(player, targetPlayer) then
print("Grip action approved. Player:", player.Name, "Victim:", targetPlayer.Name)
GripEvent:FireClient(player, targetPlayer)
else
print("Grip action denied. Target too far.")
end
else
print("Grip action denied. Target is not knocked.")
end
end)
CarryEvent.OnServerEvent:Connect(function(player, targetPlayer)
local character = player.Character
local targetCharacter = targetPlayer.Character
if character and targetCharacter and targetCharacter:GetAttribute("IsKnocked") then
if isPlayerCloseEnough(player, targetPlayer) then
print("Carry action approved. Player:", player.Name, "Victim:", targetPlayer.Name)
CarryEvent:FireClient(player, targetPlayer)
else
print("Carry action denied. Target too far.")
end
else
print("Carry action denied. Target is not knocked.")
end
end)
Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
local humanoid = character:WaitForChild("Humanoid")
preventDeath(humanoid)
humanoid.HealthChanged:Connect(function()
if humanoid.Health <= 0 then
applyKnockedState(character)
end
end)
end)
end)
I assume victim is another player? A Player cannot animate another Player’s Animator (when you call Humanoid:LoadAnimation it just calls Humanoid.Animator:LoadAnimation). And, make sure the Priority of the Animation is set to something above Core.
you’re right, it checks if the event was triggered by the local player itself, but it’s redundant. The client is only going to listen to the events that it sent to itself, so this check will always be true.
You’re on the right track; however, like Judgy_Oreo said, you cannot play animations on another player’s character, the attacker (person doing the grip/carry action) can only manage assemblies that they have network ownership over (namely their own character, and any unanchored parts within a certain distance, any anything else you explicitly give them ownership with using BasePart:SetNetworkOwner.
Two things you can do for this: fire a separate remote event to the VICTIM’s client, which will play that animation on their own character, OR, you can just load and play the animation on the victim’s character directly from the server.
Another issue, but with the same cause, is that you’re trying to manage the physics of another player’s character from the attacker’s client, which once again, isn’t feasible because you don’t have network ownership over it.
To solve that issue, you can create the AlignPosition on the server instead; however, this may or may not appear delayed when you walk around, I’m not certain. What I would personally do is create a clone of the victim and hide the original victim’s character, and then give the attacker network ownership over it and then create the AlignPosition for that clone on the attacker’s client so that it looks accurate on all screens, especially for the attacker.
Now –
I know before I suggested AlignPosition, which is still a good option if you do it right, but you can also loop through the entire assembly of the victim’s character and make it massless, THEN create the Weld on the server between your attacker and the victim. Making their limbs massless means they can no longer keep ownership of their own character when the weld links them together, giving the attacker full network ownership of their character for the period of the carrying. Then, I’d still play the animation on the server to prevent any finnicky replication issues.
Just be careful if you go the route of welding, replication is really a hit or miss, there are cases where welding two players can cause other issues regardless of Mass, where if either of the welded players die, the other player dies too.
I would also try, for the sake of simplicity, giving the attacker network ownership of the victim’s character by doing victimRootPart:SetNetworkOwner(attackerPlayer) if you do use AlignPosition. That may work and no longer require you to do the whole cloning and invisibility trick.
that was it, i wouldnt have figured it out on my own tbh, this was way harder than i had initially accounted for, although i’m still having issues with synchronizing all the animations now that each one is fired by its own event handler, and also few welding issues to actually make it work as i’d like, but so far this is what i ended up with. Let me know if you have any more inputs into this, THANK you so much, that was insanely helpful.
client script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Animations = ReplicatedStorage:WaitForChild("Animations")
local Sounds = ReplicatedStorage:WaitForChild("Sounds")
local GripEvent = ReplicatedStorage.Events:WaitForChild("GripEvent")
local CarryEvent = ReplicatedStorage.Events:WaitForChild("CarryEvent")
local PlayerGripEvent = ReplicatedStorage.Events:WaitForChild("PlayerGripEvent")
local PlayerCarryEvent = ReplicatedStorage.Events:WaitForChild("PlayerCarryEvent")
local VictimGripEvent = ReplicatedStorage.Events:WaitForChild("VictimGripEvent")
local VictimCarryEvent = ReplicatedStorage.Events:WaitForChild("VictimCarryEvent")
local UserInputService = game:GetService("UserInputService")
local Player = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")
local cooldownTime = 1
local lastPressed = 0
local function ensureBodyAttachment(hrp)
if not hrp:FindFirstChild("BodyAttachment") then
local attachment = Instance.new("Attachment", hrp)
attachment.Name = "BodyAttachment"
print("BodyAttachment added to", hrp.Parent.Name)
end
end
local playerHRP = Character:WaitForChild("HumanoidRootPart")
ensureBodyAttachment(playerHRP)
local function createAlignPosition(victimHRP, playerHRP)
local alignPosition = Instance.new("AlignPosition")
alignPosition.Attachment0 = playerHRP:FindFirstChild("BodyAttachment")
alignPosition.Attachment1 = victimHRP:FindFirstChild("BodyAttachment")
alignPosition.RigidityEnabled = true
alignPosition.MaxForce = math.huge
alignPosition.MaxVelocity = 20
alignPosition.Parent = victimHRP
print("AlignPosition created for", victimHRP.Parent.Name)
return alignPosition
end
local function playGripAnimation(victim)
print("Playing grip animation for victim:", victim.Name)
local victimHRP = victim:WaitForChild("HumanoidRootPart")
ensureBodyAttachment(victimHRP)
local gripAnimation = Animations:FindFirstChild("Grip")
local victimAnimation = Animations:FindFirstChild("BeingGripped")
if gripAnimation and victimAnimation then
Humanoid:LoadAnimation(gripAnimation):Play()
victim:FindFirstChild("Humanoid"):LoadAnimation(victimAnimation):Play()
print("Grip animations playing.")
task.delay(0.3, function()
Sounds:WaitForChild("Hit"):Play()
print("Grip sound played.")
end)
local alignPosition = createAlignPosition(victimHRP, playerHRP)
task.delay(5, function()
alignPosition:Destroy()
end)
else
warn("Grip or victim animation missing")
end
end
local function playCarryAnimation(victim)
print("Playing carry animation for victim:", victim.Name)
local victimHRP = victim:WaitForChild("HumanoidRootPart")
ensureBodyAttachment(victimHRP)
local carryAnimation = Animations:FindFirstChild("Carry")
local victimAnimation = Animations:FindFirstChild("BeingCarried")
if carryAnimation and victimAnimation then
Humanoid:LoadAnimation(carryAnimation):Play()
victim:FindFirstChild("Humanoid"):LoadAnimation(victimAnimation):Play()
print("Carry animations playing.")
task.delay(0.3, function()
Sounds:WaitForChild("Splurge2"):Play()
print("Carry sound played.")
end)
local alignPosition = createAlignPosition(victimHRP, playerHRP)
task.delay(5, function()
alignPosition:Destroy()
end)
else
warn("Carry or victim animation missing")
end
end
UserInputService.InputBegan:Connect(function(input, isProcessed)
if isProcessed then return end
local currentTime = tick()
if currentTime - lastPressed < cooldownTime then return end
local targetPlayer
for _, otherPlayer in pairs(game.Players:GetPlayers()) do
if otherPlayer ~= Player and otherPlayer.Character and otherPlayer.Character:GetAttribute("IsKnocked") then
targetPlayer = otherPlayer
print("Target player identified for action:", targetPlayer.Name)
break
end
end
if input.KeyCode == Enum.KeyCode.B and targetPlayer then
print("Grip key (B) pressed. Sending request to server.")
lastPressed = currentTime
GripEvent:FireServer(targetPlayer)
elseif input.KeyCode == Enum.KeyCode.C and targetPlayer then
print("Carry key (C) pressed. Sending request to server.")
lastPressed = currentTime
CarryEvent:FireServer(targetPlayer)
end
end)
PlayerGripEvent.OnClientEvent:Connect(function(_, victim)
print("Grip event received for player.")
playGripAnimation(victim)
end)
PlayerCarryEvent.OnClientEvent:Connect(function(_, victim)
print("Carry event received for player.")
playCarryAnimation(victim)
end)
VictimGripEvent.OnClientEvent:Connect(function()
print("Playing victim's grip animation.")
playGripAnimation(Player.Character)
end)
VictimCarryEvent.OnClientEvent:Connect(function()
print("Playing victim's carry animation.")
playCarryAnimation(Player.Character)
end)