Transform/Position Issues When Loading Save With Custom GameObjects

Discuss modding questions and implementation details.
User avatar
Magicono43
Posts: 1141
Joined: Tue Nov 06, 2018 7:06 am

Transform/Position Issues When Loading Save With Custom GameObjects

Post by Magicono43 »

So I'll try to keep this as concise as I can. Basically these custom gameobjects I'm adding, initially the positions/transforms work fine, because they are piggy-backing off the transforms of already existing objects in the dungeon scene, that being the random loot-piles.

But the issue occurs in this case when trying to load a save where those previously present loot-piles have already been replaced and no longer exist. When I'm restoring the save data in this case, I'm using the "GetBestParent()" method as the initial gameobject's transform. This actually works out fine for chests that were initially within the primary block of the dungeon, that being the central one with the exit. But for any chests that were inside of other secondary blocks connected to the primary one, this parent is not sufficient, and their position context spawns them inside weird places within that central dungeon block, instead of the secondary blocks they were initially created in.

So basically I'm trying to think of a solution for how I might provide these chest objects with the appropriate parent/transform when loading from a save, so they actually spawn within the proper context of whatever dungeon module they were created in, not just the "GetBestParent()" primary central dungeon block.

The main dungeon gameobject has these blocks as direct children, but is there some way I could serialize whichever child dungeon block to use its transform when loading a save? I know how to serialize the sub-properties of a transform such as, position, localposition, localrotation, localscale, etc. But is there anyway to do similar for the parent/child hierarchy of gameobject and their component parts?

The only thing I can think of right now is possibly going by individual dungeon module name as a string, or some other unique identifying property and serializing that with the individual chest. Then somehow using that value after deserialization/loading to try and "reconnect" the chest object with the original parent dungeon block in question.

But I don't know, I might just be talking non-sense here, anyone that might know better I'd appreciate any advice.

Here is a screenshot that may or may not help explain a bit:
Capture.PNG
Capture.PNG (185.38 KiB) Viewed 1442 times
The highlighted dungeon module is the "main" one, that all the chests are trying to be created around when loading from a save, even the ones that should be spawning in the context of the secondary module to the left of it.

User avatar
Interkarma
Posts: 7242
Joined: Sun Mar 22, 2015 1:51 am

Re: Transform/Position Issues When Loading Save With Custom GameObjects

Post by Interkarma »

Are these all DaggerfallLoot styled objects? In base game, dropped loot containers are just loose objects parented to the DaggerfallDungeon, DaggerfallInterior, or StreamingTarget nodes, not any specific block or child object. They serialize/deserialize their positions easily enough. Your issue could be down to game expecting object transform to be relative to parent node and setting transform relative to some other object deserializes to wrong position.

Does looking at GameObjectHelper.CreateDroppedLootContainer() and CreateLootContainer() help at all? Creating loot objects through those helpers or copying their process will hopefully help.

If you're dropping objects outside, you also need to inform StreamingWorld to track a loose object using GameManager.Instance.StreamingWorld.TrackLooseObject(). You'll see this in CreateDroppedLootContainer().

User avatar
Magicono43
Posts: 1141
Joined: Tue Nov 06, 2018 7:06 am

Re: Transform/Position Issues When Loading Save With Custom GameObjects

Post by Magicono43 »

Interkarma wrote: Sun Mar 05, 2023 9:50 pm Are these all DaggerfallLoot styled objects? In base game, dropped loot containers are just loose objects parented to the DaggerfallDungeon, DaggerfallInterior, or StreamingTarget nodes, not any specific block or child object. They serialize/deserialize their positions easily enough. Your issue could be down to game expecting object transform to be relative to parent node and setting transform relative to some other object deserializes to wrong position.

Does looking at GameObjectHelper.CreateDroppedLootContainer() and CreateLootContainer() help at all? Creating loot objects through those helpers or copying their process will hopefully help.

If you're dropping objects outside, you also need to inform StreamingWorld to track a loose object using GameManager.Instance.StreamingWorld.TrackLooseObject(). You'll see this in CreateDroppedLootContainer().
In this case I'm currently just doing interiors for now, dungeons for now (but eventually in a later release maybe have some interaction with exterior things such as World of Daggerfall bandit camps, etc. But that's another story.)

Lucky enough, for now atleast the "opened chest" objects are just DaggerfallLootContainers, and the base DFU serialization and saveloadmanager stuff deals with them fine without any extra input on my part.

The weird part in this case is the "closed chest" objects, which are a custom MonoBehaviour component, which I add to a DaggerfallBillboard gameobject. So far what I've got with the serializing of these "closed chest" objects is basically all working when it comes to the actual serialization, deserialization, and RestoreSaveData process.

But yeah, as you said the main problem I guess is the actual parenting part when it comes to the RestoreSaveData part. Since the initial way I was getting the positions and transform values for these chests is by randomly replacing the randomtreasure containers when transitioning into a dungeon. It work fine in those case since I have objects to work with that already have something they are parented to when the dungeon scene is actually created, like randomtreasure container being a child of dungeon block N000013 or whatever, and that block being a child of the entire dungeon itself. Maybe I'm just being dumb somehow, but when loading a save, chests that were inside the "primary" central dungeon block are in their correct spots, but any that were in other blocks are usually floating somewhere in the void of that primary dungeon block (which makes sense I guess since I am using "GetBestParent()" rather than attaching them to the correct individual dungeon block itself.)

