From ad5387d6ebb05755d2d95b9d965b896fec69d6a2 Mon Sep 17 00:00:00 2001 From: mikx Date: Tue, 17 Feb 2026 05:18:00 -0500 Subject: [PATCH] (1.6.3) EventSystem Debug Fix / KillFeed show biome icon --- MxValheim/EventSystem/Patch.cs | 4 +- MxValheim/KillFeed/Patch.cs | 120 ++++++++++++++++++++++++++++++--- MxValheim/MxValheim.cs | 6 +- MxValheim/MxValheim.csproj | 9 +++ 4 files changed, 125 insertions(+), 14 deletions(-) diff --git a/MxValheim/EventSystem/Patch.cs b/MxValheim/EventSystem/Patch.cs index d9ac643..7f24e22 100644 --- a/MxValheim/EventSystem/Patch.cs +++ b/MxValheim/EventSystem/Patch.cs @@ -42,8 +42,8 @@ namespace MxValheim.EventSystem { static void Prefix(RandEventSystem __instance) { - __instance.m_eventIntervalMin = 10f; - __instance.m_eventChance = 100f; + //__instance.m_eventIntervalMin = 10f; + //__instance.m_eventChance = 100f; } } diff --git a/MxValheim/KillFeed/Patch.cs b/MxValheim/KillFeed/Patch.cs index ccefeff..682bc20 100644 --- a/MxValheim/KillFeed/Patch.cs +++ b/MxValheim/KillFeed/Patch.cs @@ -2,6 +2,7 @@ using HarmonyLib; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Reflection.Emit; using System.Threading; @@ -14,7 +15,39 @@ using static MxValheimMod; namespace MxValheim.KillFeed { public class KillFeed_Patch - { + { + public static Sprite LoadCustomSprite(string fileName) + { + string path = Path.Combine(BepInEx.Paths.PluginPath, "MxValheim", "Icons", fileName); + if (!File.Exists(path)) return null; + + try + { + byte[] fileData = File.ReadAllBytes(path); + Texture2D tex = new Texture2D(2, 2); + + // We use Reflection to find the LoadImage method inside the game's assemblies + var imageConversion = System.Reflection.Assembly.Load("UnityEngine.ImageConversionModule") + .GetType("UnityEngine.ImageConversion"); + + var loadImageMethod = imageConversion.GetMethod("LoadImage", new[] { typeof(Texture2D), typeof(byte[]) }); + + // Invoke the method: LoadImage(tex, fileData) + bool success = (bool)loadImageMethod.Invoke(null, new object[] { tex, fileData }); + + if (success) + { + return Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f)); + } + } + catch (Exception e) + { + UnityEngine.Debug.LogError($"[MxKillFeed] Reflection Load failed: {e.Message}"); + } + + return null; + } + public static void SendKillToAll(string attacker, string victim, string victimInternalName, string weaponPrefab, int encodedType) { if (ZRoutedRpc.instance != null) @@ -29,11 +62,32 @@ namespace MxValheim.KillFeed if (zn.IsDedicated()) return; if (attacker == "The World") return; - float distance = (encodedType / 1000) / 10.0f; - int remainder = encodedType % 1000; - bool isBoss = (remainder >= 100); - int level = (remainder % 100) / 10; - int type = remainder % 10; + // --- DECODING START --- + int biomeIndex = encodedType / 100000; + int mainRemainder = encodedType % 100000; + + float distance = (mainRemainder / 1000) / 10.0f; + int subRemainder = mainRemainder % 1000; + + bool isBoss = (subRemainder >= 100); + int level = (subRemainder % 100) / 10; + int type = subRemainder % 10; + // --- DECODING END --- + + // Inside OnReceiveKillMsg... + Sprite biomeSprite = null; + switch (biomeIndex) + { + case 1: biomeSprite = LoadCustomSprite("biome_meadows.png"); break; + case 2: biomeSprite = LoadCustomSprite("biome_blackforest.png"); break; + case 3: biomeSprite = LoadCustomSprite("biome_swamp.png"); break; + case 4: biomeSprite = LoadCustomSprite("biome_mountain.png"); break; + case 5: biomeSprite = LoadCustomSprite("biome_plains.png"); break; + case 6: biomeSprite = LoadCustomSprite("biome_mistland.png"); break; + case 7: biomeSprite = LoadCustomSprite("biome_deepnorth.png"); break; + case 8: biomeSprite = LoadCustomSprite("biome_ashlands.png"); break; + case 9: biomeSprite = LoadCustomSprite("biome_ocean.png"); break; + } Sprite victimIcon = GetCreatureIcon(victimInternalName); @@ -128,13 +182,14 @@ namespace MxValheim.KillFeed lock (_msgQueue) { _msgQueue.Enqueue(finalMsg); + _biomeIconQueue.Enqueue(biomeSprite); _borderColQueue.Enqueue(borderColor); _iconQueue.Enqueue(weaponIcon); _victimIconQueue.Enqueue(victimIcon); } } - public void ShowNextMessage(string msg, Sprite weaponIcon, Sprite victimIcon, Color borderColor) + public void ShowNextMessage(string msg, Sprite biome, Sprite weaponIcon, Sprite victimIcon, Color borderColor) { if (_hudRoot == null) CreateCustomHud(); @@ -154,6 +209,9 @@ namespace MxValheim.KillFeed _killText.text = msg; _border.effectColor = borderColor; _border.enabled = true; + ///////////////////// + _biomeIconSlot.sprite = biome; + _biomeIconSlot.gameObject.SetActive(biome != null); // Weapon icon (Left) _weaponIconSlot.sprite = weaponIcon; _weaponIconSlot.enabled = (weaponIcon != null); @@ -240,6 +298,9 @@ namespace MxValheim.KillFeed // This check should now pass because ApplyDamage happens before the object is invalidated if (nview == null || !nview.IsValid() || !nview.IsOwner()) return; + Heightmap.Biome currentBiome; + int biomeIndex = 0; + float distance = 0f; Character attacker = hit.GetAttacker(); if (attacker != null) @@ -272,14 +333,45 @@ namespace MxValheim.KillFeed string victimName = __instance.GetHoverName(); int type = 0; - if (__instance.IsPlayer()) type = 1; - else if (attackerName == Player.m_localPlayer?.GetHoverName()) type = 2; + if (__instance.IsPlayer()) + { + type = 1; + currentBiome = Player.m_localPlayer.GetCurrentBiome(); + Debug.Log($"KillFeed: {currentBiome}"); + biomeIndex = 0; + if (currentBiome == Heightmap.Biome.Meadows) biomeIndex = 1; + else if (currentBiome == Heightmap.Biome.BlackForest) biomeIndex = 2; + else if (currentBiome == Heightmap.Biome.Swamp) biomeIndex = 3; + else if (currentBiome == Heightmap.Biome.Mountain) biomeIndex = 4; + else if (currentBiome == Heightmap.Biome.Plains) biomeIndex = 5; + else if (currentBiome == Heightmap.Biome.Mistlands) biomeIndex = 6; + else if (currentBiome == Heightmap.Biome.DeepNorth) biomeIndex = 7; + else if (currentBiome == Heightmap.Biome.AshLands) biomeIndex = 8; + else if (currentBiome == Heightmap.Biome.Ocean) biomeIndex = 9; + } + + if (attackerName == Player.m_localPlayer?.GetHoverName()) + { + type = 2; + currentBiome = Player.m_localPlayer.GetCurrentBiome(); + Debug.Log($"KillFeed: {currentBiome}"); + biomeIndex = 0; + if (currentBiome == Heightmap.Biome.Meadows) biomeIndex = 1; + else if (currentBiome == Heightmap.Biome.BlackForest) biomeIndex = 2; + else if (currentBiome == Heightmap.Biome.Swamp) biomeIndex = 3; + else if (currentBiome == Heightmap.Biome.Mountain) biomeIndex = 4; + else if (currentBiome == Heightmap.Biome.Plains) biomeIndex = 5; + else if (currentBiome == Heightmap.Biome.Mistlands) biomeIndex = 6; + else if (currentBiome == Heightmap.Biome.DeepNorth) biomeIndex = 7; + else if (currentBiome == Heightmap.Biome.AshLands) biomeIndex = 8; + else if (currentBiome == Heightmap.Biome.Ocean) biomeIndex = 9; + } int level = __instance.GetLevel(); bool isBoss = __instance.IsBoss(); int distInt = (int)(Math.Min(distance, 999f) * 10); - int encodedType = type + (level * 10) + (isBoss ? 100 : 0) + (distInt * 1000); + int encodedType = type + (level * 10) + (isBoss ? 100 : 0) + (distInt * 1000) + (biomeIndex * 100000); if (ZRoutedRpc.instance != null) { @@ -349,6 +441,14 @@ namespace MxValheim.KillFeed pRect.sizeDelta = new Vector2(400, 35); // Shorter and narrower pRect.localScale = Vector3.one; + GameObject biomeObj = new GameObject("BiomeIcon", typeof(RectTransform), typeof(Image)); + biomeObj.transform.SetParent(panel.transform, false); // Use 'false' for worldPositionStays + _biomeIconSlot = biomeObj.GetComponent(); + _biomeIconSlot.preserveAspect = true; + LayoutElement biomeLayout = biomeObj.AddComponent(); + biomeLayout.preferredWidth = 32; + biomeLayout.preferredHeight = 32; + // 2. Compact Icon GameObject iconObj = new GameObject("Icon", typeof(RectTransform), typeof(Image)); iconObj.transform.SetParent(panel.transform, false); diff --git a/MxValheim/MxValheim.cs b/MxValheim/MxValheim.cs index 81d5bbe..9f7a345 100644 --- a/MxValheim/MxValheim.cs +++ b/MxValheim/MxValheim.cs @@ -28,7 +28,7 @@ public class MxValheimMod : BaseUnityPlugin private const string ModGUID = "ovh.mxdev.mxvalheim"; private const string ModName = "MxValheim"; - private const string ModVersion = "1.6.2"; + private const string ModVersion = "1.6.3"; public static ConfigEntry Config_Locked; public static ConfigEntry Config_OreMultiplier; @@ -64,6 +64,7 @@ public class MxValheimMod : BaseUnityPlugin public static Image _weaponIconSlot; public static Image _victimIconSlot; public static Image _panelImage; + public static Image _biomeIconSlot; public static Outline _border; public static Color borderColor = Color.white; public static CanvasGroup _canvasGroup; @@ -74,6 +75,7 @@ public class MxValheimMod : BaseUnityPlugin public static readonly Queue _borderColQueue = new Queue(); public static readonly Queue _iconQueue = new Queue(); public static readonly Queue _victimIconQueue = new Queue(); + public static readonly Queue _biomeIconQueue = new Queue(); public static readonly Dictionary _activeTrackers = new Dictionary(); public static readonly Queue _doorQueueNview = new Queue(); @@ -221,7 +223,7 @@ public class MxValheimMod : BaseUnityPlugin if (_msgQueue.Count > 0 && _displayTimer <= 0) { borderColor = new Color(0.141f, 0.141f, 0.153f); - kfp.ShowNextMessage(_msgQueue.Dequeue(), _iconQueue.Dequeue(), _victimIconQueue.Dequeue(), _borderColQueue.Dequeue()); + kfp.ShowNextMessage(_msgQueue.Dequeue(), _biomeIconQueue.Dequeue(), _iconQueue.Dequeue(), _victimIconQueue.Dequeue(), _borderColQueue.Dequeue()); } if (_displayTimer > 0) diff --git a/MxValheim/MxValheim.csproj b/MxValheim/MxValheim.csproj index 730b7bb..103b8e2 100644 --- a/MxValheim/MxValheim.csproj +++ b/MxValheim/MxValheim.csproj @@ -13,6 +13,7 @@ 12.0 512 true + true @@ -96,6 +97,14 @@ False E:\SteamLibrary\steamapps\common\Valheim\Valheim_Data\Managed\UnityEngine.UIModule.dll + + False + E:\SteamLibrary\steamapps\common\Valheim\Valheim_Data\Managed\UnityEngine.UnityWebRequestModule.dll + + + False + E:\SteamLibrary\steamapps\common\Valheim\Valheim_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll +