using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
[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("JarOfDirt_ServerPlugin")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("JarOfDirt_ServerPlugin")]
[assembly: AssemblyTitle("JarOfDirt_ServerPlugin")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 JarOfDirtPlugin
{
[BepInPlugin("jarofdirt.ServerPlugin", "JarOfDirt Server Plugin", "1.1.1")]
public class ServerPlugin : BaseUnityPlugin
{
public const string PluginGUID = "jarofdirt.ServerPlugin";
public const string PluginName = "JarOfDirt Server Plugin";
public const string PluginVersion = "1.1.1";
public const string ModpackHash = "4ef40130e9478ce0";
private static ManualLogSource _log;
private static Harmony _harmony;
private static readonly HashSet<string> BalrondClayPieces = new HashSet<string> { "clay_stair_bal", "ClayBeam_bal", "ClayCube_bal", "ClayPole_bal", "clayr_arch_bal", "ClayWall_bal", "clay_floor_2x2_bal" };
private static readonly HashSet<long> ValidatedPeers = new HashSet<long>();
private static readonly HashSet<long> ModpackVerifiedPeers = new HashSet<long>();
private static readonly HashSet<string> BlockedAdmins = new HashSet<string>();
private static readonly Dictionary<long, string> PeerSteamIds = new Dictionary<long, string>();
private static readonly HashSet<string> BlockedCommands = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"spawn", "give", "god", "ghost", "heal", "puke", "hair", "beard", "model", "raiseskill",
"resetskill", "resetcharacter", "event", "stopevent", "randomevent", "exploremap", "resetmap", "goto", "pos", "tame",
"hatch", "location", "genloc", "setpower", "resetenv", "wind", "resetwind", "freefly", "ffsmooth", "dpsdebug",
"save"
};
private void Awake()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Expected O, but got Unknown
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Expected O, but got Unknown
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Expected O, but got Unknown
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00d2: Expected O, but got Unknown
//IL_0156: Unknown result type (might be due to invalid IL or missing references)
//IL_0163: Expected O, but got Unknown
//IL_011b: Unknown result type (might be due to invalid IL or missing references)
//IL_0129: Expected O, but got Unknown
_log = ((BaseUnityPlugin)this).Logger;
_harmony = new Harmony("jarofdirt.ServerPlugin");
_harmony.Patch((MethodBase)AccessTools.Method(typeof(ZNet), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ServerPlugin), "ZNetAwake_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
_harmony.Patch((MethodBase)AccessTools.Method(typeof(ZNet), "RPC_PeerInfo", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ServerPlugin), "RPC_PeerInfo_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
MethodInfo methodInfo = AccessTools.Method(typeof(Terminal), "InputText", (Type[])null, (Type[])null);
if (methodInfo != null)
{
_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ServerPlugin), "Terminal_InputText_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
MethodInfo methodInfo2 = AccessTools.Method(typeof(ZNet), "Disconnect", new Type[1] { typeof(ZNetPeer) }, (Type[])null);
if (methodInfo2 != null)
{
_harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(ServerPlugin), "ZNet_Disconnect_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
_harmony.Patch((MethodBase)AccessTools.Method(typeof(ZNetScene), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ServerPlugin), "ZNetScene_Awake_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
_log.LogInfo((object)"JarOfDirt Server Plugin v1.1.1 loaded (modpack hash: 4ef40130e9478ce0)");
}
private static void ZNetAwake_Postfix(ZNet __instance)
{
ValidatedPeers.Clear();
ModpackVerifiedPeers.Clear();
BlockedAdmins.Clear();
PeerSteamIds.Clear();
ZRoutedRpc.instance.Register<string>("JOD_Validate", (Action<long, string>)RPC_ServerOnValidate);
bool flag = __instance.IsServer();
_log.LogInfo((object)$"ZNet initialized (server={flag})");
if (!flag)
{
((MonoBehaviour)__instance).StartCoroutine(ClientSendValidation());
}
}
private static IEnumerator ClientSendValidation()
{
for (float waited = 0f; waited < 30f; waited += 1f)
{
if ((Object)(object)ZNet.instance == (Object)null)
{
yield break;
}
ZNetPeer serverPeer = ZNet.instance.GetServerPeer();
if (serverPeer != null && serverPeer.IsReady())
{
break;
}
yield return (object)new WaitForSeconds(1f);
}
yield return (object)new WaitForSeconds(3f);
if ((Object)(object)ZNet.instance != (Object)null && ZRoutedRpc.instance != null)
{
ZRoutedRpc.instance.InvokeRoutedRPC("JOD_Validate", new object[1] { "4ef40130e9478ce0" });
_log.LogInfo((object)"Sent JOD_Validate to server (hash: 4ef40130e9478ce0)");
}
}
private static void RPC_ServerOnValidate(long sender, string clientHash)
{
if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
{
return;
}
ValidatedPeers.Add(sender);
bool flag = string.Equals(clientHash, "4ef40130e9478ce0", StringComparison.OrdinalIgnoreCase);
if (flag)
{
ModpackVerifiedPeers.Add(sender);
_log.LogInfo((object)$"Peer {sender} validated - plugin present, modpack hash MATCHES");
}
else
{
_log.LogWarning((object)string.Format("Peer {0} validated - plugin present, but modpack hash MISMATCH (client: {1}, server: {2})", sender, clientHash, "4ef40130e9478ce0"));
try
{
ZRoutedRpc.instance.InvokeRoutedRPC(sender, "ShowMessage", new object[2] { 2, "Your modpack is outdated! Please update JarOfDirt_Valheim in your mod manager." });
}
catch
{
}
if (PeerSteamIds.TryGetValue(sender, out var value))
{
BlockedAdmins.Add(value);
_log.LogWarning((object)("Admin blocked for " + value + " due to modpack mismatch"));
}
}
if (flag && PeerSteamIds.TryGetValue(sender, out var value2) && BlockedAdmins.Remove(value2))
{
_log.LogInfo((object)("Late validation from " + value2 + " - restoring admin access"));
}
}
private static void RPC_PeerInfo_Postfix(ZRpc rpc, ZNet __instance)
{
if (!__instance.IsServer())
{
return;
}
ZNetPeer val = null;
foreach (ZNetPeer peer in __instance.GetPeers())
{
if (peer.m_rpc == rpc)
{
val = peer;
break;
}
}
if (val == null)
{
return;
}
string hostName = val.m_socket.GetHostName();
long uid = val.m_uid;
PeerSteamIds[uid] = hostName;
_log.LogInfo((object)$"Peer connected: UID={uid}, SteamID={hostName}");
try
{
object value = Traverse.Create((object)__instance).Field("m_adminList").GetValue();
if (value != null)
{
MethodInfo method = value.GetType().GetMethod("Contains", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(string) }, null);
if (method != null && (bool)method.Invoke(value, new object[1] { hostName }))
{
_log.LogInfo((object)$"Peer {uid} ({hostName}) is admin - starting validation timer");
((MonoBehaviour)__instance).StartCoroutine(ValidateAdminPeer(uid, hostName));
}
}
}
catch (Exception ex)
{
_log.LogError((object)("Error checking admin list: " + ex.Message));
}
}
private static IEnumerator ValidateAdminPeer(long uid, string steamId)
{
yield return (object)new WaitForSeconds(20f);
if (!ValidatedPeers.Contains(uid))
{
_log.LogWarning((object)$"Admin peer {uid} ({steamId}) has NO JarOfDirt plugin - blocking admin");
BlockedAdmins.Add(steamId);
try
{
ZRoutedRpc.instance.InvokeRoutedRPC(uid, "ShowMessage", new object[2] { 2, "Admin access requires JarOfDirt modpack. Install the modpack to receive admin." });
yield break;
}
catch
{
yield break;
}
}
if (!ModpackVerifiedPeers.Contains(uid))
{
_log.LogWarning((object)$"Admin peer {uid} ({steamId}) has outdated modpack - admin blocked");
}
else
{
_log.LogInfo((object)$"Admin peer {uid} ({steamId}) fully validated - plugin present, modpack current");
}
}
private static void ZNet_Disconnect_Prefix(ZNetPeer peer)
{
if (peer != null)
{
long uid = peer.m_uid;
ValidatedPeers.Remove(uid);
ModpackVerifiedPeers.Remove(uid);
if (PeerSteamIds.TryGetValue(uid, out var value))
{
BlockedAdmins.Remove(value);
PeerSteamIds.Remove(uid);
}
}
}
private static bool Terminal_InputText_Prefix(Terminal __instance)
{
if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
{
return true;
}
try
{
object value = Traverse.Create((object)__instance).Field("m_input").GetValue();
if (value == null)
{
return true;
}
PropertyInfo property = value.GetType().GetProperty("text");
if (property == null)
{
return true;
}
string text = (string)property.GetValue(value);
if (string.IsNullOrEmpty(text))
{
return true;
}
string text2 = text.Trim();
if (text2.StartsWith("/"))
{
text2 = text2.Substring(1);
}
text2 = text2.Split(new char[1] { ' ' })[0].ToLower();
if (BlockedCommands.Contains(text2))
{
__instance.AddString("<color=orange>[JarOfDirt]</color> <color=red>Command '" + text2 + "' is restricted by server policy.</color>");
PropertyInfo property2 = value.GetType().GetProperty("text");
if (property2 != null)
{
property2.SetValue(value, "");
}
return false;
}
}
catch (Exception ex)
{
_log.LogError((object)("Error in command filter: " + ex.Message));
}
return true;
}
private static void ZNetScene_Awake_Postfix(ZNetScene __instance)
{
if (!((Object)(object)__instance == (Object)null))
{
((MonoBehaviour)__instance).StartCoroutine(DelayedRemoveBalrondClay(__instance));
}
}
private static IEnumerator DelayedRemoveBalrondClay(ZNetScene scene)
{
yield return null;
yield return null;
yield return null;
if ((Object)(object)scene == (Object)null)
{
yield break;
}
int num = 0;
int num2 = scene.m_prefabs.RemoveAll((GameObject prefab) => (Object)(object)prefab != (Object)null && BalrondClayPieces.Contains(((Object)prefab).name));
try
{
Dictionary<int, GameObject> value = Traverse.Create((object)scene).Field("m_namedPrefabs").GetValue<Dictionary<int, GameObject>>();
if (value != null)
{
List<int> list = new List<int>();
foreach (KeyValuePair<int, GameObject> item in value)
{
if ((Object)(object)item.Value != (Object)null && BalrondClayPieces.Contains(((Object)item.Value).name))
{
list.Add(item.Key);
}
}
foreach (int item2 in list)
{
value.Remove(item2);
}
}
}
catch
{
}
foreach (GameObject prefab in scene.m_prefabs)
{
if ((Object)(object)prefab == (Object)null)
{
continue;
}
ItemDrop component = prefab.GetComponent<ItemDrop>();
if ((Object)(object)component == (Object)null)
{
continue;
}
PieceTable val = component.m_itemData?.m_shared?.m_buildPieces;
if (!((Object)(object)val == (Object)null))
{
int num3 = val.m_pieces.RemoveAll((GameObject piece) => (Object)(object)piece != (Object)null && BalrondClayPieces.Contains(((Object)piece).name));
num += num3;
}
}
if (num2 > 0 || num > 0)
{
_log.LogInfo((object)$"Removed Balrond clay pieces: {num2} from ZNetScene, {num} from PieceTables");
}
else
{
_log.LogInfo((object)"Balrond clay piece removal: none found (already removed or not loaded)");
}
}
}
}