Unhashing a value

I have never really understood what hashes are or why the exist. And I’m having a problem at the moment.
I have a level select screen with various objects that link to different levels. It would be useful to access the ID of each object within its code, because all of the object IDs are numbers and it would be useful to automatically have 1 access the collection proxy called 1. But when i do go.get_id the value i get is hash: [/9]. Is there any way of easily getting rid of everything but the 9?

my ideal code would be something like

go.property("level", go.get_id())

any help?

You can try
go.property("level", msg.url())
it’s will be something like:

or numbers:
go.property("level", 0)

More information here http://www.defold.com/manuals/script-properties/

Hash functions are awesome! You can read more about them at wikipedia (https://en.wikipedia.org/wiki/Hash_function) but I’ll give a brief and simplified explanation below.

(TL;DR, don’t rely on reverse hashing for your game logic, it’s not available in release mode)

A hash function will take a value (input) of variable length (like a string) and convert it to a value (output) of fixed length. A hash algorithm has certain properties, one of which is uniformity, another one which is Non-invertible.

Uniformity means that the output from a hashing function should be evenly spread over the output space, in a uniform distribution. This could be seen as a more relaxed requirement compared to collision resistance which is an important aspect of cryptographic hash functions, but for Defold is enough to know that the hash value (output) for "/main" is very unlikely to be the same as the hash value (output) for "/level".

Non-invertible means that given h(x) = y, there should be no known function f(y) = x. And if such a function exists, it would be very expensive to compute. This is an important aspect when it comes to storing password, but it also allows for hashes to be computed relatively fast, which is important for Defold.

The big benefit of passing hashes between functions in Defold is that they are a lot faster to compare, and will require less memory than the input that created the hash. The drawback is that you can’t retrieve the original input from the hash. The output from Defold’s hash function is a 64 bit integer, which can be compared using a single instruction, whereas comparing the input would require at least N instructions, and in reality a lot more. Passing the hash value between different functions will require 8 bytes of memory, whereas passing the input would require N bytes of memory.

When the engine is run in debug/development mode, we will store the input for each hash in a lookup-table so we can reverse the hash, which is required because of the Non-invertible property. This requires extra work, and is something that is optimized away in release mode. Thus you should never rely on reverse hashing for your game logic, since it will be unavailable when you release your game.

8 Likes

Interesting! but ultimately, frustrating!!! haha

2 Likes

@britzl

This is what I was asking about in the other thread. I have 200 levels in my game, and so in my level select screen, I have 200 instances of a game object called “level”. The script for this GO has a property called “levelproperty” which is a number from 1 to 200. Clicking on a level loads its collection, based on the value of “levelproperty”.

It would be really great to be able to do what I did in stencyl, which was to automatically set the “levelproperty” to the ID of its GO instance.

To be honest it is not very important. I gave up and manually adjusted the levelproperty value for 100 of them, and it didn’t take very long. But I can think of a couple of other situations where it might be useful.

And these 200 instances are manually created and placed in the collection and not created via a factory?

Yes. The level select is kind of like blossom blast, or any of those kind of games.

Also remember that it’s easy to generate/regenerate such things via tiny scripts (e.g Python) due to the fact that we use text based formats.

I see. I don’t see the problem though. I would create a lookup table mapping game object ids to their respective level meta data (like the level id/property, game mode, etc). Something like this:

local NUM_LEVELS = 200

function init(self)
	-- create a lookup table that maps game object ids to their level id/property/index
	self.levels = {}
	for i=1,NUM_LEVELS do
		self.levels[hash("level" .. i)] = i
	end
end


-- call this function when you have detected which game object the user clicked on
-- The id is the game object id
local function on_level_go_selected(self, id)
	local levelproperty = self.levels[id]
	-- load level collection based on levelproperty
end

@britzl you’re right. It isn’t a big problem. I was just wondering if it were possible to access an instance’s ID from a script as it was something I did many times when I was starting out in stencyl (imagine something like “self.id”).

Of course. go.get_id(). But I guess you mean an unhashed name.

@sicher, yes that’s it… (which is why the thread is titled “how to unhash a value”!)

If you have a lot of manually placed objects and really need reverse lookup it’s easy to make a script that dumps a lookup table to use in the game, then run that that in debug mode. Either as @britzl suggests or by doing a reverse lookup.

There ain’t any non debug lookup because we believe the engine should be simple and scaled down. But it should be useful too. Ifyou have a good use case where you really can show the benefit of reverse lookup please post it and we’ll evaluate.

1 Like