Other players can not see an object duplicate - lua

I have this script that duplicates an object and teleports it to the player when the GUI button is pressed (You can think of GMod to make things easier). It is stored in a LocalScript inside the button and when you press it, but it's only visible for the player that clicked the button.
I'm not exactly sure how I would solve the problem or what the problem is, but I think it's because it's all stored into a LocalScript. I'm new to Lua and Roblox game development and I didn't really take any lessons on it, I'm just working from my memory and experience. Any and all suggestions are greatly appreciated. Also, if I need to give more information, please ask and I will provide it.
My script:
local player = game.Players.LocalPlayer
script.Parent.MouseButton1Click:Connect(function()
local rag = game.Lighting.ragdolls_presets["Wood Crate"]:Clone()
local X = player.Character.UpperTorso.Position.X
local Y = player.Character.UpperTorso.Position.Y + 10
local Z = player.Character.UpperTorso.Position.Z
rag.Parent = game.Workspace.ragdolls
local children = rag:GetChildren()
for i = 1, #children do
local child = children[i]
child.Position = Vector3.new(X,Y,Z)
end
end)
Thank you in advance!

When you clone something in a LocalScript, it only clones on the client side. Changes done on the client side never gets replicated to the server side, however all changes done on the server side would get replicated to all clients, which are the players.
So to fix this you'd need to use RemoteEvents, which is a way for the client to tell the server to do something.
So instead of doing this in a LocalScript
local player = game.Players.LocalPlayer
script.Parent.MouseButton1Click:Connect(function()
local rag = game.Lighting.ragdolls_presets["Wood Crate"]:Clone()
local X = player.Character.UpperTorso.Position.X
local Y = player.Character.UpperTorso.Position.Y + 10
local Z = player.Character.UpperTorso.Position.Z
rag.Parent = game.Workspace.ragdolls
local children = rag:GetChildren()
for i = 1, #children do
local child = children[i]
child.Position = Vector3.new(X,Y,Z)
end
end)
Put a new RemoteEvent in game.Replicated Storage, then:
This should be the LocalScript
local Event = game.ReplicatedStorage.RemoteEvent
script.Parent.MouseButton1Click:Connect(function()
Event:Fire()
end)
And this should be the ServerScript (or Script for short)
local Event = game.ReplicatedStorage.RemoteEvent
Event.OnServerEvent:Connect(function(player)
local rag = game.Lighting.ragdolls_presets["Wood Crate"]:Clone()
local X = player.Character.UpperTorso.Position.X
local Y = player.Character.UpperTorso.Position.Y + 10
local Z = player.Character.UpperTorso.Position.Z
rag.Parent = game.Workspace.ragdolls
local children = rag:GetChildren()
for i = 1, #children do
local child = children[i]
child.Position = Vector3.new(X,Y,Z)
end
end)
Also, it is very important to do server-side validation when using RemoteEvents, for example: instead of checking whether a player has enough money to spawn something in a LocalScript before the RemoteEvent is fired, it should be done in both LocalScript and the ServerScript. The cause for this is that players can change anything in their client side, so information from the client can NOT be trusted. Optionally you can also have time-outs in each side because, lets say a player has millions of money, he can keep executing the RemoteEvent hundreds of times in under a minute which can crash the server or cause extreme lag. So a 3 second - 1 minute time out is sometimes necessary
More information about Roblox's Client-Server Model: https://create.roblox.com/docs/scripting/networking/client-server-model
More information about Roblox RemoteEvents: https://create.roblox.com/docs/reference/engine/classes/RemoteEvent

Related

Roblox Lua: Issue defining a value in a player's leaderstats folder (no error message)

