Decompiled source of ValheimClientLogger v1.0.2

plugins/ValheimClientLogger.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using ValheimClientLogger.Utils;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("ValheimClientLogger")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Valheim Client Logger")]
[assembly: AssemblyTitle("ValheimClientLogger")]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ValheimClientLogger
{
	[BepInPlugin("com.paim.valheimlogger.client", "Valheim Client Logger", "1.0.0")]
	public class ValheimClientLogger : BaseUnityPlugin
	{
		public const string PluginGUID = "com.paim.valheimlogger.client";

		public const string PluginName = "Valheim Client Logger";

		public const string PluginVersion = "1.0.0";

		public const string ServerPluginGUID = "com.paim.valheimlogger";

		private readonly Harmony _harmony = new Harmony("com.paim.valheimlogger.client");

		public static ConfigEntry<bool> EnableDebugLogs;

		public static ConfigEntry<string> ServerName;

		public static ManualLogSource StaticLogger { get; private set; }

		private void Awake()
		{
			StaticLogger = ((BaseUnityPlugin)this).Logger;
			LoadConfiguration();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Valheim Client Logger v1.0.0 is loading...");
			try
			{
				_harmony.PatchAll();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"All Harmony patches applied successfully");
				IEnumerable<MethodBase> patchedMethods = _harmony.GetPatchedMethods();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"=== PATCHED METHODS ===");
				foreach (MethodBase item in patchedMethods)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("  Patched: " + item.DeclaringType?.Name + "." + item.Name));
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)"=== END PATCHED METHODS ===");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Failed to apply Harmony patches: " + ex.Message + "\n" + ex.StackTrace));
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Valheim Client Logger v1.0.0 loaded successfully!");
		}

		private void LoadConfiguration()
		{
			ServerName = ((BaseUnityPlugin)this).Config.Bind<string>("Server", "Name", "Tios Doteiros", "Nome do servidor que aparecerá nos eventos enviados");
			EnableDebugLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableDebugLogs", true, "Habilita logs de debug detalhados (útil para troubleshooting)");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Configuration loaded:");
			((BaseUnityPlugin)this).Logger.LogInfo((object)("  Server Name: " + ServerName.Value));
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"  Debug Logs: {EnableDebugLogs.Value}");
		}

		public static void SendEventToServer(string eventType, Dictionary<string, object> eventData)
		{
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			try
			{
				if (ZRoutedRpc.instance == null)
				{
					ManualLogSource staticLogger = StaticLogger;
					if (staticLogger != null)
					{
						staticLogger.LogWarning((object)"ZRoutedRpc not ready, cannot send event");
					}
					return;
				}
				if ((Object)(object)ZNet.instance == (Object)null)
				{
					ManualLogSource staticLogger2 = StaticLogger;
					if (staticLogger2 != null)
					{
						staticLogger2.LogWarning((object)"ZNet not ready, skipping event send");
					}
					return;
				}
				if (ZNet.instance.IsServer() && !ZNet.instance.IsDedicated())
				{
					ManualLogSource staticLogger3 = StaticLogger;
					if (staticLogger3 != null)
					{
						staticLogger3.LogDebug((object)"Running as local host, skipping event send to avoid loop");
					}
					return;
				}
				string text = JsonHelper.Serialize(eventData);
				if (EnableDebugLogs.Value)
				{
					ManualLogSource staticLogger4 = StaticLogger;
					if (staticLogger4 != null)
					{
						staticLogger4.LogDebug((object)("[CLIENT] Sending event to server: " + eventType));
					}
					ManualLogSource staticLogger5 = StaticLogger;
					if (staticLogger5 != null)
					{
						staticLogger5.LogDebug((object)("[CLIENT] Event data: " + text));
					}
				}
				ZPackage val = new ZPackage();
				val.Write(eventType);
				val.Write(text);
				ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "com.paim.valheimlogger.LogEvent", new object[1] { val });
				ManualLogSource staticLogger6 = StaticLogger;
				if (staticLogger6 != null)
				{
					staticLogger6.LogInfo((object)("[CLIENT] Event sent to server: " + eventType));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource staticLogger7 = StaticLogger;
				if (staticLogger7 != null)
				{
					staticLogger7.LogError((object)("Error sending event to server: " + ex.Message + "\n" + ex.StackTrace));
				}
			}
		}

		private void OnDestroy()
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Valheim Client Logger is shutting down...");
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Valheim Client Logger shutdown complete");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "ValheimClientLogger";

		public const string PLUGIN_NAME = "Valheim Client Logger";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace ValheimClientLogger.Utils
{
	public static class JsonHelper
	{
		public static string Serialize(Dictionary<string, object> dict)
		{
			if (dict == null)
			{
				return "null";
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("{");
			bool flag = true;
			foreach (KeyValuePair<string, object> item in dict)
			{
				if (!flag)
				{
					stringBuilder.Append(",");
				}
				stringBuilder.Append("\"");
				stringBuilder.Append(EscapeString(item.Key));
				stringBuilder.Append("\":");
				stringBuilder.Append(SerializeValue(item.Value));
				flag = false;
			}
			stringBuilder.Append("}");
			return stringBuilder.ToString();
		}

		private static string SerializeValue(object value)
		{
			if (value == null)
			{
				return "null";
			}
			if (value is string str)
			{
				return "\"" + EscapeString(str) + "\"";
			}
			if (value is bool)
			{
				if (!(bool)value)
				{
					return "false";
				}
				return "true";
			}
			if (value is int || value is long || value is float || value is double)
			{
				return value.ToString().Replace(",", ".");
			}
			if (value is Dictionary<string, object> dict)
			{
				return Serialize(dict);
			}
			return "\"" + EscapeString(value.ToString()) + "\"";
		}

		private static string EscapeString(string str)
		{
			if (string.IsNullOrEmpty(str))
			{
				return "";
			}
			return str.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n")
				.Replace("\r", "\\r")
				.Replace("\t", "\\t");
		}
	}
}
namespace ValheimClientLogger.Patches
{
	[HarmonyPatch(typeof(Character), "OnDeath")]
	public static class Patch_Character_OnDeath
	{
		[HarmonyPostfix]
		public static void Postfix(Character __instance)
		{
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)__instance == (Object)null || __instance.IsPlayer())
				{
					return;
				}
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					return;
				}
				object? obj = typeof(Character).GetField("m_lastHit", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(__instance);
				HitData val = (HitData)((obj is HitData) ? obj : null);
				if (val == null)
				{
					return;
				}
				Character attacker = val.GetAttacker();
				if ((Object)(object)attacker == (Object)null || !attacker.IsPlayer())
				{
					return;
				}
				Player val2 = (Player)(object)((attacker is Player) ? attacker : null);
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 != (Object)(object)localPlayer))
				{
					string text = ((Object)((Component)__instance).gameObject).name.Replace("(Clone)", "").Trim();
					string hoverName = __instance.GetHoverName();
					ManualLogSource staticLogger = ValheimClientLogger.StaticLogger;
					if (staticLogger != null)
					{
						staticLogger.LogInfo((object)("[CLIENT] Mob killed: " + text + " (" + hoverName + ") by " + val2.GetPlayerName()));
					}
					Dictionary<string, object> eventData = new Dictionary<string, object>
					{
						["timestamp"] = DateTime.UtcNow.ToString("o"),
						["serverName"] = ValheimClientLogger.ServerName.Value,
						["eventType"] = "mob_kill",
						["playerName"] = val2.GetPlayerName(),
						["playerID"] = val2.GetPlayerID().ToString(),
						["details"] = new Dictionary<string, object>
						{
							["mobName"] = text,
							["mobDisplayName"] = hoverName,
							["mobLevel"] = __instance.GetLevel(),
							["mobMaxHealth"] = __instance.GetMaxHealth(),
							["position"] = new Dictionary<string, object>
							{
								["x"] = ((Component)__instance).transform.position.x,
								["y"] = ((Component)__instance).transform.position.y,
								["z"] = ((Component)__instance).transform.position.z
							},
							["isBoss"] = __instance.IsBoss()
						}
					};
					ValheimClientLogger.SendEventToServer("mob_kill", eventData);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource staticLogger2 = ValheimClientLogger.StaticLogger;
				if (staticLogger2 != null)
				{
					staticLogger2.LogError((object)("Error in Patch_Character_OnDeath: " + ex.Message + "\n" + ex.StackTrace));
				}
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "Pickup")]
	public static class Patch_Humanoid_Pickup
	{
		[HarmonyPostfix]
		public static void Postfix(Humanoid __instance, GameObject go, bool __result)
		{
		}
	}
	[HarmonyPatch(typeof(Player), "OnSpawned")]
	public static class Patch_Player_Login
	{
		public static bool _hasLogged;

		[HarmonyPostfix]
		public static void Postfix(Player __instance)
		{
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (_hasLogged)
				{
					return;
				}
				if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					_hasLogged = true;
					ManualLogSource staticLogger = ValheimClientLogger.StaticLogger;
					if (staticLogger != null)
					{
						staticLogger.LogInfo((object)("[CLIENT] Player logged in: " + __instance.GetPlayerName()));
					}
					Dictionary<string, object> eventData = new Dictionary<string, object>
					{
						["timestamp"] = DateTime.UtcNow.ToString("o"),
						["serverName"] = ValheimClientLogger.ServerName.Value,
						["eventType"] = "player_login",
						["playerName"] = __instance.GetPlayerName(),
						["playerID"] = __instance.GetPlayerID().ToString(),
						["details"] = new Dictionary<string, object> { ["position"] = new Dictionary<string, object>
						{
							["x"] = ((Component)__instance).transform.position.x,
							["y"] = ((Component)__instance).transform.position.y,
							["z"] = ((Component)__instance).transform.position.z
						} }
					};
					ValheimClientLogger.SendEventToServer("player_login", eventData);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource staticLogger2 = ValheimClientLogger.StaticLogger;
				if (staticLogger2 != null)
				{
					staticLogger2.LogError((object)("Error in Patch_Player_Login: " + ex.Message + "\n" + ex.StackTrace));
				}
			}
		}
	}
	[HarmonyPatch(typeof(Game), "Logout")]
	public static class Patch_Player_Logout
	{
		[HarmonyPrefix]
		public static void Prefix()
		{
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null))
				{
					ManualLogSource staticLogger = ValheimClientLogger.StaticLogger;
					if (staticLogger != null)
					{
						staticLogger.LogInfo((object)("[CLIENT] Player logging out: " + localPlayer.GetPlayerName()));
					}
					Dictionary<string, object> eventData = new Dictionary<string, object>
					{
						["timestamp"] = DateTime.UtcNow.ToString("o"),
						["serverName"] = ValheimClientLogger.ServerName.Value,
						["eventType"] = "player_logout",
						["playerName"] = localPlayer.GetPlayerName(),
						["playerID"] = localPlayer.GetPlayerID().ToString(),
						["details"] = new Dictionary<string, object>
						{
							["position"] = new Dictionary<string, object>
							{
								["x"] = ((Component)localPlayer).transform.position.x,
								["y"] = ((Component)localPlayer).transform.position.y,
								["z"] = ((Component)localPlayer).transform.position.z
							},
							["playTime"] = Time.time
						}
					};
					ValheimClientLogger.SendEventToServer("player_logout", eventData);
					Patch_Player_Login._hasLogged = false;
					Patch_Skills_RaiseSkill.ResetTracking();
					Thread.Sleep(500);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource staticLogger2 = ValheimClientLogger.StaticLogger;
				if (staticLogger2 != null)
				{
					staticLogger2.LogError((object)("Error in Patch_Player_Logout: " + ex.Message + "\n" + ex.StackTrace));
				}
			}
		}
	}
	[HarmonyPatch(typeof(Skills), "RaiseSkill")]
	public static class Patch_Skills_RaiseSkill
	{
		private static Dictionary<SkillType, int> _lastLoggedLevel = new Dictionary<SkillType, int>();

		public static void ResetTracking()
		{
			_lastLoggedLevel.Clear();
		}

		[HarmonyPostfix]
		public static void Postfix(Skills __instance, SkillType skillType, float factor)
		{
			//IL_0071: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				object? obj = typeof(Skills).GetField("m_player", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(__instance);
				Player val = (Player)((obj is Player) ? obj : null);
				if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer || !(typeof(Skills).GetField("m_skillData", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(__instance) is Dictionary<SkillType, Skill> dictionary) || !dictionary.ContainsKey(skillType))
				{
					return;
				}
				int num = (int)dictionary[skillType].m_level;
				if (!_lastLoggedLevel.ContainsKey(skillType) || _lastLoggedLevel[skillType] < num)
				{
					int num2 = (_lastLoggedLevel.ContainsKey(skillType) ? _lastLoggedLevel[skillType] : (num - 1));
					_lastLoggedLevel[skillType] = num;
					ManualLogSource staticLogger = ValheimClientLogger.StaticLogger;
					if (staticLogger != null)
					{
						staticLogger.LogInfo((object)$"[CLIENT] Skill level up: {skillType} reached level {num} (was {num2})");
					}
					Dictionary<string, object> eventData = new Dictionary<string, object>
					{
						["timestamp"] = DateTime.UtcNow.ToString("o"),
						["serverName"] = ValheimClientLogger.ServerName.Value,
						["eventType"] = "skill_level_up",
						["playerName"] = val.GetPlayerName(),
						["playerID"] = val.GetPlayerID().ToString(),
						["details"] = new Dictionary<string, object>
						{
							["skillType"] = ((object)(SkillType)(ref skillType)).ToString(),
							["newLevel"] = num,
							["previousLevel"] = num2
						}
					};
					ValheimClientLogger.SendEventToServer("skill_raise", eventData);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource staticLogger2 = ValheimClientLogger.StaticLogger;
				if (staticLogger2 != null)
				{
					staticLogger2.LogError((object)("Error in Patch_Skills_RaiseSkill: " + ex.Message + "\n" + ex.StackTrace));
				}
			}
		}
	}
}