Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of MinimapPlayerColor v1.0.0
MinimapPlayerColor.dll
Decompiled 3 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; 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; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_guiutils")] [assembly: IgnoresAccessChecksTo("assembly_utils")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("MinimapPlayerColor")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+536c06ee6a90090c130053c1dfab6ae622ef1b48")] [assembly: AssemblyProduct("MinimapPlayerColor")] [assembly: AssemblyTitle("MinimapPlayerColor")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 MinimapPlayerColor { [HarmonyPatch(typeof(Achievements), "IsCheatedAtAll")] internal static class Achievements_IsCheatedAtAll_Patch { private static void Prefix(out bool __state) { __state = Game.isModded; if (Plugin.AllowAchievements.Value) { Game.isModded = false; } } private static void Finalizer(bool __state) { Game.isModded = __state; } } internal struct PlayerColors { public Color? Person; public Color? Gear; public bool IsVanilla { get { if (!Person.HasValue) { return !Gear.HasValue; } return false; } } public bool Equals(PlayerColors other) { if (Nullable.Equals<Color>(Person, other.Person)) { return Nullable.Equals<Color>(Gear, other.Gear); } return false; } } internal static class ColorSync { [HarmonyPatch(typeof(ZNet), "Awake")] private static class ZNet_Awake_Patch { private static void Postfix() { Colors.Clear(); _broadcastPending = false; _nextBroadcast = 0f; ZRoutedRpc.instance.Register<string, string>("MinimapPlayerColor_Color", (Action<long, string, string>)RPC_Color); ZRoutedRpc.instance.Register("MinimapPlayerColor_Request", (Action<long>)RPC_Request); } } [HarmonyPatch(typeof(Player), "OnSpawned")] private static class Player_OnSpawned_Patch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && ZRoutedRpc.instance != null) { BroadcastOwnColor(); ZRoutedRpc.instance.InvokeRoutedRPC(0L, "MinimapPlayerColor_Request", Array.Empty<object>()); } } } [HarmonyPatch(typeof(ZRoutedRpc), "RPC_RoutedRPC")] private static class ZRoutedRpc_RPC_RoutedRPC_Patch { private static bool Prefix(ZRoutedRpc __instance, ZRpc rpc, ZPackage pkg) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (!__instance.m_server) { return true; } long num; int num2; try { pkg.ReadLong(); num = pkg.ReadLong(); pkg.ReadLong(); pkg.ReadZDOID(); num2 = pkg.ReadInt(); } catch (Exception) { pkg.SetPos(0); return true; } pkg.SetPos(0); if (num2 != RpcColorHash && num2 != RpcRequestHash) { return true; } foreach (ZNetPeer peer in __instance.m_peers) { if (peer.m_rpc == rpc) { return peer.m_uid == num; } } return false; } } private const string RpcColor = "MinimapPlayerColor_Color"; private const string RpcRequest = "MinimapPlayerColor_Request"; private static readonly int RpcColorHash = StringExtensionMethods.GetStableHashCode("MinimapPlayerColor_Color"); private static readonly int RpcRequestHash = StringExtensionMethods.GetStableHashCode("MinimapPlayerColor_Request"); private const int MaxColors = 256; private const float BroadcastInterval = 2f; private static readonly Dictionary<long, PlayerColors> Colors = new Dictionary<long, PlayerColors>(); private static bool _broadcastPending; private static float _nextBroadcast; public static bool TryGetColors(long userId, out PlayerColors colors) { return Colors.TryGetValue(userId, out colors); } public static bool TryParse(string hex, out Color color) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) hex = (hex ?? "").Trim(); if (!hex.StartsWith("#")) { hex = "#" + hex; } if (hex.Length == 7 && ColorUtility.TryParseHtmlString(hex, ref color)) { color.a = 1f; return true; } color = Color.white; return false; } public static bool TryParseOptional(string hex, out Color? color) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) color = null; if (string.IsNullOrWhiteSpace(hex)) { return true; } if (hex.Length > 16 || !TryParse(hex, out var color2)) { return false; } color = color2; return true; } private static string ToHex(Color? color) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!color.HasValue) { return ""; } return "#" + ColorUtility.ToHtmlStringRGB(color.Value); } public static void BroadcastOwnColor() { _broadcastPending = true; } public static void Tick() { if (_broadcastPending && !(Time.unscaledTime < _nextBroadcast)) { _broadcastPending = false; if (ZRoutedRpc.instance != null && !((Object)(object)ZNet.instance == (Object)null)) { _nextBroadcast = Time.unscaledTime + 2f; ZRoutedRpc.instance.InvokeRoutedRPC(0L, "MinimapPlayerColor_Color", new object[2] { ToHex(Plugin.OwnColors.Person), ToHex(Plugin.OwnColors.Gear) }); } } } private static void RPC_Color(long sender, string personHex, string gearHex) { PlayerColors playerColors = default(PlayerColors); if (!TryParseOptional(personHex, out playerColors.Person) || !TryParseOptional(gearHex, out playerColors.Gear)) { return; } bool flag; if (playerColors.IsVanilla) { flag = Colors.Remove(sender); } else { PlayerColors value; bool flag2 = Colors.TryGetValue(sender, out value); if (!flag2 && Colors.Count >= 256 && !PruneAbsentPlayers()) { return; } flag = !flag2 || !value.Equals(playerColors); Colors[sender] = playerColors; } if (flag && (Object)(object)Minimap.instance != (Object)null) { Minimap.instance.m_pinUpdateRequired = true; } } private static bool PruneAbsentPlayers() { if ((Object)(object)ZNet.instance == (Object)null) { return false; } HashSet<long> present = new HashSet<long>(ZNet.instance.m_players.Select((PlayerInfo p) => ((ZDOID)(ref p.m_characterID)).UserID)); foreach (long item in Colors.Keys.Where((long id) => !present.Contains(id)).ToList()) { Colors.Remove(item); } return Colors.Count < 256; } private static void RPC_Request(long sender) { if (sender != ZNet.GetUID()) { BroadcastOwnColor(); } } } internal static class MinimapPatches { [HarmonyPatch(typeof(Minimap), "UpdatePins")] private static class Minimap_UpdatePins_Patch { private static void Postfix(Minimap __instance) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) if (PinSprites.IsOverCapacity) { PinSprites.Clear(); } int num = Mathf.Min(__instance.m_playerPins.Count, __instance.m_tempPlayerInfo.Count); for (int i = 0; i < num; i++) { PinData val = __instance.m_playerPins[i]; if ((Object)(object)val.m_iconElement == (Object)null) { continue; } PlayerInfo val2 = __instance.m_tempPlayerInfo[i]; long userID = ((ZDOID)(ref val2.m_characterID)).UserID; Sprite val3 = val.m_icon; if (ColorSync.TryGetColors(userID, out var colors)) { val3 = PinSprites.Get(val.m_icon, colors) ?? val.m_icon; if (colors.Person.HasValue && val.m_NamePinData != null && (Object)(object)val.m_NamePinData.PinNameText != (Object)null) { ((Graphic)val.m_NamePinData.PinNameText).color = colors.Person.Value; } } if ((Object)(object)val.m_iconElement.sprite != (Object)(object)val3) { val.m_iconElement.sprite = val3; } } } } [HarmonyPatch(typeof(Minimap), "Start")] private static class Minimap_Start_Patch { private static void Postfix(Minimap __instance) { PinSprites.Clear(); VanillaMarkerColors.Clear(); Capture(__instance.m_smallMarker); Capture(__instance.m_largeMarker); ApplyOwnMarkerColor(); } } private static readonly Dictionary<Image, Color> VanillaMarkerColors = new Dictionary<Image, Color>(); private static void Capture(RectTransform marker) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)marker == (Object)null)) { Image[] componentsInChildren = ((Component)marker).GetComponentsInChildren<Image>(true); foreach (Image val in componentsInChildren) { VanillaMarkerColors[val] = ((Graphic)val).color; Plugin.Log.LogInfo((object)("Vanilla colour of " + ((Object)val).name + ": #" + ColorUtility.ToHtmlStringRGBA(((Graphic)val).color))); } } } public static void ApplyOwnMarkerColor() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) foreach (KeyValuePair<Image, Color> vanillaMarkerColor in VanillaMarkerColors) { if ((Object)(object)vanillaMarkerColor.Key != (Object)null) { ((Graphic)vanillaMarkerColor.Key).color = (Color)(((??)Plugin.OwnColors.Person) ?? vanillaMarkerColor.Value); } } } } internal static class PinSprites { private struct Key : IEquatable<Key> { public int Source; public int Person; public int Gear; public bool Equals(Key other) { if (Source == other.Source && Person == other.Person) { return Gear == other.Gear; } return false; } public override bool Equals(object obj) { if (obj is Key other) { return Equals(other); } return false; } public override int GetHashCode() { return (((Source * 397) ^ Person) * 397) ^ Gear; } } private class SourcePixels { public Color[] Pixels; public int Width; public int Height; public float MaxRed; } private const int MaxCached = 64; private static readonly Dictionary<Key, Sprite> Cache = new Dictionary<Key, Sprite>(); private static readonly Dictionary<int, SourcePixels> Sources = new Dictionary<int, SourcePixels>(); public static bool IsOverCapacity => Cache.Count > 64; public static Sprite Get(Sprite source, PlayerColors colors) { if ((Object)(object)source == (Object)null) { return null; } Key key = new Key { Source = ((Object)source).GetInstanceID(), Person = Pack(colors.Person), Gear = Pack(colors.Gear) }; if (Cache.TryGetValue(key, out var value)) { return value; } try { value = Build(source, colors); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not recolour pin icon: " + ex.Message)); value = null; } Cache[key] = value; return value; } public static void Clear() { foreach (Sprite value in Cache.Values) { if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value.texture); Object.Destroy((Object)(object)value); } } Cache.Clear(); Sources.Clear(); } private static int Pack(Color? color) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (!color.HasValue) { return -1; } Color32 val = Color32.op_Implicit(color.Value); return (val.r << 16) | (val.g << 8) | val.b; } private static Sprite Build(Sprite source, PlayerColors colors) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) SourcePixels source2 = GetSource(source); Color val = (Color)(((??)colors.Gear) ?? Color.white); Color[] array = (Color[])(object)new Color[source2.Pixels.Length]; for (int i = 0; i < array.Length; i++) { Color val2 = source2.Pixels[i]; float num = Mathf.Min(val2.r, Mathf.Min(val2.g, val2.b)); float num2 = Mathf.Max(0f, val2.r - Mathf.Max(val2.g, val2.b)); Color val3 = (Color)(colors.Person.HasValue ? (colors.Person.Value * (num2 / source2.MaxRed)) : new Color(num2, 0f, 0f)); array[i] = new Color(Mathf.Clamp01(num * val.r + val3.r), Mathf.Clamp01(num * val.g + val3.g), Mathf.Clamp01(num * val.b + val3.b), val2.a); } Texture2D val4 = new Texture2D(source2.Width, source2.Height, (TextureFormat)4, false) { filterMode = ((Texture)source.texture).filterMode, wrapMode = (TextureWrapMode)1 }; val4.SetPixels(array); val4.Apply(); return Sprite.Create(val4, new Rect(0f, 0f, (float)source2.Width, (float)source2.Height), new Vector2(0.5f, 0.5f), source.pixelsPerUnit); } private static SourcePixels GetSource(Sprite source) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) int instanceID = ((Object)source).GetInstanceID(); if (Sources.TryGetValue(instanceID, out var value)) { return value; } Texture2D texture = source.texture; RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2); RenderTexture active = RenderTexture.active; Texture2D val = new Texture2D(((Texture)texture).width, ((Texture)texture).height, (TextureFormat)4, false); try { Graphics.Blit((Texture)(object)texture, temporary); RenderTexture.active = temporary; val.ReadPixels(new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height), 0, 0); val.Apply(); Rect textureRect = source.textureRect; value = new SourcePixels { Width = (int)((Rect)(ref textureRect)).width, Height = (int)((Rect)(ref textureRect)).height }; value.Pixels = val.GetPixels((int)((Rect)(ref textureRect)).x, (int)((Rect)(ref textureRect)).y, value.Width, value.Height); } finally { RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); Object.Destroy((Object)(object)val); } Color[] pixels = value.Pixels; foreach (Color val2 in pixels) { value.MaxRed = Mathf.Max(value.MaxRed, (val2.a > 0f) ? (val2.r - Mathf.Max(val2.g, val2.b)) : 0f); } value.MaxRed = Mathf.Max(value.MaxRed, 0.01f); Sources[instanceID] = value; return value; } } [BepInPlugin("com.jakubecdev.minimapplayercolor", "MinimapPlayerColor", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "com.jakubecdev.minimapplayercolor"; public const string PluginName = "MinimapPlayerColor"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Log; internal static PlayerColors OwnColors; internal static ConfigEntry<bool> AllowAchievements; private static ConfigEntry<string> _colorConfig; private static ConfigEntry<string> _gearColorConfig; private readonly Harmony _harmony = new Harmony("com.jakubecdev.minimapplayercolor"); private float _nextConfigCheck; private DateTime _configWritten; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; _colorConfig = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Color", "", "Colour of the person in your map icon, your name label and your own arrow, as hex RRGGBB (e.g. #FF8800). Seen by other players who have this mod. Leave empty for the game's default."); _gearColorConfig = ((BaseUnityPlugin)this).Config.Bind<string>("General", "GearColor", "", "Colour of the sword and shield in your map icon, as hex RRGGBB. Seen by other players who have this mod. Leave empty for the game's default."); _colorConfig.SettingChanged += delegate { OnColorChanged(); }; _gearColorConfig.SettingChanged += delegate { OnColorChanged(); }; ReadColors(); AllowAchievements = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AllowAchievements", true, "The game disables achievements when any mod is loaded. Enable this to keep earning them; cheats still disable achievements as usual."); _harmony.PatchAll(); Log.LogInfo((object)"MinimapPlayerColor 1.0.0 loaded"); } private void Update() { ColorSync.Tick(); if (Time.unscaledTime < _nextConfigCheck) { return; } _nextConfigCheck = Time.unscaledTime + 1f; try { if (File.GetLastWriteTimeUtc(((BaseUnityPlugin)this).Config.ConfigFilePath) != _configWritten) { if (_configWritten != default(DateTime)) { ((BaseUnityPlugin)this).Config.Reload(); } _configWritten = File.GetLastWriteTimeUtc(((BaseUnityPlugin)this).Config.ConfigFilePath); } } catch (Exception ex) { Log.LogDebug((object)("Config reload skipped: " + ex.Message)); } } private void OnDestroy() { _harmony.UnpatchSelf(); } private static void OnColorChanged() { ReadColors(); MinimapPatches.ApplyOwnMarkerColor(); ColorSync.BroadcastOwnColor(); } private static void ReadColors() { Read(_colorConfig, ref OwnColors.Person); Read(_gearColorConfig, ref OwnColors.Gear); } private static void Read(ConfigEntry<string> entry, ref Color? target) { if (ColorSync.TryParseOptional(entry.Value, out var color)) { target = color; return; } Log.LogWarning((object)("Invalid " + ((ConfigEntryBase)entry).Definition.Key + " '" + entry.Value + "', expected hex like #FF8800. Keeping the previous colour.")); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }