using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ArgusMagnus")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("ArgusMagnus")] [assembly: AssemblyDescription("Various multiplayer tweaks")] [assembly: AssemblyFileVersion("1.99.8.0")] [assembly: AssemblyInformationalVersion("1.99.8-beta+328851184cc278c858ffbc70e717af9f9d7b6973")] [assembly: AssemblyProduct("ServersideQoL.MultiplayerTweaks")] [assembly: AssemblyTitle("ServersideQoL.MultiplayerTweaks")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ArgusMagnus/ValheimServersideQoL")] [assembly: AssemblyVersion("1.99.8.0")] [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 ServersideQoL.MultiplayerTweaks { public sealed class Config : ConfigBase { public sealed class AdvancedConfig { public float MaxTimeSinceLastPingSeconds { get; init; } = 1.5f; } private const string Section = "MultiplayerTweaks"; public override ConfigEntry Enabled { get; } = ConfigBase.BindEx(cfg, "MultiplayerTweaks", true, "Enables/disables the entire mod", (AcceptableValueBase)null, (Deprecated)null, "Enabled"); public ConfigEntry ForcePlayerMapPin { get; } = ConfigBase.BindEx(cfg, "MultiplayerTweaks", false, "True to force player map pins to be visible for all players", (AcceptableValueBase)null, (Deprecated)null, "ForcePlayerMapPin"); public ConfigEntry AssignInteractablesToClosestPlayer { get; } = ConfigBase.BindEx(cfg, "MultiplayerTweaks", false, "True to assign ownership of some interactable objects (such as smelters or cooking stations) to the closest player.\r\nThis should help avoiding the loss of ore, etc. due to networking issues.", (AcceptableValueBase)null, (Deprecated)null, "AssignInteractablesToClosestPlayer"); public ConfigEntry AssignMobsToClosestPlayer { get; } = ConfigBase.BindEx(cfg, "MultiplayerTweaks", false, "True to assign ownership of hostile mobs to the closest player.\r\nThis should help reduce issues with dodging/parrying due to networking issues.", (AcceptableValueBase)null, (Deprecated)null, "AssignMobsToClosestPlayer"); public ConfigEntry AssignShipsToCaptain { get; } = ConfigBase.BindEx(cfg, "MultiplayerTweaks", false, "True to assign ownership of ships to the player controlling the ship.\r\nThis should help reduce issues with ship control due to networking issues.", (AcceptableValueBase)null, (Deprecated)null, "AssignShipsToCaptain"); public YamlConfigEntry Advanced { get; } = ConfigBase.BindYaml(cfg, "Advanced"); public Config(ConfigFile cfg, Logger logger) : base(cfg, logger) { } } [BepInPlugin("ArgusMagnus.ServersideQoL.MultiplayerTweaks", "ServersideQoL.MultiplayerTweaks", "1.99.8")] public sealed class MultiplayerTweaksPlugin : ServersideQoLPluginBase { public const string Author = "ArgusMagnus"; public const string PluginName = "ServersideQoL.MultiplayerTweaks"; public const string PluginGuid = "ArgusMagnus.ServersideQoL.MultiplayerTweaks"; public const string PluginVersion = "1.99.8"; public const string PluginInformationalVersion = "1.99.8-beta"; internal static Harmony HarmonyInstance { get; } = new Harmony("ArgusMagnus.ServersideQoL.MultiplayerTweaks"); private DateTimeOffset BuildTimestamp { get; } = new DateTimeOffset(639215507746036581L, default(TimeSpan)); protected override Config CreateConfigSingleton(ConfigFile configFile, Logger logger) { return new Config(configFile, logger); } protected override void RegisterProcessors(IProcessorCollection processors) { processors.Add(); } private void Awake() { ServersideQoLPluginBase.Logger.LogWarning((object)string.Format("You are running a pre-release version: {0} ({1})", "1.99.8-beta", BuildTimestamp.LocalDateTime)); } } [Processor("71988cd7-0b04-4603-8759-21ab8585ac05")] [DependsOn] public sealed class Processor : Processor { public sealed record PrefabInfo(Ship? Ship, Smelter? Smelter, CookingStation? CookingStation, Character? Character) : ProcessorPrefabInfo() { [CompilerGenerated] public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("PrefabInfo"); stringBuilder.Append(" { "); if (((ProcessorPrefabInfo)this).PrintMembers(stringBuilder)) { stringBuilder.Append(' '); } stringBuilder.Append('}'); return stringBuilder.ToString(); } [CompilerGenerated] protected override bool PrintMembers(StringBuilder builder) { if (((ProcessorPrefabInfo)this).PrintMembers(builder)) { builder.Append(", "); } builder.Append("Ship = "); builder.Append(Ship); builder.Append(", Smelter = "); builder.Append(Smelter); builder.Append(", CookingStation = "); builder.Append(CookingStation); builder.Append(", Character = "); builder.Append(Character); return true; } [CompilerGenerated] public override int GetHashCode() { return (((((ProcessorPrefabInfo)this).GetHashCode() * -1521134295 + EqualityComparer.Default.GetHashCode(Ship)) * -1521134295 + EqualityComparer.Default.GetHashCode(Smelter)) * -1521134295 + EqualityComparer.Default.GetHashCode(CookingStation)) * -1521134295 + EqualityComparer.Default.GetHashCode(Character); } [CompilerGenerated] public sealed override bool Equals(ProcessorPrefabInfo? other) { return ((object)this).Equals((object?)other); } [CompilerGenerated] public bool Equals(PrefabInfo? other) { if ((object)this != other) { if (((ProcessorPrefabInfo)this).Equals((ProcessorPrefabInfo)(object)other) && EqualityComparer.Default.Equals(Ship, other.Ship) && EqualityComparer.Default.Equals(Smelter, other.Smelter) && EqualityComparer.Default.Equals(CookingStation, other.CookingStation)) { return EqualityComparer.Default.Equals(Character, other.Character); } return false; } return true; } [CompilerGenerated] private PrefabInfo(PrefabInfo original) : base((ProcessorPrefabInfo)(object)original) { Ship = original.Ship; Smelter = original.Smelter; CookingStation = original.CookingStation; Character = original.Character; } } [HarmonyPatch(typeof(ZNet), "RPC_ServerSyncedPlayerData")] private static class ZNetServerSyncedPlayerDataPatch { [HarmonyPostfix] public static void Postfix(ZNet __instance) { if (!ConfigBase.Instance.ForcePlayerMapPin.Value) { return; } foreach (ZNetPeer peer in __instance.GetPeers()) { peer.m_publicRefPos = true; } } } private bool _patched; private Timestamp _maxOwnerTimestamp; protected override void Initialize() { if (!_patched && ConfigBase.Instance.ForcePlayerMapPin.Value) { _patched = true; MultiplayerTweaksPlugin.HarmonyInstance.PatchAll(typeof(ZNetServerSyncedPlayerDataPatch)); } } protected override void PreProcess(PeersEnumerable peers) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) Timestamp now = Timestamp.Now; _maxOwnerTimestamp = ((Timestamp)(ref now)).AddSeconds(2f); } protected override ProcessResult Process(ServersideQoLZDO zdo, IReadOnlyList peers, PrefabInfo prefabInfo) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) if (zdo.ZDO.Persistent) { if (prefabInfo.Ship != null && ConfigBase.Instance.AssignShipsToCaptain.Value) { ZDOVars vars = zdo.Vars; long user = ((ZDOVars)(ref vars)).GetUser(0L); PlayerState stateForPlayerID = Processor.Instance().GetStateForPlayerID(user); if (stateForPlayerID != null) { zdo.ZDO.SetOwner(stateForPlayerID.Owner); } return (ProcessResult)0; } if (ShouldAssignToClosestPlayer(zdo, prefabInfo)) { int count = peers.Count; if (count > 1 && zdo.OwnerTimestamp < _maxOwnerTimestamp) { Peer val = null; float num = float.MaxValue; Enumerator enumerator = ListExtensions.Enumerate(peers).GetEnumerator(); try { while (enumerator.MoveNext()) { Peer current = enumerator.Current; PlayerState playerState = current.PlayerState; if (playerState != null) { float num2 = Utils.DistanceSqr(zdo.ZDO.GetPosition(), playerState.ZDO.ZDO.GetPosition()); if (num2 < num) { num = num2; val = current; } } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (((val != null) ? new float?(val.ZNetPeer.m_rpc.GetTimeSinceLastPing()) : ((float?)null)) < ConfigBase.Instance.Advanced.Value.MaxTimeSinceLastPingSeconds) { zdo.ZDO.SetOwner(val.ZNetPeer.m_uid); } } return (ProcessResult)32; } return (ProcessResult)2; } return (ProcessResult)2; } private bool ShouldAssignToClosestPlayer(ServersideQoLZDO zdo, PrefabInfo prefabInfo) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (!ConfigBase.Instance.AssignInteractablesToClosestPlayer.Value || ((object)prefabInfo != null && prefabInfo.Smelter == null && prefabInfo.CookingStation == null)) { if (ConfigBase.Instance.AssignMobsToClosestPlayer.Value && prefabInfo.Character != null) { ZDOVars vars = zdo.Vars; return !((ZDOVars)(ref vars)).GetTamed(false); } return false; } return true; } } }