private IEnumerable <AssetMetadata> MakeMaterialWriteSafe(
            Guid Id,
            UnityEngine.Material mat,
            UnityEngine.Material copyMat,
            AssetMetadata?dependency,
            AssetMetadata?updatedDependency)
        {
            // update material's texture reference to the new copy
            if (dependency != null && updatedDependency != null)
            {
                var matDef      = MREAPI.AppsAPI.MaterialPatcher.GeneratePatch(App, mat);
                var updatePatch = new Material();
                if (matDef.MainTextureId == dependency.Value.Id)
                {
                    updatePatch.MainTextureId = dependency.Value.Id;
                }
                if (matDef.EmissiveTextureId == dependency.Value.Id)
                {
                    updatePatch.EmissiveTextureId = dependency.Value.Id;
                }
                MREAPI.AppsAPI.MaterialPatcher.ApplyMaterialPatch(App, copyMat, updatePatch);
            }

            // update actors that use this material
            AssetReferenceChanged?.Invoke(Id);

            // identify prefabs that reference this material
            return(Assets.Values.Where(a =>
            {
                if (a.Asset is GameObject prefab)
                {
                    var renderers = prefab.GetComponentsInChildren <Renderer>();

                    // if prefab is already write-safe, just update
                    if (a.Source == null)
                    {
                        foreach (var r in renderers)
                        {
                            var sharedMats = r.sharedMaterials;
                            for (int i = 0; i < sharedMats.Length; i++)
                            {
                                if (sharedMats[i] == mat)
                                {
                                    sharedMats[i] = copyMat;
                                    r.sharedMaterials = sharedMats;
                                    break;
                                }
                            }
                        }
                        return false;
                    }
                    // gotta make the prefab write-safe
                    else
                    {
                        return renderers.Any(r => r.sharedMaterials.Any(m => m == mat));
                    }
                }
                else
                {
                    return false;
                }
            }).ToArray());
        }
Beispiel #2
0
        /// <summary>
        /// Recursively copy shared assets from cache into manager so the app can modify them.
        /// </summary>
        /// <param name="metadata"></param>
        private void MakeWriteSafe(AssetMetadata metadata, AssetMetadata?dependency = null, AssetMetadata?updatedDependency = null)
        {
            if (metadata.Source == null)
            {
                return;
            }

            // copy asset
            var    originalAsset = metadata.Asset;
            Object copyAsset;

            if (originalAsset is UnityEngine.Texture2D tex2d)
            {
                // can't Instantiate GPU-only textures
                var copyTex = new Texture2D(tex2d.width, tex2d.height, tex2d.format, tex2d.mipmapCount > 1);
                Graphics.CopyTexture(tex2d, copyTex);
                copyAsset = copyTex;
            }
            else
            {
                copyAsset = Object.Instantiate(originalAsset);
            }

            var copyMetadata = new AssetMetadata(
                metadata.Id,
                metadata.ContainerId,
                asset: copyAsset,
                metadata.ColliderGeometry,
                source: null);

            Assets[metadata.Id] = copyMetadata;

            IEnumerable <AssetMetadata> dependents;

            if (originalAsset is UnityEngine.Texture tex)
            {
                // identify materials that use this texture
                dependents = Assets.Values.Where(a =>
                {
                    if (a.Asset is UnityEngine.Material mat)
                    {
                        return(MREAPI.AppsAPI.MaterialPatcher.UsesTexture(App, mat, tex));
                    }
                    else
                    {
                        return(false);
                    }
                }).ToArray();
            }
            else if (originalAsset is UnityEngine.Material mat)
            {
                // update material's texture reference to the new copy
                if (dependency != null && updatedDependency != null)
                {
                    var matDef      = MREAPI.AppsAPI.MaterialPatcher.GeneratePatch(App, mat);
                    var updatePatch = new Material();
                    if (matDef.MainTextureId == dependency.Value.Id)
                    {
                        updatePatch.MainTextureId = dependency.Value.Id;
                    }
                    if (matDef.EmissiveTextureId == dependency.Value.Id)
                    {
                        updatePatch.EmissiveTextureId = dependency.Value.Id;
                    }
                    MREAPI.AppsAPI.MaterialPatcher.ApplyMaterialPatch(App, (UnityEngine.Material)copyAsset, updatePatch);
                }

                // update actors that use this material
                AssetReferenceChanged?.Invoke(metadata.Id);

                // identify prefabs that reference this material
                dependents = Assets.Values.Where(a =>
                {
                    if (a.Asset is GameObject prefab)
                    {
                        var renderers = prefab.GetComponentsInChildren <Renderer>();
                        return(renderers.Any(r => r.sharedMaterial == mat));
                    }
                    else
                    {
                        return(false);
                    }
                }).ToArray();
            }
            else if (copyAsset is GameObject prefab)
            {
                // copy prefab into local cache
                prefab.transform.SetParent(CacheRootGO().transform, false);

                // update materials
                if (dependency != null && updatedDependency != null)
                {
                    var renderers = prefab.GetComponentsInChildren <Renderer>();
                    foreach (var r in renderers)
                    {
                        if (r.sharedMaterial == (UnityEngine.Material)dependency.Value.Asset)
                        {
                            r.sharedMaterial = (UnityEngine.Material)updatedDependency.Value.Asset;
                        }
                    }
                }

                dependents = new AssetMetadata[0];
            }
            else
            {
                dependents = new AssetMetadata[0];
            }

            // update dependents
            foreach (var dependent in dependents)
            {
                MakeWriteSafe(dependent, metadata, copyMetadata);
            }

            // return original assets to cache
            MREAPI.AppsAPI.AssetCache.StoreAssets(metadata.Source.ParsedUri, new Object[] { originalAsset }, metadata.Source.Version);
        }