How to make a Roblox script search a player's backpack - roblox

I am trying to make a script that searches a players backpack when they touch a door, so it can tell if the player has a key card. If the player has a key card, it should say "Yes", but for some reason it keeps bringing up an error. Here is my code:
function onTouched(m)
p = m.Parent:findFirstChild("Humanoid")
if p ~= nil then
n = p.parent
local letin = game.Players(n).Backpack:FindFirstChild("Key Card")
if letin then
print("Yes")
else
print("No")
end
end
end
script.Parent.Touched:connect(onTouched)
The error is:
Trying to call method on object of type: 'Player' with incorrect arguments.
Does anyone know why this might not work?

I think you've got two problems :
It looks like you are trying to access an array index, but you're using () instead of [].
The game.Players object is a service class, not an array. But you can call game.Players:GetPlayers() to get that array of the players.
Since you are already getting the player object, you can simply grab the player's name and use that to lookup the player from game.Players.
Your script just about works, here's a fix for you :
function onTouched(m)
-- get the player in game that touched the thing
local p = m.Parent:findFirstChild("Humanoid")
if p ~= nil then
-- grab the player's name
local n = p.parent.Name
-- find the player in the player list, escape if something goes wrong
local player = game.Players:FindFirstChild(n, false)
if player == nil then
return
end
-- search the player's backpack for the keycard
local keycard = player.Backpack:FindFirstChild("Key Card")
if keycard then
print("Yes")
else
print("No")
end
end
end
script.Parent.Touched:connect(onTouched)

The following line of code is incorrect, because instead of finding a child in
'game.Players', you call it as a function by using parenthesis.
local letin = game.Players(n).Backpack:FindFirstChild("Key Card")
What you probably intended was:
local letin = game.Players[n].Backpack:FindFirstChild("Key Card")
A more clean approach to getting that 'Key Card' is to also check if 'n' really is the name of a player, rather than that of a NPC.
local player = game.Players:FindFirstChild(n)
if player then
local letin = player.Backpack:FindFirstChild("Key Card")
print(letin)
end

Related

Roblox: BindToClose works, PlayerRemoving does not

I am trying to store CFrame X, Y, and Z data into DataStore so that the player can start off where they left off. I am testing by trying to save hardcoded values.
The loading of data using PlayerAdded works fine.
For some reason, the SetAsync() in PlayerRemoving wasn't completing when the player leaves in game or in studio. The weird thing is that when I added BindToClose, the save function runs correctly when in Studio but not in game.
If anyone can tell me why, I'd be very grateful.
local function save(plr)
local data = {
CFrameX = -1232;
CFrameY = 1232;
CFrameZ = -1235;
}
local success, errormessage = pcall(function()
MandoSimStore:SetAsync(plr.UserId.."-Location_StorageData", data)
end)
if success then
print("Successfully saved data!")
else
warn("ERROR: "..errormessage)
end
end
local gameShutDown = false
game.Players.PlayerRemoving:Connect(function(plr)
wait(0.1)
if not gameShutDown then
save(plr)
end
end)
game:BindToClose(function()
gameShutDown = true
for _, plr in ipairs(game.Players:GetPlayers()) do
save(plr)
end
end)
Maybe try
wait(1)
It worked for me

How do I assign a variable to a thing in roblox?

There is a variable called f, And this code is supposed to play random audio whenever it's clicked
local clickDetector = script.Parent.ClickDetector
f = math.random(1,3)
function onMouseClick()
script.Parent.f.TimePosition = 0
script.Parent.f.Playing = true
end
clickDetector.MouseClick:connect(onMouseClick)
How do I make it so it will thing it's not inside
assuming the parent exist, try
script.Parent[f]

BodyPosition not changing?

