using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Extensions;
using Jotunn.Utils;
using Logging;
using Microsoft.CodeAnalysis;
using Steamworks;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("NetworkTweaks")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("NetworkTweaks")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("08a6f7d7-cf93-4931-aecd-abf2ce6ed34c")]
[assembly: AssemblyFileVersion("0.1.5")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.5.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 NetworkTweaks
{
internal static class ModCompat
{
internal const string NetworkGUID = "org.bepinex.plugins.network";
internal const string ReturnToSenderGUID = "redseiko.valheim.returntosender";
internal static bool IsNetworkInstalled => IsPluginInstalled("org.bepinex.plugins.network");
internal static bool IsReturnToSenderInstalled => IsPluginInstalled("redseiko.valheim.returntosender");
internal static bool HasIncompatibleMods()
{
bool isNetworkInstalled = IsNetworkInstalled;
bool isReturnToSenderInstalled = IsReturnToSenderInstalled;
if (isNetworkInstalled)
{
Log.LogWarning("Incompatible mod: org.bepinex.plugins.network is installed!");
}
if (isReturnToSenderInstalled)
{
Log.LogWarning("Incompatible mod: redseiko.valheim.returntosender is installed!");
}
return isNetworkInstalled || isReturnToSenderInstalled;
}
private static bool IsPluginInstalled(string pluginGUID)
{
return Chainloader.PluginInfos.ContainsKey(pluginGUID);
}
}
[BepInPlugin("Searica.Valheim.NetworkTweaks", "NetworkTweaks", "0.1.5")]
[BepInDependency("com.jotunn.jotunn", "2.24.2")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
internal sealed class NetworkTweaks : BaseUnityPlugin
{
public const string PluginName = "NetworkTweaks";
internal const string Author = "Searica";
public const string PluginGUID = "Searica.Valheim.NetworkTweaks";
public const string PluginVersion = "0.1.5";
internal static NetworkTweaks Instance;
internal static ConfigFile ConfigFile;
internal const string GlobalSection = "Global";
internal ConfigEntry<int> PeersPerUpdate;
public void Awake()
{
Instance = this;
ConfigFile = ((BaseUnityPlugin)this).Config;
Log.Init(((BaseUnityPlugin)this).Logger);
((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
SetUpConfigEntries();
((BaseUnityPlugin)this).Config.Save();
((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
if (ModCompat.HasIncompatibleMods())
{
Log.LogWarning("Incompatible mods detected, NetworkTweaks will not load!");
return;
}
Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "Searica.Valheim.NetworkTweaks");
Game.isModded = true;
}
internal void SetUpConfigEntries()
{
PeersPerUpdate = ConfigFileExtensions.BindConfigInOrder<int>(((BaseUnityPlugin)this).Config, "Global", "Peers Per Update", 10, "Number of peers to sync data to each update tick. Vanilla default is 1. The higher this is the more data needs to be transferred each update tick.", true, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
}
public void OnDestroy()
{
((BaseUnityPlugin)this).Config.Save();
}
}
}
namespace NetworkTweaks.Patches
{
[HarmonyPatch]
internal static class SteamDataTransferPatches
{
private const int VanillaTransferRate = 153600;
private const int MaxTransferRate = 50000000;
private const int BufferSize = 100000000;
[HarmonyTranspiler]
[HarmonyPatch(typeof(ZSteamSocket), "RegisterGlobalCallbacks")]
private static IEnumerable<CodeInstruction> ChangeSendingLimitTranspiler(IEnumerable<CodeInstruction> instructions)
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Expected O, but got Unknown
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Expected O, but got Unknown
CodeMatch[] array = (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Ldc_I4, (object)153600, (string)null)
};
return new CodeMatcher(instructions, (ILGenerator)null).MatchForward(false, array).ThrowIfInvalid("Could not patch ZSteamSocket.RegisterGlobalCallbacks()!").SetInstructionAndAdvance(new CodeInstruction(OpCodes.Ldc_I4, (object)50000000))
.InstructionEnumeration();
}
[HarmonyPostfix]
[HarmonyPatch(typeof(ZSteamSocket), "RegisterGlobalCallbacks")]
private static void IncreaseSendBufferSize()
{
if (!(CSteamAPIContext.GetSteamClient() == IntPtr.Zero))
{
GCHandle gCHandle = GCHandle.Alloc(100000000, GCHandleType.Pinned);
SteamNetworkingUtils.SetConfigValue((ESteamNetworkingConfigValue)9, (ESteamNetworkingConfigScope)1, IntPtr.Zero, (ESteamNetworkingConfigDataType)1, gCHandle.AddrOfPinnedObject());
gCHandle.Free();
}
}
}
[HarmonyPatch]
internal static class ZDOToPeersPatches
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(ZDOMan), "Update")]
private static IEnumerable<CodeInstruction> UpdateTranspiler(IEnumerable<CodeInstruction> instructions)
{
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Expected O, but got Unknown
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
CodeMatch val = new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(ZDOMan), "SendZDOToPeers2", (Type[])null, (Type[])null), (string)null);
return new CodeMatcher(instructions, (ILGenerator)null).Start().MatchStartForward((CodeMatch[])(object)new CodeMatch[1] { val }).ThrowIfInvalid("Could not patch ZDOMan.Update()! (send-zdo-to-peers)")
.SetOperandAndAdvance((object)AccessTools.Method(typeof(ZDOToPeersPatches), "SendZDOToPeers", (Type[])null, (Type[])null))
.InstructionEnumeration();
}
private static void SendZDOToPeers(ZDOMan zdoManager, float dt)
{
int count = zdoManager.m_peers.Count;
if (count <= 0)
{
return;
}
zdoManager.m_sendTimer += dt;
if (!(zdoManager.m_sendTimer < 0.05f))
{
zdoManager.m_sendTimer = 0f;
List<ZDOPeer> peers = zdoManager.m_peers;
int num = Math.Max(zdoManager.m_nextSendPeer, 0);
int num2 = Math.Min(num + NetworkTweaks.Instance.PeersPerUpdate.Value, count);
for (int i = num; i < num2; i++)
{
zdoManager.SendZDOs(peers[i], false);
}
zdoManager.m_nextSendPeer = ((num2 < count) ? num2 : 0);
}
}
}
[HarmonyPatch]
internal static class ZPkgBufferPatches
{
private static readonly List<ZPackage> zpkgBuffer = new List<ZPackage>();
[HarmonyPostfix]
[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
private static void StartBuffering(ZNet __instance, ZNetPeer peer)
{
if (Object.op_Implicit((Object)(object)__instance) && !__instance.IsServer())
{
peer.m_rpc.Register<ZPackage>("ZDOData", (Action<ZRpc, ZPackage>)delegate(ZRpc _, ZPackage package)
{
zpkgBuffer.Add(package);
});
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(ZNet), "Shutdown")]
private static void ClearBufferOnShutdown()
{
zpkgBuffer.Clear();
}
[HarmonyPostfix]
[HarmonyPatch(typeof(ZDOMan), "AddPeer")]
private static void ParseBufferedZPackages(ZDOMan __instance, ZNetPeer netPeer)
{
foreach (ZPackage item in zpkgBuffer)
{
__instance.RPC_ZDOData(netPeer.m_rpc, item);
}
zpkgBuffer.Clear();
}
}
}
namespace Logging
{
internal static class Log
{
internal enum InfoLevel
{
Low,
Medium,
High
}
private static ManualLogSource logSource;
internal static ConfigEntry<InfoLevel> Verbosity { get; set; }
internal static InfoLevel VerbosityLevel => Verbosity.Value;
internal static bool IsVerbosityLow => Verbosity.Value >= InfoLevel.Low;
internal static bool IsVerbosityMedium => Verbosity.Value >= InfoLevel.Medium;
internal static bool IsVerbosityHigh => Verbosity.Value >= InfoLevel.High;
internal static void Init(ManualLogSource logSource)
{
Log.logSource = logSource;
}
internal static void LogDebug(object data)
{
logSource.LogDebug(data);
}
internal static void LogError(object data)
{
logSource.LogError(data);
}
internal static void LogFatal(object data)
{
logSource.LogFatal(data);
}
internal static void LogMessage(object data)
{
logSource.LogMessage(data);
}
internal static void LogWarning(object data)
{
logSource.LogWarning(data);
}
internal static void LogInfo(object data, InfoLevel level = InfoLevel.Low)
{
if (Verbosity == null || VerbosityLevel >= level)
{
logSource.LogInfo(data);
}
}
internal static void LogGameObject(GameObject prefab, bool includeChildren = false)
{
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Expected O, but got Unknown
LogInfo("***** " + ((Object)prefab).name + " *****");
Component[] components = prefab.GetComponents<Component>();
for (int i = 0; i < components.Length; i++)
{
LogComponent(components[i]);
}
if (!includeChildren)
{
return;
}
LogInfo("***** " + ((Object)prefab).name + " (children) *****");
foreach (Transform item in prefab.transform)
{
Transform val = item;
if (Object.op_Implicit((Object)(object)val))
{
LogInfo(" - " + ((Object)val).name);
components = ((Component)val).GetComponents<Component>();
for (int i = 0; i < components.Length; i++)
{
LogComponent(components[i]);
}
}
}
}
internal static void LogComponent(Component compo)
{
if (!Object.op_Implicit((Object)(object)compo))
{
return;
}
try
{
LogInfo("--- " + ((object)compo).GetType().Name + ": " + ((Object)compo).name + " ---");
}
catch (Exception ex)
{
LogError(ex.ToString());
LogWarning("Could not get type name for component!");
return;
}
try
{
foreach (PropertyInfo declaredProperty in AccessTools.GetDeclaredProperties(((object)compo).GetType()))
{
try
{
LogInfo($" - {declaredProperty.Name} = {declaredProperty.GetValue(compo)}");
}
catch (Exception ex2)
{
LogError(ex2.ToString());
LogWarning("Could not get property: " + declaredProperty.Name + " for component!");
}
}
}
catch (Exception ex3)
{
LogError(ex3.ToString());
LogWarning("Could not get properties for component!");
}
try
{
foreach (FieldInfo declaredField in AccessTools.GetDeclaredFields(((object)compo).GetType()))
{
try
{
LogInfo($" - {declaredField.Name} = {declaredField.GetValue(compo)}");
}
catch (Exception ex4)
{
LogError(ex4.ToString());
LogWarning("Could not get field: " + declaredField.Name + " for component!");
}
}
}
catch (Exception ex5)
{
LogError(ex5.ToString());
LogWarning("Could not get fields for component!");
}
}
}
}