Localscript under StarterCharacterScripts loading late

Hello
I have a script below

local rs = game:GetService("ReplicatedStorage")
local plrs = game:GetService("Players")
local run = game:GetService("RunService")

local player = plrs.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local mouse = player:GetMouse()

local torso = char:WaitForChild("Torso")
local rightArm = char:WaitForChild("Right Arm")

local event = rs:WaitForChild("events"):WaitForChild("LightsaberMove")

local armOffset = torso.CFrame:Inverse() * rightArm.CFrame

-- weld to attach right arm to torso
local armWeld = Instance.new("Weld")
armWeld.Part0 = torso
armWeld.Part1 = rightArm
armWeld.Parent = rightArm

local rotCFrame -- store rotation data
local armPos -- store arm position relative to torso

-- update arm's position and rotation every frame
run.RenderStepped:Connect(function()
	local torsoPos = torso.Position
	local mouseHit = mouse.Hit.Position

	-- lock movement to y-z plane
	mouseHit = Vector3.new(torsoPos.X, mouseHit.Y, mouseHit.Z)

	-- calculate direction to mouse
	local lookAtCFrame = CFrame.lookAt(torsoPos, mouseHit)
	rotCFrame = CFrame.new(torsoPos) * CFrame.Angles(lookAtCFrame:ToEulerAnglesXYZ())

	-- store arm's relative position
	armPos = rightArm.CFrame.Position - torso.CFrame.Position

	-- update weld with new rotation
	armWeld.C0 = armOffset * torso.CFrame:toObjectSpace(rotCFrame)
end)

-- send rotation and position data to server
local function sendData()
	if rotCFrame and armPos then
		event:FireServer(rotCFrame, armPos, torso.CFrame)
	end
end

-- run continuously
while true do
	sendData()
	wait(0.05)
end

Works great on the first load, but after it loads a bit late, and breaks. However, the serverside of it works great even if it loads late on the client.

I would appreciate any insight on this.
thanks!

2 Likes

hi, im not sure what do you mean with this: ā€˜ā€˜Works great on the first load, but after it loads a bit late, and breaks.’’ because isnt spelled correctly, but i guess you mean when the player spawns. so, if im right, then basically this behavior is common when scripts do not properly handle the character’s lifecycle, especially during respawns, so i recode your script, obviously fixing that issue, here:

local rs = game:GetService("ReplicatedStorage")
local plrs = game:GetService("Players")
local run = game:GetService("RunService")

local player = plrs.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local mouse = player:GetMouse()

local torso = char:WaitForChild("Torso")
local rightArm = char:WaitForChild("Right Arm")

local event = rs:WaitForChild("events"):WaitForChild("LightsaberMove")

local armOffset = torso.CFrame:Inverse() * rightArm.CFrame

-- Weld to attach right arm to torso
local armWeld = Instance.new("Weld")
armWeld.Part0 = torso
armWeld.Part1 = rightArm
armWeld.Parent = rightArm

local rotCFrame -- Store rotation data
local armPos -- Store arm position relative to torso

-- Function to initialize character components
local function initializeCharacter(character)
    torso = character:WaitForChild("Torso")
    rightArm = character:WaitForChild("Right Arm")
    armOffset = torso.CFrame:Inverse() * rightArm.CFrame

    -- Recreate the weld
    armWeld:Destroy()
    armWeld = Instance.new("Weld")
    armWeld.Part0 = torso
    armWeld.Part1 = rightArm
    armWeld.Parent = rightArm
end

-- Update arm's position and rotation every frame
run.RenderStepped:Connect(function()
    local torsoPos = torso.Position
    local mouseHit = mouse.Hit.Position

    -- Lock movement to y-z plane
    mouseHit = Vector3.new(torsoPos.X, mouseHit.Y, mouseHit.Z)

    -- Calculate direction to mouse
    local lookAtCFrame = CFrame.lookAt(torsoPos, mouseHit)
    rotCFrame = CFrame.new(torsoPos) * CFrame.Angles(lookAtCFrame:ToEulerAnglesXYZ())

    -- Store arm's relative position
    armPos = rightArm.CFrame.Position - torso.CFrame.Position

    -- Update weld with new rotation
    armWeld.C0 = armOffset * torso.CFrame:toObjectSpace(rotCFrame)
end)

