ViewModel position relative to camera desyncing when using RenderStepped

When getting the position of a MeshPart or Part while using RunService.RenderStepped, the position of the parts desyncs in the workspace. Here is a video of the bug, where the Position value of parts do not correlate with their position in physical space. This causes undefined behavior in any code referencing the position of parts, causing any bullets fired to fire from the random desynced position.

When using Heartbeat, the position syncs just fine. However, this is not a working solution as code to add visuals to a viewmodel cause jittering and doesn’t work properly. Here is the expected behavior when using heartbeat where the position is correct:

Here is the full code for the weapon script:

local Players = game:GetService("Players")
local CollectionService = game:GetService("CollectionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local MouseUtils = require(game.ReplicatedStorage.Shared.MouseUtils)
local ProjectileWeapon = require(game.ReplicatedStorage.Shared.Objects.ProjectileWeapon)
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local Character = Players.LocalPlayer.Character

local RevolverModel = ReplicatedStorage.Models.Weapons.Revolver:Clone()
local RevolverMeshPart = RevolverModel.PrimaryPart 
RevolverModel.Parent = workspace.CurrentCamera
local offset = RevolverModel:FindFirstChild("CameraOffset")
local rotationOffset = RevolverModel:FindFirstChild("RotationOffset")
local Revolver = {}
setmetatable(Revolver, ProjectileWeapon:new())

----------------- Section Where Desync Happens -----------------
RunService.RenderStepped:Connect(function(step)
    RevolverMeshPart.CFrame = workspace.CurrentCamera.CFrame
    * CFrame.new(Vector3.new(2, -2, -4)) 
    * CFrame.Angles(0, math.rad(180), 0)
end)
----------------------------------------------------------------

function Revolver.InputCallback(input, gameProcessedInput)
    if input.UserInputType == Enum.UserInputType.MouseButton1 then
        local raycastResult = MouseUtils:raycastFromCursor(500, {Players.LocalPlayer.Character},
            Enum.RaycastFilterType.Exclude)

        if raycastResult ~= nil then
            local projectile = Revolver:GetProjectile()

            local projectileController = ReplicatedStorage.Shared.ModuleClones.ProjectileController:Clone()
            projectileController.Parent = projectile
            projectileController = require(projectileController)
            projectileController:setTouchedCallback(Revolver.ProjectileCallback)
            projectileController.Damage = 10

            ProjectileWeapon:FireBodyVelocityProjectile(projectile, 
                RevolverModel.FirePointTop.CFrame.Position,
                raycastResult.Position, 5)
        end
	end
end

function Revolver.ProjectileCallback(hit)
    if (hit and hit.Parent) then
        local humanoid = hit.Parent:FindFirstChild("Humanoid")
        if (humanoid) then
            humanoid:TakeDamage(10)
        end
    end
end

function Revolver:Init()
    self:SetProjectile(ReplicatedStorage.Models.Projectiles.OrbLauncherProjectile)
    UserInputService.InputBegan:Connect(Revolver.InputCallback)
end

return Revolver

The code tracking the position in the guis is simple, and is here:

local function round(n)
	return math.floor(n + 0.5)
end

function m(n)
	return round(n * 100) / 100
end

while not workspace.CurrentCamera:FindFirstChild("Revolver") do task.wait(0.1) end

game:GetService("RunService").RenderStepped:Connect(function(step)
	script.Parent.CameraPositionX.Text = "X: " .. tostring(m(workspace.CurrentCamera.CFrame.Position.X))
	script.Parent.CameraPositionY.Text = "Y: " .. tostring(m(workspace.CurrentCamera.CFrame.Position.Y))
	script.Parent.CameraPositionZ.Text = "Z: " .. tostring(m(workspace.CurrentCamera.CFrame.Position.Z))

	script.Parent.MeshPartPositionX.Text = "X: " .. tostring(m(workspace.CurrentCamera:FindFirstChild("Revolver").PrimaryPart.CFrame.Position.X))
	script.Parent.MeshPartPositionY.Text = "Y: " .. tostring(m(workspace.CurrentCamera:FindFirstChild("Revolver").PrimaryPart.CFrame.Position.Y))
	script.Parent.MeshPartPositionZ.Text = "Z: " .. tostring(m(workspace.CurrentCamera:FindFirstChild("Revolver").PrimaryPart.CFrame.Position.Z))
	
end)

I can post code from inherited classes if need be, but I’m not confident any of their code is influencing the desync here. What on earth is going on here?

1 Like

Some additional information: The gun itself is a model of parts held together by some welds. All parts have the properties:

Anchored = false
CanCollide = false

image

image

Issue was found!

Make sure to anchor the “Root Part” that you are basing your welds off of. In this case, this was the “Revolver” MeshPart in the above post. Here is the gun working as expected with added weapon sway made possible by the fix!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.