Here I took some screenshots of the main code I'm using for the saving and reloading process, maybe that can clear up some of my overly wordy explanation:
Capture1.PNG
Capture1.PNG (18.15 KiB) Viewed 1407 times
Capture2.PNG
Capture2.PNG (43.5 KiB) Viewed 1407 times
Capture3.PNG
Capture3.PNG (12.79 KiB) Viewed 1407 times
Thanks for the reply btw, clearly I'm still pretty bad when it comes to Unity positional context stuff, lol.

User avatar
Interkarma
Posts: 7242
Joined: Sun Mar 22, 2015 1:51 am

Re: Transform/Position Issues When Loading Save With Custom GameObjects

Post by Interkarma »

Do you need to deserialise both transform.position and transform.localPosition? The first is the world position, the second is relative to parent. The order of operations can matter when setting position and parenting.

Try serialising/deserialising the world position only and just parent to DaggerfallDungeon object. Dungeons are at least fairly simple and always relative to origin. At least You won't have any floating origin stuff to worry about in dungeons.

User avatar
Magicono43
Posts: 1141
Joined: Tue Nov 06, 2018 7:06 am

Re: Transform/Position Issues When Loading Save With Custom GameObjects

Post by Magicono43 »

Interkarma wrote: Mon Mar 06, 2023 12:19 am Do you need to deserialise both transform.position and transform.localPosition? The first is the world position, the second is relative to parent. The order of operations can matter when setting position and parenting.

Try serialising/deserialising the world position only and just parent to DaggerfallDungeon object. Dungeons are at least fairly simple and always relative to origin. At least You won't have any floating origin stuff to worry about in dungeons.
Yeah in that case I was just including all of them because I figure "more info the better." I'll give that a try and see how it goes, thanks.

User avatar
Magicono43
Posts: 1141
Joined: Tue Nov 06, 2018 7:06 am

Re: Transform/Position Issues When Loading Save With Custom GameObjects

Post by Magicono43 »

Alright, so I seem to have resolved the chest position/parent transform issue, in a sort of weird way that I'm not entirely happy with, but it seems to work fine for the time being atleast.

Here is the changes in the code that were made:
Capture1.PNG
Capture1.PNG (31.77 KiB) Viewed 1371 times
Capture2.PNG
Capture2.PNG (36.64 KiB) Viewed 1371 times
Capture3.PNG
Capture3.PNG (12.58 KiB) Viewed 1371 times
The gist is that since the randomtreasure loot-piles that I was piggy-backing off of, don't actually get destroyed when they are emptied, but instead their gameobject is set to "inactive", that meant I could when loading into the same dungeon, just check for all the DaggerfallLoot type objects in the current scene, make a list of those, then compare the loadID for each chest that is being recreated into the scene with the inactive loot-pile objects and essentially do the same as when just entering the dungeon normally on transition.

While this does appears to work so far, I am having another issue that I thought would be resolved by instead of "Destroying" the replaced random loot-piles, instead setting them as "inactive" as DFU already does when the loot-pile becomes empty. But unfortunately that is not the case it seems.

The issue being when I load a save inside a dungeon that has loot-piles replaced with these chest objects, when loading that save the random loot marker locations get filled with a random loot-pile, so there is a chest and a loot-pile directly ontop of each other, but I don't know why in these cases the loot-piles are regenerating. If I save again in this case, and then load that save, the loot-piles don't regenerate but stay in their state they were when the save was created, this one I'm really not sure how to prevent from happening now.

User avatar
Magicono43
Posts: 1141
Joined: Tue Nov 06, 2018 7:06 am

Re: Transform/Position Issues When Loading Save With Custom GameObjects

Post by Magicono43 »

Doing more digging around, I feel like this is probably what I should look at to try and understand my problem, but I keep looking at it and going down some of the methods in it and I can't really think of exactly how to work around the issue.
Capture.PNG
Capture.PNG (35.17 KiB) Viewed 1369 times

User avatar
Magicono43
Posts: 1141
Joined: Tue Nov 06, 2018 7:06 am

Re: Transform/Position Issues When Loading Save With Custom GameObjects

Post by Magicono43 »

Found a good opportunity for an example, so decided to make a short video showing the issue that's going on:


User avatar
Magicono43
Posts: 1141
Joined: Tue Nov 06, 2018 7:06 am

Re: Transform/Position Issues When Loading Save With Custom GameObjects

Post by Magicono43 »

Wrote a message and after hitting submit the page 404'ed basically, so that message is dead now.

Anyway, basically I may have some idea of a potential cause of my issue, potentially rooting from the fact I was copying the LoadID value of the original loot-piles, rather than making a new one for the chests and their resulting loot-piles, will have to see if this leads to any progress on the problem.

User avatar
Interkarma
Posts: 7242
Joined: Sun Mar 22, 2015 1:51 am

Re: Transform/Position Issues When Loading Save With Custom GameObjects

Post by Interkarma »

The loadID has two jobs here. The first job is to match saved data and restore state against treasure objects loaded from gamedata at scene build time (fixed treasure piles). The second is to restore loose treasure objects created after scene build (dropped loot, enemy corpses). These are two paths in if/else of RestoreLootContainerData().

You're right that stealing the loadID of a fixed resource could result in state being applied weirdly. You don't need to do anything state-wise with fixed treasure piles other than switch them off and ignore them. I'd grab their position, clear them out, and drop my custom objects in the same spot with a unique ID like any other post-scene-build object. You can use "DaggerfallUnity.NextUID" to grab a UID for new objects being added to scene after build time.

Post Reply