Help in remaking how you hold Roblox tools

(This is my first post and I’m very new to scripting so any help is appreciated)
Most tools (in this case a rocket launcher) on Roblox are kind of bland because you just point them forward of the character while being able to make the bullets shoot left and right and back.

Well, I’m trying to make it so you can spin the tool all around while using Inverse Kinematics to connect the hand to the tool. I need help optimizing the code because broadcasting a remote event very frequently lags the game (You can see the lag in the videos, especially when you move).

A solution I thought of (well it’s not really a solution, it’s an illusion) was to replicate the rocket launcher on the client so the client’s rocket launcher doesn’t lag because the player is going to be focusing the most on his/her rocket launcher than anyone else’s.
But there has to be a better solution, right?

The following videos show what I’m trying to do:

Without Inverse Kinematics hand:
Video1

With Inverse Kinematics hand:
Video2

Stuff in Starter player (Vector3Value for mouse pos and StringValue for ToolEquipped):
Screenshot 2025-01-28 at 6.22.41 PM

What the playerfolder is and how stuff is sorted in the workspace:

I have the following code in a Server Script in ServerScriptService:

game.Players.PlayerAdded:Connect(function(player)
	local playerfolder = Instance.new("Folder")
	playerfolder.Name = tostring(player)
	playerfolder.Parent = game.Workspace.Players

	local RocketLauncher = game.Workspace.Assets.RocketLauncher:Clone()
	RocketLauncher.Parent = playerfolder
	RocketLauncher.Name = "RocketLauncher"
	RocketLauncher.Model.Transparency = 1

	local IKcontrol = nil
	player.CharacterAdded:Connect(function(character)
		character.Parent = playerfolder

		IKcontrol = Instance.new("IKControl")
		IKcontrol.Parent = character
		IKcontrol.Type = "Position"
		IKcontrol.ChainRoot = character.RightUpperArm
		IKcontrol.EndEffector = character.RightHand
		IKcontrol.Target = nil
		IKcontrol.Enabled = false

		character.ChildAdded:Connect(function(Child)
			if Child.Name == "RocketLauncher" then
				RocketLauncher.Model.Transparency = 0
				IKcontrol.Target = RocketLauncher.Handle
				IKcontrol.Enabled = true
			end
		end)

		character.ChildRemoved:Connect(function(Child)
			if Child.Name == "RocketLauncher" then
				RocketLauncher.Model.Transparency = 1
				IKcontrol.Target = nil
				IKcontrol.Enabled = false
			end
		end)
	end)


	local RemoteEvent = Instance.new("RemoteEvent")
	RemoteEvent.Parent = game.ReplicatedStorage
	RemoteEvent.Name = tostring(player).."RemoteEvent"

	game.ReplicatedStorage[tostring(player).."RemoteEvent"].OnServerEvent:Connect(function(player, Pos, mousepos, weapon)
		if weapon == "RocketLauncher" then
			RocketLauncher:MoveTo(Pos)
			RocketLauncher:SetPrimaryPartCFrame(CFrame.lookAt(RocketLauncher.PrimaryPart.Position, mousepos))
			RocketLauncher:SetPrimaryPartCFrame(RocketLauncher.PrimaryPart.CFrame * CFrame.Angles(0,math.rad(180),0))
		end
	end)


end)


game.Players.PlayerRemoving:Connect(function(player)
	game.Workspace.Players[tostring(player)]:Destroy()
	game.ReplicatedStorage[tostring(player).."RemoteEvent"]:Destroy()
end)

I have the following code in a local script in StarterCharacterScripts:
(The Rocket Launcher position is determined by going in front of the playerpart)

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local player = game.Players.LocalPlayer
local playerfolder = game.Workspace.Players:WaitForChild(tostring(player))


local PlayerPart = Instance.new("Part")
PlayerPart.Size = Vector3.new(1, 1, 1)
PlayerPart.Parent = player
PlayerPart.Name = "PlayerPart"
PlayerPart.CanCollide = false
PlayerPart.CanTouch = false
PlayerPart.CanQuery = false
PlayerPart.Transparency = 1

local mouse = player:GetMouse()
mouse.TargetFilter = playerfolder

local MouseLoop = nil 
local ToolEquippedVal = game.StarterPlayer.ToolEquipped
local PlayerPos = game.StarterPlayer.PlayerPos
local MousePos = game.StarterPlayer.MousePos

RunService.RenderStepped:Connect(function()
	MousePos.Value = mouse.Hit.Position
end)

ToolEquippedVal.Changed:Connect(function()
	if ToolEquippedVal == "none" then
		MouseLoop:Disconnect()
	end
	MouseLoop = MousePos.Changed:Connect(function()
		local ArmPosition = player.Character.RightUpperArm.Position

		PlayerPart.CFrame = CFrame.lookAt(Vector3.new(ArmPosition.X, ArmPosition.Y + 0.5, ArmPosition.Z), mouse.Hit.Position)

		game.ReplicatedStorage[tostring(player).."RemoteEvent"]:FireServer(PlayerPart.Position + PlayerPart.CFrame.LookVector * 1.8, mouse.hit.Position, ToolEquippedVal.Value)
	end)

end)

The following script in the tool:

local Tool = script.Parent
local ToolEquippedVal = game.StarterPlayer.ToolEquipped -- The StringValue in StarterPlayer

Tool.Equipped:Connect(function()
	ToolEquippedVal.Value = "RocketLauncher"
end)

Tool.Unequipped:Connect(function()
	ToolEquippedVal.Value = "none"
end)
1 Like