How to get PlayerGUI from a Server Script? - roblox

I am working on an inventory system and and now i need to make it save, but when trying to save it prints this in the output
PlayerGui is not a valid member of Player "Players.RidhoMBLR"
local function save(player)
local invTable = {}
for i, v in pairs(player.PlayerGui.ScreenGui.Inventory.InvFrame:GetChildren()) do
if v:IsA("TextButton") then
table.insert(invTable, v)
end
end
dataStore:SetAsync(player.UserId, invTable)
end
players.PlayerRemoving:Connect(save)

While you are accessing the path to the PlayerGui correctly, it is probably not replicated to the server (ie, it's existence is only observable on the client in LocalScripts).
So you will likely need to use a LocalScript to pull all of the relevant information out of the UI, and communicate it up to the server using a RemoteEvent. So move your code to a LocalScript :
local players = game.Players
local saveEvent = game.ReplicatedStorage.RemoteEvent -- find your RemoteEvent here
local function save(player)
-- only tell the server about it if we are the one leaving
if player ~= players.LocalPlayer then
return
end
-- get information about the inventory
local inventory = player.PlayerGui.ScreenGui.Inventory.InvFrame:GetChildren()
local invTable = {}
for i, v in ipairs(intentory) do
if v:IsA("TextButton") then
-- grab the text out of each button
table.insert(invTable, v.Text)
end
end
-- tell the server about our inventory
saveEvent:FireServer(invTable)
end
players.PlayerRemoving:Connect(save)
Then in a server Script, listen for when clients fire the event and save their data then :
local saveEvent = game.ReplicatedStorage.RemoteEvent -- find that same RemoteEvent
-- listen for when players report that they are leaving
saveEvent.OnServerEvent:Connect(function(player, inventoryTable)
-- save their information
dataStore:SetAsync(player.UserId, inventoryTable)
end)

So basically you can't access a player's PlayerGui through the server. PlayerGui is replicated locally for each client, hence in order to interact with a Player's Gui I'd recommend using RemoteEvents. By using Remote events you'd be sending a signal to the client which can then by picked up by a LocalScript. On the local script you can then fire another RemoteEvent back to the server with a list of all the items which you can then SetAsync on the server.

Related

Roblox Studio - how do I run a script right before game starts?

I'm attempting to create a plugin that fetches additional code from a server before the user plays the game on roblox studio.
Basically, the user will use something like blockly to create luau code on a website and I want to sent that code to roblox studio. I've seen some plugins that fetch new data from a server from time to time and I've been able to do that, but I'd like to see if there's a way to only fetch the new code when the user clicks the play button because it could be expensive to request new data every 5 seconds or so.
Below is a simple plugin that attempts to send a request to the server when the game loads, but the script never goes beyond game.Loaded:Wait()
Main file:
local Request = require(script.Parent.Request)
local URL = "http://localhost:3333"
local toolbar = plugin:CreateToolbar("Test")
local button = toolbar:CreateButton("Test", "Test", "rbxassetid://4458901886")
local isListening = false
local request = Request.new()
local ok
local json
local function onClick ()
isListening = not isListening
if (isListening == false) then
return print("Not listening")
end
print("Listening")
if not game:IsLoaded() then
print(game.Loaded)
game.Loaded:Wait()
print("Game has started")
ok, json = request:Get(URL)
print(ok, json)
end
end
button.Click:Connect(onClick)
Request file:
local Request = {}
Request.__index = Request
function Request.new()
return setmetatable({}, Request)
end
function Request:Get(URL)
local ok, result = pcall(game.HttpService.GetAsync, game.HttpService, URL)
local json = game.HttpService:JSONDecode(result)
return ok, json
end
return Request
There isn't an explicit signal to detect when a game is about to start.
But, whenever you hit the Play button, the Edit session ends and the Play session begins. When a session ends, all of the plugins are unloaded. So you could use the plugin.Unloading signal to detect when the Edit session is ending, but it will also fire when the user closes the place, when you stop play testing, or when the plugin is disabled or uninstalled.
You could combine that signal with the RunService:IsEdit() function so that the behavior only triggers when exiting Edit mode, but this is still a really hazy signal.
So in a Script in your plugin, you could do something like this :
local RunService = game:GetService("RunService")
local Request = require(script.Parent.Request)
local URL = "<YOUR URL>"
-- listen for when sessions end
plugin.Unloading:Connect(function()
-- disregard sessions that aren't Edit Mode
if not RunService:IsEdit() end
return
end
print("Game about to start... maybe. The game might also be closing, or the plugin might be disabled from the PluginManager.")
local ok, json = request:Get(URL)
print(ok, json)
end)
Debugging this may be difficult as the Output console is cleared any time you start a Play session, so you won't see any of your print statements. But if you close the place, your logs will be preserved on the Welcome Screen. Just go View > Output to open the Output window.

Roblox: How to kill player if they don't complete a task correctly?

I'm using a pre-made code door in which the player(s) must enter correct passwords to pass through. I would like the last door the local player must go through to kill them if they guess the password wrong. The door is a 2323 code door. It already came with a script. I've tried to edit the code for the incorrect password:
Input = ""
local player = game.Players.LocalPlayer
local character = player.Character
character.health = 0
print("Wrong Code")
However, I get a nil value "Character."
Any idea what I am doing wrong? Thanks.
You cannot access localplayer from a server script. Here is what you can do alternatively:
Make server script
Make a remote event
Fire the remote event with the password as the arg
Put this in your server script:
local remoteevent = -- reference remote event path here
local correctpass = 2323
remoteevent.OnServerEvent:Connect(function(p, pass)
-- p is player and pass is the password the user entered
if tonumber(pass) == correctpass then
-- User entered correct pass so open the door
else
p.Character.Humanoid.Health = 0
end
end)
And finally, fire the remote event from the local script just like this:
local remoteevent = -- reference remote event path here
local userinput = -- get the password the user entered here
remoteevent:FireServer(userinput)

Roblox - attempt to call a nil value

When trying to create a code, that on FireServer with Specific Player chosen a GUI would've been cloned into their PlayerGui, But instead I get a nil value.
Code:
local Blinder = game.ReplicatedStorage.RCD.Blind
Blinder.OnServerEvent:Connect(function(player, PlayerToBlind)
if not player:IsInGroup(7465879) then return false end;
script.BL:Clone().Parent = PlayerToBlind:WaitForChild("PlayerGui")
print("Done")
end)
Basically what I try to reach is if my Admin Panel Remoteevent is fired, and a Target has been chosen, the Targeted Player will become a Cloned GUI into their PlayerGui
Any fix on this error?
The error message itself is telling you that you are calling a function that doesn't exist. This issue is caused by an object not being the type you expect.
Unfortunately, the message is pointing at a line that has a few function calls, so it's difficult to say what is causing the exact error. Either script.BL isn't an object with a Clone() function, or PlayerToBlind isn't an object with a WaitForChild() function.
If you can break the operations into a few different lines and add safety checks along the way, you can guarantee that your code is safe and being called properly.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Blinder = ReplicatedStorage.RCD.Blind
local BL = script.BL
Blinder.OnServerEvent:Connect(function(player, PlayerToBlind)
-- check that the person calling Blinder:FireServer actually provided a PlayerToBlind
assert(type(PlayerToBind) == "string", "Blinder expects PlayerToBind to be the name of a player")
-- escape if the player is not in the appropriate group
if not player:IsInGroup(7465879) then
return
end
-- find the Player object based on the name provided from PlayerToBlind
local blindedPlayer = Players:FindFirstChild(PlayerToBlind)
if not blindedPlayer then
warn("Could not find player named : ", PlayerToBlind)
return
end
-- create a blinding UI on the other player
local targetGui = blindedPlayer:WaitForChild("PlayerGui")
local newBL = BL:Clone()
newBL.Parent = targetGui
print("Done")
end)
By adding asserts into your code, it won't stop your code from breaking, in fact it will force your code to break faster and in expected ways.
The issue has been fixed,
I have been setting up the LocalScript wrong.
(I grabbed the Text from a TextButton, Instead of the TextBox)

Animation Script not working in ReplicatedStorager

I have a a Gun model that shows up on my screen using the code from https://www.youtube.com/watch?v=VDYtZxnz7FI&t=25s youtube video. But when I try to add animations to it the animations dont work. What I think is happening is that the script isnt loading in because its in Replicated Storage. I Know this because I tested a simple print command and it worked when the script was in the workspace but not in replicated storage. I cant move the model to the workspace because the code depends on it being in replicated storage. If anyone could help me that would be much abliged. Thank You! Im not new to the Roblox scene but im just starting as a Scripter, Either then a mesh modeler.[Picture of Explorer][1]
Here Is the code that puts the viewmodel on my screen
local cam = workspace.CurrentCamera
local run = game:GetService("RunService")
local reps = game:GetService("ReplicatedStorage")
local model = reps:WaitForChild("Henry Rifle"):Clone()
for i,v in pairs (model:GetChildren()) do
if v:IsA("BasePart") then
if v ~= model.PrimaryPart then
local weld = Instance.new("Weld")
weld.Part0 = model.PrimaryPart
weld.Part1 = v
weld.C0 = model.PrimaryPart.CFrame:inverse()
weld.C1 = v.CFrame:inverse()
weld.Name = v.Name
weld.Parent = model.PrimaryPart
end
end
end
model.Parent = cam
run.RenderStepped:connect(function()
model:SetPrimaryPartCFrame(cam.CFrame *CFrame.new(0,-1.5,1.5))
end)
Here is the simple code that start the animation when the game starts
(Used for Testing)
local player = game.Players.LocalPlayer
local controller = script.Parent.Humanoid
local inspect = controller:LoadAnimation(script.Parent.Inspect)
inspect.Looped = true
inspect:Play()
I'm pretty sure your script doesn't work because Roblox forces Filtering Enabled now.
Filtering Enabled (FE)
Difference with non FE and FE games
With FE, Changes made by the Client/Roblox Player is sent to the server, but the server will never replicate the changes made by the Client to others Clients in the same game server.
That video was made when FE was still an option. Roblox forces FE now, this is why your script doesn't work.
Only way for Client to replicate with others Clients, You must use Remotes.
Roblox wiki explains better than me FE and Remotes, so check it out: http://roblox.wikia.com/wiki/Replication_filtering

Sending a model through remote functions? ROBLOX

well hello there,
So I'll get right to the point..
Everyone knows that in Roblox you have a ReplicatedStorage (for Client and Server) and a ServerStorage (only for Server).
So I want to store all my assets in ServerStorage .. you know, since exploiters/hackers can't see the ServerStorage if they tried.
However my game has virtual worlds..meaning that the client sees different objects than the other clients at any given time, so I can't just load an object from a server scripts because then everyone will see it.
Heres the question: Can I perhaps set up a remote function that lets the Client invoke the Server, and then the Server returns a model object or its location or something like that? And can I then use the Client to load the model into the player's workspace?
^That way I can securely store my important game assets in the serverstorage
The answer to your question is "Yes, you can!"
First off, you're going to want to create a RemoteFunction in the ReplicatedStorage. Call this RemoteFunction, 'GetModel'
Now, we're going to set up a local script inside of the StarterPack. This local script should have the following code:
local RS = game:GetService("ReplicatedStorage")
local RF = RS:WaitForChild("GetModel")
local model = RF:InvokeServer("ModelName") -- This code can go anywhere you'd like it to go. 'ModelName' is the name of the model you want to get.
print(model.Name) -- This will print the model's name.
Alright, so we've setup our code to invoke the remotefunction. Now, let's make that RemoteFunction do something. We'll create a server script inside of ServerScriptService. Here's the code:
local RS = game:GetService("ReplicatedStorage")
local RF = RS:WaitForChild("GetModel")
RF.OnServerInvoke = function(player, modelName)
local model = game.ServerStorage:FindFirstChild(modelName)
if model == nil then
return nil
else
return model
end
end
Most of this is basic code, and from what you said in the question it seems you understand lua fine. Hope I helped you! :)