Skip to content

Commit

Permalink
[ME] Shortcut to remove orphaned properties on the current outfit (#251)
Browse files Browse the repository at this point in the history
  • Loading branch information
RikkiBalboa authored May 1, 2024
1 parent 58b8b57 commit f29cc01
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 5 deletions.
113 changes: 110 additions & 3 deletions src/MaterialEditor.Core/Core.MaterialEditor.CharaController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ protected override void OnReload(GameMode currentGameMode, bool maintainState)
GameObjectToSet = null;
}
base.Update();
if (MaterialEditorPlugin.PurgeOrphanedPropertiesHotkey.Value.IsDown())
PurgeOrphanedProperties();
}

/// <summary>
Expand Down Expand Up @@ -2358,10 +2360,10 @@ private GameObject FindGameObject(ObjectType objectType, int slot)
/// <summary>
/// Purge unused textures from TextureDictionary
/// </summary>
protected void PurgeUnusedTextures()
protected int PurgeUnusedTextures()
{
if (TextureDictionary.Count <= 0)
return;
return 0;

HashSet<int> unuseds = new HashSet<int>(TextureDictionary.Keys);

Expand All @@ -2378,6 +2380,7 @@ protected void PurgeUnusedTextures()
TextureDictionary[texID].Dispose();
TextureDictionary.Remove(texID);
}
return unuseds.Count;
}

#if KK || KKS
Expand All @@ -2398,6 +2401,110 @@ internal void PurgeUnusedCoordinates()
}
#endif

internal void PurgeOrphanedProperties()
{
int removedCount = 0;

for (var i = 0; i < ChaControl.GetClothes().Length; i++)
removeProperties(ObjectType.Clothing, i, ChaControl.GetClothes()[i]);
for (var i = 0; i < ChaControl.GetAccessoryObjects().Length; i++)
removeProperties(ObjectType.Accessory, i, ChaControl.GetAccessoryObjects()[i]);
for (var i = 0; i < ChaControl.GetHair().Length; i++)
removeProperties(ObjectType.Hair, i, ChaControl.GetHair()[i]);
//The same is not done for the body because some properties are not exposed, while technically still there and used
//An example would be the face alpha mask not being exposed in koikatsu's v+ shaders, while still being applied if set in a shader that does expose it

void removeProperties(ObjectType objectType, int slot, GameObject go)
{
if (go == null) return;
var renderers = GetRendererList(go);
if (renderers == null) return;

var materialNames = renderers.SelectMany(x => x.materials).Select(x => x.NameFormatted()).ToList();
var projectors = GetProjectorList(objectType, go);
materialNames.AddRange(projectors.Select(x => x.material.NameFormatted()));

var materialPropertiesDict = renderers
.SelectMany(x => x.materials)
.GroupBy(x => x.NameFormatted())
.Select(x => x.First())
.ToDictionary(
x => x.NameFormatted(),
x => XMLShaderProperties[XMLShaderProperties.ContainsKey(x.shader.NameFormatted()) ? x.shader.NameFormatted() : "default"].Select(i => i.Key)
);

removedCount += ProjectorPropertyList.RemoveAll(
x => x.CoordinateIndex == CurrentCoordinateIndex
&& x.Slot == slot
&& x.ObjectType == objectType
&& !projectors.Select(projector => projector.NameFormatted()).Contains(x.ProjectorName)
);
removedCount += RendererPropertyList.RemoveAll(
x => x.CoordinateIndex == CurrentCoordinateIndex
&& x.Slot == slot
&& x.ObjectType == objectType
&& !renderers.Select(rend => rend.NameFormatted()).Contains(x.RendererName)
);
removedCount += MaterialFloatPropertyList.RemoveAll(
x => x.CoordinateIndex == CurrentCoordinateIndex
&& x.Slot == slot
&& x.ObjectType == objectType
&& (
!materialNames.Contains(x.MaterialName)
|| !materialPropertiesDict.ContainsKey(x.MaterialName)
|| !materialPropertiesDict[x.MaterialName].Contains(x.Property)
)
);
removedCount += MaterialColorPropertyList.RemoveAll(
x => x.CoordinateIndex == CurrentCoordinateIndex
&& x.Slot == slot
&& x.ObjectType == objectType
&& (
!materialNames.Contains(x.MaterialName)
|| !materialPropertiesDict.ContainsKey(x.MaterialName)
|| !materialPropertiesDict[x.MaterialName].Contains(x.Property)
)
);
removedCount += MaterialKeywordPropertyList.RemoveAll(
x => x.CoordinateIndex == CurrentCoordinateIndex
&& x.Slot == slot
&& x.ObjectType == objectType
&& (
!materialNames.Contains(x.MaterialName)
|| !materialPropertiesDict.ContainsKey(x.MaterialName)
|| !materialPropertiesDict[x.MaterialName].Contains(x.Property)
)
);
removedCount += MaterialTexturePropertyList.RemoveAll(
x => x.CoordinateIndex == CurrentCoordinateIndex
&& x.Slot == slot
&& x.ObjectType == objectType
&& (
!materialNames.Contains(x.MaterialName)
|| !materialPropertiesDict.ContainsKey(x.MaterialName)
|| !materialPropertiesDict[x.MaterialName].Contains(x.Property)
)
);
removedCount += MaterialShaderList.RemoveAll(
x => x.CoordinateIndex == CurrentCoordinateIndex
&& x.Slot == slot
&& x.ObjectType == objectType
&& !materialNames.Contains(x.MaterialName)
);
removedCount += MaterialCopyList.RemoveAll(
x => x.CoordinateIndex == CurrentCoordinateIndex
&& x.Slot == slot
&& x.ObjectType == objectType
&& !materialNames.Contains(x.MaterialName)
);
}
var purgedTextures = PurgeUnusedTextures();
if(purgedTextures == 0)
MaterialEditorPluginBase.Logger.LogMessage($"Removed {removedCount} orphaned propertie(s)");
else
MaterialEditorPluginBase.Logger.LogMessage($"Removed {removedCount} orphaned propertie(s) and {purgedTextures} orphaned texture(s)");
}

