tower.Name is nil?

I tried to make an inventory system but it says tower.Name is nil? This is the code

    for i, tower in pairs(playerData.OwnedTowers) do
        print(playerData.OwnedTowers)
        print(tower)
        --find any old buttons
            

        --creating new button
        print(tower.Name)
        print(tower.Rarity)
        local newButton = template:Clone()
        newButton.Name = tower.Name

Im kinda confused since the tower looks like this

["CCTV-Man"] = {
                ["Name"] = "CCTV-Man",
            ["ImageAsset"] = "http://www.roblox.com/asset/?id=13749054780",
            ["Rarity"] = "Common"

And when I print playerdata.OwnedTowers, it looks like this?
image

4 Likes

For some reason it seems to be treating the whole dictionary as nonexistant, displaying the access key in an array but nothing else. There may be other code affecting it. Are you able to provide any more code that could be affecting it?

1 Like

Heres some more content, this is the whole inventoryClient code:

local replicatedStorage = game:GetService("ReplicatedStorage")
local MarketplaceService = game:GetService("MarketplaceService")
local badgeService = game:GetService("BadgeService")

local getDataFunc = replicatedStorage:WaitForChild("GetData")
local interactItemFunc = replicatedStorage:WaitForChild("InteractItem")

local players = game:GetService("Players")
local player = players.LocalPlayer
local gui = script.Parent
local inventoryFrame = gui.InventoryFrame
local template = inventoryFrame.Template

local playerData = {}


local function getItemStatus(itemName)
	if table.find(playerData.SelectedTowers, itemName) then
		return "Equipped"
	elseif table.find(playerData.OwnedTowers, itemName) then
		return "Owned"
	end
end


local function interactItem(itemName)
	local data = interactItemFunc:InvokeServer(itemName)
	if data then
		playerData = data
		updateItems()
	end
end

function updateItems()
	

	for i, tower in pairs(playerData.OwnedTowers) do
		print(playerData.OwnedTowers)
		print(tower)
		--find any old buttons
			

		--creating new button
		print(tower.Name)
		print(tower.Rarity)
		local newButton = template:Clone()
		newButton.Name = tower.Name
		newButton.Image = tower.ImageAsset	

		newButton.Parent = inventoryFrame


		local status = getItemStatus(tower.Name)
		
		if status == "Equipped" then
			print(newButton.Name.." is equipped!")
		else
			print(newButton.Name.." is owned!")
		end

		newButton.Activated:Connect(function()
			interactItem(tower.Name)
		end)
	end
end


local function toggleShop()
		playerData = getDataFunc:InvokeServer()
		updateItems()
end


script.Parent.Parent.SidebarGui.SidebarHolder.InventoryButton.Activated:Connect(function()
	toggleShop()
end)

Maybe theres something there that could affect it?

Within the toggleShop function, what is outputted if you output playerData?

It just simply outputs my data
image

OwnedTowers is shown as the list of names, which was outputted in the screenshot in the original topic post. What script returns the playerData?

What you’re saving is the keys of the dictionary, not the dictionary itself, so to fix it use them to index the actual dictionary:

local towerDictionary = --the dictionary that contains tower data, not the player one
for _, key in pairs(playerData.OwnedTowers) do
	local tower = towerDictionary[key]
	--rest of the code
end

But the thing about that is my dictionaries are built like this

	local TowerShop = {
	
		["Common"] = {
			["CCTV-Man"] = {
				["Name"] = "CCTV-Man",
			["ImageAsset"] = "http://www.roblox.com/asset/?id=13749054780",
			["Rarity"] = "Common"

			},
			["Speakerman"] = {
				["Name"] = "Speakerman",
			["ImageAsset"] = 'http://www.roblox.com/asset/?id=13749300689',
			["Rarity"] = "Common"

			},
			["TV-Man"] = {
				["Name"] = "TV-Man",
				["ImageAsset"] = "http://www.roblox.com/asset/?id=13767180458",
				["Rarity"] = "Common"
			},
	},

So its not gonna be the first result, is there anyway to do something similar to FindFirstDescendant?

local TowerShop = --reference to your tower shop dictionary

type tower = {Name: string, ImageAsset: string, Rarity: string}
local function getTowerByKey(key: string): tower?
	for _, rarity in pairs(TowerShop) do
		if rarity[key] then return rarity[key] end
	end
	return nil
end

for _, key in pairs(playerData.OwnedTowers) do
	local tower = getTowerByKey(key)
	--rest of your code
end

Thanks! That worked perfectly, just one question, what does this line do?

	type tower = {Name: string, ImageAsset: string, Rarity: string}

I’ve never seen “type” before?

It’s used for error detection and auto-completion. This has no impact in the real game even if it detects an error, but it tells you by making the line red. Basically, it tells the interpreter that what the function getTowerByKey returns is a dictionary with exactly 3 properties named Name, ImageAsset and Rarity and are all of type string. The ? next to tower means it can also return nil. So if you try to type tower. for the result it should suggest you those properties, and if you try to set or use any of them as non-string properties, it will make that line red.

Basically, for the simulation, it’s completely useless, but it helps keep code organized and detect logic errors more easily.

If this topic interests you check Type checking for beginners.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.