Been seeing some strange discrepancies between getObject and getObjectByKey. Wanted to get some insights if others are seeing this too. @Bill_Uncork-It and @npfoss
When using getObject, we provide the object’s known ID, and we’re getting back a null value. However, when using the same object’s key instead, it provides the proper object which includes the ID that we tried using in the getObject function.
Since we cannot setObjects with our own keys, we must create objects with known IDs. We then create a dictionary of ID/Key pairs, so we can refer to them properly by ID or Key. In cases where we delete an object and recreate it, the key will change, so we need to update it in our dictionary by getting the new key. We’re trying to use getObject for that, but the server crashes when it returns a null value.
Does this make sense? Is there a way for us to set the key ourselves, so we don’t have to use the ID to find the key for new objects? Is there a different between getObject and getObjectByKey that is causing this discrepancy? Would it be possible to get a function like setObjectByKey?
Looking at Game.ts it appears that getObject uses completeMaps while getObjectByKey uses partialMaps. I didn’t think that would cause the issue I’m seeing, but it is a difference between the two functions.
In any case, we’re just wondering if others are seeing this as well, whether this is a bug or not, and if there are workarounds and/or solutions.
That is a good look into the workings and limitations of the new [key]:object setup, and I feel like I can add a few things:
[key] can be set through the REST API, unsurprisingly. However, it is unclear if this process breaks something about object generation/storage (mostly as I do not know what processes are run/should be run to validate the input).
The [key] cannot be a value greater than 5 characters. This means that meaningful keys are hard to encode (ie “flower_pot_1” cannot be a key, it would have to be “fpot1” or something similar). For this reason, I feel like a ‘setObjectByKey’ would have some serious limitations, both from an implementation side, and a DX side (you would have to describe the character limit to devs somehow).
(Only tested this a bit, so bear with me) It looks like addObject does not include customState, even when it is set on the included object definition. If true, this is probably just an oversight, not a bug, but can make adding objects with included ‘data’ a problem.
Now, solutions:
I think for now, we ought to be able to use Object.keys(game.completeMaps[/*MapID*/].objects).includes("ObjKi") as a guard clause against getObject returning null. Definitely a half-measure, but one that should allow for more continuous runtime. You can even build in a “whoops, its not there, lets find it and update our DB” routine underneath it.
Filters. As a workaround, I’ve started adding in an ‘object filter’ helper function, which enables me to look for objects based on a number of criteria. Its not great (feels a little brute-forcey), but it does the job. I’ll see about posting it if this issue stalls out.
This is more a wishlist item, but it would be great if game.addObject would return the key of the added object, similar to many SQL create style functions. This way, if you do have to add the object, you can immediately update your DB with the new key, instead of having to get -> add -> get, and hope that the update is reflected in the game.completeMaps or game.partialMaps you are referencing. This change could also be reflected if Gather adds some sort of mass object add function (game.addObjects or game.addManyObjects, for clarity?).
Some final points:
I am pleased with how the id → key transition has gone, and I think it was the right move. I would be interested to hear if the update is considered ‘Done’ or if its in more of a post-launch update cycle, and we can expect more changes in the coming months.
The philosophy here is to separate identifiers from data, including what an object ‘means’ or how it should be treated. This is something we keep tripping over at Gather (best example: spaceIds include the space name and this is very hard to undo ). I’m still on the fence about being able to set the key despite this. For now http is the only way, and it does do the necessary validation.
addObject customState
It does work, I used this just last week
set object by key (updating, not adding)
This exists! It’s called updateObject. It will fail if the object doesn’t exist though
getObject returning null (main question)
very odd… this function is super trivial, the only thing I can think of is complete vs partial maps. Does the map you’re testing on have all the required stuff? Background, collisions, dimensions, etc? Is the object in game.completeMaps?.[mapId]?.objects?
+1 would be great. Not super easy with the way txns are set up at the moment, but on my wishlist also. Probably not coming super soon though
“considered Done”
It’s considered “done”. I have some minor followups for a bit of internal cleanup but don’t expect to make any changes that necessitate a new client release. There’s a chance of some QoL tweaks as we migrate away from ids internally, but that’s going to be very slow and low-pri