I've been sitting at my laptop for about an hour trying to figure out what's going on. I did this exact same thing yesterday and it worked. Please help.
Explaining the program:
The program takes the object that the mouse is pointing at, if you click the object gravitates toward the mouse.
local player = game.Players.LocalPlayer
local runservice = game:GetService("RunService")
local character = player.Character
local humanoid = character.Humanoid
local camera = workspace.Camera
local mouse = player:GetMouse()
local mousepos = mouse.hit.p
local grabbed = false
local function grabbedobj(obj) --this is the thing i need help on
local bodypos = obj.BodyPosition.Position
local pos = obj.Position
obj.Anchored = false
mouse.Button1Down:Connect(function()
grabbed = true
end)
mouse.Button1Up:Connect(function()
grabbed = false
end)
if grabbed == true then
print(obj.BodyPosition.Position)
bodypos = Vector3.new(mousepos.X, mousepos.Y, mousepos.Z) --really important
end
if grabbed == false then
bodypos = Vector3.new(pos.X, -25, pos.Z)
pos = Vector3.new(bodypos.X, pos.Y, bodypos.Z)
end
end
local function setup()
mousepos = mouse.hit.p
if mouse.Target ~= nil and mouse.Target.Parent == game.Workspace.IntObj then
grabbedobj(mouse.Target) --takes object that the mouse is pointing at
end
end
while wait(.1) do
setup()
end
Lets shuffle the code a little bit so it does what I think you want to do. You might have mixed up some things while trying to debug this. So here:
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local grabbed = false
local obj
mouse.Button1Down:Connect(function()
if mouse.Target ~= nil and mouse.Target.Parent == game.Workspace.IntObj then
obj = mouse.Target
obj.Anchored = false
grabbed = true
end
end)
mouse.Button1Up:Connect(function()
if (grabbed) then
grabbed = false--BodyPosition
obj.BodyPosition.Position = Vector3.new(obj.Position.X, 0.1, obj.Position.Z)
obj.Anchored = true
end
end)
local function move()
if (grabbed) then
local mousepos = mouse.hit.p
obj.BodyPosition.Position = Vector3.new(mousepos.X, mousepos.Y, mousepos.Z)
print(obj.BodyPosition.Position)
end
end
while wait(.1) do
move()
end
When you click the mouse it checks if you click your part that is in IntObj. It will retain a reference to that part and then moves it with the mouse. When you release the button it will drop it at its location.
So this LocalScript should work but it has an issue updating the BodyPosition as you said in the title. The reason for that is that you can only update server parts from your client if you give the client permission from the server for it. You could write a remote function on the server and say:
game.ReplicatedStorage.RemoteFunction.OnServerInvoke = function(plr)
Workspace.IntObj.Part:SetNetworkOwner(plr)
end
If you call this from your local script's initialization, it will work. Note, that your part cannot be anchored for that.
Another way would be to just let the server do the updating. So instead of setting the
obj.BodyPosition.Position on the client you would call the remote function like this:
game.ReplicatedStorage.RemoteFunction:InvokeServer(Vector3.new(mousepos.X, mousepos.Y, mousepos.Z))
and then on the server you set the position:
game.ReplicatedStorage.RemoteFunction.OnServerInvoke = function(plr, bodyPos)
script.Parent.BodyPosition.Position = bodyPos
end
In that case, if you anchor/unanchor the part, do that on the server as well. Otherwise you'll get weird results.

Roblox- how to store large arrays in roblox datastores

