Managing Large Item Databases

I’m currently in the beginning stages of creating a game that could grow to 100’s of items of different categories and wanted to see if anyone else has any ideas with storing all these items efficiently.

Player inventory data will be saved using ID’s so I need to assign them to the items as well.

In most cases I would just throw items into one module, which is fine until you get to a few thousand lines and the editor starts lagging.

My current idea is to create a hierarchy of databases, with one module at the top to fetch items based on name, or id while starting each database in the 1000’s to give room for up to 999 items per database which i doubt it’d ever reach.

Database:

Melee (1 - 999)
Range (1000 - 1999)
Armor (2000 - 2999)

An example of how this might look is:

Range:

return {
    [1000] = {
        Name = "Bow",

        Damage = 10,
        Health = 15
        Price = 5,
       
    },

    [1001] = {
        Name = "Longbow",

        Damage = 15,
        Health = 20
        Price = 12,
       
    },
}

Instead of typing in and using large arrays for defining the static values of your items, I would suggest a possibly modular approach.

As a ModuleScript is required to return a value, how about letting it return a function, and then call that function with a reference to the “item database” that needs to be build when the server starts.


-- Script, preferably placed in ServerScriptStorage
local itemDatabase = require(script:WaitForChild("ItemDatabaseModule"))
require(script:WaitForChild("WeaponItems"  ))(itemDatabase)
require(script:WaitForChild("ArmorItems"   ))(itemDatabase)
require(script:WaitForChild("CraftingItems"))(itemDatabase)

print("--ItemDatabase--")
for _,itemId in ipairs( itemDatabase.GetAllItemIds() ) do
	local item = itemDatabase.GetItemById(itemId)
	print( ("Id=%i, Name=%s"):format(itemId, item.Name) )
end
print("----")

-- ModuleScript named "ItemDatabaseModule"
local module = {}

module.items = {}

function module.AddItem(itemId, itemName, itemProperties)
  local newItem = { Name = itemName }
  for propertyName, propertyValue in pairs(itemProperties) do
    newItem[propertyName] = propertyValue
  end
  module.items[itemId] = newItem
end

function module.GetAllItemIds()
	local itemIds = {}
	for itemId,item in pairs(module.items) do
		table.insert(itemIds, itemId)
	end
	return itemIds
end

function module.GetItemById(itemId)
  return module.items[itemId]
end

function module.GetItemByName(itemName)
  for itemId,itemProperties in pairs(module.items) do
    if itemProperties.Name == itemName then
      return itemProperties
    end
  end
  -- No item by that name
  return nil
end

return module

-- ModuleScript named "WeaponItems"
return function(itemDb)
  itemDb.AddItem( 1000, "Bow",     { Damage = 10, Health = 15, Price = 5 } )
  itemDb.AddItem( 1001, "LongBow", { Damage = 10, Health = 15, Price = 5 } )
  -- etc.
end

-- ModuleScript named "ArmorItems"
return function(itemDb)
	local function ArmorItem(id, name, price, armorValue, magicResistance, weight)
		itemDb.AddItem(
			id,
			name,
			{
				Price = price,
				ArmorValue = armorValue,
				MagicResist = magicResistance,
				ArmorWeight = weight,
			}
		)
	end
	
	ArmorItem(2000, "Leather",    50, 100, false,  25)
	ArmorItem(2001, "Ironplate", 250, 500, true,  200)
	-- etc.
end

-- ModuleScript named "CraftingItems"
return function(itemDb)
	local function Craftable(id, name, stackable, ...)
		local recipe = {}
		for _,recipeItem in pairs( {...} ) do
			local itemName, itemAmount = recipeItem:split(":")
			recipe[itemName] = tonumber(itemAmount)
		end
		
		local itemProps = {
			Stackable = stackable,
			Recipe = recipe,
		}
		itemDb.AddItem( id, name, itemProps )
	end
	
	Craftable( 5000, "Workbench", false, "Plank:4" )
	Craftable( 5001, "Furnace",   false, "Cobblestone:8" )
	Craftable( 5002, "Sword",     false, "Stick:1", "Plank:2" )
	-- etc.
end

2 Likes