(Case 956356) Creating scene outputs different .unity file always

(Programmatically) creating a scene with the same content, produces an .unity file with different content always. It seems the GameObject's inside the scene file are stored randomly.

The provided example creates a new scene and places a few prefabs at hard-coded positions. It's always the same. However, comparing the produced .unity file with a diff tool (such as TortoiseMerge), shows the scene file is different always.

This causes version control issues. Most likely different asset bundles as well, even though the actual scene is identical.


C# Source Code

[spoiler]

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

class CreateSceneTest
{
    [MenuItem("Test/Create Scene A")]
    static void DoMenuItem()
    {
        // create a new scene
        var scene = UnityEditor.SceneManagement.EditorSceneManager.NewScene(UnityEditor.SceneManagement.NewSceneSetup.EmptyScene);

        // create a floor place
        var floor = (GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Art/Floor.prefab"));
        floor.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);
        floor.transform.SetAsLastSibling();

        // create a few prefabs
        foreach (var pos in new Vector3[] {
            new Vector3(5, 0, 0),
            new Vector3(0, 5, 0),
            new Vector3(0, 0, 5),})
        {
            var cube = (GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Art/Cube.prefab"));
            cube.transform.SetPositionAndRotation(pos, Quaternion.identity);
            cube.transform.SetAsLastSibling();
        }

        // save scene
        UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(scene);
        UnityEditor.SceneManagement.EditorSceneManager.SaveScene(scene, "Assets/Scenes/Scene A.unity");
    }
}

[/spoiler]

Reproduce

  • Open user attached project
  • Press Mainmenu/Test/Create Scene A
  • Duplicate generated "Scenes/Scene A.unity" and rename it to "Backup"
  • Press Mainmenu/Test/Create Scene A
  • Compare "Scenes/Scene A.unity" and rename it to "Scenes/Backup" with a diff tool

Observe the file content is different.

Expected
The produced file should be the same. If the input is identical, the output should be identical as well.

QA was able to reproduce the issue and it's now added to the public Issue Tracker
https://issuetracker.unity3d.com/issues/creating-identical-scene-always-outputs-different-unity-file

This is not a bug.
Sorting of objects in the scene file is based on an internal ID given to the objects the first time they are saved.

Even though you are creating identical objects everytime you run your script you are actually creating new objects which does not have an ID allocated until you save the file. When you save the file all GameObjects and Prefabs are given random IDs, components are given ID based on either the GameObject or the Prefab they belong to. This is to ensure objects are grouped nicely.

The order of objects in the scene file is not based on the order in the hierarchy but only on the ids, this ensure that changes to order in the hierarchy does not produce massive changes to the scene which can be a problem if the scenes are in version control.


Which is exactly the problem we have.

We use an external application (not Unity) to create levels. It's a level editor that is optimized for the kind of content we need to produce. We save the level created by that external editor to the Unity project and have custom code that converts this file to an Unity scene.

However, every time we convert the same level (input), the Unity scene file (output) is completely different.

How do I get "deterministic scene files"? If there is a solution to this at all.

Only way to get deterministic scenes is to reuse existing objects.

Load the existing scene, load your generated data, match objects and patch if required, create new objects if required and delete objects that does not have a matching object in your data.

1 Like

I see, thanks for your help!