diff --git a/Winch/Core/AssetLoader.cs b/Winch/Core/AssetLoader.cs index 207e4103..498f41d2 100644 --- a/Winch/Core/AssetLoader.cs +++ b/Winch/Core/AssetLoader.cs @@ -40,6 +40,7 @@ internal static void LoadAssets() private static void LoadAssetFolder(string path) { + string bundlesFolderpath = Path.Combine(path, "Bundles"); string localizationFolderPath = Path.Combine(path, "Localization"); string textureFolderPath = Path.Combine(path, "Textures"); string gridConfigFolderpath = Path.Combine(path, "GridConfigs"); @@ -51,6 +52,7 @@ private static void LoadAssetFolder(string path) string dialogueFolderpath = Path.Combine(path, "Dialogues"); string characterFolderpath = Path.Combine(path, "Characters"); + if(Directory.Exists(bundlesFolderpath)) LoadAssetBundleFiles(bundlesFolderpath); if(Directory.Exists(localizationFolderPath)) LoadLocalizationFiles(localizationFolderPath); if(Directory.Exists(textureFolderPath)) LoadTextureFiles(textureFolderPath); if(Directory.Exists(gridConfigFolderpath)) LoadGridConfigFiles(gridConfigFolderpath); @@ -63,6 +65,23 @@ private static void LoadAssetFolder(string path) if(Directory.Exists(characterFolderpath)) LoadCharacterFiles(characterFolderpath); } + private static void LoadAssetBundleFiles(string bundlesFolderpath) + { + string[] bundleFiles = Directory.GetFiles(bundlesFolderpath); + foreach (string file in bundleFiles) + { + try + { + if (file.EndsWith("manifest")) continue; + AssetBundleUtil.LoadBundle(file); + } + catch (Exception ex) + { + WinchCore.Log.Error($"Failed to load asset bundle from {file}: {ex}"); + } + } + } + private static Dictionary _poiPathData = new Dictionary() { { typeof(CustomHarvestPOI), "Harvest"}, diff --git a/Winch/Util/AssetBundleUtil.cs b/Winch/Util/AssetBundleUtil.cs new file mode 100644 index 00000000..554f3d68 --- /dev/null +++ b/Winch/Util/AssetBundleUtil.cs @@ -0,0 +1,126 @@ +using InControl; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using Winch.Core; +using static Mono.Security.X509.X520; + +namespace Winch.Util +{ + public static class AssetBundleUtil + { + public static Dictionary AssetBundles = new(); + + private static Dictionary cachedShaders = new Dictionary(); + + internal static Shader CacheShader(this Shader shader) + { + if (!cachedShaders.ContainsKey(shader.name)) cachedShaders.Add(shader.name, shader.DontDestroyOnLoad()); + + return shader; + } + + public static Shader GetReplacementShader(string name) + { + Shader replacementShader; + if (cachedShaders.TryGetValue(name, out replacementShader)) return replacementShader; + + replacementShader = Resources.FindObjectsOfTypeAll().Reverse().FirstOrDefault(shader => shader.name == name);// Shader.Find(name); + if (replacementShader != null) + return replacementShader.CacheShader(); + + return null; + } + + public static AssetBundle? GetBundle(string assetBundleName) + { + if (AssetBundles.TryGetValue(assetBundleName, out AssetBundle bundle)) + return bundle; + return null; + } + + public static AssetBundle? LoadBundle(string assetBundlePath) + { + string key = Path.GetFileName(assetBundlePath); + AssetBundle bundle; + + try + { + + if (AssetBundles.ContainsKey(key)) + { + bundle = AssetBundles[key]; + } + else + { + bundle = AssetBundle.LoadFromFile(assetBundlePath); + if (bundle == null) + { + WinchCore.Log.Error($"Couldn't load asset bundle at [{assetBundlePath}]"); + return null; + } + + AssetBundles[key] = bundle; + } + return bundle; + } + catch (Exception e) + { + WinchCore.Log.Error($"Couldn't load asset bundle at [{assetBundlePath}]:\n{e}"); + return null; + } + } + + /// + /// Replaces shaders on all of the asset bundle's prefabs with one's from the game (if they are available) + /// + /// The bundle to get the prefabs from and replace their shaders + public static void ReplaceShaders(this AssetBundle bundle) + { + foreach (GameObject prefab in bundle.LoadAllAssets()) + { + if (prefab != null) + { + prefab.ReplaceShaders(); + } + } + } + + /// + /// Replaces shaders on an asset bundle prefab with one's from the game (if they are available) + /// + /// The prefab to replace the shaders of + public static void ReplaceShaders(this GameObject prefab) + { + foreach (var renderer in prefab.GetComponentsInChildren(true)) + { + foreach (var material in renderer.sharedMaterials) + { + if (material == null) continue; + + var replacementShader = GetReplacementShader(material.shader.name); + if (replacementShader == null) continue; + + // preserve override tag and render queue (for Standard shader) + // keywords and properties are already preserved + if (material.renderQueue != material.shader.renderQueue) + { + var renderType = material.GetTag("RenderType", false); + var renderQueue = material.renderQueue; + material.shader = replacementShader; + material.SetOverrideTag("RenderType", renderType); + material.renderQueue = renderQueue; + } + else + { + material.shader = replacementShader; + } + } + } + } + } +} \ No newline at end of file