using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("EnemySkinManager")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("A mod library for R.E.P.O. to manage enemy skin variations.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("EnemySkinManager")]
[assembly: AssemblyTitle("EnemySkinManager")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace EnemySkinManager
{
public class SkinData
{
public string Identifier { get; set; }
public Material[] Materials { get; set; }
public Mesh SharedMesh { get; set; }
public Dictionary<string, Texture2D> TextureOverrides { get; set; }
public bool OverrideProtectedParts { get; set; } = false;
public SkinData(string id, Material[] materials = null, Mesh mesh = null, Dictionary<string, Texture2D> textures = null, bool overrideProtectedParts = false)
{
Identifier = id;
Materials = (Material[])(((object)materials) ?? ((object)new Material[0]));
SharedMesh = mesh;
TextureOverrides = textures ?? new Dictionary<string, Texture2D>();
OverrideProtectedParts = overrideProtectedParts;
}
}
public static class EnemySkinManager
{
internal static ManualLogSource Log;
internal static ConfigEntry<bool> MasterEnableConfig;
private static ConfigFile AppConfig;
public const string VanillaSkinIdentifier = "Vanilla";
internal static readonly Dictionary<string, List<SkinData>> RegisteredSkins = new Dictionary<string, List<SkinData>>();
private static readonly Dictionary<string, Dictionary<string, ConfigEntry<int>>> enemySkinWeightsConfigs = new Dictionary<string, Dictionary<string, ConfigEntry<int>>>();
public static Func<string, string, bool> IsSkinEnabledCheck = (string enemyId, string skinId) => true;
internal static void Initialize(ManualLogSource log, ConfigEntry<bool> masterEnableConfig, ConfigFile config)
{
Log = log;
MasterEnableConfig = masterEnableConfig;
AppConfig = config;
Log.LogInfo((object)"EnemySkinManager Initialized. Skins will be configured with weights per enemy.");
}
public static void RegisterSkin(string enemyId, SkinData newSkin, string? friendlyCategoryName = null)
{
//IL_02af: Unknown result type (might be due to invalid IL or missing references)
//IL_02b9: Expected O, but got Unknown
//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
//IL_01d6: Expected O, but got Unknown
if (string.IsNullOrEmpty(enemyId) || newSkin == null || string.IsNullOrEmpty(newSkin.Identifier))
{
Log.LogError((object)"Invalid parameters for RegisterSkin.");
return;
}
if (!RegisteredSkins.ContainsKey(enemyId))
{
RegisteredSkins[enemyId] = new List<SkinData>();
}
if (!RegisteredSkins[enemyId].Any((SkinData s) => s.Identifier == newSkin.Identifier))
{
RegisteredSkins[enemyId].Add(newSkin);
Log.LogInfo((object)("Registered skin '" + newSkin.Identifier + "' for enemy '" + enemyId + "'."));
}
string text = (string.IsNullOrEmpty(friendlyCategoryName) ? enemyId : friendlyCategoryName);
string text2 = text + " Skins";
if (!enemySkinWeightsConfigs.ContainsKey(enemyId))
{
Log.LogInfo((object)("Creating new weight configuration section for enemy: " + enemyId + " (displaying as '" + text2 + "')"));
enemySkinWeightsConfigs.Add(enemyId, new Dictionary<string, ConfigEntry<int>>());
if (!enemySkinWeightsConfigs[enemyId].ContainsKey("Vanilla"))
{
Log.LogInfo((object)("Creating weight config for 'Vanilla' skin in section '" + text2 + "'"));
ConfigEntry<int> value = AppConfig.Bind<int>(text2, "Vanilla", 10, new ConfigDescription("Spawn weight for 'Vanilla' (original game skin) on " + text + ". 0 = disabled. Higher values increase spawn chance relative to other enabled skins.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
enemySkinWeightsConfigs[enemyId].Add("Vanilla", value);
}
}
if (!enemySkinWeightsConfigs[enemyId].ContainsKey(newSkin.Identifier))
{
Log.LogInfo((object)("Creating weight config for skin '" + newSkin.Identifier + "' in section '" + text2 + "'"));
ConfigEntry<int> value2 = AppConfig.Bind<int>(text2, newSkin.Identifier, 10, new ConfigDescription("Spawn weight for '" + newSkin.Identifier + "' on " + text + ". 0 = disabled. Higher values increase spawn chance relative to other enabled skins.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
enemySkinWeightsConfigs[enemyId].Add(newSkin.Identifier, value2);
}
}
public static SkinData GetRandomSkinForEnemy(string enemyId)
{
if (MasterEnableConfig != null && !MasterEnableConfig.Value)
{
return null;
}
if (!enemySkinWeightsConfigs.TryGetValue(enemyId, out var value))
{
Log.LogWarning((object)("No weight configuration section found for enemy '" + enemyId + "'. Skins may be registered, but weights are missing. Using vanilla."));
return null;
}
RegisteredSkins.TryGetValue(enemyId, out var value2);
value2 = value2 ?? new List<SkinData>();
List<KeyValuePair<SkinData, int>> list = new List<KeyValuePair<SkinData, int>>();
int num = 0;
if (value.TryGetValue("Vanilla", out var value3) && value3.Value > 0)
{
list.Add(new KeyValuePair<SkinData, int>(null, value3.Value));
num += value3.Value;
}
foreach (SkinData item in value2)
{
if (value.TryGetValue(item.Identifier, out var value4) && value4.Value > 0)
{
list.Add(new KeyValuePair<SkinData, int>(item, value4.Value));
num += value4.Value;
}
}
if (list.Count == 0 || num == 0)
{
return null;
}
int num2 = Random.Range(0, num);
foreach (KeyValuePair<SkinData, int> item2 in list)
{
if (num2 < item2.Value)
{
return item2.Key;
}
num2 -= item2.Value;
}
if (list.Any((KeyValuePair<SkinData, int> opt) => opt.Key == null && opt.Value > 0))
{
return null;
}
return list.FirstOrDefault((KeyValuePair<SkinData, int> opt) => opt.Key != null).Key;
}
public static void ApplySkin(GameObject enemyInstance, SkinData skinData)
{
if ((Object)(object)enemyInstance == (Object)null || skinData == null)
{
Log.LogWarning((object)"ApplySkin called with null enemyInstance or skinData.");
return;
}
Renderer componentInChildren = enemyInstance.GetComponentInChildren<Renderer>();
if ((Object)(object)componentInChildren == (Object)null)
{
Log.LogWarning((object)("Could not find a Renderer component on '" + ((Object)enemyInstance).name + "' or its children to apply skin '" + (skinData.Identifier ?? "Unnamed") + "'."));
return;
}
if (skinData.Materials != null && skinData.Materials.Length != 0)
{
if (componentInChildren.sharedMaterials.Length != skinData.Materials.Length)
{
Log.LogWarning((object)("Skin '" + skinData.Identifier + "' for " + ((Object)enemyInstance).name + ": " + $"Provided material count ({skinData.Materials.Length}) " + $"differs from renderer's material slot count ({componentInChildren.sharedMaterials.Length}). " + "Applying materials anyway. This might lead to an incomplete or unexpected appearance if counts don't effectively match."));
}
componentInChildren.sharedMaterials = skinData.Materials;
if (Plugin.EnableDebugLogging.Value)
{
Log.LogDebug((object)$"Applied {skinData.Materials.Length} material(s) from skin '{skinData.Identifier}' to {((Object)enemyInstance).name}.");
}
}
else if (Plugin.EnableDebugLogging.Value)
{
Log.LogDebug((object)("Skin '" + (skinData.Identifier ?? "Unnamed") + "' has no materials defined."));
}
if (skinData.TextureOverrides != null && skinData.TextureOverrides.Count > 0)
{
foreach (KeyValuePair<string, Texture2D> textureOverride in skinData.TextureOverrides)
{
Material[] sharedMaterials = componentInChildren.sharedMaterials;
foreach (Material val in sharedMaterials)
{
if (val.HasProperty(textureOverride.Key))
{
val.SetTexture(textureOverride.Key, (Texture)(object)textureOverride.Value);
if (Plugin.EnableDebugLogging.Value)
{
Log.LogDebug((object)("Applied texture override '" + textureOverride.Key + "' to material '" + ((Object)val).name + "' on '" + ((Object)componentInChildren).name + "'."));
}
}
}
}
}
else if (Plugin.EnableDebugLogging.Value)
{
Log.LogDebug((object)("Skin '" + (skinData.Identifier ?? "Unnamed") + "' has no texture overrides defined."));
}
if ((Object)(object)skinData.SharedMesh != (Object)null)
{
MeshFilter component = ((Component)componentInChildren).GetComponent<MeshFilter>();
SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((componentInChildren is SkinnedMeshRenderer) ? componentInChildren : null);
if ((Object)(object)component != (Object)null)
{
component.sharedMesh = skinData.SharedMesh;
if (Plugin.EnableDebugLogging.Value)
{
Log.LogDebug((object)("Applied shared mesh '" + ((Object)skinData.SharedMesh).name + "' to MeshFilter on '" + ((Object)componentInChildren).name + "'."));
}
}
else if ((Object)(object)val2 != (Object)null)
{
val2.sharedMesh = skinData.SharedMesh;
if (Plugin.EnableDebugLogging.Value)
{
Log.LogDebug((object)("Applied shared mesh '" + ((Object)skinData.SharedMesh).name + "' to SkinnedMeshRenderer on '" + ((Object)componentInChildren).name + "'."));
}
}
else
{
Log.LogWarning((object)("Could not apply mesh '" + ((Object)skinData.SharedMesh).name + "'. No MeshFilter or SkinnedMeshRenderer found on '" + ((Object)componentInChildren).name + "'."));
}
}
Log.LogInfo((object)("Successfully applied skin '" + (skinData.Identifier ?? "Unnamed") + "' to '" + ((Object)enemyInstance).name + "'."));
}
}
[BepInPlugin("JustSomeDevGuy.EnemySkinManager.Alpha", "EnemySkinManager (ALPHA)", "0.1.0")]
public class Plugin : BaseUnityPlugin
{
private Harmony harmony;
private static ConfigEntry<bool> MasterEnableToggle;
internal static ManualLogSource Log { get; private set; }
public static ConfigEntry<bool> EnableDebugLogging { get; private set; }
private void Awake()
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
harmony = new Harmony("JustSomeDevGuy.EnemySkinManager.Alpha");
MasterEnableToggle = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Master Enable", true, "Globally enable or disable all custom skins from this manager.");
EnableDebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable Detailed Logging", false, "Enable detailed debug messages in the log, useful for troubleshooting skin application.");
EnemySkinManager.Initialize(Log, MasterEnableToggle, ((BaseUnityPlugin)this).Config);
harmony.PatchAll();
Log.LogInfo((object)"Registering default 'Vanilla' skins...");
string[] array = new string[19]
{
"Duck", "Animal", "Banger", "Bowtie", "Chef", "Clown", "Gnome", "Headman", "Hidden", "Huntsman",
"Peeper", "Mentalist", "Reaper", "Robe", "Rugrat", "Shadow Child", "Spewer", "Trudge", "Upscream"
};
string[] array2 = array;
foreach (string enemyId in array2)
{
EnemySkinManager.RegisterSkin(enemyId, new SkinData("Vanilla"));
}
Log.LogInfo((object)"Finished registering default 'Vanilla' skins.");
Log.LogInfo((object)"Plugin JustSomeDevGuy.EnemySkinManager.Alpha patched methods.");
Log.LogInfo((object)"Plugin JustSomeDevGuy.EnemySkinManager.Alpha is loaded!");
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "JustSomeDevGuy.EnemySkinManager.Alpha";
public const string PLUGIN_NAME = "EnemySkinManager (ALPHA)";
public const string PLUGIN_VERSION = "0.1.0";
}
}
namespace EnemySkinManager.Patches
{
[HarmonyPatch]
internal class EnemySpawnPatches
{
private const string LOG_PREFIX = "[EnemySkinMod] ";
private static ManualLogSource Log => Plugin.Log;
[HarmonyPatch(typeof(EnemyParent), "Spawn")]
[HarmonyPostfix]
private static void EnemyParent_Spawn_Postfix(EnemyParent __instance)
{
Plugin.Log.LogInfo((object)string.Format("{0}--- EnemyParent_Spawn_Postfix executing for instance {1} (Name: {2}) ---", "[EnemySkinMod] ", ((Object)__instance).GetInstanceID(), ((Object)((Component)__instance).gameObject).name));
if (!EnemySkinManager.MasterEnableConfig.Value)
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)"EnemySkinManager is disabled via config. Skipping skin application.");
}
return;
}
string name = ((Object)((Component)__instance).gameObject).name;
string text = name.Replace("(Clone)", "").Trim();
string text2 = text;
if (text.StartsWith("Enemy - "))
{
text2 = text.Substring("Enemy - ".Length).Trim();
}
if (string.IsNullOrEmpty(text2))
{
Plugin.Log.LogWarning((object)("Could not get valid Enemy ID from GameObject name: '" + name + "'. Cannot apply skin."));
return;
}
Plugin.Log.LogInfo((object)("Enemy ID derived from GameObject name: '" + text2 + "' (Original: '" + name + "')"));
if (!EnemySkinManager.RegisteredSkins.ContainsKey(text2) || EnemySkinManager.RegisteredSkins[text2].Count == 0)
{
Plugin.Log.LogInfo((object)("No skins registered for enemy ID '" + text2 + "'. Skipping."));
return;
}
Plugin.Log.LogInfo((object)("Getting random skin for enemy '" + text2 + "'..."));
SkinData randomSkinForEnemy = EnemySkinManager.GetRandomSkinForEnemy(text2);
if (randomSkinForEnemy == null || randomSkinForEnemy.Identifier == null)
{
Plugin.Log.LogInfo((object)("GetRandomSkinForEnemy returned no specific skin (maybe all disabled or only 'Vanilla' exists and was chosen). Enemy ID: '" + text2 + "'. No custom skin applied."));
return;
}
Plugin.Log.LogInfo((object)("Selected skin '" + randomSkinForEnemy.Identifier + "' for enemy '" + text2 + "'. Applying..."));
GameObject gameObject = ((Component)__instance).gameObject;
if ((Object)(object)gameObject == (Object)null)
{
Plugin.Log.LogError((object)"EnemyParent_Spawn_Postfix triggered on a null instance or GameObject.");
}
else
{
ApplySkinLogic(gameObject, randomSkinForEnemy);
}
}
private static bool IsSkinEnabledCheck(string enemyId, string skinId)
{
return EnemySkinManager.IsSkinEnabledCheck(enemyId, skinId);
}
private static void ApplySkinLogic(GameObject enemyInstance, SkinData skinData)
{
if ((Object)(object)enemyInstance == (Object)null || skinData.Identifier == null)
{
Plugin.Log.LogError((object)"ApplySkinLogic: Received null enemyInstance or skinData.Identifier.");
return;
}
if (skinData.TextureOverrides != null && skinData.TextureOverrides.Count > 0)
{
Plugin.Log.LogInfo((object)string.Format("{0}ApplySkinLogic: Attempting to apply {1} texture overrides using INSTANCED materials.", "[EnemySkinMod] ", skinData.TextureOverrides.Count));
bool flag = false;
Renderer[] componentsInChildren = enemyInstance.GetComponentsInChildren<Renderer>(true);
if (componentsInChildren == null || componentsInChildren.Length == 0)
{
Plugin.Log.LogWarning((object)("[EnemySkinMod] ApplySkinLogic: No Renderers found on '" + ((Object)enemyInstance).name + "' or its children."));
}
else
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)string.Format("{0}ApplySkinLogic: Found {1} renderers on '{2}'. Iterating...", "[EnemySkinMod] ", componentsInChildren.Length, ((Object)enemyInstance).name));
}
foreach (KeyValuePair<string, Texture2D> textureOverride in skinData.TextureOverrides)
{
string key = textureOverride.Key;
Texture2D value = textureOverride.Value;
Plugin.Log.LogInfo((object)("[EnemySkinMod] ApplySkinLogic: Processing override: Key='" + key + "', Texture='" + (((Object)(object)value != (Object)null) ? ((Object)value).name : "NULL") + "'"));
if (string.IsNullOrEmpty(key) || (Object)(object)value == (Object)null)
{
Plugin.Log.LogWarning((object)("[EnemySkinMod] ApplySkinLogic: Skipping invalid texture override entry (null key or value). Key: " + key));
continue;
}
bool flag2 = false;
Renderer[] array = componentsInChildren;
foreach (Renderer val in array)
{
Material[] materials = val.materials;
for (int j = 0; j < materials.Length; j++)
{
Material val2 = materials[j];
if (val2.HasProperty(key))
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)string.Format("{0}ApplySkinLogic: Found property '{1}' on material instance '{2}' (Index {3}) of renderer '{4}'. Applying texture '{5}'.", "[EnemySkinMod] ", key, ((Object)val2).name, j, ((Object)val).name, ((Object)value).name));
}
val2.SetTexture(key, (Texture)(object)value);
flag2 = true;
flag = true;
}
else if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)string.Format("{0}ApplySkinLogic: Material instance '{1}' (Index {2}) of renderer '{3}' does not have property '{4}'.", "[EnemySkinMod] ", ((Object)val2).name, j, ((Object)val).name, key));
}
}
val.materials = materials;
}
if (!flag2)
{
Plugin.Log.LogWarning((object)("[EnemySkinMod] ApplySkinLogic: Texture override key '" + key + "' was not found on ANY material instance of ANY renderer on '" + ((Object)enemyInstance).name + "'."));
}
}
}
if (flag)
{
Plugin.Log.LogInfo((object)("[EnemySkinMod] ApplySkinLogic: Finished applying texture overrides for '" + skinData.Identifier + "' on '" + ((Object)enemyInstance).name + "'."));
}
else
{
Plugin.Log.LogWarning((object)("[EnemySkinMod] ApplySkinLogic: Finished applying texture overrides for '" + skinData.Identifier + "' on '" + ((Object)enemyInstance).name + "', but no matching properties were found on any materials."));
}
}
else if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Skin '" + skinData.Identifier + "' has no texture overrides defined."));
}
if (skinData.Materials != null && skinData.Materials.Length != 0)
{
Plugin.Log.LogInfo((object)string.Format("{0}ApplySkinLogic: Skin '{1}' has {2} material(s). Attempting to apply.", "[EnemySkinMod] ", skinData.Identifier, skinData.Materials.Length));
bool flag3 = false;
Renderer[] componentsInChildren2 = enemyInstance.GetComponentsInChildren<Renderer>(true);
if (componentsInChildren2 == null || componentsInChildren2.Length == 0)
{
Plugin.Log.LogWarning((object)("[EnemySkinMod] ApplySkinLogic: No Renderers found on '" + ((Object)enemyInstance).name + "' or its children for shared material application."));
}
else
{
string text = ((Object)enemyInstance).name;
if (text.EndsWith("(Clone)"))
{
text = text.Substring(0, text.Length - "(Clone)".Length);
}
if (text.StartsWith("Enemy - "))
{
text = text.Substring("Enemy - ".Length);
}
switch (text)
{
case "Head":
{
Plugin.Log.LogInfo((object)"[EnemySkinMod] ApplySkinLogic: Special handling for enemy 'Head'. Targeting 'Eye L Mesh' and 'Eye R Mesh'.");
Renderer[] array6 = componentsInChildren2;
foreach (Renderer val14 in array6)
{
if ((((Object)((Component)val14).gameObject).name == "Eye L Mesh" || ((Object)((Component)val14).gameObject).name == "Eye R Mesh") && skinData.Materials.Length != 0)
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Applying material '" + ((Object)skinData.Materials[0]).name + "' to '" + ((Object)((Component)val14).gameObject).name + "' on 'Head' enemy."));
}
val14.material = skinData.Materials[0];
flag3 = true;
}
}
break;
}
case "Upscream":
{
Plugin.Log.LogInfo((object)"[EnemySkinMod] ApplySkinLogic: Special handling for enemy 'Upscream'. Applying head/leg materials to specific parts.");
if (skinData.Materials == null || skinData.Materials.Length < 2)
{
ManualLogSource log = Plugin.Log;
string identifier = skinData.Identifier;
Material[] materials2 = skinData.Materials;
log.LogError((object)string.Format("{0}ApplySkinLogic: 'Upscream' skin '{1}' requires 2 materials (head, legs) but found {2}. Aborting skin application for this enemy.", "[EnemySkinMod] ", identifier, (materials2 != null) ? materials2.Length : 0));
break;
}
Material val7 = skinData.Materials[0];
Material val8 = skinData.Materials[1];
if ((Object)(object)val7 == (Object)null || (Object)(object)val8 == (Object)null)
{
Plugin.Log.LogError((object)string.Format("{0}ApplySkinLogic: One or both materials for 'Upscream' skin '{1}' are null. Head: {2}, Legs: {3}. Aborting.", "[EnemySkinMod] ", skinData.Identifier, (Object)(object)val7 == (Object)null, (Object)(object)val8 == (Object)null));
break;
}
Renderer[] array4 = componentsInChildren2;
foreach (Renderer val9 in array4)
{
string name3 = ((Object)((Component)val9).gameObject).name;
switch (name3)
{
default:
if (!(name3 == "eye_R"))
{
switch (name3)
{
default:
if (!(name3 == "leg front R3"))
{
goto end_IL_0747;
}
break;
case "leg back L1":
case "leg back L2":
case "leg back R1":
case "leg back R2":
case "leg front L1":
case "leg front L2":
case "leg front R1":
case "leg front R2":
case "leg back L3":
case "leg back R3":
case "leg front L3":
break;
}
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Applying LEGS material '" + ((Object)val8).name + "' to '" + name3 + "' on 'Upscream'."));
}
val9.material = val8;
flag3 = true;
break;
}
goto case "Upscream_Head - Mouth Closed";
case "Upscream_Head - Mouth Closed":
case "Upscream_Head - Mouth Open":
case "eye_L":
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Applying HEAD material '" + ((Object)val7).name + "' to '" + name3 + "' on 'Upscream'."));
}
val9.material = val7;
flag3 = true;
break;
}
end_IL_0747:
break;
}
}
break;
}
case "Duck":
{
Plugin.Log.LogInfo((object)"[EnemySkinMod] ApplySkinLogic: Special handling for enemy 'Duck'. Applying two materials to specified parts and preserving particles.");
if (skinData.Materials == null || skinData.Materials.Length < 2)
{
ManualLogSource log2 = Plugin.Log;
string identifier2 = skinData.Identifier;
Material[] materials3 = skinData.Materials;
log2.LogWarning((object)string.Format("{0}ApplySkinLogic: SkinData for '{1}' on 'Duck' requires 2 materials, but found {2}. No materials applied.", "[EnemySkinMod] ", identifier2, (materials3 != null) ? materials3.Length : 0));
break;
}
Material val10 = skinData.Materials[0];
Material val11 = skinData.Materials[1];
Renderer[] array5 = componentsInChildren2;
foreach (Renderer val12 in array5)
{
bool flag6 = false;
string name4 = ((Object)((Component)val12).gameObject).name;
switch (name4)
{
default:
if (!(name4 == "mesh Mon Mouth Bot"))
{
break;
}
goto case "mesh Eye R";
case "mesh Eye R":
case "mesh Eye L":
case "mesh Mon Eye L":
case "mesh Mon Eye R":
case "mesh Mon Mouth Top":
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Skipping renderer '" + name4 + "' on 'Duck' to keep its material vanilla (eye or mouth part)."));
}
flag6 = true;
break;
}
if (!flag6)
{
string text4 = name4.ToLower();
if (text4.Contains("particle") || text4.Contains("effect") || text4.Contains("vfx"))
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Skipping renderer '" + name4 + "' on 'Duck' due to name containing particle/effect keywords."));
}
flag6 = true;
}
if (!flag6 && val12.sharedMaterials != null)
{
Material[] sharedMaterials3 = val12.sharedMaterials;
foreach (Material val13 in sharedMaterials3)
{
if (!((Object)(object)val13 != (Object)null) || !((Object)(object)val13.shader != (Object)null))
{
continue;
}
string name5 = ((Object)val13.shader).name;
if (name5 == "Particles/Standard Unlit" || name5 == "Particles/Standard Surface")
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Skipping renderer '" + name4 + "' on 'Duck' due to material '" + ((Object)val13).name + "' using shader '" + name5 + "'."));
}
flag6 = true;
break;
}
}
}
}
if (flag6)
{
continue;
}
switch (name4)
{
default:
if (!(name4 == "mesh Mon Head"))
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Applying main body material (" + ((Object)val10).name + ") to '" + name4 + "' on 'Duck'."));
}
val12.material = val10;
flag3 = true;
break;
}
goto case "mesh Mon Body";
case "mesh Mon Body":
case "mesh Mon Wing L":
case "mesh Mon Wing R":
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Applying 'Monster' material (" + ((Object)val11).name + ") to '" + name4 + "' on 'Duck'."));
}
val12.material = val11;
flag3 = true;
break;
}
}
break;
}
case "Animal":
{
Plugin.Log.LogInfo((object)"[EnemySkinMod] ApplySkinLogic: Special handling for enemy 'Animal'. Preserving 'Eyes' and particles.");
if (skinData.Materials == null || skinData.Materials.Length == 0 || (Object)(object)skinData.Materials[0] == (Object)null)
{
Plugin.Log.LogError((object)("[EnemySkinMod] ApplySkinLogic: Skin '" + skinData.Identifier + "' for 'Animal' has no valid material at index 0. Aborting skin application for this instance."));
return;
}
Material val15 = skinData.Materials[0];
Renderer[] array7 = componentsInChildren2;
foreach (Renderer val16 in array7)
{
bool flag7 = false;
string name6 = ((Object)((Component)val16).gameObject).name;
if (name6 == "Eyes")
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Skipping renderer '" + name6 + "' on 'Animal' to keep its material vanilla."));
}
flag7 = true;
}
if (!flag7)
{
string text5 = name6.ToLower();
if (text5.Contains("particle") || text5.Contains("effect") || text5.Contains("vfx"))
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Skipping renderer '" + name6 + "' on 'Animal' due to name containing particle/effect keywords."));
}
flag7 = true;
}
if (!flag7 && val16.sharedMaterials != null)
{
Material[] sharedMaterials4 = val16.sharedMaterials;
foreach (Material val17 in sharedMaterials4)
{
if (!((Object)(object)val17 != (Object)null) || !((Object)(object)val17.shader != (Object)null))
{
continue;
}
string name7 = ((Object)val17.shader).name;
if (name7 == "Particles/Standard Unlit" || name7 == "Particles/Standard Surface")
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Skipping renderer '" + name6 + "' on 'Animal' due to material '" + ((Object)val17).name + "' using shader '" + name7 + "'."));
}
flag7 = true;
break;
}
}
}
}
if (!flag7)
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Applying skin material (" + ((Object)val15).name + ") to '" + name6 + "' on 'Animal'."));
}
val16.material = val15;
}
}
break;
}
case "Bowtie":
{
Plugin.Log.LogInfo((object)"[EnemySkinMod] ApplySkinLogic: Special handling for enemy 'Bowtie'. Preserving 'bend body' and particle effects.");
if (skinData.Materials == null || skinData.Materials.Length == 0)
{
Plugin.Log.LogWarning((object)("[EnemySkinMod] ApplySkinLogic: SkinData for '" + skinData.Identifier + "' on 'Bowtie' has no materials. No materials applied."));
break;
}
Renderer[] array3 = componentsInChildren2;
foreach (Renderer val5 in array3)
{
bool flag5 = false;
if (((Object)((Component)val5).gameObject).name == "bend body")
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)"[EnemySkinMod] ApplySkinLogic: Skipping renderer 'bend body' on 'Bowtie' to keep its material vanilla.");
}
flag5 = true;
}
if (!flag5)
{
string text3 = ((Object)((Component)val5).gameObject).name.ToLower();
if (text3.Contains("particle") || text3.Contains("effect") || text3.Contains("vfx"))
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Skipping renderer '" + ((Object)((Component)val5).gameObject).name + "' on 'Bowtie' due to name containing particle/effect keywords."));
}
flag5 = true;
}
if (!flag5 && val5.sharedMaterials != null)
{
Material[] sharedMaterials2 = val5.sharedMaterials;
foreach (Material val6 in sharedMaterials2)
{
if (!((Object)(object)val6 != (Object)null) || !((Object)(object)val6.shader != (Object)null))
{
continue;
}
string name2 = ((Object)val6.shader).name;
if (name2 == "Particles/Standard Unlit" || name2 == "Particles/Standard Surface")
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Skipping renderer '" + ((Object)((Component)val5).gameObject).name + "' on 'Bowtie' due to material '" + ((Object)val6).name + "' using shader '" + name2 + "'."));
}
flag5 = true;
break;
}
}
}
}
if (flag5)
{
continue;
}
if (val5.sharedMaterials == null || val5.sharedMaterials.Length == 0)
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Renderer '" + ((Object)((Component)val5).gameObject).name + "' on 'Bowtie' has no materials to replace. Skipping."));
}
continue;
}
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)string.Format("{0}ApplySkinLogic: Applying skin materials to renderer '{1}' on 'Bowtie'. Original material count: {2}, New material count: {3}", "[EnemySkinMod] ", ((Object)((Component)val5).gameObject).name, val5.sharedMaterials.Length, skinData.Materials.Length));
}
val5.materials = skinData.Materials;
flag3 = true;
}
break;
}
default:
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)string.Format("{0}ApplySkinLogic: Found {1} renderers on '{2}' ({3}). Applying shared materials, skipping particle systems if named appropriately.", "[EnemySkinMod] ", componentsInChildren2.Length, ((Object)enemyInstance).name, text));
}
if (skinData.Materials != null && skinData.Materials.Length != 0)
{
Renderer[] array2 = componentsInChildren2;
foreach (Renderer val3 in array2)
{
bool flag4 = false;
string text2 = ((Object)((Component)val3).gameObject).name.ToLower();
if (text2.Contains("particle") || text2.Contains("effect") || text2.Contains("vfx"))
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Skipping renderer '" + ((Object)((Component)val3).gameObject).name + "' on '" + text + "' due to name containing particle/effect keywords."));
}
flag4 = true;
}
if (!flag4 && val3.sharedMaterials != null)
{
Material[] sharedMaterials = val3.sharedMaterials;
foreach (Material val4 in sharedMaterials)
{
if (!((Object)(object)val4 != (Object)null) || !((Object)(object)val4.shader != (Object)null))
{
continue;
}
string name = ((Object)val4.shader).name;
if (name == "Particles/Standard Unlit" || name == "Particles/Standard Surface")
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Skipping renderer '" + ((Object)((Component)val3).gameObject).name + "' on '" + text + "' due to material '" + ((Object)val4).name + "' using shader '" + name + "'."));
}
flag4 = true;
break;
}
}
}
if (flag4)
{
continue;
}
if (val3.sharedMaterials == null || val3.sharedMaterials.Length == 0)
{
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Renderer '" + ((Object)((Component)val3).gameObject).name + "' on '" + text + "' has no materials to replace. Skipping."));
}
continue;
}
if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)string.Format("{0}ApplySkinLogic: Applying skin materials to renderer '{1}' on '{2}'. Original material count: {3}, New material count: {4}", "[EnemySkinMod] ", ((Object)((Component)val3).gameObject).name, text, val3.sharedMaterials.Length, skinData.Materials.Length));
}
val3.materials = skinData.Materials;
flag3 = true;
}
}
else
{
Plugin.Log.LogWarning((object)("[EnemySkinMod] ApplySkinLogic: SkinData for '" + skinData.Identifier + "' on '" + text + "' has no materials. No general materials applied."));
}
break;
}
}
if (flag3)
{
Plugin.Log.LogInfo((object)("[EnemySkinMod] ApplySkinLogic: Finished applying shared materials for '" + skinData.Identifier + "' on '" + ((Object)enemyInstance).name + "'."));
}
else
{
Plugin.Log.LogWarning((object)("[EnemySkinMod] ApplySkinLogic: Finished applying shared materials for '" + skinData.Identifier + "' on '" + ((Object)enemyInstance).name + "', but no materials were actually applied (e.g., specific renderers not found for 'Head', or no renderers for others, or no materials in skinData)."));
}
}
else if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Skin '" + skinData.Identifier + "' has no shared materials defined."));
}
if ((Object)(object)skinData.SharedMesh != (Object)null)
{
Plugin.Log.LogInfo((object)("[EnemySkinMod] ApplySkinLogic: Skin '" + skinData.Identifier + "' has a shared mesh defined. Attempting to apply."));
MeshFilter componentInChildren = enemyInstance.GetComponentInChildren<MeshFilter>(true);
if ((Object)(object)componentInChildren != (Object)null)
{
componentInChildren.mesh = skinData.SharedMesh;
Plugin.Log.LogInfo((object)("[EnemySkinMod] ApplySkinLogic: Successfully applied shared mesh '" + ((Object)skinData.SharedMesh).name + "' to MeshFilter on '" + ((Object)((Component)componentInChildren).gameObject).name + "'."));
}
else
{
Plugin.Log.LogWarning((object)("[EnemySkinMod] ApplySkinLogic: No MeshFilter found on '" + ((Object)enemyInstance).name + "' or its children to apply shared mesh."));
}
}
else if (Plugin.EnableDebugLogging.Value)
{
Plugin.Log.LogDebug((object)("[EnemySkinMod] ApplySkinLogic: Skin '" + skinData.Identifier + "' has no shared mesh defined."));
}
Plugin.Log.LogInfo((object)("[EnemySkinMod] ApplySkinLogic completed for '" + ((Object)enemyInstance).name + "' with skin '" + skinData.Identifier + "'. Check logs for details."));
}
[HarmonyPatch(typeof(EnemyDirector), "Awake")]
[HarmonyPostfix]
private static void EnemyDirector_Awake_Patch(EnemyDirector __instance)
{
Plugin.Log.LogInfo((object)$"--- EnemyDirector_Awake_Patch executing for instance {((Object)__instance).GetInstanceID()} ---");
string name = ((Object)((Component)__instance).gameObject).name;
string text = name.Replace("(Clone)", "").Trim();
string text2 = text;
if (text.StartsWith("Enemy - "))
{
text2 = text.Substring("Enemy - ".Length).Trim();
}
if (string.IsNullOrEmpty(text2))
{
Plugin.Log.LogWarning((object)(" Could not get valid Enemy ID from GameObject name: '" + name + "'. Cannot apply skin."));
return;
}
Plugin.Log.LogInfo((object)(" Enemy ID derived from GameObject name: '" + text2 + "' (Original: '" + name + "')"));
if (!EnemySkinManager.RegisteredSkins.ContainsKey(text2) || EnemySkinManager.RegisteredSkins[text2].Count == 0)
{
Plugin.Log.LogInfo((object)(" No skins registered for enemy ID '" + text2 + "'. Skipping."));
return;
}
SkinData randomSkinForEnemy = EnemySkinManager.GetRandomSkinForEnemy(text2);
if (randomSkinForEnemy.Identifier == null)
{
Plugin.Log.LogInfo((object)(" GetRandomSkinForEnemy returned no skin (likely all disabled or only Vanilla exists and was chosen). Enemy ID: '" + text2 + "'"));
return;
}
if (randomSkinForEnemy.Identifier == "Vanilla")
{
Plugin.Log.LogInfo((object)(" Selected skin is 'Vanilla'. No custom skin applied for enemy ID: '" + text2 + "'."));
return;
}
Plugin.Log.LogInfo((object)(" Selected skin '" + randomSkinForEnemy.Identifier + "' for enemy ID '" + text2 + "'. Applying..."));
GameObject gameObject = ((Component)__instance).gameObject;
ApplySkinLogic(gameObject, randomSkinForEnemy);
}
}
}