Baffled by the lack of string properties

I’m about to do some kind of silly stuff in order to get an original string back out of a game object. I need the original string, not a hash, in order to maintain compatibility with a text-based external source-of-truth (a .ink file, GitHub - inkle/ink: inkle's open source scripting language for writing interactive narrative.).

Since I’m new to defold, my immediate concern is that maybe there’s something that I’m overlooking (Chesterton’s fence). I’ve searched the forums and found some very historical (circa 2016) posts about this topic, but I’ve been generally unsatisfied with the rationale. You don’t often need unhashed strings, but when you do, you do. I can find a way to store them and retrieve them, but it’s just extra complexity that seems needless.

Cheers!
Hunter

1 Like

I don’t think I have a deep enough understanding of the “why no string properties” to help you tear down the fence, however what I can say is that I would probably use a module for what you want to achieve:

1 Like

This is the rationale of Lua (and Defold); don’t make it more complex than it needs to be. A hash is to (notionally) make the code faster and storing the original string with the hash would work against this. Create a table with the hash as a key and the string as it’s value. You could put this in a closure or module with the said table as an up-value. I guess this is what you have done. This can be a bit strange/annoying in comparison to (say) Python where everything you could possibly want is in there somewhere. It is a deliberate design decision.

1 Like

Thanks @Alex_8BitSkull and @iotaHum for replying with suggestions!

I don’t believe either of those paths will achieve what I need, but if I’m wrong I’d be happy about that (edit: I was wrong and essentially ended up following these suggestions!)

I’m working with a designer who is laying out levels. The entire game logic and state is both written and stored in the .ink format, external to the defold game. So it has specific keywords (for example the name of the dialog tree that should be started upon interaction with a character). Those keywords are strings and I need to preserve them.

I need to expose this configuration in the editor so my colleague can mark, “this character maps to the dialog tree FooBar in the ink story”.

Despite the silliness, the best option I have found so far is to include a zero opacity label component and piggyback on its text property. That’s obviously a terrible way to go, but it is simpler than trying to duplicate hundreds of text keys in a table and telling my designer to manually keep them in sync.

Actually, in testing, that approach has the same problem as the simpledata extension: unlike game object properties, that can be overridden on a per-instance basis, changing the data from the editor within different collections actually changes the underlying definition. Whereas game object properties allow per-instance overrides:

In case anyone else runs across this, here’s the method I’ve settled on until defold supports string properties (which, in some newer forum posts, it sounds like they’re planning to do. But that was 1.5 years ago, so…)

I created an unhash.lua module:

local hash_to_string = {}
local list_file = "/strings/list.txt"
local raw = sys.load_resource(list_file)
assert(raw, "Failed to load " .. list_file .. " custom resource")

for line in raw:gmatch("[^\r\n]+") do
    local trimmed = line:match("^%s*(.-)%s*$")
    if trimmed ~= "" then
        hash_to_string[hash(trimmed)] = trimmed
    end
end

local function unhash(h)
    local s = hash_to_string[h]
    assert(s, "Missing hash " .. h .. " in " .. list_file)
    return s
end

return unhash

Then I created strings/list.txt which is just a text file with strings on each line. This is sadly just an extra chore for the other people working on the project - any string that needs to maintain an external reference (like to parts of our .ink story) must be listed in this file. So there are several places with silly code like this:

go.property("area_name_hash", hash(""))
-- ...
self.area_name = unhash(self.area_name_hash) -- this string must exist in list.txt

However, it does work, and it’s not too onerous, and when you miss a string the assert shows you right away.

I hate to say this, but, I am pretty sure that this won’t work in release builds - only in debug.

It seems to work - is a release build something other than this?

Project → Bundle → Linux application → Variant: Release

I think this is no different from building a lua table that maps hash("foo")"foo", just slightly automated by reading list.txt first so my design partners can just add strings to a text file instead of messing with lua.

No that’s indeed what I meant by release build.

I base it on this: How to get the string value from a hash("string") - #8 by britzl

It’s not something I’ve paid attention to but I haven’t seen evidence of this changing (other than your post just now!).

I know there are some issues that it works when testing but if you build it then run it from the executable it no longer works. So be sure you test with a fully compiled version in your testing to see if it works.

I see, thanks!

In your case of matching a flipbook animation id to a string you’d need to create the look-up table from hash to string yourself, or even better always work with the hashed values.

I think this is essentially what I’m doing, whereas the original poster was using string operations to try to extract strings from hashed values (which will only work when the relationship between strings and hashes is known and string-compatible, so not in release builds).

3 Likes

Your unhash.lua module will be fine in a release build, as long as the resource is there. This is what Britzl (and Alex and me) suggested to do. I don’t fully understand what you are doing with the properties part of your solution,but if it works for you then it must be good.

1 Like

Thanks! Love how active the defold forums are.

The properties stuff is to try to make collaboration as easy as possible for my non-software-eng partners. I can show them where to update property values in the defold UI, and where they can add those strings in list.txt, then on the lua side I can translate what are really hashes into string values. The original strings are important because my partners are also the ones writing the ink story, so “mayor” in ink needs to match with “mayor” in defold.

1 Like

This is secretly the best community to learn actually-good programming practices honed by experience, promptly. :smiling_face_with_three_hearts:

I can also add to iotaHum’s comment about Lua/Defold: there are many little bits of extra complexity that seem needless at first. After more experience, my impression of Lua/Defold is that you end up saving more code than you write, because you no longer have to navigate rigid channels to configure & conform the engine/language to your project.

That’s how it feels flip-flopping from Defold to Godot 3, and now back to Defold again, in the last 365 days.

1 Like