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));
}
}
}
}
}