using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("RandomHandCosmetics")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("RandomHandCosmetics")]
[assembly: AssemblyTitle("RandomHandCosmetics")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace RandomHandCosmetics;
[BepInPlugin("com.yourname.RandomHandCosmetics", "Random Hand Cosmetics", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
[HarmonyPatch(typeof(CL_CosmeticManager), "GetCosmeticInHand")]
public static class GetCosmeticInHandPatch
{
private static bool Prefix(int i, ref Cosmetic_HandItem __result)
{
if (string.IsNullOrEmpty(leftSelectedId) || string.IsNullOrEmpty(rightSelectedId))
{
InitializeCosmetics();
SelectRandomCosmetics();
}
string text = ((i == 0) ? leftSelectedId : rightSelectedId);
if (!string.IsNullOrEmpty(text) && text != "default" && text != "climber")
{
FieldInfo field = typeof(CL_CosmeticManager).GetField("cosmeticHandDict", BindingFlags.Static | BindingFlags.NonPublic);
if (field != null && field.GetValue(null) is Dictionary<string, Cosmetic_HandItem> dictionary && dictionary.TryGetValue(text, out var value))
{
__result = value;
if (i == 0)
{
SettingsManager.settings.cosmeticSaveData.leftHandCosmetic.id = text;
}
else
{
SettingsManager.settings.cosmeticSaveData.rightHandCosmetic.id = text;
}
return false;
}
}
return true;
}
}
[HarmonyPatch(typeof(ENT_Player), "Start")]
public static class PlayerStartPatch
{
private static void Postfix(ENT_Player __instance)
{
if (!((Object)(object)__instance == (Object)null) && !((GameEntity)__instance).dead)
{
ForceApplyCosmeticToHand(__instance, 0, leftSelectedId);
ForceApplyCosmeticToHand(__instance, 1, rightSelectedId);
if (!(ChangeInterval.Value <= 0f))
{
((MonoBehaviour)__instance).StartCoroutine(DynamicChangeRoutine(__instance));
}
}
}
private static IEnumerator DynamicChangeRoutine(ENT_Player player)
{
float interval = ChangeInterval.Value;
while (true)
{
yield return (object)new WaitForSeconds(interval);
if (!((Object)(object)player == (Object)null) && !((GameEntity)player).dead && !CL_GameManager.gMan.isPaused)
{
SelectRandomCosmetics();
ForceApplyCosmeticToHand(player, 0, leftSelectedId);
ForceApplyCosmeticToHand(player, 1, rightSelectedId);
}
}
}
}
[HarmonyPatch(typeof(Hand), "OnEnable")]
public static class HandOnEnablePatch
{
private static void Postfix(Hand __instance)
{
ENT_Player player = __instance.GetPlayer();
if (!((Object)(object)player == (Object)null) && !((GameEntity)player).dead)
{
string text = ((__instance.id == 0) ? leftSelectedId : rightSelectedId);
if (!string.IsNullOrEmpty(text) && text != "default" && text != "climber")
{
ForceApplyCosmeticToHand(player, __instance.id, text);
}
}
}
}
[HarmonyPatch(typeof(Hand), "LateUpdate")]
public static class HandLateUpdatePatch
{
private static void Postfix(Hand __instance)
{
ENT_Player player = __instance.GetPlayer();
if (!((Object)(object)player == (Object)null) && !((GameEntity)player).dead && !CL_GameManager.gMan.isPaused)
{
string text = ((__instance.id == 0) ? leftSelectedId : rightSelectedId);
if (!string.IsNullOrEmpty(text) && text != "default" && text != "climber")
{
ForceApplyCosmeticToHand(player, __instance.id, text);
}
}
}
}
public static ConfigEntry<string> ExcludedIdsConfig;
public static ConfigEntry<bool> SameCosmeticForBothHands;
public static ConfigEntry<float> ChangeInterval;
private static List<Cosmetic_HandItem> availableCosmetics = new List<Cosmetic_HandItem>();
private static List<string> recentIds = new List<string>();
private const int historySize = 4;
private static bool isInitialized = false;
private static string leftSelectedId = null;
private static string rightSelectedId = null;
private void Awake()
{
ExcludedIdsConfig = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ExcludedCosmeticIds", "default,climber", "English: List of cosmetic IDs (comma separated) to exclude from randomization.\nРусский: Список ID косметики (через запятую), исключаемых из рандома.");
SameCosmeticForBothHands = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SameCosmeticForBothHands", false, "English: True = both hands get the same cosmetic; False = each hand gets its own.\nРусский: True = обе руки получают одинаковую косметику; False = каждая руку свою.");
ChangeInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ChangeInterval", 30f, "English: Interval in seconds between cosmetic changes (0 = disable dynamic change).\nРусский: Интервал смены скинов в секундах (0 = отключить динамическую смену).");
SceneManager.sceneLoaded += OnSceneLoaded;
Harmony.CreateAndPatchAll(typeof(GetCosmeticInHandPatch), (string)null);
Harmony.CreateAndPatchAll(typeof(PlayerStartPatch), (string)null);
Harmony.CreateAndPatchAll(typeof(HandOnEnablePatch), (string)null);
Harmony.CreateAndPatchAll(typeof(HandLateUpdatePatch), (string)null);
((BaseUnityPlugin)this).Logger.LogInfo((object)"RandomHandCosmetics loaded with forced application.");
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
if (((Scene)(ref scene)).name == "Game-Main")
{
isInitialized = false;
recentIds.Clear();
leftSelectedId = null;
rightSelectedId = null;
((BaseUnityPlugin)this).Logger.LogInfo((object)"Cosmetic selection reset for new run.");
}
}
private static void InitializeCosmetics()
{
if (isInitialized)
{
return;
}
CL_CosmeticManager.Initialize();
FieldInfo field = typeof(CL_CosmeticManager).GetField("cosmeticHands", BindingFlags.Static | BindingFlags.NonPublic);
if (field == null)
{
Debug.LogError((object)"cosmeticHands field not found.");
}
else if (field.GetValue(null) is List<Cosmetic_HandItem> { Count: not 0 } list)
{
HashSet<string> excludedIds = new HashSet<string> { "default", "climber" };
string value = ExcludedIdsConfig.Value;
if (!string.IsNullOrEmpty(value))
{
foreach (string item in from s in value.Split(',')
select s.Trim())
{
excludedIds.Add(item);
}
}
List<Cosmetic_HandItem> list2 = list.Where((Cosmetic_HandItem c) => ((Cosmetic_Base)c).IsUnlocked()).ToList();
if (list2.Count == 0)
{
list2 = list;
}
availableCosmetics = (from c in list2
where !excludedIds.Contains(c.cosmeticData.id) && !string.IsNullOrEmpty(c.cosmeticData.id)
group c by c.cosmeticData.id into g
select g.First()).ToList();
isInitialized = true;
Debug.Log((object)$"Initialized {availableCosmetics.Count} unique cosmetics.");
if (availableCosmetics.Count > 0)
{
string text = string.Join(", ", availableCosmetics.Select((Cosmetic_HandItem c) => c.cosmeticData.id));
Debug.Log((object)("Available IDs: " + text));
}
}
else
{
Debug.LogWarning((object)"No cosmetics found.");
}
}
private static void SelectRandomCosmetics()
{
if (availableCosmetics.Count == 0)
{
Debug.LogWarning((object)"No cosmetics available.");
return;
}
List<Cosmetic_HandItem> list = availableCosmetics;
if (recentIds.Count > 0)
{
list = availableCosmetics.Where((Cosmetic_HandItem c) => !recentIds.Contains(c.cosmeticData.id)).ToList();
if (list.Count == 0)
{
list = availableCosmetics;
}
}
List<Cosmetic_HandItem> list2 = list.Where((Cosmetic_HandItem c) => c.cosmeticData.id != "default" && c.cosmeticData.id != "climber").ToList();
if (list2.Count > 0)
{
list = list2;
}
string text = null;
string text2 = null;
for (int num = 0; num < 30; num++)
{
if (!string.IsNullOrEmpty(text) && !(text == "default") && !(text == "climber"))
{
break;
}
text = list[Random.Range(0, list.Count)].cosmeticData.id;
}
if (string.IsNullOrEmpty(text) || text == "default" || text == "climber")
{
text = list[0].cosmeticData.id;
}
if (SameCosmeticForBothHands.Value)
{
text2 = text;
}
else
{
for (int num = 0; num < 30; num++)
{
if (!string.IsNullOrEmpty(text2) && !(text2 == "default") && !(text2 == "climber") && !(text2 == text))
{
break;
}
text2 = list[Random.Range(0, list.Count)].cosmeticData.id;
}
if (string.IsNullOrEmpty(text2) || text2 == "default" || text2 == "climber")
{
text2 = text;
}
}
leftSelectedId = text;
rightSelectedId = text2;
if (!recentIds.Contains(text))
{
recentIds.Add(text);
}
if (!SameCosmeticForBothHands.Value && !recentIds.Contains(text2))
{
recentIds.Add(text2);
}
while (recentIds.Count > 4)
{
recentIds.RemoveAt(0);
}
Debug.Log((object)("Selected cosmetics: left=" + text + ", right=" + text2));
}
private static void ForceApplyCosmeticToHand(ENT_Player player, int handIndex, string id)
{
if (string.IsNullOrEmpty(id) || id == "default" || id == "climber" || handIndex >= player.hands.Length)
{
return;
}
Hand val = player.hands[handIndex];
if (val == null || (Object)(object)val.handModel == (Object)null)
{
return;
}
FieldInfo field = typeof(CL_CosmeticManager).GetField("cosmeticHandDict", BindingFlags.Static | BindingFlags.NonPublic);
if (!(field == null) && field.GetValue(null) is Dictionary<string, Cosmetic_HandItem> dictionary && dictionary.TryGetValue(id, out var value))
{
val.currentCosmetics.Clear();
val.currentCosmetics.Add(value);
Cosmetic_HandItem.ReturnSprites();
value.SpriteSwap(((Component)val.handModel).gameObject, val);
if (handIndex == 0)
{
SettingsManager.settings.cosmeticSaveData.leftHandCosmetic.id = id;
}
else
{
SettingsManager.settings.cosmeticSaveData.rightHandCosmetic.id = id;
}
}
}
}