Skip to content

Commit

Permalink
Add project files.
Browse files Browse the repository at this point in the history
  • Loading branch information
andyoneal committed Mar 4, 2023
1 parent 9ba3d6d commit 0dda1b0
Show file tree
Hide file tree
Showing 7 changed files with 383 additions and 0 deletions.
55 changes: 55 additions & 0 deletions CustomShaderDesc.cs
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
}
159 changes: 159 additions & 0 deletions CustomShaderManager.cs
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);
}
}
}
6 changes: 6 additions & 0 deletions NuGet.Config
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>
60 changes: 60 additions & 0 deletions Patch_VFPreload.cs
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;
}
}
53 changes: 53 additions & 0 deletions SphereOpt.cs
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));
}
}
25 changes: 25 additions & 0 deletions SphereOpt.csproj
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>
25 changes: 25 additions & 0 deletions SphereOpt.sln
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

0 comments on commit 0dda1b0

Please sign in to comment.