-- Send rotation and position data to server
local function sendData()
    if rotCFrame and armPos then
        event:FireServer(rotCFrame, armPos, torso.CFrame)
    end
end

-- Run continuously
while true do
    sendData()
    wait(0.05)
end

-- Listen for character respawn
player.CharacterAdded:Connect(function(newCharacter)
    char = newCharacter
    initializeCharacter(char)
end)

Hey! thanks for the response.


Here’s a video of the behavior with the script you posted as replacement.

Note that the hand is the only thing ā€œrotatingā€ from the script, I’ve got a separate one mounting the sword onto the hand.

After respawning, I think that it jumps to the direction of the cursor regardless of the axis, I’m not sure though.

1 Like

so, still being an issue right?, i mean, i think that the issue is that the whole body is moving to the mouse, instead of just the arm, right?, thats what it happens now?

1 Like

The behavior is in the video above, the arm rotates around the wrong axis or something/

1 Like

yeah it does it after dying, ill try to fix it, give me a sec.

1 Like

check it out:

local rs = game:GetService("ReplicatedStorage")
local plrs = game:GetService("Players")
local run = game:GetService("RunService")

local player = plrs.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local mouse = player:GetMouse()

local torso = char:WaitForChild("Torso")
local rightArm = char:WaitForChild("Right Arm")

local event = rs:WaitForChild("events"):WaitForChild("LightsaberMove")

local armOffset = torso.CFrame:Inverse() * rightArm.CFrame

-- Weld to attach right arm to torso
local armWeld = Instance.new("Weld")
armWeld.Part0 = torso
armWeld.Part1 = rightArm
armWeld.Parent = rightArm

local rotCFrame -- Store rotation data
local armPos -- Store arm position relative to torso

-- Function to initialize character components
local function initializeCharacter(character)
    torso = character:WaitForChild("Torso")
    rightArm = character:WaitForChild("Right Arm")
    armOffset = torso.CFrame:Inverse() * rightArm.CFrame

    -- Recreate the weld
    armWeld:Destroy()
    armWeld = Instance.new("Weld")
    armWeld.Part0 = torso
    armWeld.Part1 = rightArm
    armWeld.Parent = rightArm
end

-- Update arm's position and rotation every frame
run.Stepped:Connect(function()
    local torsoPos = torso.Position
    local mouseHit = mouse.Hit.Position

    -- Lock movement to y-z plane
    mouseHit = Vector3.new(torsoPos.X, mouseHit.Y, mouseHit.Z)

    -- Calculate direction to mouse
    local lookAtCFrame = CFrame.lookAt(torsoPos, mouseHit)
    rotCFrame = CFrame.new(torsoPos) * CFrame.Angles(lookAtCFrame:ToEulerAnglesXYZ())

    -- Store arm's relative position
    armPos = rightArm.CFrame.Position - torso.CFrame.Position

    -- Update weld with new rotation
    armWeld.Transform = armOffset * torso.CFrame:toObjectSpace(rotCFrame)
end)

-- Send rotation and position data to server
local function sendData()
    if rotCFrame and armPos then
        event:FireServer(rotCFrame, armPos, torso.CFrame)
    end
end

-- Run continuously
while true do
    sendData()
    wait(0.05)
end

-- Listen for character respawn
player.CharacterAdded:Connect(function(newCharacter)
    char = newCharacter
    initializeCharacter(char)
end)

1 Like

the script is in StarterCharacterScripts so player.CharacterAdded would never fire since the script runs after the character gets added

Also you placed the event after a loop so it wouldn’t run anyway.

2 Likes

my bad, post it wrongly, heres the new script again:

-- Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

