How do I input the CFrame from a locally created object into a Remote Event as a parameter?

So my issue is that at the moment, I am looking to input the CFrame of a locally created object into a Remote Event’s parameters in order to create a part on the server. The CFrame information is sent into a module script which then activates the remote event with the CFrame parameter that was sent into the module script. When I input the CFrame I receive this error:

  09:07:02.199 - ReplicatedStorage.3PMS:313: attempt to index nil with 'CFrame'

Here is a video of the code in action:

Here is the the part of the Local Script that is sending the information that creates the block to the module Script:

player = game.Players.LocalPlayer
mouse = player:GetMouse()
button = script.Parent
text = button.Text
repstor = game.ReplicatedStorage
partfolder = repstor.PartFolder
startGui = script.Parent.Parent.Parent
Run = game:GetService("RunService")
UIS = game:GetService("UserInputService")
guimod = require(repstor.Modules.GuiMod)

pms = require(game.ReplicatedStorage["3PMS"])
pms:Place(player, mouse, button, text, repstor, partfolder, startGui, Run, UIS)

Here is the part of the Module Script that is sending the received CFrame information into a remote event:

	BPRE = game.ReplicatedStorage:WaitForChild("BloPlaRE")
	UIS.InputBegan:Connect(function(input)
		if hovering == false then
			if SpawnEnabled == true then
				if input.UserInputType == Enum.UserInputType.MouseButton1 then
					bcf = block.CFrame
					bp = block.Position
					BPRE:FireServer(text, bcf, bp)
				end
			end
		end
	end)
end

The term “block” represents the wedge from the earlier video and is created locally for only the local player to see.

Here is the remote event:

BPRE = Instance.new("RemoteEvent")
BPRE.Name = "BloPlaRE"
BPRE.Parent = game.ReplicatedStorage
run = game:GetService("RunService")

BPRE.OnServerEvent:Connect(function(plr, label, cf, pos)
		for i, v in pairs(game.ReplicatedStorage.PartFolder:GetDescendants()) do
			if v.Name == label then
				print(label)
				if v:IsA("Part") or v:IsA("MeshPart") then
					BuildBlock = v:Clone()
					BuildBlock.Transparency = 0
					BuildBlock.Name = label
					BuildBlock.Parent = game.Workspace.PlotBlocks				
					BuildBlock.CFrame = cf
					BuildBlock.Anchored = true
					BuildBlock.CanCollide = false
					hb = BuildBlock:WaitForChild("HitBox")
					hb.CFrame = BuildBlock.CFrame
					hb.Anchored = true
					hb.CanCollide = false
					hb.Position = pos
					print(BuildBlock)
				end
			end
		end
	end)

I am looking for a way to input the CFrame from a locally created object into a remote event on the server.
2 Likes

Why not send its CFrame and other required properties as an argument? Then, you can apply the necessary settings to a new part using Instance.new.

The reason it’s attempting to index nil is because you’re sending a part instance that exists on the client boundary, but doesn’t exist on the server boundary if that makes sense. You’re sending the actual instance that exists in workspace, not just its properties.

2 Likes

Ok I understand what your saying. I will try that when I next get on studio.

1 Like

I have looked into transferring information sent from locally created objects into server-sided created objects, and this is what I have so far. When I input a locally created part as a parameter into a remote event, it returns the locally created object as “nil.”

This is the Local Script:

player = game.Players.LocalPlayer
local button = script.Parent
local text = button.Text
MT = require(game.ReplicatedStorage.MSTest)
Posi = game.ReplicatedStorage.PosiRE

button.MouseButton1Click:Connect(function()
	MT:InputTest(text)
	block = Instance.new("Part")
	block.Position = Vector3.new(0, 0, 0)
	block.Parent = game.Workspace
	Posi:FireServer(block)
end)

This is the Server Script:

Posi = game.ReplicatedStorage.PosiRE

Posi.OnServerEvent:Connect(function(plr, input)
	print(input)
end)

And this is what I receive when I run them:

nil

Here is a video of the scripts in action:

I’m not quite sure how to input the object into a remote event as a parameter. Even in the original post, I decided to input the CFrame of the object directly into the parameters of the remote event, but still received this error:

:attempting to index nil with "CFrame"
1 Like

When firing the server, send only the part’s properties.

:FireServer(part.CFrame, part.BrickColor) etc…

maybe it’s because when you recieve the parameters, you should put them in the correct order they were sent

In the original post, I did send the block’s CFrame directly into the remote event.