I have a system in my game where when a player steps on a checkpoint, a Stage value in the leaderboard will go up, and then that value is saved to that player's userId.
I want there to be a button that resets that value back to 0, and this is the code I tried for it.
local textButton = script.Parent
local Players = game:GetService("Players")
textButton.MouseButton1Up:Connect(function()
local player = game.Players.LocalPlayer
local stage = Players:WaitForChild(player):WaitForChild("leaderstats").Stage
if stage.Value > 1 then
stage.Value = 1
end
end)
I've tried debugging it by putting print commands in different places to see where the code gets, and when I try to run print(stage) it does not show anything.
LocalScripts cannot change the value on the server. To change a value once a button is clicked, RemoteEvents should be used.
There is a page documenting about them here: https://create.roblox.com/docs/scripting/networking/remote-events-and-functions
To use a RemoteEvent, first you need to put it in a place that is replicated across the server and the client. A good example of this would be to put it in ReplicatedStorage. After that, you need to set up a script that listens for the .OnServerEvent event of the RemoteEvent. To do this, you need to connect a function. As seen in your script, you already know how to do this. So I will get straight to the point.
On the server, set up a script that listens for .OnServerEvent. Next, on the client, edit your script to fire the client instead of trying to set the value. Go back to the server script, and set the value there. The event also passes the Player object, so you can utilize that to actually reset the value.
TLDR;
LocalScript inside of your TextButton:
local textButton = script.Parent
local Players = game:GetService("Players")
local RemoteEvent = 'RemoteEvent location'
textButton.MouseButton1Up:Connect(function()
RemoteEvent:FireServer()
end)
Server Script in anywhere, preferably ServerScriptService:
RemoteEvent.OnServerEvent:Connect(function(player)
local Players = game:GetService("Players")
local stage = Players:WaitForChild(player):WaitForChild("leaderstats").Stage
if stage.Value > 1 then
stage.Value = 1
end
end)
Good luck!

Cloning Locally and not locally [Lua]

I've been trying to make a sword fight game on Roblox studio. I've made a shop Gui so you can click the text button to buy the sword. It works well, You click it checks your kills and if you have enough you get the weapon. In this case, it's 0 kills. But when you take out the sword you cant use it. I've done my research and I believe that's because it's been cloned locally and not globally. Is this the case and if so how do I fix it?
The script in the Text Button:
local player = game.Players.LocalPlayer
script.Parent.MouseButton1Click:Connect(function()
if player.leaderstats.Kills.Value >= 0 then
local clonar = game.ServerStorage.ClassicSword:Clone()
clonar.Parent = player.Backpack
end
end)
Thanks in advance!
When work needs to be performed on the server (as opposed to locally on the client), you can use RemoteEvents to communicate across the client-server boundary.
So first, you'll need to create a RemoteEvent in a shared location, like ReplicatedStorage.
Next, update your client-side LocalScript to fire the RemoteEvent :
local player = game.Players.LocalPlayer
local buyEvent = game.ReplicatedStorage.RemoteEvent
script.Parent.MouseButton1Click:Connect( function()
buyEvent:FireServer()
end)
Finally, you need to create a Script in the Workspace or ServerScriptService that listens for that RemoteEvent and performs the work of giving the player the item :
local buyEvent = game.ReplicatedStorage.RemoteEvent
buyEvent.OnServerEvent:Connect( function(player)
if player.leaderstats.Kills.Value >= 0 then
local clonar = game.ServerStorage.ClassicSword:Clone()
clonar.Parent = player.Backpack
end
end)

IntValue changing but not shown

I'm scripting a lawn-mowing game in Roblox Studio and I've come across a problem. So every time I cut the grass(trawa) the IntValue goes up by 1. It works fine when it is assigned to a pick-up object and the points go straight to Player's Inventory folder:
local trawa = script.Parent
local function collect(otherPart)
local player = game.Players:FindFirstChild(otherPart.Parent.Name)
if player then
local trawaType = trawa.Name
local trawaStat = player.Inventory:FindFirstChild(trawaType)
if trawaStat then
trawa:Destroy()
trawaStat.Value = trawaStat.Value + 1
end
end
end
trawa.Touched:Connect(collect)
So that script works fine, but that's not the way I want it to work. I want the points to be assigned directly after cutting grass, not after I collect a pick-up it drops. So I changed the script above so that the points are assigned to the tool's inventory and then are copied to player's inventory.
local trawa = script.Parent
local function onTouch(otherPart)
local tool = otherPart.Parent
if tool:IsA('Tool') and tool.Kosa.Value == true then
trawa.Parent = nil
local trawaType = trawa.Name
local trawaStat = tool.Inventory:FindFirstChild(trawaType)
trawaStat.Value = trawaStat.Value + 1
print(trawaStat.Value)
wait(3)
trawa.Parent = workspace
end
end
trawa.Touched:Connect(onTouch)
The value does indeed change because it goes up when I print it, but it's not changing in the properties and is not registered by other scripts, because it's not copied to player's inventory.
Then this is the script in ServerScriptService that should transfer points from the tool to player:
local starter = game:GetService("StarterPack")
local tool = starter:FindFirstChildWhichIsA('Tool')
local player = game:GetService("Players").LocalPlayer
function points(player)
player.Inventory.Trawa2.Value = player.Inventory.Trawa2.Value + tool.Inventory.Trawa2.Value
tool.Inventory.Trawa2.Value = 0
end
tool.Inventory.Trawa2.Changed:Connect(points)
Changing IntValue to NumberValue doesn't solve the problem.
Use a local script with a RemoteEvent that runs it in server script, local scripts are client side. So they don't save to the server, but if you run it on the server, it saves.
Click this link if you want to know more about RemoteEvents.
https://roblox.fandom.com/wiki/Class:RemoteEvent