-- Player and Character
local player = Players.LocalPlayer
local mouse = player:GetMouse()
local character = script.Parent
local humanoid = character:WaitForChild("Humanoid")

-- Remote Event
local event = ReplicatedStorage:WaitForChild("events"):WaitForChild("LightsaberMove")

-- Variables
local torso = character:WaitForChild("Torso")
local rightArm = character:WaitForChild("Right Arm")
local rightShoulder = torso:FindFirstChild("Right Shoulder") or torso:FindFirstChild("RightShoulder")

-- Ensure the right shoulder is a Motor6D
if not rightShoulder or not rightShoulder:IsA("Motor6D") then
    warn("Right Shoulder not found or is not a Motor6D.")
    return
end

-- Store the original C0 and C1
local originalC0 = rightShoulder.C0
local originalC1 = rightShoulder.C1

-- Function to update arm rotation
local function updateArm()
    local mousePos = mouse.Hit.p
    local torsoPos = torso.Position

    -- Calculate direction from torso to mouse
    local direction = (mousePos - torsoPos).unit

    -- Calculate the desired CFrame for the shoulder
    local targetCFrame = CFrame.new(torsoPos, torsoPos + direction)

    -- Update the Motor6D's C0 to rotate the arm
    rightShoulder.C0 = originalC0:ToObjectSpace(torso.CFrame:ToObjectSpace(targetCFrame))
end

-- Update arm rotation every frame
RunService.RenderStepped:Connect(function()
    if humanoid.Health > 0 then
        updateArm()
    end
end)

1 Like

forgot to mention, its r6 not r15

Also I don’t know if we need to mess with the actual script functionality, It only happens when the character respawns.

1 Like

my bad with the rig type, here again xd:

-- Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

-- Player and Character
local player = Players.LocalPlayer
local mouse = player:GetMouse()
local character = script.Parent
local humanoid = character:WaitForChild("Humanoid")

-- Remote Event
local event = ReplicatedStorage:WaitForChild("events"):WaitForChild("LightsaberMove")

-- Variables
local torso = character:WaitForChild("Torso")
local rightArm = character:WaitForChild("Right Arm")
local rightShoulder = torso:WaitForChild("Right Shoulder")

-- Ensure the right shoulder is a Motor6D
if not rightShoulder or not rightShoulder:IsA("Motor6D") then
    warn("Right Shoulder not found or is not a Motor6D.")
    return
end

-- Store the original C0 and C1
local originalC0 = rightShoulder.C0
local originalC1 = rightShoulder.C1

-- Function to update arm rotation
local function updateArm()
    local mousePos = mouse.Hit.p
    local torsoPos = torso.Position

    -- Calculate direction from torso to mouse
    local direction = (mousePos - torsoPos).unit

    -- Calculate the desired CFrame for the shoulder
    local targetCFrame = CFrame.new(torsoPos, torsoPos + direction)

    -- Update the Motor6D's C0 to rotate the arm
    rightShoulder.C0 = originalC0:ToObjectSpace(torso.CFrame:ToObjectSpace(targetCFrame))
end

-- Update arm rotation every frame
RunService.RenderStepped:Connect(function()
    if humanoid.Health > 0 then
        updateArm()
    end
end)

1 Like

tested this:

1 Like

omg, check it now:

-- Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

-- Player and Character
local player = Players.LocalPlayer
local mouse = player:GetMouse()
local character = script.Parent
local humanoid = character:WaitForChild("Humanoid")

-- Remote Event
local event = ReplicatedStorage:WaitForChild("events"):WaitForChild("LightsaberMove")

-- Variables
local torso = character:WaitForChild("Torso")
local rightArm = character:WaitForChild("Right Arm")
local rightShoulder = torso:WaitForChild("Right Shoulder")

-- Ensure the right shoulder is a Motor6D
if not rightShoulder or not rightShoulder:IsA("Motor6D") then
    warn("Right Shoulder not found or is not a Motor6D.")
    return
end

-- Store the original C0
local originalC0 = rightShoulder.C0

