static bool ValidateSimAssetIdForPrefab(SimAsset prefab)
 {
     if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(prefab, out string guid, out long localId))
     {
         if (prefab.Guid != guid)
         {
             prefab.Editor_SetGuid(guid);
             EditorUtility.SetDirty(prefab);
             DebugEditor.LogAssetIntegrity($"[{nameof(SimAssetBankUpdater)}] Updated {prefab.name}'s assetId to: {guid}");
             PrefabUtility.RecordPrefabInstancePropertyModifications(prefab);
             return(true);
         }
     }
     return(false);
 }
    public static void UpdateSimAssetIds()
    {
        SimAssetBank bank = AssetDatabaseX.LoadOrCreateScriptableObjectAsset <SimAssetBank>(ASSET_PATH);

        bank.EditorSimAssets.Clear();

        AssetDatabaseX.LoadPrefabAssetsWithComponentOnRoot <SimAsset>(out List <KeyValuePair <string, GameObject> > loadResult);
        foreach (KeyValuePair <string, GameObject> item in loadResult)
        {
            var prefab = item.Value.GetComponent <SimAsset>();

            ValidateSimAssetIdForPrefab(prefab);

            bank.EditorSimAssets.Add(prefab);
        }

        DebugEditor.LogAssetIntegrity($"[{nameof(SimAssetBankUpdater)}] Updated {typeof(SimAssetBank)}");

        EditorUtility.SetDirty(bank);
        AssetDatabase.SaveAssets();
    }
    static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
    {
        if (AssetPostprocessorUtility.ExitImportLoop(importedAssets, ASSET_PATH, ref s_importLoopCounter))
        {
            return;
        }

        SimAssetBank bank      = null;
        bool         saveAsset = false;

        importedAssets.Where((assetPath) => assetPath.EndsWith(".prefab"))
        .Select((assetPath) => AssetDatabase.LoadAssetAtPath <GameObject>(assetPath))
        .Where((gameObject) => gameObject.GetComponent <SimAsset>() != null)
        .Select((gameObject) => gameObject.GetComponent <SimAsset>())
        .ToList()
        .ForEach((SimAsset prefab) =>
        {
            if (bank == null)
            {
                bank = AssetDatabaseX.LoadOrCreateScriptableObjectAsset <SimAssetBank>(ASSET_PATH);
            }

            saveAsset |= ValidateSimAssetIdForPrefab(prefab);

            if (!bank.EditorSimAssets.Contains(prefab))
            {
                saveAsset = true;
                bank.EditorSimAssets.Add(prefab);

                DebugEditor.LogAssetIntegrity($"Added {prefab.gameObject.name} to {nameof(SimAssetBank)}.");
            }
        });

        if (saveAsset)
        {
            EditorUtility.SetDirty(bank);
            AssetDatabase.SaveAssets();
        }
    }
    public void UpdateBankComplete()
    {
        TBank bank = AssetDatabaseX.LoadOrCreateAsset(_bankAssetPath, () => ScriptableObject.CreateInstance <TBank>());

        var storedObjects = _getStoredObjectsFromBankDelegate(bank);

        storedObjects.Clear();

        LoadAll(out List <(string, TAsset)> loadResult);

        foreach ((string guid, TAsset asset) in loadResult)
        {
            if (_evaluateAssetDelegate(asset, out TStoredObject storedObject))
            {
                storedObjects.Add(storedObject);
            }
        }

        DebugEditor.LogAssetIntegrity($"{bank.name} bank updated.");
        EditorUtility.SetDirty(bank);
        AssetDatabase.SaveAssets();
    }
    private void UpdateBank(List <TStoredObject> changedPrefabs)
    {
        TBank bank = AssetDatabaseX.LoadOrCreateAsset(_bankAssetPath, () => ScriptableObject.CreateInstance <TBank>());

        var storedObjects = _getStoredObjectsFromBankDelegate(bank);

        bool change = false;

        foreach (var item in changedPrefabs)
        {
            if (!storedObjects.Contains(item))
            {
                storedObjects.Add(item);
                change = true;
            }
        }

        if (change)
        {
            DebugEditor.LogAssetIntegrity($"{bank.name} updated.");
            EditorUtility.SetDirty(bank);
            AssetDatabase.SaveAssets();
        }
    }
    public static void Generate(LevelGridAuth levelGridAuth)
    {
        if (levelGridAuth == null)
        {
            Log.Error($"No {nameof(LevelGridAuth)} found.");
            return;
        }

        if (!levelGridAuth.gameObject.scene.IsValid())
        {
            Log.Error("Can only generate assets for levelGridAuth in scenes");
            return;
        }

        GameObject sceneGrid = levelGridAuth.gameObject;

        string simAssetPath  = GetGeneratedFilePath(sceneGrid, isForView: false);
        string viewAssetPath = GetGeneratedFilePath(sceneGrid, isForView: true);

        // Create & Save Assets
        {
            GameObject simGridPrefab = new GameObject();
            simGridPrefab.AddComponent <SimAsset>();
            simGridPrefab.GetComponent <SimAsset>().HasTransform = true;
            simGridPrefab.GetComponent <SimAsset>().Editor_SetShowGhost(false);
            simGridPrefab.GetComponent <SimAsset>().ViewTechType = ViewTechType.GameObject;

            GameObject viewGridPrefab = new GameObject();
            viewGridPrefab.AddComponent <Grid>();
            viewGridPrefab.GetComponent <Grid>().cellSize    = new Vector3(1, 1, 0);
            viewGridPrefab.GetComponent <Grid>().cellGap     = new Vector3(0, 0, 0);
            viewGridPrefab.GetComponent <Grid>().cellLayout  = GridLayout.CellLayout.Rectangle;
            viewGridPrefab.GetComponent <Grid>().cellSwizzle = GridLayout.CellSwizzle.XYZ;

            SetupSceneGrid(sceneGrid);

            foreach (TilemapRenderer tilemapRenderer in sceneGrid.GetComponentsInChildren <TilemapRenderer>())
            {
                // Simulation Grid doesn't need to be copied in a prefab
                if (tilemapRenderer.sortingLayerName == GameConstants.LAYER_GRID_SIMULATION)
                {
                    continue;
                }

                Tilemap tilemap = tilemapRenderer.GetComponent <Tilemap>();
                if (tilemapRenderer == null || tilemap == null)
                {
                    Log.Error("Grid is invalid since there's no tilemap or tilemaprenderer");
                    continue;
                }

                GameObject tilemapCopy = CloneTilemap(tilemapRenderer, tilemap);
                tilemapCopy.transform.parent = viewGridPrefab.transform;
            }

            PrefabUtility.SaveAsPrefabAsset(simGridPrefab, simAssetPath);
            simGridPrefab.DestroyImmediate();

            PrefabUtility.SaveAsPrefabAsset(viewGridPrefab, viewAssetPath);
            viewGridPrefab.DestroyImmediate();
        }

        // Bind assets
        {
            GameObject simPrefab  = AssetDatabase.LoadAssetAtPath <GameObject>(simAssetPath);
            GameObject viewPrefab = AssetDatabase.LoadAssetAtPath <GameObject>(viewAssetPath);
            simPrefab.GetComponent <SimAsset>().Editor_SetBindedViewPrefab(viewPrefab);
            EditorUtility.SetDirty(simPrefab);

            sceneGrid.GetComponent <LevelGridAuth>().PrefabSimAsset = simPrefab.GetComponent <SimAsset>();
            PrefabUtility.RecordPrefabInstancePropertyModifications(sceneGrid.GetComponent <LevelGridAuth>());
        }

        EditorSceneManager.MarkSceneDirty(sceneGrid.scene);
        AssetDatabase.SaveAssets();

        DebugEditor.LogAssetIntegrity($"Grid Assets Updated");
    }
    static void UpdateMetaData(LogMode logMode)
    {
        SceneMetaDataBank dataAsset = AssetDatabaseX.LoadOrCreateScriptableObjectAsset <SceneMetaDataBank>(ASSET_PATH);

        if (dataAsset == null)
        {
            Debug.LogWarning($"Could not update SceneMetaDataBank. None found at [{ASSET_PATH}]");
            return;
        }

        List <SceneMetaDataBank.SceneMetaData> oldData = dataAsset.SceneMetaDatasInternal;
        List <SceneMetaDataBank.SceneMetaData> newData = new List <SceneMetaDataBank.SceneMetaData>();

        int buildIndex = 0;

        foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes)
        {
            SceneMetaDataBank.SceneMetaData metaData = new SceneMetaDataBank.SceneMetaData();

            metaData.AssetGuid  = scene.guid.ToString();
            metaData.Path       = scene.path;
            metaData.Name       = Path.GetFileNameWithoutExtension(scene.path);
            metaData.BuildIndex = buildIndex;

            newData.Add(metaData);
            buildIndex++;
        }

        dataAsset.SceneMetaDatasInternal = newData;

        // fbessette this diff algo could be optimized
        if (logMode == LogMode.Full || logMode == LogMode.ChangesOnly)
        {
            if (oldData != null)
            {
                for (int i = 0; i < oldData.Count; i++)
                {
                    if (newData.FindIndex((x) => x.AssetGuid == oldData[i].AssetGuid) == -1)
                    {
                        DebugEditor.LogAssetIntegrity($"<color=red>Removed scene meta-data:</color> {oldData[i].Name}");
                    }
                }
                for (int i = 0; i < newData.Count; i++)
                {
                    int oldDataIndex = oldData.FindIndex((x) => x.AssetGuid == newData[i].AssetGuid);
                    if (oldDataIndex == -1)
                    {
                        DebugEditor.LogAssetIntegrity($"<color=green>Added scene meta-data:</color> {newData[i].Name}");
                    }
                    else if (oldData[oldDataIndex].ContentEquals(newData[i]) == false)
                    {
                        DebugEditor.LogAssetIntegrity($"<color=green>Updated scene meta-data:</color> {newData[i].Name}");
                    }
                }
            }
            else
            {
                for (int i = 0; i < newData.Count; i++)
                {
                    DebugEditor.LogAssetIntegrity($"<color=green>Added scene meta-data:</color> {newData[i].Name}");
                }
            }
        }

        if (logMode == LogMode.Full)
        {
            DebugEditor.LogAssetIntegrity("Scene meta-data bank updated");
        }

        EditorUtility.SetDirty(dataAsset);
        AssetDatabase.SaveAssets();
    }