System for automatic, persistent id generation?

I need some way to automatically generate persistent ids for items in my game (e.g. A sword may have id 1)
This is so that when I serialize my data for datastore, it can just be serialized as the item id number
The issue, however, is that if I just rely on ids assigning when the object is created, then the ids could be assigned out of order.
Is there any easy way to automatically generate persistent ids? I’ve considered just hashing the sword name to some value, but it seems kinda hacky and not particularly scalable (also prone to typos/errors, and prevents me from renaming items if I have to)

2 Likes

This isn’t automatic…
I’d have to manually insert id NumberValues into the models and this isn’t what I want.

This is starting to seem like the only way to do this.

Maybe I should invest some time into writing a plugin interface for a mini database system in Roblox Studio (to manage stuff like item names/ids)

Could you not just hard code an id’s association with an item in a ModuleScript or something and have every script fetch from that ModuleScript whenever it needs to handle something related to ids or items? I don’t think automatic, persistent id generation is something necessary here.

This is precisely what I want to avoid - It gets incredibly annoying to have to manage ids in an ever growing list, and it would be much easier in the long run to automatically handle it. I have done this in the past, but it just takes too much effort and time to manage after a certain point (not to mention the possibility for human errors to occur)

I manually define ids for each item, it isn’t so bad
it also has the added benefit that when I remove something from the game I can manually shift every id down and reorganization is just really easy too
I now use spreadsheets for data instead of modulescripts, so I have all of the google sheet functionality built in when manipulating ids (very trivial to do so), but I remember it wasn’t much of a hassle before…what are you specifically doing that is impeded by manually defining ids?

In the end, you are going to be manually adding items and will need some way to associate an item with an id. You absolutely cannot avoid any manual work in this scenario and automatic generation itself sounds like enough of a chore. I can’t think of any game that actually does this, personally.

That also being said, a poor algorithm can also lead to errors akin to human errors or even gamebreaking bugs, corrupted data or the like.

Separating categories of items by id is annoying since you now have to maintain several different id mappings.

Really, the goal of this question is just to figure out a better way of doing it other than hardcoding (or atleast some way to go about hardcoding more efficiently). It is just an annoyance more than an actual barrier to getting stuff done.

are spreadsheets really that inefficient?
https://streamable.com/4w0f2

2 Likes

Not at all - they are a much better approach than dumping stuff into a modulescript.

The real question here is then how you quickly port a spreadsheet to studio.

This is my code, the only external dependency is to parse the individual cells (if something is a number/string/nil/etc), where I do an overkill of calling my lua loadstring, but you can probably get away with some other evaluating method

--assumes the entries are escaped
local api='https://docs.google.com/spreadsheets/d/{key}/gviz/tq?tqx=out:csv&sheet={sheet_name}'

return function(key,sheet,maxcols)
	local api=api:gsub('{key}',key):gsub('{sheet_name}',sheet)
	local response
	repeat
		pcall(function()
			response=_G.http:RequestAsync{
				Url=api,
				Method='GET',
				Headers={
					
				},
				Body=nil,
			}
		end)
	until response or not wait(5)
	
	if not response.Success then return false end
	local t={}
	local s=response.Body
	local i=1
	local len=#s
	for r=1,1/0 do
		t[r]={}
		for c=1,1/0 do
			i=i+1--opening quote
			local b=i
			while i<=len and s:sub(i,i)~='\"'or i<len and s:sub(i+1,i+1)=='\"'do
				if s:sub(i,i)=='\"'then i=i+1 end
				i=i+1
			end
			local w=s:sub(b,i-1):gsub('\"\"','\"')
			if c<=maxcols then--for some reason it will have empty ones too
				t[r][c]=w
			end
			i=i+1--closing quote
			if i>len or s:sub(i,i)=='\n'then break end
			i=i+1
		end
		i=i+1
		if i>len then break end
	end
	
	for r,row in next,t do
		for c,w in next,row do
			_G.debug.assertf(pcall(function()
				row[c]=_G.lua.loadstring('return '..w)()
			end),'(r%d,c%d) Failed to parse: %s',r,c,tostring(w))
		end
	end
	local data={}
	for r=2,#t do
		local info={}
		for c,v in next,t[r]do
			info[t[1][c]]=v
		end
		data[info.name]=info
		data[info.id]=info
	end
	return data
end

An separate module called ‘items’ references this ‘sheetdata’ module:



if _G.isserver then
	local rem=_G.network'senditems'
	local items=_G.sheetdata('1zpZzuYogz1Y3kQOWMi4rAgNYyLspRgMAOGqXqzU3Bzk','Items',10)
	for _,info in ipairs(items)do
		local model=script:FindFirstChild(info.name,true)
		info.model=model
		model.Name='model'
		local rel=CFrame.new(_G.model.aabb(model)):inverse()
		info.camcf=model.offset.Value
		info.code,info.alt=_G.metaphone.phrase(info.name)
		model.offset:destroy()
		model:SetPrimaryPartCFrame(rel*model.PrimaryPart.CFrame)
	end
	_G.bindjoined(function(plr)
		rem(plr,_G.table.serialize(items))
	end)
	return items
elseif _G.isclient then
	local items=_G.table.deserialize(_G.network'senditems':wait())
	return items
else
	local items=_G.sheetdata('1zpZzuYogz1Y3kQOWMi4rAgNYyLspRgMAOGqXqzU3Bzk','Items',10)
	for _,info in ipairs(items)do
		local model=script:FindFirstChild(info.name,true)
		info.model=model
		model.Name='model'
		info.code,info.alt=_G.metaphone.phrase(info.name)
	end
	return items
end

Sorry if this is a little vague, but hopefully it is still helpful
I have to go to bed now but it might be better anyways if you make a separate thread on this if it is something you want to do

4 Likes

Hm this seems like a good solution.

My only concern here would be if Google API throttled you (as this is probably occurring every time a server is started)

1 Like

The google spreadsheet api limits you to about 5 requests per second and the Roblox http limit is (roughly) 8 per second. Unless your creating multiple servers a second you should be fine.

2 Likes

I think it would be easiest if; any item you add to the game gets placed in a folder in the server somewhere and then you run an executable script in studio that will check each item in the folder and if it does not have a “tag” in it (string or int value) then it creates one and generates a random number (for examples sake we will go with 5 digits long) and makes sure none of the other tags are matching it and then assigns the new tag that value.

Then when saving their data it just checks the tag value, and when loading data it can compare to your folder of items that have the tags in them.

This way you can add many items at once without having to do anything to them, besides manually clicking run and selecting your executable script.

1 Like