-- Function to update arm rotation
local function updateArm()
    local mousePos = Vector3.new(mouse.Hit.p.X, mouse.Hit.p.Y, torso.Position.Z)
    local torsoPos = torso.Position

    -- Calculate the direction to the mouse in 2D space
    local direction = (mousePos - torsoPos).unit

    -- Calculate the angle between the arm's default position and the mouse direction
    local angle = math.atan2(direction.Y, direction.X)

    -- Update the Motor6D's C0 to rotate the arm around its local axis
    rightShoulder.C0 = originalC0 * CFrame.Angles(0, 0, -angle)
end

-- Update arm rotation every frame
RunService.RenderStepped:Connect(function()
    if humanoid.Health > 0 then
        updateArm()
    end
end)

2 Likes

So the original functionality is gone, probably because your script is trying to use r15 instead of r6. Again, I dont know if we need to change anything other than something related to calibration on respawn.

Let me know if I am wrong

1 Like

look, i stated since the first script you post it, so check it out and tell me what happens:

local rs = game:GetService("ReplicatedStorage")
local plrs = game:GetService("Players")
local run = game:GetService("RunService")

local player = plrs.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local mouse = player:GetMouse()

local function setupCharacter(character)
    local torso = character:WaitForChild("Torso")
    local rightArm = character:WaitForChild("Right Arm")

    local event = rs:WaitForChild("events"):WaitForChild("LightsaberMove")

    local armOffset = torso.CFrame:Inverse() * rightArm.CFrame

    -- Weld to attach right arm to torso
    local armWeld = Instance.new("Weld")
    armWeld.Part0 = torso
    armWeld.Part1 = rightArm
    armWeld.Parent = rightArm

    local rotCFrame -- store rotation data
    local armPos -- store arm position relative to torso

    -- Update arm's position and rotation every frame
    run.RenderStepped:Connect(function()
        if not torso or not rightArm then return end
        local torsoPos = torso.Position
        local mouseHit = mouse.Hit.Position

        -- Lock movement to y-z plane
        mouseHit = Vector3.new(torsoPos.X, mouseHit.Y, mouseHit.Z)

        -- Calculate direction to mouse
        local lookAtCFrame = CFrame.lookAt(torsoPos, mouseHit)
        rotCFrame = CFrame.new(torsoPos) * CFrame.Angles(lookAtCFrame:ToEulerAnglesXYZ())

        -- Store arm's relative position
        armPos = rightArm.CFrame.Position - torso.CFrame.Position

        -- Update weld with new rotation
        armWeld.C0 = armOffset * torso.CFrame:toObjectSpace(rotCFrame)
    end)

    -- Send rotation and position data to server
    local function sendData()
        if rotCFrame and armPos then
            event:FireServer(rotCFrame, armPos, torso.CFrame)
        end
    end

    -- Run continuously
    while true do
        sendData()
        wait(0.05)
    end
end

-- Setup character on spawn
setupCharacter(char)

-- Handle character respawn
player.CharacterAdded:Connect(function(newCharacter)
    char = newCharacter
    setupCharacter(char)
end)

1 Like

So Here the functionality of following the mouse works great, but the same thing happens when respawning

1 Like

Try this

local rs = game:GetService("ReplicatedStorage")
local plrs = game:GetService("Players")
local run = game:GetService("RunService")

local player = plrs.LocalPlayer
local mouse = player:GetMouse()

local function setupCharacter(character)

    local torso = character:WaitForChild("Torso")
    local rightArm = character:WaitForChild("Right Arm")

    local event = rs:WaitForChild("events"):WaitForChild("LightsaberMove")

    local armWeld = Instance.new("Weld")
    armWeld.Part0 = torso
    armWeld.Part1 = rightArm
    armWeld.Parent = rightArm

    local armOffset = torso.CFrame:Inverse() * rightArm.CFrame
    local rotCFrame -- store rotation data
    local armPos -- store arm position relative to torso

    run.RenderStepped:Connect(function()
        if not torso or not rightArm then return end
        local torsoPos = torso.Position
        local mouseHit = mouse.Hit.Position

 
        mouseHit = Vector3.new(torsoPos.X, mouseHit.Y, mouseHit.Z)

  
        local lookAtCFrame = CFrame.lookAt(torsoPos, mouseHit)
        rotCFrame = CFrame.new(torsoPos) * CFrame.Angles(lookAtCFrame:ToEulerAnglesXYZ())

        -- Store arm's relative position
        armPos = rightArm.CFrame.Position - torso.CFrame.Position

        -- Update weld with new rotation
        armWeld.C0 = armOffset * torso.CFrame:toObjectSpace(rotCFrame)
    end)

    -- Send rotation and position data to server
    local function sendData()
        if rotCFrame and armPos then
            event:FireServer(rotCFrame, armPos, torso.CFrame)
        end
    end

    -- Run continuously
    while true do
        sendData()
        wait(0.05) -- Send data at regular intervals
    end
end

-- Setup character on initial spawn
setupCharacter(player.Character or player.CharacterAdded:Wait())

-- Handle character respawn with a wait to ensure all parts are loaded
player.CharacterAdded:Connect(function(newCharacter)
    -- Ensure that all necessary parts are loaded before calling setupCharacter
    newCharacter:WaitForChild("Torso")
    newCharacter:WaitForChild("Right Arm")
    
    setupCharacter(newCharacter)
end)

Idk if this fixes ur problem but I tried.

1 Like

Fixed The respawning issue thanks!
But the right arm is inside the torso now instead of at its normal position, Any idea how to keep it in the same spot relative to the torso?

local rs = game:GetService("ReplicatedStorage")
local plrs = game:GetService("Players")
local run = game:GetService("RunService")

local player = plrs.LocalPlayer
local mouse = player:GetMouse()

local function setupCharacter(character)

    local torso = character:WaitForChild("Torso")
    local rightArm = character:WaitForChild("Right Arm")

    local event = rs:WaitForChild("events"):WaitForChild("LightsaberMove")

    for _, obj in pairs(rightArm:GetChildren()) do
        if obj:IsA("Weld") then
            obj:Destroy()
        end
    end

    local armWeld = Instance.new("Weld")
    armWeld.Part0 = torso
    armWeld.Part1 = rightArm
    armWeld.Parent = rightArm

    local armOffset = torso.CFrame:Inverse() * rightArm.CFrame
    local rotCFrame -- store rotation data
    local armPos -- store arm position relative to torso

    run.RenderStepped:Connect(function()
        if not torso or not rightArm then return end
        

        local torsoPos = torso.Position
        local mouseHit = mouse.Hit.Position
        mouseHit = Vector3.new(torsoPos.X, mouseHit.Y, mouseHit.Z)


        local lookAtCFrame = CFrame.lookAt(torsoPos, mouseHit)
        rotCFrame = CFrame.new(torsoPos) * CFrame.Angles(lookAtCFrame:ToEulerAnglesXYZ())

        armPos = rightArm.CFrame.Position - torso.CFrame.Position

        armWeld.C0 = armOffset * torso.CFrame:toObjectSpace(rotCFrame)
    end)


    local function sendData()
        if rotCFrame and armPos then
            event:FireServer(rotCFrame, armPos, torso.CFrame)
        end
    end

    while true do
        sendData()
        wait(0.05) -- Send data at regular intervals
    end
end

setupCharacter(player.Character or player.CharacterAdded:Wait())


player.CharacterAdded:Connect(function(newCharacter)

    local torso = newCharacter:WaitForChild("Torso")
    local rightArm = newCharacter:WaitForChild("Right Arm")
    
    -- Setup the character again after respawn
    setupCharacter(newCharacter)
end)

Try this
I made the weld creation reset after respawn

1 Like

The arm rotates, but doesn’t point to the cursor, and the sword is not welded for some reason…
I want the Arm position from