i am trying to make a game where players create their own buildings and can then save them for other players to see and play on. However, roblox doesn't let me store all the data needed for the whole creation(there are several properties for each brick)
All i get is this error code:
104: Cannot store Array in DataStore
any help would be greatly appreciated!
I'm not sure if this is the best method, but it's my attempt. Below is an example of a table, you can use tables to store several values. I think you can use HttpService's JSONEncode function to convert tables into strings (which hopefully can be saved more efficiently)
JSONEncode (putting brick's data into a string, which you can save into the DataStore
local HttpService = game:GetService("HttpService")
-- this is an example of what we'll convert into a json string
local exampleBrick = {
["Size"] = Vector3.new(3,3,3),
["Position"] = Vector3.new(0,1.5,0),
["BrickColor"] = BrickColor.new("White")
["Material"] = "Concrete"
}
local brickJSON = HttpService:JSONEncode(exampleBrick)
print(brickJSON)
-- when printed, you'll get something like
-- { "Size": Vector3.new(3,3,3), "Position": Vector3.new(0,1.5,0), "BrickColor": BrickColor.new("White"), "Material": "Concrete"}
-- if you want to refer to this string in a script, surround it with two square brackets ([[) e.g. [[{"Size": Vector3.new(3,3,3)... }]]
JSONDecode (reading the string and converting it back into a brick)
local HttpService = game:GetService("HttpService")
local brickJSON = [[ {"Size": Vector3.new(3,3,3), "Position": Vector3.new(0,1.5,0), "BrickColor": BrickColor.new("White"), "Material": "Concrete"} ]]
function createBrick(tab)
local brick = Instance.new("Part")
brick.Parent = <insert parent here>
brick.Size = tab[1]
brick.Position= tab[2]
brick.BrickColor= tab[3]
brick.Material= tab[4]
end
local brickData = HttpService:JSONDecode(brickJSON)
createBrick(brickData) --this line actually spawns the brick
The function can also be wrapped in a pcall if you want to account for any possible datastore errors.
Encoding a whole model into a string
Say your player's 'building' is a model, you can use the above encode script to convert all parts inside a model into a json string to save.
local HttpService = game:GetService("HttpService")
local StuffWeWantToSave = {}
function getPartData(part)
return( {part.Size,part.Position,part.BrickColor,part.Material} )
end
local model = workspace.Building --change this to what the model is
local modelTable = model:Descendants()
for i,v in pairs(modelTable) do
if v:IsA("Part") or v:IsA("WedgePart") then
table.insert(StuffWeWantToSave, HttpService:JSONEncode(getPartData(modelTable[v])))
end
end
Decoding a string into a whole model
This will probably occur when the server is loading a player's data.
local HttpService = game:GetService("HttpService")
local SavedStuff = game:GetService("DataStoreService"):GetDataStore("blabla") --I don't know how you save your data, so you'll need to adjust this and the rest of the scripts (as long as you've saved the string somewhere in the player's DataStore)
function createBrick(tab)
local brick = Instance.new("Part")
brick.Parent = <insert parent here>
brick.Size = tab[1]
brick.Position= tab[2]
brick.BrickColor= tab[3]
brick.Material= tab[4]
end
local model = Instance.new("Model") --if you already have 'bases' for the players to load their stuff in, remove this instance.new
model.Parent = workspace
for i,v in pairs(SavedStuff) do
if v[1] ~= nil then
CreateBrick(v)
end
end
FilteringEnabled
If your game uses filteringenabled, make sure that only the server handles saving and loading data!! (you probably already knew that) If you want the player to save by clicking a gui button, make the gui button fire a RemoteFunction that sends their base's data to the server to convert it to a string.
BTW I'm not that good at scripting so I've probably made a mistake somehwere.. good luck though
Crabway's answer is correct in that the HttpService's JSONEncode and JSONDecode methods are the way to go about tackling this problem. As it says on the developer reference page for the DataStoreService, Data is ... saved as a string in data stores, regardless of its initial type. (https://developer.roblox.com/articles/Datastore-Errors.) This explains the error you received, as you cannot simply push a table to the data store; instead, you must first encode a table's data into a string using JSONEncode.
While I agree with much of Crabway's answer, I believe the function createBrick would not behave as intended. Consider the following trivial example:
httpService = game:GetService("HttpService")
t = {
hello = 1,
goodbye = 2
}
s = httpService:JSONEncode(t)
print(s)
> {"goodbye":2,"hello":1}
u = httpService:JSONDecode(s)
for k, v in pairs(u) do print(k, v) end
> hello 1
> goodbye 2
As you can see, the table returned by JSONDecode, like the original, uses strings as keys rather than numeric indices. Therefore, createBrick should be written something like this:
function createBrick(t)
local brick = Instance.new("Part")
brick.Size = t.Size
brick.Position = t.Position
brick.BrickColor = t.BrickColor
brick.Material = t.Material
-- FIXME: set any other necessary properties.
-- NOTE: try to set parent last for optimization reasons.
brick.Parent = t.Parent
return brick
end
As for encoding a model, calling GetChildren would produce a table of the model's children, which you could then loop through and encode the properties of everything within. Note that in Crabway's answer, he only accounts for Parts and WedgeParts. You should account for all parts using object:IsA("BasePart") and also check for unions with object:IsA("UnionOperation"). The following is a very basic example in which I do not store the encoded data; rather, I am just trying to show how to check the necessary cases.
function encodeModel(model)
local children = model:GetChildren()
for _, child in ipairs(children) do
if ((child:IsA("BasePart")) or (child:IsA("UnionOperation"))) then
-- FIXME: encode child
else if (child:IsA("Model")) then
-- FIXME: using recursion, loop through the sub-model's children.
end
end
return
end
For userdata, such as Vector3s or BrickColors, you will probably want to convert those to strings when you go to encode them with JSONEncode.
-- Example: part with "Brick red" BrickColor.
color = tostring(part.BrickColor)
print(string.format("%q", color))
> "Bright red"
I suggest what #Crabway said, use HttpService.
local httpService = game:GetService("HttpService")
print(httpService:JSONEncode({a = "b", b = "c"}) -- {"a":"b","b":"c"}
But if you have any UserData values such as Vector3s, CFrames, Color3s, BrickColors and Enum items, then use this library by Defaultio. It's actually pretty nice.
local library = require(workspace:WaitForChild("JSONWithUserdata"))
library:Encode({Vector3.new(0, 0, 0)})
If you want a little documentation, then look at the first comment in the script:
-- Defaultio
--[[
This module adds support for encoding userdata values to JSON strings.
It also supports lists which skip indices, such as {[1] = "a", [2] = "b", [4] = "c"}
Userdata support is implemented by replacing userdata types with a new table, with keys _T and _V:
_T = userdata type enum (index in the supportedUserdataTypes list)
_V = a value or table representing the value
Follow the examples bellow to add suppport for additional userdata types.
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
Usage example:
local myTable = {CFrame.new(), BrickColor.Random(), 4, "String", Enum.Material.CorrodedMetal}
local jsonModule = require(PATH_TO_MODULE)
local jsonString = jsonModule:Encode(myTable)
local decodedTable = jsonModule:Decode(jsonString)
--]]

How do I assign usernames to a ROBLOX Team Spawner?

I would like to know how to assign certain usernames to a team spawner.
Basically when a certain username joins the game, they get placed into a team on the leader board and spawn at the correct spawn in game.
You can do this by checking the username and assigning the team. So something like this, assuming you don't have teams already set up.
team = Instance.new("Team",game:GetService'Teams')
game:GetService'Players'.PlayerAdded:connect(function(p)
if p.Name == "name" then
p.Team = team
end
end
Obviously you can set the team name and color through this script or create it your own.
You have to do the player handling yourself. Basically you want to listen on new players with PlayerAdded and set the team (based on some kind of magical function) with Team.
However you can assign Spawners to a team by setting the TeamColor to equal the Team's TeamColor.
Example code:
local Teams = game:GetService("Teams")
local RedTeam = Teams["Red Team"]
local OtherTeam = Teams["Other Team"]
local PlayersInTeamRed = { "Player1" , "Player2" }
game:GetService("Players").PlayerAdded:connect(function(player)
for playerName in ipairs(PlayersInTeamRed) do
if player.Name == playerName then
player.Team = RedTeam
return
end
end
-- Maybe another list here
-- not in "Team red"
player.Team = OtherTeam
end)
Note that you might want to check against the UserId instead, because some players changes their name.
Also make sure that the Spawn's Neutral value is false.