Decompiled source of SeedSeer v1.0.0

SeedSeer.dll

Decompiled 4 days 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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Splatform;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Jubaroo")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © 2026 Jubaroo")]
[assembly: AssemblyDescription("Logs the world seed on server startup so you always know what seed your dedicated server is running — by Jubaroo")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SeedSeer")]
[assembly: AssemblyTitle("SeedSeer")]
[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 SeedSeer
{
	[BepInPlugin("com.jubaroo.seedseer", "SeedSeer", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__10_0;

			internal void <Awake>b__10_0(ConsoleEventArgs args)
			{
				Console instance = Console.instance;
				if (instance != null)
				{
					((Terminal)instance).AddString(SeedText);
				}
				if ((Object)(object)MessageHud.instance != (Object)null)
				{
					MessageHud.instance.ShowMessage((MessageType)1, SeedText, 0, (Sprite)null, false, true);
				}
			}
		}

		public const string PluginGuid = "com.jubaroo.seedseer";

		public const string PluginName = "SeedSeer";

		public const string PluginVersion = "1.0.0";

		public static ManualLogSource Log = null;

		public static string WorldSeedName = "";

		public static int WorldSeedHash;

		public static ConfigEntry<bool> ShowOnSpawn = null;

		public static ConfigEntry<bool> AdminOnlyCommand = null;

		public static string SeedText
		{
			get
			{
				if (!string.IsNullOrEmpty(WorldSeedName))
				{
					return $"World seed: \"{WorldSeedName}\" (hash: {WorldSeedHash})";
				}
				return "World seed: unknown (world not loaded yet)";
			}
		}

		private void Awake()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ShowOnSpawn = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowOnSpawn", true, "Client-side: show the world seed as an in-game message the first time your character spawns into a world.");
			AdminOnlyCommand = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AdminOnlyCommand", false, "Server-side: when true, only players listed in adminlist.txt receive a reply to the /seed chat command. When false, any player can request the seed.");
			new Harmony("com.jubaroo.seedseer").PatchAll();
			object obj = <>c.<>9__10_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate
				{
					Console instance = Console.instance;
					if (instance != null)
					{
						((Terminal)instance).AddString(SeedText);
					}
					if ((Object)(object)MessageHud.instance != (Object)null)
					{
						MessageHud.instance.ShowMessage((MessageType)1, SeedText, 0, (Sprite)null, false, true);
					}
				};
				<>c.<>9__10_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("seed", "Shows the current world seed (SeedSeer)", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			string[] commandLineArgs = Environment.GetCommandLineArgs();
			for (int num = 0; num < commandLineArgs.Length - 1; num++)
			{
				if (commandLineArgs[num].Equals("-seed", StringComparison.OrdinalIgnoreCase))
				{
					Log.LogInfo((object)("Launch argument -seed detected: " + commandLineArgs[num + 1]));
				}
			}
		}
	}
	[HarmonyPatch(typeof(WorldGenerator), "Initialize")]
	public static class WorldGeneratorInitializePatch
	{
		private static void Postfix(World world)
		{
			Plugin.WorldSeedName = world.m_seedName;
			Plugin.WorldSeedHash = world.m_seed;
			SeedSpawnMessagePatch.ShownForCurrentWorld = false;
			string text = "[SeedSeer] " + Plugin.SeedText;
			ZLog.Log((object)text);
			Plugin.Log.LogInfo((object)text);
		}
	}
	[HarmonyPatch(typeof(Player), "OnSpawned")]
	public static class SeedSpawnMessagePatch
	{
		public static bool ShownForCurrentWorld;

		private static void Postfix()
		{
			if (!ShownForCurrentWorld && Plugin.ShowOnSpawn.Value && !((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer() && !((Object)(object)MessageHud.instance == (Object)null) && !string.IsNullOrEmpty(Plugin.WorldSeedName))
			{
				ShownForCurrentWorld = true;
				MessageHud.instance.ShowMessage((MessageType)1, "[SeedSeer] " + Plugin.SeedText, 0, (Sprite)null, false, true);
			}
		}
	}
	[HarmonyPatch(typeof(ZRoutedRpc), "RouteRPC")]
	public static class SeedChatCommandPatch
	{
		private static readonly int SayHash = StringExtensionMethods.GetStableHashCode("Say");

		private static readonly int ChatMessageHash = StringExtensionMethods.GetStableHashCode("ChatMessage");

		private static readonly Dictionary<long, (string Text, float Time)> _recentCommands = new Dictionary<long, (string, float)>();

		private static void Postfix(RoutedRPCData rpcData)
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || (rpcData.m_methodHash != SayHash && rpcData.m_methodHash != ChatMessageHash))
			{
				return;
			}
			Vector3 pos;
			string text;
			try
			{
				ExtractMessage(rpcData, out text, out pos);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Failed to read chat payload: " + ex.Message));
				return;
			}
			text = text?.Trim() ?? "";
			if (text.Equals("/seed", StringComparison.OrdinalIgnoreCase) || text.Equals("!seed", StringComparison.OrdinalIgnoreCase))
			{
				long senderPeerID = rpcData.m_senderPeerID;
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				if (!_recentCommands.TryGetValue(senderPeerID, out (string, float) value) || !(value.Item1 == text) || !(realtimeSinceStartup - value.Item2 < 1f))
				{
					_recentCommands[senderPeerID] = (text, realtimeSinceStartup);
					ReplyWithSeed(senderPeerID, pos);
				}
			}
		}

		private static void ExtractMessage(RoutedRPCData rpcData, out string text, out Vector3 pos)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			ZPackage parameters = rpcData.m_parameters;
			parameters.SetPos(0);
			if (rpcData.m_methodHash == ChatMessageHash)
			{
				pos = parameters.ReadVector3();
				parameters.ReadInt();
			}
			else
			{
				parameters.ReadInt();
				pos = Vector3.zero;
				if (!((ZDOID)(ref rpcData.m_targetZDO)).IsNone())
				{
					ZDO zDO = ZDOMan.instance.GetZDO(rpcData.m_targetZDO);
					ZNetView val = ((zDO != null) ? ZNetScene.instance.FindInstance(zDO) : null);
					if ((Object)(object)val != (Object)null)
					{
						pos = ((Component)val).transform.position;
					}
				}
			}
			new UserInfo().Deserialize(ref parameters);
			text = parameters.ReadString();
		}

		private static void ReplyWithSeed(long senderPeerId, Vector3 pos)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			ZNet instance = ZNet.instance;
			ZNetPeer peer = instance.GetPeer(senderPeerId);
			if (peer != null)
			{
				string hostName = peer.m_socket.GetHostName();
				PlatformUserID val = default(PlatformUserID);
				((PlatformUserID)(ref val))..ctor(hostName);
				if (!Plugin.AdminOnlyCommand.Value || instance.PlayerIsAdmin(val) || instance.IsAdmin(hostName))
				{
					string text = "[SeedSeer] " + Plugin.SeedText;
					ZRoutedRpc.instance.InvokeRoutedRPC(senderPeerId, "ChatMessage", new object[4]
					{
						pos,
						0,
						(object)new UserInfo
						{
							Name = "SeedSeer",
							UserId = val
						},
						text
					});
					ZLog.Log((object)$"[SeedSeer] Sent world seed to peer {senderPeerId} ({peer.m_playerName})");
				}
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}