attempt to index nil with 'leaderstats' in roblox studio

local garbage = game.Teams["Glizzy Garbage"]
local player = game.Players.LocalPlayer
if player.leaderstats.Pounds.Value <= 1000 then --this is the line that the output is detecting the error
player.Team = garbage
end
I am trying to make it where when the player reaches a certain amount of 'pounds' then they will automatically receive a roll. I've searched through many youtube videos and haven't found a fix or an alternative way to do this, and I'm not sure why this isn't working. This script is located in the workspace. All help is appreciated.
The LocalPlayer object is only exposed in LocalScripts. Because you're using a Script in the Workspace, you'll have to access the player object another way. It's also a good idea to handle this kind of logic inside a function that is fired any time the Pounds value changes.
Try using the game.Players.PlayerAdded signal :
local garbage = game.Teams["Glizzy Garbage"]
game.Players.PlayerAdded:Connect(function(player)
local Pounds = player.leaderstats.Pounds
Pounds.Changed:Connect(function(value)
if value <= 1000 then
player.Team = garbage
end
end)
end)
Mine is just
local plrStage = plr.leaderstats.Stage.Value
try instead of putting team name put team colour
also use
player.Team.Service = garbage
end)

The block is not being cloned and no error message is showing.(Roblox Studio)

I am making a placing system (it is basic so far) but it is not placing anything. the code works up until the 'while whenclicked = true' part, here's the code:
print('works')
while true do
print('works2')
local ImportedValueX = game.ReplicatedStorage.ActPosX
local ImportedValueY = game.ReplicatedStorage.ActPosY
local ImportedValueZ = game.ReplicatedStorage.ActPosZ
local Block = game.ReplicatedStorage.Experimental
local WhenClicked = game.ReplicatedStorage.WhenClicked.Value
print('works3')
while WhenClicked == true do
print('wore')
PlacedBlock = Block:Clone()
PlacedBlock.Parent = workspace
PlacedBlock.Position.X = ImportedValueX
PlacedBlock.Position.Y = ImportedValueY
PlacedBlock.Position.Z = ImportedValueZ
WhenClicked = false
wait(1)
end
wait(0.1)
end
The variables work fine and the whenclick part also works, i think the while whenclicked part is broken.
I see a problem here:
PlacedBlock.Position.X = ImportedValueX
PlacedBlock.Position.Y = ImportedValueY
PlacedBlock.Position.Z = ImportedValueZ
The X, Y, Z are read-only properties. You need to populate them by creating a new Vector3 object and assigning it to the Position property, like this:
PlacedBlock.Position = Vector3.new(ImportedValueX, ImportedValueY, ImportedValueZ)
Updated:
I am making the assumption that you are trying to use replicate storage to signal the mouse click state (whenClicked) from your client to the server. The server then checks on the state as well as the x/y/z position in a loop. This is not working, because ReplicatedStorage does not replicate your values to the server. That would probably be an opening for exploits otherwise.
So, in order to signal something from your client to your server you should use RemoteEvent or RemoteFunction (look those up in the reference manual). In your case, your server script could look something like this:
local event = Instance.new("RemoteEvent", game.ReplicatedStorage)
event.Name = "MyRemoteEvent"
local Block = game.ReplicatedStorage.Experimental
event.OnServerEvent:Connect(function(plr, position, whenClicked)
if whenClicked then
print('wore')
local placedBlock = Block:Clone()
placedBlock.Parent = workspace
placedBlock.Position = position
end
end)
So this would create a remote event in ReplicatedStorage and then listen to it. When it is called from the client, it will then do what you wanted to do (clone the part and position it).
In your client script you would trigger the event like this:
-- wait until the server has created the remote event
local event = game.ReplicatedStorage:WaitForChild("MyRemoteEvent")
-- do whatever you need to do, then call trigger the event:
event:FireServer(Vector3.new(5,5,5), true)

Resources