Table.insert removing contents of array

This is the script that runs in my “ship” collection, which is where the contents of the cargo should be loaded as physical objects. It works perfectly the first time (currently the cargo array in the save file contains 1 value: “Crate” and 1 crate is being physically loaded in the ship)

function init(self)
	savefile_path = sys.get_save_file("StellarSalvagers", "SaveFile")--defines file path where game data is saved
	SavedData = sys.load(savefile_path)--loads the data file and assigns it to a variable

	inventory = {}--creates inventory array incase there isnt a saved one
	cargo = {}--creates cargo array incase there isnt a saved one
	if SavedData.inventory ~= nil then
		inventory = json.decode(SavedData.inventory)--loads inventory from saved data or create a new array if there's not one saved
	end

	if SavedData.inventory == nil then
		print("Inventory is nil")
	end

	for i =1,#inventory do--prints the entire inventory array
		print("Inventory Item",i,":",inventory[i])
	end

	if SavedData.cargo ~= nil then
		cargo = json.decode(SavedData.cargo)--loads cargo from saved data or create a new array if there's not one saved
	end

	if SavedData.cargo == nil then
		print("Cargo is nil")
	end
	
	for i =1,#cargo do--prints the entire cargo array
		print("Cargo Item",i,":",cargo[i])
	end

	if #cargo < 15 then--wont continue adding items from the inventory if cargo is full (15 slots)
		for i = 1, #inventory do--inserts each value from inv into cargo one at a time
			NewItem = inventory[i]
			table.insert(cargo, NewItem)
			if #cargo >= 15 then
				break
			end
		end
	end

	sys.save(savefile_path, {cargo = json.encode(cargo)})--saves the cargo array to the data file
end

I then load into the “level” collection where i can pick up crates, which adds them to the inventory array, then saves the inventory array to the save file just before the “ship” collection is loaded again.

Part of the player script that handles the inventory:

	if message_id == hash("ItemPickedUp") then--(for the item picking up) if it receives a message from an object that it has been picked up
		if #inventory < MaxSlots then --only runs if the number of objects in the inventory array is less than the number of max slots)
			local itempickedup = message.objecturl
			table.insert(inventory, itempickedup)--adds the item picked up to the inventory
			sys.save(savefile_path, {inventory = json.encode(inventory)})--cant save arrays themselves, have to encode them first into a string to save them
		end
	end

This part is running as intended and the inventory array is correct, the only issue is that at this point, if i had 1 crate in cargo to start with, then loaded the “level” collection, picked up eg 2 crates, then loaded the “ship” collection again, it would load 2 crates, rather than 3. Im unsure what’s wrong here.

The SaveData, inventory, cargo etc are all global variables. I don’t think that is intentional? It can cause problems in your code, especially if you try to create an inventory table in more than one script. I strongly recommend that you use either the local keyword or store the variables on the self object.

I may be being dumb but i dont see how that would cause an issue declaring them at the start

You don’t see the issue until you have 2 “ship” running at the same time ^^

I dont have 2 running though, i unload ship then load level, then unload level then load ship

Ok, if you don’t care about it then just back to your script, I see that when you save data, you don’t keep the old data, for example when you save inventory, you drop cargo.
Do you think of using a module to store those data rather than save and load them from file?

Sorry, im confused as to what you mean about when i save inventory and drop cargo

Um, this code. When you select items and save, your file now just contains inventory data. That’s why when you back to reload ship, you don’t have your previous cargo data

1 Like

but this saves to the inventory, not to the cargo, then in the other script i add the contents of inventory to cargo right? or have i gone wrong

I think the easy solution for you is that having 2 seperate files, one for current ship cargo, one for picked items (inventory).
Somehow I see passing your data via files is quite unconvenient. You could use a global table or a module to handle that

1 Like

ah, is it not possible to have two different things/array saved in one file?

Of course it’s possible but I guess you are misunderstanding how it works. When you save it will replace your old content with the new one.

sys.save(file, { cargo = [...] }) => file content: { cargo = [...] }

sys.save(file, { inventory = [...] }) => file content: { inventory = [...] }

It means if you want to have file content: { cargo = [...], inventory = [...] } you have to use
sys.save(file, { cargo = [...], inventory = [...] })

Basically, you can load it to get the table, take changes on the table and then save the table again

2 Likes

Ah, i see, yes. It seems i was misunderstanding how saving works. I’ve tried using seperate files now and im getting nil inventory and nil cargo when i can see the inventory file contains two crates.