/// <summary>
/// Type of object, used for saving MaterialEditor data.
/// </summary>
Expand Down Expand Up @@ -2555,7 +2662,7 @@ public MaterialKeywordProperty(ObjectType objectType, int coordinateIndex, int s
ValueOriginal = valueOriginal;
}
}

/// <summary>
/// Data storage class for float properties
/// </summary>
Expand Down
6 changes: 4 additions & 2 deletions src/MaterialEditor.Core/Core.MaterialEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public partial class MaterialEditorPlugin : MaterialEditorAPI.MaterialEditorPlug
internal static ConfigEntry<KeyboardShortcut> EnableReceiveShadows { get; private set; }
internal static ConfigEntry<KeyboardShortcut> ResetReceiveShadows { get; private set; }
internal static ConfigEntry<KeyboardShortcut> PasteEditsHotkey { get; private set; }
internal static ConfigEntry<KeyboardShortcut> PurgeOrphanedPropertiesHotkey { get; private set; }

internal static ConfigEntry<bool> RendererCachingEnabled { get; private set; }

Expand Down Expand Up @@ -152,6 +153,7 @@ public override void Awake()
EnableReceiveShadows = Config.Bind("Keyboard Shortcuts", "Enable ReceiveShadows", new KeyboardShortcut(KeyCode.N, KeyCode.LeftAlt), "Enable ReceiveShadows for all selected items and their child items in Studio");
ResetReceiveShadows = Config.Bind("Keyboard Shortcuts", "Reset ReceiveShadows", new KeyboardShortcut(KeyCode.N, KeyCode.LeftControl, KeyCode.LeftAlt), "Reset ReceiveShadows for all selected items and their child items in Studio");
PasteEditsHotkey = Config.Bind("Keyboard Shortcuts", "Paste Edits", new KeyboardShortcut(KeyCode.N), "Paste any copied edits for all selected items and their child items in Studio");
PurgeOrphanedPropertiesHotkey = Config.Bind("Keyboard Shortcuts", "Purge Orphaned Properties", new KeyboardShortcut(KeyCode.R, KeyCode.LeftShift, KeyCode.LeftControl), "Remove any properties no longer associated with anything on the current outfit");
#if PH
//Disable ShaderOptimization since it doesn't work properly
ShaderOptimization.Value = false;
Expand Down Expand Up @@ -995,7 +997,7 @@ internal static void ConvertNormalMap(Material material, string propertyName)
}
#endif

protected override Texture ConvertNormalMap( Texture tex)
protected override Texture ConvertNormalMap(Texture tex)
{
var material = NormalMapConvertMaterial;
if (IsUncompressedNormalMap(tex))
Expand Down Expand Up @@ -1033,4 +1035,4 @@ public static void ClearCache(GameObject gameObject)
Hooks.ClearCache(gameObject);
}
}
}
}

0 comments on commit f29cc01

Please sign in to comment.