Network ownership being updated after manually setting in script

I’m trying to make an item system that allows a player to pick up an item and drag it around. Only the “owner” of this item should be able to move it, but at the moment anyone can move the item.

On the client side, a cursor part is cloned from the replicated storage. When the player joins the game. When the player clicks on an object the script checks to see if the object is moveable and if it is it welds the cursor to the object. Then the cursor moves around and unwelds when the player lets go of the grab button. This works fine.

On the server side, the network ownership of the object is set to the first player who picks it up.

The issue is the network ownership updates again whenever another player tries to pick up the object. I am not changing the network ownership of the part this time, but it still updates. Why is this happening?

Client-side item movement script.

local UserInputService = game:GetService("UserInputService")
local ContextActionService = game:GetService("ContextActionService")

local Players = game:GetService("Players")
local Player = Players.LocalPlayer
local Mouse = game.Players.LocalPlayer:GetMouse()

local RequestOwnership = game.ReplicatedStorage.Remote.RequestOwnership


local setPosConnection

local MaxDist = 30
local currentDist = MaxDist

local cursor = game.ReplicatedStorage.Cursor:Clone()
cursor.Parent = game.Workspace


local weld = cursor.WeldConstraint




local playerconfig = require(game:GetService("Players").LocalPlayer.PlayerScripts:WaitForChild("PlayerModule"))
local ctrls = playerconfig:GetControls()



local function SetPosition()

	local character = Player.Character

	-- Calculate the position in front of the player's head
	local headPosition = character:WaitForChild("Head").Position
	local cursorPosition = Mouse.Hit.p
	local direction = (cursorPosition - headPosition).unit
	local positionInFront = headPosition + direction * currentDist


	cursor.AlignPosition.Position = positionInFront

end

local function FindTopLevelModel(part:Part)
	local model

	if not part then
		return nil
	end

	if part.Parent ~= game.Workspace and part.Parent:IsA("Model") then
		model = part.Parent
	else
		return false
	end

	while true do
		wait(0.01)
		if model.Parent ~= game.Workspace and model.Parent:IsA("Model") then
			model = model.Parent
		else
			break
		end
	end

	return model
end

local function handleManipulation(actionName, inputState, inputObject)
	if actionName == "AdjustDist" then
		if inputState == Enum.UserInputState.Change then
			if inputObject.Position.Z == 1 then
				currentDist = math.clamp(currentDist + 5, 5, MaxDist)
			elseif inputObject.Position.Z == -1 then
				currentDist = math.clamp(currentDist - 5, 5, MaxDist)
			end
		elseif inputState == Enum.UserInputState.Begin then
			if inputObject.KeyCode == Enum.KeyCode.DPadUp then
				currentDist = math.clamp(currentDist + 5, 5, MaxDist)
			else
				currentDist = math.clamp(currentDist - 5, 5, MaxDist)
			end
		
		end
	end
end




local function StartGrab()	
	currentDist = MaxDist
	
	ContextActionService:BindAction("AdjustDist",handleManipulation,false,Enum.UserInputType.MouseWheel ,Enum.KeyCode.DPadUp,Enum.KeyCode.DPadDown)
	
	
	setPosConnection = game:GetService("RunService").Heartbeat:Connect(function()
		SetPosition()
	end)

	local topmodel:Model  = FindTopLevelModel(Mouse.Target)

	if topmodel then
		RequestOwnership:FireServer(topmodel)
	end


	print(topmodel)


	if topmodel and topmodel:GetAttribute("Moveable") and Player:DistanceFromCharacter(topmodel.PrimaryPart.Position) <= MaxDist then
		currentDist = Player:DistanceFromCharacter(topmodel.PrimaryPart.Position)

		cursor.Position = Mouse.Hit.Position
		print("Welding", topmodel.PrimaryPart)
		weld.Part1 = topmodel.PrimaryPart
	end



	cursor.Transparency = 0.5
	cursor.Trail.Enabled = true
end


local function StopGrab()
	if setPosConnection and setPosConnection.Connected then
		setPosConnection:Disconnect()
	end
	
	ContextActionService:UnbindAction("AdjustDist")
	

	weld.Part1 = nil

	cursor.Transparency = 1
	cursor.Trail.Enabled = false
end



local function handleAction(actionName, inputState, inputObject)
	if actionName == "GrabItem" then
		if inputState == Enum.UserInputState.Begin then
			StartGrab()
		elseif inputState == Enum.UserInputState.End then
			StopGrab()
		end
		
	elseif actionName == "AdjustDist" then
		print(inputObject)
	end
end


ContextActionService:BindAction("GrabItem",handleAction,false,Enum.UserInputType.MouseButton1,Enum.KeyCode.ButtonR2)

Server-side ownership script.

local RequestOwnership = game.ReplicatedStorage.Remote.RequestOwnership


local function setOwnership(player :Player ,Model :Model)


	if Model:IsA("Model") == true and Model:GetAttribute("Moveable") == true then
		print("debug 0")
		if Model:GetAttribute("OwnerId") == nil or Model:GetAttribute("OwnerId") == player.UserId then
			print("debug 1")
			if Model.PrimaryPart then
				print("debug 2")
				Model:SetAttribute("OwnerId",player.UserId)
				Model.PrimaryPart:SetNetworkOwner(player)
				print("updated ownership")
			end
		end
	end

end



RequestOwnership.OnServerEvent:Connect(setOwnership)

The ownership is only set by the server-side script to the first player to interact with it, but the network ownership of the object still updates when another player tries to pick it up. I have checked and the server-side script is working like it is meant to, but something else is causing the network ownership to change. What could it be?

2 Likes

This happens because at the time of moving you do not check who the owner is.

	if topmodel and topmodel:GetAttribute("Moveable") and topmodel:GetAttribute("OwnerId") == Player.UserId  and Player:DistanceFromCharacter(topmodel.PrimaryPart.Position) <= MaxDist then
		currentDist = Player:DistanceFromCharacter(topmodel.PrimaryPart.Position)

		cursor.Position = Mouse.Hit.Position
		print("Welding", topmodel.PrimaryPart)
		weld.Part1 = topmodel.PrimaryPart
	end
1 Like

This is in the client script. The client shouldn’t be able to change a part’s network ownership after a server script has set it.

Can I saw the output ?

local RequestOwnership = game.ReplicatedStorage.Remote.RequestOwnership

local function setOwnership(player :Player ,Model :Model)

	if Model:IsA("Model") == true and Model:GetAttribute("Moveable") == true then

		print("debug 0")

		if Model.PrimaryPart then
            print("debug 1")

			if Model:GetAttribute("OwnerId") == nil or Model:GetAttribute("OwnerId") == player.UserId then
	
				print(Model:GetAttribute("OwnerId"), Model.Name)
	
				Model:SetAttribute("OwnerId",player.UserId)
				Model.PrimaryPart:SetNetworkOwner(player)
	            print("updated ownership for: ", player.Name)

			end

		end

	end

end



RequestOwnership.OnServerEvent:Connect(setOwnership)