DEBUG:SCRIPT: Inventory is nil
DEBUG:SCRIPT: Cargo is nil

function init(self)
	InvFile = sys.get_save_file("StellarSalvagers", "Inventory")
	CargoFile = sys.get_save_file("StellarSalvagers", "Cargo")
	InvData = sys.load(InvFile)--assigns the contents of the Inventory file to a variable
	CargoData = sys.load(CargoFile)--assigns the contents of the Cargo file to a variable
	
	sound.play("/Ship#Ship")

	inventory = {}--creates inventory array incase there isnt a saved one
	cargo = {}--creates cargo array incase there isnt a saved one

	if InvFile.inventory ~= nil then
		inventory = json.decode(InvData.inventory)--loads inventory from saved data or create a new array if there's not one saved
	end

	if InvFile.inventory == nil then
		print("Inventory is nil")
	end

	for i =1,#inventory do--prints the entire inventory array
		print("Inventory Item",i,":",inventory[i])
	end

	if CargoFile.cargo ~= nil then
		cargo = json.decode(CargoData.cargo)--loads cargo from saved data or create a new array if there's not one saved
	end

	if CargoFile.cargo == nil then
		print("Cargo is nil")
	end
	
	for i =1,#cargo do--prints the entire cargo array
		print("Cargo Item",i,":",cargo[i])
	end

	if #cargo < 15 then--wont continue adding items from the inventory if cargo is full (15 slots)
		for i = 1, #inventory do--inserts each value from inv into cargo one at a time
			NewItem = inventory[i]
			table.insert(cargo, NewItem)
			if #cargo >= 15 then
				break
			end
		end
	end

	sys.save(CargoFile, {cargo = json.encode(cargo)})--saves the cargo array to the data file
	SpawnItem()
end

function SpawnItem()--function to spawn an item in
	local CargoSlots = {
		{11,{x = 170, y = 1220, z = 1}},
		{12,{x = 245, y = 1220, z = 1}},
		{13,{x = 320, y = 1220, z = 1}},
		{21,{x = 170, y = 1145, z = 1}},
		{22,{x = 245, y = 1145, z = 1}},
		{23,{x = 320, y = 1145, z = 1}},
		{31,{x = 170, y = 1070, z = 1}},
		{32,{x = 245, y = 1070, z = 1}},
		{33,{x = 320, y = 1070, z = 1}},
		{41,{x = 170, y = 1000, z = 1}},
		{42,{x = 245, y = 1000, z = 1}},
		{43,{x = 320, y = 1000, z = 1}},
		{51,{x = 170, y = 920, z = 1}},
		{52,{x = 245, y = 920, z = 1}},
		{53,{x = 320, y = 920, z = 1}}
	}--array storing each slot and its coordinates but with a z of 1 so that the items spawn on top

	for i=1,#cargo do--starts at 1 and ends when the array ends
		local XCoord = CargoSlots[i][2].x--sets x coordinate of variable to the one in the array
		local YCoord = CargoSlots[i][2].y--sets y coordinate of variable to the one in the array
		local ZCoord = CargoSlots[i][2].z--sets z coordinate of variable to the one in the array
		local pos = vmath.vector3(XCoord,YCoord,ZCoord)--creates variable of coordinates based on the xyz values in the array
		if cargo[i] == "Crate" then
			factory.create("/Factories#Crate", pos)--spawns the object at the pos
		end
	end
end

function on_message(self, message_id, message, sender)
	if message_id == hash("CrateSold") then
		OldCargo = json.decode(CargoData.cargo)
		while CrateRemoved == false do
			for i = 1,#OldCargo do
				if OldCargo[i] == "Crate" then
					table.remove(OldCargo, i)
					CrateRemoved = true
				end
			end
		end
	end
end
				
	if message_id == hash("ItemPickedUp") then--(for the item picking up) if it receives a message from an object that it has been picked up
		if #inventory < MaxSlots then --only runs if the number of objects in the inventory array is less than the number of max slots)
			local itempickedup = message.objecturl
			table.insert(inventory, itempickedup)--adds the item picked up to the inventory
			InvFile = sys.get_save_file("StellarSalvagers", "Inventory")
			sys.save(InvFile, {inventory = json.encode(inventory)})--cant save arrays themselves, have to encode them first into a string to save them
		end
	end

Do you notice any problems?

It’s InvData.inventory not InvFile.inventory. the same fir CargoData

1 Like

thank you pal :+1: