Issues with Tables, pulling a value from a variable index

Hey, I’m looking to pull a model from a table based on the number in the table and do things with it. I’m new to tables, and don’t know much other than what the DevWiki provides.

Specifically variables chosenSpawn and newRoom are causing me issues, not too sure how to pull the model from the table using the index I defined as a variable. I suspect that there’s simply a method hiding before my eyes but I can’t find the answer. Seems to be a fundamental for table usage.

It’s important to note that there is already entries in the ‘roomSpawn’ table due to the way the first room generates in a seperate part of the script, as well as the different rooms being indexed in ‘rooms’ as well.

Also feedback for other parts of my code is appreciated as well.

This is my code, this and the error log that shows after.

function createRoom()
	print("ok")
	local chosenRoom = math.random(1,table.getn(roomSpawn)) -- 'randomly' a number between 1 to # of spawns available (tabled on generation)
	print(chosenRoom)
	local chosenSpawn = roomSpawn.chosenRoom 				-- looking to pull the model from the table based on chosenRoom
	local newRoomNumber = math.random(1, table.getn(rooms)) -- 'randomly' a number between 1 to # rooms (tabled from a folder)
	print(newRoomNumber)
	local newRoom = rooms.NewRoomNumber:Clone()				-- looking to clone the chosen room from the list
	newRoom.Parent = dungeonModel							-- parents to the dungeon model
	newRoom:SetPrimaryPartCFrame(chosenSpawn)				-- sets the rooms orientation and pos to the spawn point
	chosenSpawn:Destroy()									-- destroys spawn to prevent it from being used again
	table.remove(roomSpawn,table.find(chosenRoom))			-- removes spawn point from table to prevent it from being used again
	print("room created")
	for i, v in pairs(newRoom:GetChildren()) do				-- loops through children of new room
		if v:IsA("BasePart") and v.Name == "SPAWN" then		-- finds spawn(s) for new rooms
			table.insert(roomSpawn, v)						-- inserts new spawn(s) into spawntable
			print("spawn integrated")
		end
	end
end


function generation()
	for i = 1,Limit,1 do
		wait(0.1)
		createRoom()
	end
end
  01:47:07.200   ▶ Spawn Indexed to roomSpawn (x4)  -  Server - RoomMaker:38
  01:47:08.834  ok  -  Server - RoomMaker:49
  01:47:08.834  4  -  Server - RoomMaker:51
  01:47:08.835  1  -  Server - RoomMaker:54
  01:47:08.835  ServerScriptService.RoomMaker:55: attempt to index nil with 'Clone'  -  Server - RoomMaker:55
  01:47:08.835  Stack Begin  -  Studio
  01:47:08.835  Script 'ServerScriptService.RoomMaker', Line 55 - function createRoom  -  Studio - RoomMaker:55
  01:47:08.835  Script 'ServerScriptService.RoomMaker', Line 73 - function generation  -  Studio - RoomMaker:73
  01:47:08.835  Script 'ServerScriptService.RoomMaker', Line 80  -  Studio - RoomMaker:80
  01:47:08.836  Stack End  -  Studio

TL;DR: I’m trying to find how to pull a model from a table based on the index, with the index being a variable.

What is the layout of the table? is there only number indexes ex. {a,5,x,m,7,l} or is there string indexes? ex.

{
["Apple"] = 24;
}
1 Like

For both tables they start as blank;

local table = {}

then are filled with a model;

table.insert(table, modelToBeInserted)

clicking on what’s printed in the error log for what spawn is selected highlights it in explorer, so I’d imagine this is a successful integration.
edit: this only applies for a seperate part script that prints as it inserts into the table.

I’m a little confused as to how your hierarchy is laid out. Is it just a folder with different rooms in it and these rooms have different parts which should have more rooms connected to them?

I don’t think you would need an external table as you can just use :GetChildren().

local rooms = game:GetService('ServerStorage'):WaitForChild('Rooms')

local function createRoom() -- make sure functions are local as I am pretty sure they allocate less memory
    local chosenRoom = math.random(1,#roomSpawn)
	print(chosenRoom)
	local chosenSpawn = roomSpawn:GetChildren()[chosenRoom] -- this will take the child whose index is chosenRoom
	local newRoomNumber = math.random(1, #rooms)
	print(newRoomNumber)
	local newRoom = rooms:GetChildren()[newRoomNumber]:Clone()
	newRoom.Parent = dungeonModel
	newRoom:SetPrimaryPartCFrame(chosenSpawn)
	chosenSpawn:Destroy()
	print("room created")
	for i, v in pairs(newRoom:GetChildren()) do
		if v:IsA("BasePart") and v.Name == "SPAWN" then
			print("spawn integrated")
		end
	end
end
1 Like

table[chosenRoom] to index the model in the table.

1 Like

In short, yes. The rooms are kept in a folder in ServerStorage, and indexed into the “rooms” table via this code:

local ServerStorage = game:GetService("ServerStorage")
local RoomsHere = ServerStorage:WaitForChild("Rooms")

for i, v in pairs(RoomsHere:GetChildren()) do
	if v:IsA("Model") and v.Name ~= "spawnRoom" then
		--print("Spawn Indexed to roomSpawn")
		table.insert(rooms, v)
		--print(roomSpawn)
	end
end

the second print only returns {} in the output.

How is the spawn indexed to roomSpawn when you are inserting it into a table called rooms?

1 Like

Alright. I’m still a bit confused but I tried to add some comments on parts I am not 100% sure on and maybe some to help you understand where I’m going with things haha.

for i,v in pairs(roomsHere:GetChildren()) do -- so this is generated first
    if v:IsA('Model') and v.Name ~= 'spawnRoom' then
        rooms[#rooms + 1] = v
    end
end
local function createRoom(index)
    local chosenRoom = math.random(1,#roomSpawn) -- not sure what roomSpawn is, probably the amount of spawns in the room?
    local chosenSpawn = roomSpawn[chosenRoom] -- use square brackets to index tables with a variable/number
    local newRoomNumber = math.random(1, #rooms)
    local newRoom = rooms[newRoomNumber]:Clone()
    newRoom.Parent = dungeonModel
    newRoom:SetPrimaryPartCFrame(chosenSpawn)
    chosenSpawn:Destroy()
    table.remove(roomSpawn, chosenRoom) -- since we already have a number that is between 1 and # roomSpawn, we don't have to use table.find
    for i,v in pairs(newRoom:GetChildren()) do
        if v:IsA('BasePart') and v.Name == 'SPAN' then
            roomSpawn[#roomSpawn + 1] = v
        end
    end
end
    
local function generation()
    for i = 1,limit do -- also, no need to specify the step here as it's 1 by default
        wait(.1)
        createRoom(i)
    end
end
1 Like

My thought process when creating the system was to have two tables; one for the places rooms can spawn (spawnpoints as BaseParts) and the other for the rooms (Models), the code that puts the rooms in a table is in my previous post, and the process of spawning the first room puts some spawn points for rooms in a table. Spawning a room puts the spawn points from that respective room in a table as seen in my original post.

Here’s my code for spawning the origin room:

function createSpawn()
	local newspawn = SpawnRoom:Clone()
	newspawn.Parent = spawnParent
	newspawn:SetPrimaryPartCFrame(spawnOrigin)
	for i, v in pairs(newspawn:GetChildren()) do
		if v:IsA("BasePart") and v.Name == "SPAWN" then
			print("Spawn Indexed to roomSpawn")
			table.insert(roomSpawn, v)
		end
	end
end

This code block with some minor changes was successful, thank you! I was unaware of the functionality of square brackets, as I am still fairly new to scripting. I’m going to dissect the given code in comparison to my own, and hopefully improve my original script to match yours so it’s not straight up plagarism haha.
I’ll be back in one moment once I understand the changes.

1 Like

No worries.

Basically, the reason why using a period doesn’t work is because it is looking for a child or property whose name is “chosenRoom”, “NewRoomNumber” etc…

You can also use brackets to index things whose indexes are instances, tables etc

local t = {}

local t2 = {
    [t] = 'table';
}
print(t2.t) -- this would be nil because no entry exists whose index is "t"
print(t2[t]) -- this would be 'table' because the index is the table object

Same thing with instances

local t = {
    [workspace] = 'cool the index is the workspace'
}
print(t.workspace) --> nil
print(t[workspace]) --> nil

Basically, doing table.string is the same as doing table[‘string’].
Only upside to using brackets for names is that you can use spaces (which is very uncommon if not nonexistent in professional cases).

local part = workspace['this part has a name with spaces']
local part2 = workspace.this part has a name with spaces --> would error with something like expected function call because it's basically the same as doing

local part2 = workspace.this
part
has
a
name
with
spaces
-- or
local part2 = workspace.this
nil
nil
nil
nil
nil
nil
-- because the variables, part, has, a, name, with, and spaces are all nil if that makes sense
2 Likes

Thanks for the lesson! I was entirely unaware, when I absolutely had to refer to a child with spaces in the name before I’d use a WaitForChild("") - which has obvious issues in itself.

After understanding and modifying my base code, it successfully generates in the way I’d expect. Now I’ve only to code the doors between rooms becoming destroyed when a room is created, and preventing a spawn location from being used when already inside the room, however that’ll have to be for a future date as it’s 3am local time and I’ve work in the morning. Hopefully I won’t have to make another post requesting assistance on that topic, LOL.

Thanks again, I appreciate the help.

1 Like