Preventing player from unequiping tool

local Tool = script.Parent

local Player = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild('Humanoid')

script.Parent.Unequipped:Connect(function()
	Humanoid:EquipTool(Tool) -- Error
end)

Something unexpectedly tried to set the parent of Sword to NinjoOnline while trying to set the parent of Sword. Current parent is Backpack.

Can anyone explain why this is happening?? The way I see it, Tool is the scripts parent, which is the tool, and so Humanoid:EquipTool(Tool) should equip the tool?

12 Likes

The problem is that when Unequipped is first called, you can’t equip it - because it’s still in the process of unequipping it.

What you can do is add a wait() in there, just before you call EquipTool, and that should fix it. Gives it a few ms to finish up the unequip first.

5 Likes

This might be leaning away from your intended vision, but if the tool is never supposed to be unequipped, you could code your own tool logic and have it act as a tool (meaning that you don’t need a tool instance, just a local script)

Example:

local tool = { }

tool.name = "sword"

tool.animating = false
tool.model = nil
tool.welds = { }
tool.damage = 30

function tool.equip( )
 --do something
end

function tool.slash( )
--animation logic
end

And then you can use UserInputService events to implement some of the “tool” / item logic.

A very common point of discussion I like to raise with myself and sometimes with other developers is the benefits of a pseudotool versus that of an actual tool. This use case is in the favour of pseudotools; if you don’t want players to unequip tools, then you best not rely on the Tool instance at all.

Script a tool like you normally would, but change the tool to a model and cover for cases you may not have access to. Handle the welding, tool backend and API all on your own. You can use the above as an example for coding pseudotools.

Addendum

If you’re interested in my discussion topics, you can view those here (they’re pretty much repeats with different wording, somewhat):

Tool Instances vs Pseudo Tools: Aiming to find a reasonable preference

Preference for handling tools?

3 Likes

cc @colbert2677

Problem I’ve had with this kinda stuff is the whole welding it to the player etc. Made it really frustrating to do all this extra stuff when the tool object provides it all to me already

Just a quick write up of how I tried to do it in the past

local Tool = script.Parent

local Player = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild('Humanoid')

local RightHand = Character:WaitForChild('RightHand')

local Weld = Instance.new('Weld')
	
Weld.C0 = RightHand.RightGripAttachment.CFrame
Weld.C1 = Tool.Handle.CFrame

Weld.Part0 = Character.RightHand
Weld.Part1 = Tool.Handle	

Weld.Parent = Tool.Handle
Tool.Parent = Character

And it would go into the players character, but it would be somewhere random in the map, not actually attached to my players hand

Try doing

Weld.C0 = CFrame.new(RightHand.RightGripAttachment.Position)

Alternatively, create a dictionary with different CFrames for each Tool as where you grip one one tool, may be different on another.

This is my first time hearing about pseudo tool terminology. I’ve coded them before but never knew this was a common practice.

Welding is probably the biggest challenge I faced in the past. I solved this by anchoring the WeldTooPart and the pseudo ToolHandlePart, process the weld, then unanchoring after the weld.

I think this happens because during the render step the players are pinging the server with a movement request and and server physics are trying to move the player in a different direction. So the weld is processed with this variable state situation.

That’s not true. A player can still press backspace to unequip

Following up what @ThomasChabot suggested. You can probably catch the next immediate render step which would process all the parent changing before you try to equip again. You just need to someway of tracking toolIsEquiped.

game:GetService('RunService').Stepped:Connect(function()
    if not toolIsEquiped then
        Humanoid:EquipTool(Tool)
    end
end)

Using that made no difference visually than just having

Weapon.Unequipped:Connect(function()
	wait()
	Humanoid:EquipTool(Weapon)
end)

Not sure which one would be better to use, if there is a specific reason to use either one. But in terms of keeping the script clean/less variables, I’ve stuck with the just using wait() after its unequipped and then requipping

4 Likes

Yeah I think wait() is better too. Definitely more efficient. Does that solve your problem?

Ye, not exactly the nicest way of fixing it but it works i guess

You don’t actually need to go through all that trouble. There’s always alternate ways to weld things other than that hard-coding nonsense.

The first; Roblox has added left and right grip attachments to both R6 and R15 rigs. This enables you to line up attachments and create a Motor6D between two core parts.

The second; create proxy parts and weld them up. This is the most common way of handling welds and it’s satisfyingly easy. Yes, it does introduce an extra part, but I’ve yet to see any actual problems arising out of it. I have an explanation here of how it works.

3 Likes

The hardest part about psuedo-tools is arguably welding, animations, and animation replication for other clients. Truly understanding how welding + CFraming works w/ a character, along with linear interpolation animating isn’t something you will learn instantly (coming from a guy that’s been developing pseudo-tools for about a year now).

Games like Phantom Forces use pseudo-tools and the level of quality is amazing.

2 Likes