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()); }
/// <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); }