Here is the part of the script:

	BPRE = game.ReplicatedStorage:WaitForChild("BloPlaRE")
	UIS.InputBegan:Connect(function(input)
		if hovering == false then
			if SpawnEnabled == true then
				if input.UserInputType == Enum.UserInputType.MouseButton1 then
					bcf = block.CFrame
					bp = block.Position
					BPRE:FireServer(text, bcf, bp)
				end
			end
		end
	end)

So that suggestion isn’t a solution to the issue at hand :confused:

1 Like

Don’t send the part, it doesn’t exist when the server tries to index it. Only send the CFrame and size.

Here’s an example:

Create a button, then paste this on a local script:

local remoteEvent = script.Parent:WaitForChild('RemoteEvent')
script.Parent.MouseButton1Click:Connect(function()
    local Part = Instance.new('Part') -- never parenting it to workspace on the client side
    Part.Size = Vector3.new(8, 1, 8)
    Part.CFrame = CFrame.new(1, 5, 1)
    remoteEvent:FireServer(Part.CFrame, Part.Size) -- never sending the part, only its properties
end

Put this in a server script, which is also a parent of the button above (just for testing purposes)

local remoteEvent = Instance.new('RemoteEvent', script.Parent)
remoteEvent.OnServerEvent:Connect(function(player, cframe, size)
    local part = Instance.new('Part')
    part.CFrame = cframe
    part.Size = size

    print(part)
end)

A table is great for this because you can recreate part properties using an iterator loop (pairs loop).

Fire the server a dictionary of your party properties you want to change, with property name as ones and value as the current property value.

Then, the server needs to create a new part and assign the properties of the created part accordingly to the properties found in the table.

Here’s how the code could work:

-- local script
local t = { -- fill in the ...
    CFrame = ...,
    Parent = workspace
}
remoteEvent:FireServer(t)
-- server code
remoteEvent.OnServerEvent:Connect(function(player, partData)
    local part = Instance.new(“Part”)
    for property, assigned in pairs(partData) do
        part[property] = assigned
    end
end)

One optimization you can do is to not have specific part properties in the table when sending over if they’re akin to the default property.

For example, a part’s default brick color will be “Medium stone grey” so if the properties table has that value, you remove the BrickColor value from it.


Also, may I ask what you are trying to use this for? Depending on your use case, this could even be unnecessary.

I will take a look at sending part properties instead of instances when I next get on.

I found a way to transfer the CFrame from the locally-created block object onto the server-side by inputting the block’s CFrame and Position values into tables. Then from there I inserted that value into the remote event directly.

Here is what I did if anybody is looking for another solution:

Module Script Edit:

				CfBl = {}
				PosBl = {}
				
				UIS.InputChanged:Connect(function(input)
					if input.UserInputType == Enum.UserInputType.MouseMovement then
						table.insert(CfBl, block.CFrame)
						table.insert(PosBl, block.Position)
						
						for i, v in pairs(CfBl) do
							if block.CFrame == v then
								UpBlCf = v
							end
						end
						
						for i, v in pairs(PosBl) do
							if block.Position == v then
								UpBlPos = v
							end
						end
					end
				end)

Remote Event Call:

	BPRE = game.ReplicatedStorage:WaitForChild("BloPlaRE")
	UIS.InputBegan:Connect(function(input)
		if hovering == false then
			if SpawnEnabled == true then
				if input.UserInputType == Enum.UserInputType.MouseButton1 then
					BPRE:FireServer(text, UpBlCf)
				end
			end
		end
	end)
end

Server-Sided Script:

BPRE = Instance.new("RemoteEvent")
BPRE.Name = "BloPlaRE"
BPRE.Parent = game.ReplicatedStorage
run = game:GetService("RunService")

BPRE.OnServerEvent:Connect(function(plr, label, cf)
		for i, v in pairs(game.ReplicatedStorage.PartFolder:GetDescendants()) do
			if v.Name == label then
				print(label)

				if v:IsA("Part") or v:IsA("MeshPart") then
					BuildBlock = v:Clone()
					BuildBlock.Transparency = 0
					BuildBlock.Name = label
					BuildBlock.Parent = game.Workspace.PlotBlocks				
					BuildBlock.CFrame = cf
					BuildBlock.Anchored = true
					BuildBlock.CanCollide = false
					hb = BuildBlock:WaitForChild("HitBox")
					hb.CFrame = BuildBlock.CFrame
					hb.Anchored = true
					hb.CanCollide = false
					print(BuildBlock)
				end
			end
		end
	end)
1 Like

I want to explain why this is happening for anyone who may be experiencing this issue.

When you’re sending the part from the client, the server goes to workspace and looks for the part, but when it’s unable to find the same part that was sent from the client, it returns an error, which is why you’re experiencing this.

1 Like