-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
383 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using UnityEngine; | ||
|
||
namespace SphereOpt; | ||
|
||
public class CustomShaderDesc | ||
{ | ||
public readonly string shortName; | ||
public readonly Shader shader; | ||
public readonly string shaderName; | ||
public readonly string replacementForShader; | ||
public readonly Dictionary<string, EShaderPropType> addedProperties; | ||
|
||
public CustomShaderDesc (string shortName, string shaderToReplace, string replacementShader, Dictionary<string, EShaderPropType> addedProps) | ||
{ | ||
shader = CustomShaderManager.GetShader(replacementShader); | ||
if (shader == null) SphereOpt.logger.LogError($"Could not find shader for name: {replacementShader}"); | ||
shaderName = replacementShader; | ||
replacementForShader = shaderToReplace; | ||
if (addedProps == null) addedProps = new Dictionary<string, EShaderPropType>(); | ||
addedProperties = addedProps; | ||
this.shortName = shortName; | ||
} | ||
|
||
public Type TypeOfAddedProperty(string propName) | ||
{ | ||
if (!addedProperties.TryGetValue(propName, out var ePropType)) | ||
{ | ||
SphereOpt.logger.LogWarning($"{shaderName} has no added property named {propName}."); | ||
return null; | ||
} | ||
|
||
return ePropType switch | ||
{ | ||
EShaderPropType.Buffer => typeof(ComputeBuffer), | ||
EShaderPropType.Color => typeof(Color), | ||
EShaderPropType.Float => typeof(float), | ||
EShaderPropType.Int => typeof(int), | ||
EShaderPropType.Matrix => typeof(Matrix4x4), | ||
EShaderPropType.Vector => typeof(Vector4), | ||
_ => throw new ArgumentOutOfRangeException() | ||
}; | ||
} | ||
} | ||
|
||
public enum EShaderPropType | ||
{ | ||
Buffer, | ||
Color, | ||
Float, | ||
Int, | ||
Matrix, | ||
Vector | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
using SphereOpt; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Reflection; | ||
using UnityEngine; | ||
|
||
namespace SphereOpt; | ||
|
||
public static class CustomShaderManager | ||
{ | ||
private static readonly string AssemblyPath = Path.GetDirectoryName(Assembly.GetAssembly(typeof(SphereOpt)).Location); | ||
private static AssetBundle bundle; | ||
private static readonly List<Shader> bundleShaders = new(); | ||
private static readonly List<CustomShaderDesc> customShaderDescs = new(); | ||
private static readonly Dictionary<string, CustomShaderDesc> shortNameMap = new(); | ||
private static readonly Dictionary<string, CustomShaderDesc> replacementForShaderMap = new(); | ||
private static readonly Dictionary<CustomShaderDesc, List<Material>> shaderReplacedOnMaterialsMap = new(); | ||
|
||
public static void InitWithBundle(string bundleFileName) | ||
{ | ||
if (bundleShaders.Count > 0) | ||
{ | ||
SphereOpt.logger.LogError($"CustomShaderManager is already initialized with bundle: {bundle.name}"); | ||
return; | ||
} | ||
var path = Path.Combine(AssemblyPath, bundleFileName); | ||
if (File.Exists(path)) | ||
{ | ||
bundle = AssetBundle.LoadFromFile(path); | ||
InitWithBundle(bundle); | ||
} | ||
else SphereOpt.logger.LogError($"Bundle file not found at: {path}"); | ||
} | ||
|
||
public static void InitWithBundle(AssetBundle assetBundle) | ||
{ | ||
if (bundleShaders.Count > 0) | ||
{ | ||
SphereOpt.logger.LogError($"CustomShaderManager is already initialized with bundle: {bundle.name}"); | ||
return; | ||
} | ||
bundle = assetBundle; | ||
if (!LoadShadersFromBundle()) | ||
{ | ||
SphereOpt.logger.LogError("Failed to load custom shaders from bundle."); | ||
return; | ||
} | ||
} | ||
|
||
private static bool LoadShadersFromBundle() | ||
{ | ||
SphereOpt.logger.LogInfo("Loading custom shaders from bundle."); | ||
if (bundle != null) | ||
{ | ||
var shaders = bundle.LoadAllAssets<Shader>(); | ||
foreach (var s in shaders) | ||
{ | ||
bundleShaders.Add(s); | ||
SphereOpt.logger.LogInfo($"Loaded custom shader: {s.name}"); | ||
} | ||
} | ||
else | ||
{ | ||
SphereOpt.logger.LogError("Failed to load custom shaders from bundle".Translate()); | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
public static void AddCustomShaderDesc(string shortName, string shaderToReplace, string replacementShader, | ||
Dictionary<string, EShaderPropType> addedProps = null) | ||
{ | ||
CustomShaderDesc shaderDesc = new(shortName, shaderToReplace, replacementShader, addedProps); | ||
customShaderDescs.Add(shaderDesc); | ||
replacementForShaderMap.Add(shaderDesc.replacementForShader, shaderDesc); | ||
shortNameMap.Add(shaderDesc.shortName, shaderDesc); | ||
|
||
} | ||
|
||
public static CustomShaderDesc LookupReplacementShaderFor(string originalShaderName) | ||
{ | ||
return replacementForShaderMap.TryGetValue(originalShaderName, out CustomShaderDesc customShader) ? customShader : null; | ||
} | ||
|
||
public static bool ReplaceShaderIfAvailable(Material mat) | ||
{ | ||
if (replacementForShaderMap.TryGetValue(mat.shader.name, out CustomShaderDesc customShaderDesc)) | ||
{ | ||
SphereOpt.logger.LogInfo($"replacing shader on: {mat.name}"); | ||
ApplyCustomShaderToMaterial(mat, customShaderDesc); | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
public static Shader GetShader (string customShaderName) | ||
{ | ||
foreach (var shader in bundleShaders) | ||
{ | ||
if (shader.name.Equals(customShaderName)) return shader; | ||
} | ||
SphereOpt.logger.LogWarning($"Couldn't find custom shader with name: {customShaderName}"); | ||
return null; | ||
} | ||
|
||
public static CustomShaderDesc GetCustomShaderDescByShortName(string shortName) | ||
{ | ||
if (!shortNameMap.TryGetValue(shortName, out CustomShaderDesc csd)) | ||
{ | ||
SphereOpt.logger.LogError($"CustomShaderDesc with ShortName: {shortName} not found"); | ||
return null; | ||
} | ||
|
||
return csd; | ||
} | ||
|
||
public static void ApplyCustomShaderToMaterial(Material mat, CustomShaderDesc replacementShader) | ||
{ | ||
mat.shader = replacementShader.shader; | ||
|
||
if(!shaderReplacedOnMaterialsMap.TryGetValue(replacementShader, out var matList)) | ||
{ | ||
matList = new List<Material>(); | ||
shaderReplacedOnMaterialsMap.Add(replacementShader, matList); | ||
} | ||
|
||
matList.Add(mat); | ||
} | ||
|
||
public static void SetPropByShortName(string propName, float propVal, string shortName) | ||
{ | ||
CustomShaderDesc csd = GetCustomShaderDescByShortName(shortName); | ||
if (csd == null) | ||
{ | ||
SphereOpt.logger.LogError($"No CustomShaderDesc found with shortName: {shortName}"); | ||
return; | ||
} | ||
|
||
var propType = csd.TypeOfAddedProperty(propName); | ||
if (propType == null) | ||
{ | ||
SphereOpt.logger.LogError($"CustomShaderDesc has no AddedProperty named: {propName}"); | ||
return; | ||
|
||
} | ||
|
||
if (propType != typeof(float)) | ||
{ | ||
SphereOpt.logger.LogError($"Property {propName} is of type {csd.TypeOfAddedProperty(propName)} but value provided is float"); | ||
} | ||
|
||
foreach (var mat in shaderReplacedOnMaterialsMap[csd]) | ||
{ | ||
mat.SetFloat(propName, propVal); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<configuration> | ||
<packageSources> | ||
<add key="BepInEx" value="https://nuget.bepinex.dev/v3/index.json" /> | ||
</packageSources> | ||
</configuration> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
using System.ComponentModel; | ||
using HarmonyLib; | ||
using UnityEngine; | ||
|
||
namespace SphereOpt; | ||
|
||
internal class Patch_VFPreload | ||
{ | ||
[HarmonyPatch(typeof(VFPreload), "SaveMaterial")] | ||
[HarmonyPrefix] | ||
static bool VFPreload_SaveMaterial(Material mat) | ||
{ | ||
if (mat == null) | ||
{ | ||
return false; | ||
} | ||
|
||
CustomShaderManager.ReplaceShaderIfAvailable(mat); | ||
|
||
return true; | ||
} | ||
|
||
[HarmonyPatch(typeof(VFPreload), "SaveMaterials", typeof(Material[]))] | ||
[HarmonyPrefix] | ||
static bool VFPreload_SaveMaterials(Material[] mats) | ||
{ | ||
if (mats == null) | ||
{ | ||
return false; | ||
} | ||
|
||
foreach (Material mat in mats) | ||
{ | ||
if (mat == null) continue; | ||
CustomShaderManager.ReplaceShaderIfAvailable(mat); | ||
} | ||
return true; | ||
} | ||
|
||
[HarmonyPatch(typeof(VFPreload), "SaveMaterials", typeof(Material[][]))] | ||
[HarmonyPrefix] | ||
static bool VFPreload_SaveMaterials(Material[][] mats) | ||
{ | ||
if (mats == null) | ||
{ | ||
return false; | ||
} | ||
|
||
foreach (Material[] matarray in mats) | ||
{ | ||
if(matarray == null) continue; | ||
foreach (var mat in matarray) | ||
{ | ||
if(mat == null) continue; | ||
CustomShaderManager.ReplaceShaderIfAvailable(mat); | ||
} | ||
} | ||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using BepInEx; | ||
using BepInEx.Logging; | ||
using HarmonyLib; | ||
using System.IO; | ||
using System.Reflection; | ||
using UnityEngine; | ||
|
||
namespace SphereOpt; | ||
|
||
[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)] | ||
public class SphereOpt : BaseUnityPlugin | ||
{ | ||
public static ManualLogSource logger; | ||
private static AssetBundle bundle; | ||
private static readonly string AssemblyPath = Path.GetDirectoryName(Assembly.GetAssembly(typeof(SphereOpt)).Location); | ||
|
||
public static AssetBundle Bundle | ||
{ | ||
get | ||
{ | ||
if (bundle == null) | ||
{ | ||
var path = Path.Combine(AssemblyPath, "sphereopt-bundle"); | ||
if (File.Exists(path)) | ||
{ | ||
bundle = AssetBundle.LoadFromFile(path); | ||
} | ||
else | ||
{ | ||
logger.LogError("Failed to load AssetBundle!".Translate()); | ||
return null; | ||
} | ||
} | ||
return bundle; | ||
} | ||
} | ||
private void Awake() | ||
{ | ||
// Plugin startup logic | ||
logger = Logger; | ||
logger.LogInfo($"Plugin {PluginInfo.PLUGIN_GUID} is loaded!"); | ||
|
||
CustomShaderManager.InitWithBundle(Bundle); | ||
|
||
CustomShaderManager.AddCustomShaderDesc( | ||
"dysonshell", | ||
"VF Shaders/Dyson Sphere/Dyson Shell Unlit", | ||
"VF Shaders/Dyson Sphere/Dyson Shell Unlit REPLACE" | ||
); | ||
|
||
Harmony.CreateAndPatchAll(typeof(Patch_VFPreload)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net472</TargetFramework> | ||
<AssemblyName>SphereOpt</AssemblyName> | ||
<Description>Optimize Dyson Sphere rendering</Description> | ||
<Version>1.0.0</Version> | ||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||
<LangVersion>latest</LangVersion> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="BepInEx.Analyzers" Version="1.0.8" PrivateAssets="all"> | ||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||
</PackageReference> | ||
<PackageReference Include="BepInEx.Core" Version="5.*" /> | ||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" /> | ||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="0.9.27.15466-r.0" /> | ||
<PackageReference Include="UnityEngine.Modules" Version="2018.4.12" IncludeAssets="compile" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'"> | ||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.2" PrivateAssets="all" /> | ||
</ItemGroup> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 17 | ||
VisualStudioVersion = 17.4.33213.308 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SphereOpt", "SphereOpt.csproj", "{B0CB2BF6-B5FE-462C-A292-21F36273DABC}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{B0CB2BF6-B5FE-462C-A292-21F36273DABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{B0CB2BF6-B5FE-462C-A292-21F36273DABC}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{B0CB2BF6-B5FE-462C-A292-21F36273DABC}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{B0CB2BF6-B5FE-462C-A292-21F36273DABC}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {35DD321B-1781-4795-AD13-9E16A55CAAD9} | ||
EndGlobalSection | ||
EndGlobal |