Search code examples
luarobloxluau

Instance argument is nil remote event roblox


I'm creating a tower defense game and for some reason the defense argument I'm sending to the remote event to place the defence is nil.

Local script under a button:

local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local button = script.Parent
local mouseDown = false

button.MouseButton1Up:Connect(function() -- when the player presses the button to add a defence
    button.Parent.Tip.Visible = true -- a text label
    
    repeat task.wait() until mouseDown -- waits until the player clicks an area on the map
    
    local defense = game.ReplicatedStorage.Defenses.Defense:Clone() -- sets a variable to defense instance
    
    game.ReplicatedStorage.Events.AddDefence:FireServer(defense, mouse.Hit.Position) -- fires the remote that should build the defence
    print(defense.Name) -- prints defence and not nil

    button.Parent.Tip.Visible = false -- hides the text label
end)

mouse.Button1Up:Connect(function() mouseDown = false end)
mouse.Button1Down:Connect(function() mouseDown = true end)

Script in server script storage:

local events = game.ReplicatedStorage.Events

events.AddDefence.OnServerEvent:Connect(function(_, defense, mousePos) -- when the event fires
    print(_, defense, mousePos) -- printed my username, nil and the mouse position
    defense.Parent = workspace.Defenses -- supposed to parent the defence to a folder in workspace (doesn't work since the defence is nil)
    defense.Position = Vector3.new(math.floor(mousePos.X/8+0.5)*8, 6, math.floor(mousePos.Z/8+0.5)*8)-- supposed to position the defence (doesn't work again)
end)

Solution

  • Something to keep in mind is that changes made to the world in a LocalScript are invisible to all other players and the server. To be specific, the changes are not replicated to other players.

    In your LocalScript, you have :

    button.MouseButton1Up:Connect(function()
        ...
        local defense = game.ReplicatedStorage.Defenses.Defense:Clone()
    

    You have created this Defense clone in a LocalScript, but then tried to tell the server to access it. In the server's eyes, this object does not exist.

    If you want this object to appear for everyone, then the server is the one that must create it. Like this :

    local function snapToNearest(val, gridSize)
        return math.floor((val / gridSize) + 0.5) * gridSize
    end
    
    events.AddDefence.OnServerEvent:Connect(function(player, mousePos)
        local GRID_SIZE = 8
    
        -- create the defense object where the player clicked
        local defense = game.ReplicatedStorage.Defenses.Defense:Clone()
        defense.Parent = workspace.Defenses
        defense.Position = Vector3.new(snapToNearest(mousePos.X, GRID_SIZE), 6, snapToNearest(mousePos.Z, GRID_SIZE))
    end)
    

    Then just update your LocalScript :

    button.MouseButton1Up:Connect(function()
        -- tell the server to create the defense
        button.Parent.Tip.Visible = true -- a text label
        game.ReplicatedStorage.Events.AddDefence:FireServer(mouse.Hit.Position)
        button.Parent.Tip.Visible = false
    end)