local rs = game:GetService("ReplicatedStorage")
local plrs = game:GetService("Players")
local run = game:GetService("RunService")

local player = plrs.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local mouse = player:GetMouse()

local torso = char:WaitForChild("Torso")
local rightArm = char:WaitForChild("Right Arm")

local event = rs:WaitForChild("events"):WaitForChild("LightsaberMove")

local armOffset = torso.CFrame:Inverse() * rightArm.CFrame

-- weld to attach right arm to torso
local armWeld = Instance.new("Weld")
armWeld.Part0 = torso
armWeld.Part1 = rightArm
armWeld.Parent = rightArm

local rotCFrame -- store rotation data
local armPos -- store arm position relative to torso

-- update arm's position and rotation every frame
run.RenderStepped:Connect(function()
	local torsoPos = torso.Position
	local mouseHit = mouse.Hit.Position

	-- lock movement to y-z plane
	mouseHit = Vector3.new(torsoPos.X, mouseHit.Y, mouseHit.Z)

	-- calculate direction to mouse
	local lookAtCFrame = CFrame.lookAt(torsoPos, mouseHit)
	rotCFrame = CFrame.new(torsoPos) * CFrame.Angles(lookAtCFrame:ToEulerAnglesXYZ())

	-- store arm's relative position
	armPos = rightArm.CFrame.Position - torso.CFrame.Position

	-- update weld with new rotation
	armWeld.C0 = armOffset * torso.CFrame:toObjectSpace(rotCFrame)
end)

-- send rotation and position data to server
local function sendData()
	if rotCFrame and armPos then
		event:FireServer(rotCFrame, armPos, torso.CFrame)
	end
end

-- run continuously
while true do
	sendData()
	wait(0.05)
end

and the respawning fix from

local rs = game:GetService("ReplicatedStorage")
local plrs = game:GetService("Players")
local run = game:GetService("RunService")

local player = plrs.LocalPlayer
local mouse = player:GetMouse()

local function setupCharacter(character)

    local torso = character:WaitForChild("Torso")
    local rightArm = character:WaitForChild("Right Arm")

    local event = rs:WaitForChild("events"):WaitForChild("LightsaberMove")

    local armWeld = Instance.new("Weld")
    armWeld.Part0 = torso
    armWeld.Part1 = rightArm
    armWeld.Parent = rightArm

    local armOffset = torso.CFrame:Inverse() * rightArm.CFrame
    local rotCFrame -- store rotation data
    local armPos -- store arm position relative to torso

    run.RenderStepped:Connect(function()
        if not torso or not rightArm then return end
        local torsoPos = torso.Position
        local mouseHit = mouse.Hit.Position

 
        mouseHit = Vector3.new(torsoPos.X, mouseHit.Y, mouseHit.Z)

  
        local lookAtCFrame = CFrame.lookAt(torsoPos, mouseHit)
        rotCFrame = CFrame.new(torsoPos) * CFrame.Angles(lookAtCFrame:ToEulerAnglesXYZ())

        -- Store arm's relative position
        armPos = rightArm.CFrame.Position - torso.CFrame.Position

        -- Update weld with new rotation
        armWeld.C0 = armOffset * torso.CFrame:toObjectSpace(rotCFrame)
    end)

    -- Send rotation and position data to server
    local function sendData()
        if rotCFrame and armPos then
            event:FireServer(rotCFrame, armPos, torso.CFrame)
        end
    end

    -- Run continuously
    while true do
        sendData()
        wait(0.05) -- Send data at regular intervals
    end
end

-- Setup character on initial spawn
setupCharacter(player.Character or player.CharacterAdded:Wait())

-- Handle character respawn with a wait to ensure all parts are loaded
player.CharacterAdded:Connect(function(newCharacter)
    -- Ensure that all necessary parts are loaded before calling setupCharacter
    newCharacter:WaitForChild("Torso")
    newCharacter:WaitForChild("Right Arm")
    
    setupCharacter(newCharacter)
end)

Hope that makes sense…