Anaminus / roblox-bug-tracker

Formerly an unofficial bug tracker for Roblox.
31 stars 24 forks source link

ObjectValue references cannot be cloned #823

Open Domiii opened 8 years ago

Domiii commented 8 years ago

As already explained on scripthelpers here, ObjectValue references are reset whenever an object is cloned. Here is why that is really bad:

I am a big fan of Unity's Prefab and GameObject model. Basically how it works is that you can assign GameObjects or Prefabs (which are GameObjects that are not in the world, but fully prepared to be spawned whenever needed, such as bullets) to properties on scripts, and scripts can then use those properties just like (in theory) you could do that with ObjectValue instances.

For example - Here is how I would want to create a turret in Roblox:

  1. Create a Turret model with a Shoot script

  2. Add an ObjectValue called Bullet to Turret

  3. Prepare the Bullet model, put it in ServerStorage, and assign to the Turret's Bullet ObjectValue

  4. In the Shoot script, use whatever Bullet model is referenced in that ObjectValue for shooting

This has a range of advantages. Most importantly: One script can support any amount of bullets without requiring any changes to the code, even during run-time!

However, in reality, when I clone my turret, I have to re-assign all ObjectValues manually. That is especially annoying when there are many different ObjectValues on the same object, and makes run-time changes impossible.

What's worse is that ObjectValue cannot be used at all with any object that is spawned/created by script (because it would immediately be invalidated). For example, right now, I am working on a simple pick-up system where tens of pick-ups are randomly spawned on the map, but different pick-up "templates" are supposed to contain different items/objects, with different scripts/effects.

I want to avoid hard-coding of the referenced objects at any price. I can imagine several work-arounds, including:

  1. Use a ModuleScript instead of ObjectValue that returns the hard-coded object reference of choice. Any script references to the object could just be changed from X.Value to require(X). Changing the referenced object would require code changes (which is bad), but due to the simplicity of the script, it would not be too error-prone. However, changing references during run-time would not be trivial.

  2. Use a StringValue where we'd reference an object by it's full name in the DataModel hierarchy. In this case, any script references would require an extra function that decodes and looks up objects by full path in the hierarchy (since the path of an object should contain full names in dot notation, such as ServerStorage.NPCs.WeakHobo). Changing object references would not require code changes, and could happen during run-time, which makes this approach the winner for now.

My question is two-fold:

  1. Why can ObjectValues Value property not be cloned (assuming a shallow clone, just keep the reference to the original; should not be too hard)? and:

  2. Is there a better option here?

PS: (Not sure if anyone cares, but...) Unity is rather smart about this. When copying, all Prefab and non-local GameObject references are kept as-is. However, if you reference an object that is a descendant of the object being copied, it will update the reference to match the newly instantiated copy of the descendant instead.

DarraghGriffin commented 7 years ago

Do you mean copying in studio or using Clone()? I think Clone() is easier to get working in this case. Copying objects in studio serializes the objects, so values can only have a referent to other serialized objects. Fixing this is not easy and wouldn't work in all cases. I think we could probably do something to fix this though, just wanted to give some background on why it doesn't work.

Domiii commented 7 years ago

@DarraghGriffin Doesn't matter how it is cloned/copied (be it in editor or via code), the reference is always 100% reset. It's really frustrating :)