I was looking for a solution of this issue in search engines, but can't find one.
Though there's one that is almost identical, which is 'Invalid Argument #2 (String Expected, got Instance)', I tried looking ways to fix it in reverse, but it uses tostring(), and my issue is about the newest feature: Instance Attributes, which it doesn't support Instances as value, and the only thing I could do is to convert it as a string, now that the issue is about the Part.Parent, which uses Adornee/Instance or something on which I don't know the workaround for this
local LocalPlayer = Players.LocalPlayer;
local Mouse = LocalPlayer:GetMouse();
local function Part_Hide()
if (Toggle_MouseHover == true and Mouse.Target ~= nil) then
if (ReplicatedStorage:FindFirstChild("[Part_Storage]") == nil) then
local Model = Instance.new ("Model", ReplicatedStorage);
Model.Name = "[Part_Storage]";
--Mouse.Target:SetAttribute("Source", Mouse.Target:GetFullName())
Mouse.Target:SetAttribute("Source", Mouse.Target.Name)
Mouse.Target.Parent = Model;
else
local Model = ReplicatedStorage:FindFirstChild("[Part_Storage]");
--Mouse.Target:SetAttribute("Source", Mouse.Target:GetFullName())
Mouse.Target:SetAttribute("Source", Mouse.Target.Name)
Mouse.Target.Parent = Model;
end
end
end
local function Part_Unhide()
if (ReplicatedStorage:FindFirstChild("[Part_Storage]") ~= nil) then
local Storage = ReplicatedStorage:FindFirstChild("[Part_Storage]");
for _, Child in pairs (Storage:GetChildren()) do
--local Source = Child:GetAttribute("Source");
--Child.Parent = Source
Child.Parent = Child:GetAttribute("Source"); -- <-- Cause of the issue
end
end
end
I don't know if there's a way for an Attribute to accept Instances as value
Child.Parent = Child:GetAttribute("Source");
Is there a way to either convert String into an Instance, or an alternative way of saving an Instance as a value, or any kinds of workarounds for this issue? If so, answers are appreciated, thanks in advance!
As you've pointed out, Instances aren't acceptable as an Attribute type.
One workaround might be to create an ObjectValue instead, and use that to hold onto the Instance reference. You can stuff it into the object before moving it over to ReplicatedStorage, and then just delete it when you pull it out of storage.
local LocalPlayer = Players.LocalPlayer
local Mouse = LocalPlayer:GetMouse()
-- if the container for part storage doesn't exist, create it
local PartStorage = ReplicatedStorage:FindFirstChild("[Part_Storage]")
if (PartStorage == nil) then
PartStorage = Instance.new("Model", ReplicatedStorage)
PartStorage.Name = "[Part_Storage]"
end
local function Part_Hide()
if (Toggle_MouseHover == true and Mouse.Target ~= nil) then
-- alias the Mouse Target
local Part = Mouse.Target
local PartSource = Part.Parent
-- move the part to storage
Part.Parent = PartStorage
-- hold onto the reference to where this object came from
local ParentRef = Instance.new("ObjectValue")
ParentRef.Value = PartSource
ParentRef.Name = "ParentRef"
ParentRef.Parent = Part
end
end
local function Part_Unhide()
-- move all parts out of storage
for _, Child in pairs (PartStorage:GetChildren()) do
-- remove the ObjectValue from the child
local PartSource = Child:FindFirstChild("ParentRef")
PartSource.Parent = nil
-- place the child back into the world
Child.Parent = PartSource.Value
-- clean up
PartSource:Destroy()
end
end
As a small note, unless this is intended, you shouldn't do these kinds of world changing operations in a LocalScript, as those changes will only show up for the player that owns the LocalScript. The changes will be replicated to all players if you perform the work in a serverside Script.
I finally managed to make it work, thank you #Kylaaa
Turns out that your method of ObjectValue really works! I was looking for something like that, which holds a value of an instance, though I end up finding Roblox's newest feature and began focusing on it instead (which was my first mistake)
The second mistake was me not using aliases, because I thought using Instance properties/attributes directly would just work same as one being aliased and the alias part would be just for decoration or something that just adds for a line(something like making it easy for reference)
This is now the complete code:
local function Part_Hide()
if (Toggle_MouseHover == true and Mouse.Target ~= nil) then
local Part = Mouse.Target;
local Part_Source = Part.Parent;
local Source = Instance.new ("ObjectValue", Part);
Source.Value = Part_Source;
Source.Name = "Source";
if (ReplicatedStorage:FindFirstChild("[Part_Storage]") == nil) then
local Model = Instance.new ("Model", ReplicatedStorage);
Model.Name = "[Part_Storage]";
Part.Parent = Model;
else
local Model = ReplicatedStorage:FindFirstChild("[Part_Storage]");
Part.Parent = Model;
end
end
end
local function Part_Unhide()
if (ReplicatedStorage:FindFirstChild("[Part_Storage]") ~= nil) then
local Storage = ReplicatedStorage:FindFirstChild("[Part_Storage]");
for _, Child in pairs (Storage:GetChildren()) do
local Source = Child:FindFirstChild("Source");
Child.Parent = Source.Value;
Source:Destroy();
Storage:Destroy();
end
end
end
Related
Script:
local ToolFolder = game:GetService("ServerStorage"):FindFirstChild("SavedItems")
local DataStoreService = game:GetService("DataStoreService")
local SaveData = DataStoreService:GetDataStore("SaveData")
game.Players.PlayerAdded:Connect(function(player)
local ToolData = SaveData:GetAsync(player.UserId)
local BackPack = player:WaitForChild("Backpack")
local StarterGear = player:WaitForChild("StarterGear")
if ToolData ~= nil then
for i, v in pairs(ToolData) do
if ToolFolder:FindFirstChild(v) and BackPack:FindFirstChild(v) == nil and StarterGear:FindFirstChild(v) == nil then
ToolFolder[v]:Clone().Parent = BackPack
ToolFolder[v]:Clone().Parent = StarterGear
end
end
end
player.CharacterRemoving:Connect(function(Character)
Character:WaitForChild("Humanoid"):UnequipTools()
end)
end)
game.Players.PlayerRemoving:Connect(function(player)
local ToolTable = {}
for i,v in pairs(player.Backpack:GetChildren()) do
table.insert(ToolTable, v.Name)
end
if ToolTable ~= nil then
SaveData:SetAsync(player.UserId, ToolTable)
end
end)
Issue:
ServerScriptService.SaveTools:12: attempt to index nil with 'FindFirstChild'
Couldn't find a solution. Appreciate any help. :)
Any time you see "attempt to index nil with x" you need to look at where you are asking for "x" and realize that the object holding "x" doesn't exist. The job then becomes figuring out why that object doesn't exist.
In your case, whatever object that you are calling "FindFirstChild" on line 12 doesn't exist. Sadly, line 12 uses this three times :
if ToolFolder:FindFirstChild(v) and
BackPack:FindFirstChild(v) == nil and
StarterGear:FindFirstChild(v) == nil then
So let's look at where ToolFolder, BackPack, and StarterGear were created and see if that gives any clues.
local ToolFolder = game:GetService("ServerStorage"):FindFirstChild("SavedItems")
...
local BackPack = player:WaitForChild("Backpack")
local StarterGear = player:WaitForChild("StarterGear")
Backpack and StarterGear looks correct, they are both children of the Player, and both look to be spelled correctly.
ToolFolder is probably the culprit, you should make sure there is actually an object named SavedItems in ServerStorage. Double check that the spelling and capitalization are correct.
My goal here is to send the player object and the object name through to the client script to display the object name on a text label.
When I run this, it prints nil and nil. I want player.Name and name as you will see in the second code sample. Another error I get is "attempt to concatenate nil with string" from the client script.
Here is my server-side code:
script.onTouch.OnInvoke = function(button, sellObj, sellObjValue, buyObj, buyObjValue, afterWave, isLoadedPart)
if isLoadedPart == true then
local info = script.Parent.Parent.info
local player = info.player.Value
local owner = info.owner.Value
local savedItems = info.savedItems.Value
local builds = script.Parent.Parent.activeBuilds
if afterWave > info.activeWave.Value then
info.activeWave.Value = afterWave
end
button.Parent = savedItems.buttons
button.jobDone.Value = true
if sellObj ~= nil then
sellObj.Parent = savedItems.builds
end
if buyObj ~= nil then
buyObj.Parent = builds
end
local td = require(script.Parent.tycoonDictionary)
if not table.find(td.boughtButtons, button.objectId.Value) then
table.insert(td.boughtButtons, button.objectId.Value)
end
local ui = game.ReplicatedStorage:FindFirstChild('onPartLoad')
if ui then
ui:FireClient(player, 'buyObj.Name')
print('yes')
else
print('no')
end
else
local info = script.Parent.Parent.info
local player = info.player.Value
local owner = info.owner.Value
local money = info.player.Value.leaderstats.Money
local savedItems = info.savedItems.Value
local builds = script.Parent.Parent.activeBuilds
if money.Value >= buyObjValue or money.Value == buyObjValue then
if afterWave > info.activeWave.Value then
info.activeWave.Value = afterWave
end
button.Parent = savedItems.buttons
button.jobDone.Value = true
if sellObj ~= nil then
sellObj.Parent = savedItems.builds
money.Value += sellObjValue
end
if buyObj ~= nil then
buyObj.Parent = builds
money.Value -= buyObjValue
end
local td = require(script.Parent.tycoonDictionary)
if not table.find(td.boughtButtons, button.objectId.Value) then
table.insert(td.boughtButtons, button.objectId.Value)
warn(td.boughtButtons)
end
else
player.PlayerGui.inGame.error.label.invokeScript.errorInvoke:Invoke("Insufficient Funds")
end
end
script.Parent.waveChecker.afterRun:Invoke()
end
And here is my client-side code:
game.ReplicatedStorage.onPartLoad.OnClientEvent:Connect(function(player, name)
print(player.Name, name)
print(script.Parent.Text)
script.Parent.Text = name .. 'is loaded.'
print(script.Parent.Text)
end)
Here I will tell you a little about this game. It is a tycoon that saves data using a table with all button Ids in it. When it loads, it gets the button associated with the id and fires the server code for every button. If the button is a load button, it fires the client with the player and the buyObj.Name.
Is there just a little mistake or can I not send arguments to the client at all? Any help will be appreciated!
The OnInvoke callback's first argument is always the player that fired it, so you should change line 1 of the first script to:
script.onTouch.OnInvoke = function(playerFired, button, sellObj, sellObjValue, buyObj, buyObjValue, afterWave, isLoadedPart)
And :FireClient() requires a player argument as its first argument, so you should change
ui:FireClient(player, 'buyObj.Name')
to
ui:FireClient(playerFired, player, 'buyObj.Name')
Here is the solution I came up with;
First, I read through some Roblox documentation to find that the first argument I had to send when using :FireClient was the player, and because I already had the player there, it was just sending the function to that player. Now, I had 2 choices, I could send the player twice, or delete the player variable from the script. I chose the second one.
Here is what the :FireClient line in the server script looks like now:
game.ReplicatedStorage:WaitForChild('onPartLoad'):FireClient(player, buyObj.Name)
And here is what the client function script looks like now:
game.ReplicatedStorage.onPartLoad.OnClientEvent:Connect(function(name)
if name ~= 'starterFoundation' then
script.Parent.Text = name .. ' is loaded.'
end
end)
Thank you #TypeChecked for helping me realize this!
I coded out some functions in a ModuleScript to be executed by another script. Here is the code
local module = {}
wavepause = game.ReplicatedStorage.Values.WavePauseLength.Value
trollanoid = game.ReplicatedStorage.Trollanoid
spawnpoints = workspace.Test1.Spawns:GetChildren()
function trollanoidsummon()
local chosenspawn = math.random(#spawnpoints)
local clone = trollanoid:Clone().Parent == workspace.Zombies
clone.HumanoidRootPart.CFrame = chosenspawn.CFrame
end
module.Wave1 = function()
trollanoid()
wait(1)
trollanoid()
wait(1)
trollanoid()
wait(1)
trollanoid()
end
return module
What I expected was the NPC trollanoids to appear on the map, but instead I got this error in the output:
17:50:19.011 ServerScriptService.WaveModule:14: attempt to call a Instance
value - Server - WaveModule:14
I dont know what I did wrong, please help me fix this. Any help is appreciated
The error message is telling you what's wrong:
You're trying to call an object. The only things you can call in Lua are functions and objects with the __call metamethod.
You are calling an object. Like mentioned above, you can only call functions and objects with __call metamethod.
Try this:
local module = {}
wavepause = game.ReplicatedStorage.Values.WavePauseLength
trollanoid = game.ReplicatedStorage.Trollanoid
spawnpoints = workspace.Test1.Spawns:GetChildren()
function trollanoidsummon()
local chosenspawn = spawnpoints[math.random(#spawnpoints)]
local clone = trollanoid:Clone().Parent = workspace.Zombies
clone.HumanoidRootPart.CFrame = chosenspawn.CFrame
end
module:SpawnNPC(amount, threshold)
threshold = threshold or 1
amount = amount or 4
for i = 1, amount do
if wavepause.Value then break end;
trollanoidsummon()
wait(threshold)
end
end
return module
To use the module you would do this:
local spawner = require(modulescriptpath);
spawner:SpawnNPC(5, 1);
I made a few minor changes. Let me know if you need help with any :)
Im using the Corona SDK for developing games and created a new project that comes with a main.lua file, but wanted to add other seperate files such as player.lua so i could do object oriented.
My goal is to create a player from the main and i did some research on how that can be done.
a link to lua tutorial
Here is my code for those files:
player.lua :
Player = {}
Player.new = function(name, id)
local self = {}
name = name or "player"
id = id or 0
self.getName = function() return name end
self.getId = function() return id end
end
return self
main.lua :
local Player = require("scripts.player")
player1 = Player.new("Player1", 1)
print(player1.getName())
Im expecting a print in the console. The error says 'unable to index local Player (a boolean value) stack traceback' in main.lua
You do not return your player lib in player.lua. so when you call
local Player = require("scripts.player")
You shade the global variable Player created in player.lua with the result of require which is true.
References on Require: https://www.lua.org/manual/5.3/manual.html#6.3
You have 2 choices to correct this issue.
Option 1)
change player.lua
local Player = {}
Player.new = function(name, id)
local self = {}
name = name or "player"
id = id or 0
self.getName = function() return name end
self.getId = function() return id end
return self
end
return Player
OR Option 2) Change main.lua
require("scripts.player")
player1 = Player.new("Player1", 1)
print(player1.getName())
Option one follows more modern Lua module conventions, but either option will resolve your issue.
The first issue is that you have the return statement for constructor in the wrong place. It should be inside the constructor rather than outside:
Player = {}
Player.new = function(name, id)
local self = {}
name = name or "player"
id = id or 0
self.getName = function() return name end
self.getId = function() return id end
return self
end
Indenting your code consistently will help you see such problems straight away. I suggest always having end indented at the same level as the opening of the block (no matter if it is a function, for, do or whatever else).
After solving this issue you have the problem mentioned by Nifim - you need to take care of shadowing the Player. The simplest solution would be to add a return statement in the end of the player.lua:
Player = {}
-- `Player.new` and so on...
return Player
You could also make the Player local if you want. It is not needed but it might be desired.
Or you could remove the assignment from the main.lua:
require("scripts.player")
local player = Player.new()
Workspace.Part.Script:16: attempt to index local 'screengui' (a nil value)
wait(2) -- Testing to make sure assets loaded
script.Parent.Touched:connect(function(hit)
if not hit or not hit.Parent then return end
local human = hit.Parent:findFirstChild("Humanoid")
if human and human:IsA("Humanoid") then
local person = game.Players:GetPlayerFromCharacter(human.parent)
if not person then return end
person.Checklist.FirstEggCollected.Value = true
local playgui = person:FindFirstChild('PlayerGui')
print(playgui)
wait(0.2)
local screengui = playgui:FindFirstChild('ScreenGui')
wait(0.2)
print(screengui) -- This prints nil
local collectnotice = screengui:FindFirstChild('CollectionNotice') -- This is line 16
local Toggle = collectnotice.Toggle
local text = Toggle.Text
local value = text.Value
value = "The Easy Egg!"
person:WaitForChild('PlayerGui'):FindFirstChild('ScreenGui'):FindFirstChild('CollectionNotice').Toggle.Color.Value = Color3.fromRGB(0,255,0)
person:WaitForChild('PlayerGui'):FindFirstChild('ScreenGui'):FindFirstChild('CollectionNotice').Toggle.Value = true
script.Parent:Destroy()
wait(5)
game.Workspace.Variables.IfFirstEggInGame.Value = false
end
end)
I've been at this for hours. No idea how to make the error fix. FE is on, Yes its name is "ScreenGui" and it is inside "PlayerGui"
Error: Workspace.Part.Script:16: attempt to index local 'screengui' (a nil value)
From the Roblox manual: http://wiki.roblox.com/index.php?title=API:Class/Instance/FindFirstChild
Description: Returns the first child found with the given name, or nil
if no such child exists.
So there seems to be no child named "ScreenGui".
If a function may return nil you have to handle that properly. Blindly indexing possible nil values is bad practice.
Your issue is at the line local collectnotice = screengui:FindFirstChild('CollectionNotice').
You do not have an instance listed for the screengui variable.