using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
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.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("VAGhettoNetworking")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VAGhettoNetworking")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("f234bd11-429c-45e2-b280-1fb9121d050d")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[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 FiresGhettoNetworkMod
{
[BepInPlugin("com.Fire.FiresGhettoNetworkMod", "FiresGhettoNetworkMod", "1.2.0")]
public class FiresGhettoNetworkMod : BaseUnityPlugin
{
[HarmonyPatch]
public static class WackyDatabaseCompatibilityPatch
{
public static void Init(Harmony harmony)
{
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Expected O, but got Unknown
Type type = Type.GetType("wackydatabase.Util.Functions, WackysDatabase");
if (type == null)
{
LoggerOptions.LogInfo("WackyDatabase not detected — skipping compatibility patch.");
return;
}
MethodInfo method = type.GetMethod("SnapshotItem", BindingFlags.Static | BindingFlags.Public);
if (method == null)
{
LoggerOptions.LogWarning("WackyDatabase detected but SnapshotItem method not found — patch skipped.");
return;
}
harmony.Patch((MethodBase)method, new HarmonyMethod(typeof(WackyDatabaseCompatibilityPatch), "SnapshotItem_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
LoggerOptions.LogInfo("WackyDatabase compatibility patch applied — will skip snapshots for invalid/broken clones.");
}
[HarmonyPrefix]
public static bool SnapshotItem_Prefix(ref ItemDrop item)
{
if ((Object)(object)item == (Object)null)
{
LoggerOptions.LogWarning("WDB: Skipping snapshot for null ItemDrop (likely broken clone).");
return false;
}
if ((Object)(object)((Component)item).gameObject == (Object)null)
{
LoggerOptions.LogWarning("WDB: Skipping snapshot for " + ((Object)item).name + " — gameObject is null (missing prefab from removed mod).");
return false;
}
bool flag = ((Component)item).GetComponentsInChildren<Renderer>(true).Length != 0;
bool flag2 = ((Component)item).GetComponentsInChildren<MeshFilter>(true).Length != 0;
if (!flag && !flag2)
{
LoggerOptions.LogWarning("WDB: Skipping snapshot for " + ((Object)item).name + " — no renderers or meshes (broken model).");
return false;
}
return true;
}
}
[CompilerGenerated]
private sealed class <RegisterDummyRpcWhenReady>d__41 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public FiresGhettoNetworkMod <>4__this;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <RegisterDummyRpcWhenReady>d__41(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
break;
case 1:
<>1__state = -1;
break;
}
if (ZRoutedRpc.instance == null)
{
<>2__current = null;
<>1__state = 1;
return true;
}
if (_dummyRpcRegistered)
{
((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"Dummy ForceUpdateZDO RPC already registered — skipping.");
return false;
}
ZRoutedRpc.instance.Register("ForceUpdateZDO", (Action<long>)delegate
{
});
_dummyRpcRegistered = true;
((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"Dummy ForceUpdateZDO RPC registered.");
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
public const string PluginGUID = "com.Fire.FiresGhettoNetworkMod";
public const string PluginName = "FiresGhettoNetworkMod";
public const string PluginVersion = "1.2.0";
public static ConfigEntry<LogLevel> ConfigLogLevel;
public static ConfigEntry<bool> ConfigEnableCompression;
public static ConfigEntry<UpdateRateOptions> ConfigUpdateRate;
public static ConfigEntry<SendRateMinOptions> ConfigSendRateMin;
public static ConfigEntry<SendRateMaxOptions> ConfigSendRateMax;
public static ConfigEntry<QueueSizeOptions> ConfigQueueSize;
public static ConfigEntry<ForceCrossplayOptions> ConfigForceCrossplay;
public static ConfigEntry<int> ConfigPlayerLimit;
public static ConfigEntry<bool> ConfigEnableShipFixes;
public static ConfigEntry<bool> ConfigEnableServerSideShipSimulation;
public static ConfigEntry<int> ConfigExtendedZoneRadius;
public static ConfigEntry<bool> ConfigEnableZDOThrottling;
public static ConfigEntry<float> ConfigZDOThrottleDistance;
public static ConfigEntry<bool> ConfigEnableAILOD;
public static ConfigEntry<float> ConfigAILODNearDistance;
public static ConfigEntry<float> ConfigAILODFarDistance;
public static ConfigEntry<float> ConfigAILODThrottleFactor;
public static ConfigEntry<int> ConfigZoneLoadBatchSize;
public static ConfigEntry<int> ConfigZPackageReceiveBufferSize;
public static ConfigEntry<bool> ConfigEnableRpcRouter;
public static ConfigEntry<bool> ConfigEnableRpcAoI;
public static ConfigEntry<float> ConfigRpcAoIRadius;
public static ConfigEntry<bool> ConfigEnableZDODelta;
public static ConfigEntry<bool> ConfigEnableWNTServerOptimization;
public static ConfigEntry<bool> ConfigEnableServerAuthority;
private static bool _dummyRpcRegistered;
private bool _delayedInitDone = false;
internal static Harmony Harmony { get; private set; }
private void Awake()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Expected O, but got Unknown
Harmony = new Harmony("com.Fire.FiresGhettoNetworkMod");
BindConfigs();
try
{
((BaseUnityPlugin)this).Config.Save();
}
catch (Exception ex)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to save config file immediately: " + ex.Message));
}
LoggerOptions.Init(((BaseUnityPlugin)this).Logger);
ServerClientUtils.Detect(((BaseUnityPlugin)this).Logger);
bool isDedicatedServerDetected = ServerClientUtils.IsDedicatedServerDetected;
if (isDedicatedServerDetected)
{
LoggerOptions.LogInfo("Running on DEDICATED SERVER — enabling all server-side features.");
}
else
{
LoggerOptions.LogInfo("Running on CLIENT or SINGLE-PLAYER/LISTEN SERVER — only minimal client-safe features will be applied.");
}
SafeInvokeInit("FiresGhettoNetworkMod.CompressionGroup", "InitConfig", new object[1] { ((BaseUnityPlugin)this).Config });
SafeInvokeInit("FiresGhettoNetworkMod.NetworkingRatesGroup", "Init", new object[1] { ((BaseUnityPlugin)this).Config });
SafeInvokeInit("FiresGhettoNetworkMod.DedicatedServerGroup", "Init", new object[1] { ((BaseUnityPlugin)this).Config });
Harmony.PatchAll(typeof(CompressionGroup));
Harmony.PatchAll(typeof(NetworkingRatesGroup));
Harmony.PatchAll(typeof(DedicatedServerGroup));
WackyDatabaseCompatibilityPatch.Init(Harmony);
PlayerPositionSyncPatches.Init(((BaseUnityPlugin)this).Config);
Harmony.PatchAll(typeof(PlayerPositionSyncPatches));
if (isDedicatedServerDetected && ConfigEnableServerAuthority.Value)
{
Harmony.PatchAll(typeof(ShipFixesGroup));
Harmony.PatchAll(typeof(ZDOMemoryManager));
Harmony.PatchAll(typeof(ServerAuthorityPatches));
Harmony.PatchAll(typeof(MonsterAIPatches));
Harmony.PatchAll(typeof(ZDOThrottlingPatches));
Harmony.PatchAll(typeof(AILODPatches));
if (ConfigEnableRpcRouter.Value)
{
Harmony.PatchAll(typeof(RpcRouterPatches));
DamageTextHandler.Register();
HealthChangedHandler.Register();
WNTHealthChangedHandler.Register();
SetTargetHandler.Register();
AddNoiseHandler.Register();
TriggerAnimationHandler.Register();
TriggerOnDeathHandler.Register();
TalkerSayHandler.Register();
SpawnedZoneHandler.Register();
LoggerOptions.LogInfo("RPC Router enabled — DamageText, HealthChanged, WNTHealthChanged, SetTarget, AddNoise, TriggerAnimation, TriggerOnDeath, TalkerSay, SpawnedZone handlers registered.");
}
if (ConfigEnableZDODelta.Value)
{
Harmony.PatchAll(typeof(ZDODeltaPatches));
LoggerOptions.LogInfo("ZDO delta compression enabled.");
}
if (ConfigEnableWNTServerOptimization.Value)
{
Harmony.PatchAll(typeof(WearNTearServerPatches));
LoggerOptions.LogInfo("WearNTear server optimization enabled.");
}
LoggerOptions.LogInfo("All server-side features and authority patches enabled.");
}
else if (!isDedicatedServerDetected)
{
LoggerOptions.LogInfo("Server-side features skipped — not running on a dedicated server.");
}
else
{
LoggerOptions.LogInfo("Server-side features disabled via ConfigEnableServerAuthority = false.");
}
((MonoBehaviour)this).StartCoroutine(RegisterDummyRpcWhenReady());
((BaseUnityPlugin)this).Logger.LogInfo((object)"FiresGhettoNetworkMod v1.2.0 loaded.");
}
private void OnApplicationQuit()
{
}
private void TryPatchAll(Type type)
{
if (type == null)
{
((BaseUnityPlugin)this).Logger.LogError((object)"Tried to patch a null type!");
}
else
{
Harmony.PatchAll(type);
}
}
private void SafeInvokeInit(string typeName, string methodName, object[] args)
{
try
{
Type type = Type.GetType(typeName);
if (type == null)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("Type " + typeName + " not found; skipping " + methodName + "."));
return;
}
MethodInfo method = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (method == null)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("Method " + methodName + " not found on " + typeName + "."));
}
else
{
method.Invoke(null, args);
}
}
catch (TypeLoadException arg)
{
((BaseUnityPlugin)this).Logger.LogError((object)$"TypeLoadException while invoking {typeName}.{methodName}: {arg}");
}
catch (Exception arg2)
{
((BaseUnityPlugin)this).Logger.LogError((object)$"Exception while invoking {typeName}.{methodName}: {arg2}");
}
}
private void BindConfigs()
{
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
//IL_010f: Expected O, but got Unknown
//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
//IL_01cc: Expected O, but got Unknown
//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
//IL_01f7: Expected O, but got Unknown
//IL_021e: Unknown result type (might be due to invalid IL or missing references)
//IL_0228: Expected O, but got Unknown
//IL_027b: Unknown result type (might be due to invalid IL or missing references)
//IL_0285: Expected O, but got Unknown
//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
//IL_02e2: Expected O, but got Unknown
//IL_0315: Unknown result type (might be due to invalid IL or missing references)
//IL_031f: Expected O, but got Unknown
//IL_0352: Unknown result type (might be due to invalid IL or missing references)
//IL_035c: Expected O, but got Unknown
//IL_038b: Unknown result type (might be due to invalid IL or missing references)
//IL_0395: Expected O, but got Unknown
ConfigLogLevel = ((BaseUnityPlugin)this).Config.Bind<LogLevel>("General", "Log Level", LogLevel.Message, "Controls verbosity in BepInEx log.");
ConfigEnableCompression = ((BaseUnityPlugin)this).Config.Bind<bool>("Networking", "Enable Compression", true, "Enable ZSTD network compression (highly recommended).");
ConfigUpdateRate = ((BaseUnityPlugin)this).Config.Bind<UpdateRateOptions>("Networking", "Update Rate", UpdateRateOptions._100, "Server ZDO update frequency. Higher = smoother player movement, more bandwidth.\n100% (20Hz) matches vanilla and is the safe default; 150% (30Hz) is recommended\nfor high-pop servers with bandwidth headroom.");
ConfigSendRateMin = ((BaseUnityPlugin)this).Config.Bind<SendRateMinOptions>("Networking.Steamworks", "Send Rate Min", SendRateMinOptions._256KB, "Minimum send rate Steam will attempt.");
ConfigSendRateMax = ((BaseUnityPlugin)this).Config.Bind<SendRateMaxOptions>("Networking.Steamworks", "Send Rate Max", SendRateMaxOptions._512KB, "Maximum send rate Steam will attempt.");
ConfigQueueSize = ((BaseUnityPlugin)this).Config.Bind<QueueSizeOptions>("Networking", "Queue Size", QueueSizeOptions._32KB, "Send queue size. Higher helps high-player servers.");
ConfigForceCrossplay = ((BaseUnityPlugin)this).Config.Bind<ForceCrossplayOptions>("Dedicated Server", "Force Crossplay", ForceCrossplayOptions.steamworks, "Requires restart.\nsteamworks = Force crossplay DISABLED (Steam friends only)\nplayfab = Force crossplay ENABLED (PlayFab matchmaking)\nvanilla = Respect command-line -crossplay flag (default Valheim behavior)");
ConfigPlayerLimit = ((BaseUnityPlugin)this).Config.Bind<int>("Dedicated Server", "Player Limit", 10, new ConfigDescription("Max players on dedicated server. Requires restart.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 127), Array.Empty<object>()));
ConfigEnableShipFixes = ((BaseUnityPlugin)this).Config.Bind<bool>("Ship Fixes", "Enable Universal Ship Fixes", true, "Apply permanent autopilot + jitter fixes to ALL ships.");
ConfigEnableServerSideShipSimulation = ((BaseUnityPlugin)this).Config.Bind<bool>("Ship Fixes", "Server-Side Ship Simulation", false, "Server authoritatively simulates ship physics.\nDisabled by default — enable manually if you want the server to drive ship physics.");
ConfigEnableRpcRouter = ((BaseUnityPlugin)this).Config.Bind<bool>("Server Authority", "Enable RPC Router", true, "Server-side RPC filtering — drops unnecessary DamageText/HealthChanged RPCs before routing\nand prevents SetTarget exploits (targeting players/tamed creatures).\nSaves bandwidth and hardens server security.\nSERVER-ONLY — no effect on client.");
ConfigEnableRpcAoI = ((BaseUnityPlugin)this).Config.Bind<bool>("Server Authority", "Enable RPC Area-of-Interest", true, "When enabled, broadcast RPCs targeting a specific ZDO are only forwarded to peers\nwithin the configured radius of that ZDO. Massively reduces bandwidth on busy servers.\nRPCs without a target ZDO (global RPCs) are always broadcast to all peers.\nRequires Enable RPC Router = true. SERVER-ONLY.");
ConfigRpcAoIRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Server Authority", "RPC AoI Radius", 256f, new ConfigDescription("Distance (meters) from the target ZDO within which peers will receive the RPC.\nVanilla active area is ~7 zones × 64m = ~448m. Default 256m covers nearby players.\nSet higher if players report missing interactions at distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(64f, 1024f), Array.Empty<object>()));
ConfigEnableServerAuthority = ((BaseUnityPlugin)this).Config.Bind<bool>("Server Authority", "Enable Server-Side Simulation", false, new ConfigDescription("Makes the server fully authoritative over zones, ZDO ownership, monster AI, events, etc. (does NOT override your existing ship fixes).\n\nDisabled by default — enable manually on your DEDICATED SERVER if desired.\n\nWARNING: THIS IS A SERVER-ONLY FEATURE!\nEnabling this on a CLIENT will cause INFINITE LOADING SCREEN.\nThe mod automatically disables it on clients regardless of this setting.", (AcceptableValueBase)null, Array.Empty<object>()));
ConfigExtendedZoneRadius = ((BaseUnityPlugin)this).Config.Bind<int>("Server Authority", "Extended Zone Radius", 1, new ConfigDescription("Additional zone layers the server pre-loads around players for smoother zone transitions.\n0 = vanilla (no extra pre-load)\n1 = +1 layer (recommended, ~7x7 zones total)\n2 = +2 layers (~9x9 zones)\n3 = +3 layers (~11x11 zones)\n\nHigher values reduce stutter when crossing zone borders but increase server CPU/RAM usage.\nSERVER-ONLY — clients ignore this setting.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 3), Array.Empty<object>()));
ConfigEnableZDOThrottling = ((BaseUnityPlugin)this).Config.Bind<bool>("Server Authority", "Enable ZDO Throttling", true, "Reduce update frequency for distant ZDOs (creatures/structures far away) to save bandwidth.\nSERVER-ONLY — no effect on client.");
ConfigZDOThrottleDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Server Authority", "ZDO Throttle Distance", 500f, new ConfigDescription("Distance (meters) beyond which ZDOs are throttled (lower update rate).\n0 = disable throttling.\nRecommended: 400-600m.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1000f), Array.Empty<object>()));
ConfigEnableAILOD = ((BaseUnityPlugin)this).Config.Bind<bool>("Server Authority", "Enable AI LOD Throttling", true, "Reduce FixedUpdate frequency for distant AI (saves server CPU).\nNearby AI stays full speed for smooth combat.\nSERVER-ONLY — no effect on client.");
ConfigAILODNearDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Server Authority", "AI LOD Near Distance", 100f, new ConfigDescription("Full-speed AI within this range (meters).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(50f, 200f), Array.Empty<object>()));
ConfigAILODFarDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Server Authority", "AI LOD Far Distance", 300f, new ConfigDescription("Beyond this distance, AI is throttled (meters).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(200f, 600f), Array.Empty<object>()));
ConfigAILODThrottleFactor = ((BaseUnityPlugin)this).Config.Bind<float>("Server Authority", "AI LOD Throttle Factor", 0.5f, new ConfigDescription("Update multiplier for throttled AI (0.5 = half speed, 0.25 = quarter). Lower = more savings.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 0.75f), Array.Empty<object>()));
ZDOMemoryManager.ConfigMaxZDOs = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "Max Active ZDOs", 500000, new ConfigDescription("If the number of active ZDOs exceeds this value, the mod will force cleanup of orphan non-persistent ZDOs and run garbage collection.\nSet to 0 to disable. Useful on very long-running servers with high entity counts.\nDefault: 500000 (vanilla rarely goes above ~200k).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000000), Array.Empty<object>()));
ConfigEnableZDODelta = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "Enable ZDO Delta Compression", true, "On re-syncs, only send ZDO fields that changed since last send to each peer.\nInitial sync always sends full ZDO state. Re-syncs only send the diff.\nSignificant bandwidth reduction for high-field ZDOs (creatures, players) where\nonly 1-2 fields change per tick (e.g. health, position).\nSERVER-ONLY — no effect on client.");
ConfigEnableWNTServerOptimization = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "Enable WearNTear Server Optimization", true, "Skips structural support recalculation for building pieces that are at full health,\nnot wet, and not in the Ashlands. Support cannot change for intact static pieces,\nso this is a safe CPU saving on servers with large player bases.\nSERVER-ONLY — no effect on client.");
ConfigEntryBase[] array = (ConfigEntryBase[])(object)new ConfigEntryBase[24]
{
(ConfigEntryBase)ConfigLogLevel,
(ConfigEntryBase)ConfigEnableCompression,
(ConfigEntryBase)ConfigUpdateRate,
(ConfigEntryBase)ConfigSendRateMin,
(ConfigEntryBase)ConfigSendRateMax,
(ConfigEntryBase)ConfigQueueSize,
(ConfigEntryBase)ConfigForceCrossplay,
(ConfigEntryBase)ConfigPlayerLimit,
(ConfigEntryBase)ConfigEnableShipFixes,
(ConfigEntryBase)ConfigEnableServerSideShipSimulation,
(ConfigEntryBase)ConfigEnableRpcRouter,
(ConfigEntryBase)ConfigEnableRpcAoI,
(ConfigEntryBase)ConfigRpcAoIRadius,
(ConfigEntryBase)ConfigEnableServerAuthority,
(ConfigEntryBase)ConfigExtendedZoneRadius,
(ConfigEntryBase)ConfigEnableZDOThrottling,
(ConfigEntryBase)ConfigZDOThrottleDistance,
(ConfigEntryBase)ConfigEnableAILOD,
(ConfigEntryBase)ConfigAILODNearDistance,
(ConfigEntryBase)ConfigAILODFarDistance,
(ConfigEntryBase)ConfigAILODThrottleFactor,
(ConfigEntryBase)ZDOMemoryManager.ConfigMaxZDOs,
(ConfigEntryBase)ConfigEnableZDODelta,
(ConfigEntryBase)ConfigEnableWNTServerOptimization
};
ConfigEntryBase[] array2 = array;
foreach (ConfigEntryBase val in array2)
{
Type type = ((object)val).GetType();
EventInfo @event = type.GetEvent("SettingChanged");
if (@event != null)
{
EventHandler handler = delegate(object sender, EventArgs __)
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Expected O, but got Unknown
string text = (((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) ? "SERVER" : "CLIENT");
ConfigEntryBase val2 = (ConfigEntryBase)sender;
LoggerOptions.LogInfo($"[{text}] Config changed: {val2.Definition.Section} → {val2.Definition.Key} = {val2.BoxedValue}");
};
@event.AddEventHandler(val, handler);
}
}
if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer())
{
ConfigEnableServerAuthority.Value = false;
}
}
private void Start()
{
((MonoBehaviour)this).StartCoroutine(RegisterDummyRpcWhenReady());
}
[IteratorStateMachine(typeof(<RegisterDummyRpcWhenReady>d__41))]
private IEnumerator RegisterDummyRpcWhenReady()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <RegisterDummyRpcWhenReady>d__41(0)
{
<>4__this = this
};
}
}
public enum LogLevel
{
[Description("Errors/Warnings only")]
Warning,
[Description("Errors/Warnings/Messages [default]")]
Message,
[Description("Everything including Info")]
Info
}
public enum UpdateRateOptions
{
[Description("150% - 30 updates/sec [recommended for high-pop]")]
_150,
[Description("100% - 20 updates/sec [default, vanilla]")]
_100,
[Description("75% - 15 updates/sec")]
_75,
[Description("50% - 10 updates/sec")]
_50
}
public enum SendRateMinOptions
{
[Description("1024 KB/s | 8 Mbit/s")]
_1024KB,
[Description("768 KB/s | 6 Mbit/s")]
_768KB,
[Description("512 KB/s | 4 Mbit/s")]
_512KB,
[Description("256 KB/s | 2 Mbit/s [default]")]
_256KB,
[Description("150 KB/s | 1.2 Mbit/s [vanilla]")]
_150KB
}
public enum SendRateMaxOptions
{
[Description("1024 KB/s | 8 Mbit/s")]
_1024KB,
[Description("768 KB/s | 6 Mbit/s")]
_768KB,
[Description("512 KB/s | 4 Mbit/s [default]")]
_512KB,
[Description("256 KB/s | 2 Mbit/s")]
_256KB,
[Description("150 KB/s | 1.2 Mbit/s [vanilla]")]
_150KB
}
public enum QueueSizeOptions
{
[Description("80 KB")]
_80KB,
[Description("64 KB")]
_64KB,
[Description("48 KB")]
_48KB,
[Description("32 KB [default]")]
_32KB,
[Description("Vanilla (~10 KB)")]
_vanilla
}
public enum ForceCrossplayOptions
{
[Description("Vanilla behaviour - respect -crossplay flag [default]")]
vanilla,
[Description("Force crossplay ENABLED (use PlayFab backend)")]
playfab,
[Description("Force crossplay DISABLED (use Steamworks backend)")]
steamworks
}
[HarmonyPatch]
public static class AILODPatches
{
[HarmonyPatch(typeof(Character), "CustomFixedUpdate")]
[HarmonyPrefix]
public static bool CustomFixedUpdate_Prefix(Character __instance, float dt)
{
//IL_0085: 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)
if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsDedicated() || !FiresGhettoNetworkMod.ConfigEnableAILOD.Value)
{
return true;
}
if (__instance.IsPlayer() || __instance.IsTamed())
{
return true;
}
float num = float.MaxValue;
foreach (Player allPlayer in Player.GetAllPlayers())
{
if ((Object)(object)allPlayer != (Object)null)
{
float num2 = Vector3.Distance(((Component)__instance).transform.position, ((Component)allPlayer).transform.position);
if (num2 < num)
{
num = num2;
}
}
}
if (num <= FiresGhettoNetworkMod.ConfigAILODNearDistance.Value)
{
return true;
}
if (num > FiresGhettoNetworkMod.ConfigAILODFarDistance.Value)
{
int hashCode = ((object)__instance).GetHashCode();
float num3 = 1f / FiresGhettoNetworkMod.ConfigAILODThrottleFactor.Value;
if ((Time.time + (float)hashCode * 0.001f) % num3 > dt)
{
return false;
}
}
return true;
}
}
[HarmonyPatch]
public static class CompressionGroup
{
internal static class CompressionStatus
{
public class SocketStatus
{
public int version = 0;
public bool compressionEnabled = false;
public bool sendingCompressed = false;
public bool receivingCompressed = false;
}
private const int COMPRESSION_VERSION = 6;
public static readonly SocketStatus ourStatus = new SocketStatus
{
version = 6,
compressionEnabled = false
};
private static readonly Dictionary<ISocket, SocketStatus> peerStatus = new Dictionary<ISocket, SocketStatus>();
public static void AddPeer(ISocket socket)
{
if (socket != null)
{
if (peerStatus.ContainsKey(socket))
{
peerStatus.Remove(socket);
}
peerStatus[socket] = new SocketStatus();
LoggerOptions.LogMessage("Compression: New peer connected " + socket.GetEndPointString());
}
}
public static void RemovePeer(ISocket socket)
{
peerStatus.Remove(socket);
}
public static SocketStatus GetStatus(ISocket socket)
{
SocketStatus value;
return peerStatus.TryGetValue(socket, out value) ? value : null;
}
public static bool IsCompatible(ISocket socket)
{
SocketStatus status = GetStatus(socket);
return status != null && status.version == ourStatus.version;
}
public static bool GetSendCompressionStarted(ISocket socket)
{
return GetStatus(socket)?.sendingCompressed ?? false;
}
public static bool GetReceiveCompressionStarted(ISocket socket)
{
return GetStatus(socket)?.receivingCompressed ?? false;
}
public static void SetSendCompressionStarted(ISocket socket, bool started)
{
GetStatus(socket).sendingCompressed = started;
}
public static void SetReceiveCompressionStarted(ISocket socket, bool started)
{
GetStatus(socket).receivingCompressed = started;
}
}
private static string ZSTD_DICT_RESOURCE_NAME = "FiresGhettoNetworkMod.dict.small";
private static int ZSTD_LEVEL = 1;
private static object compressor;
private static object decompressor;
public static ConfigEntry<bool> ConfigCompressionEnabled;
private const string RPC_COMPRESSION_VERSION = "FiresGhetto.CompressionVersion";
private const string RPC_COMPRESSION_ENABLED = "FiresGhetto.CompressionEnabled";
private const string RPC_COMPRESSION_STARTED = "FiresGhetto.CompressedStarted";
public static void InitConfig(ConfigFile config)
{
ConfigCompressionEnabled = FiresGhettoNetworkMod.ConfigEnableCompression;
ConfigCompressionEnabled.SettingChanged += delegate
{
SetCompressionEnabledFromConfig();
};
CompressionStatus.ourStatus.compressionEnabled = ConfigCompressionEnabled?.Value ?? false;
}
public static void InitCompressor()
{
try
{
Type type = Type.GetType("ZstdSharp.Compressor, ZstdSharp");
Type type2 = Type.GetType("ZstdSharp.Decompressor, ZstdSharp");
if (type == null || type2 == null)
{
LoggerOptions.LogWarning("ZstdSharp assembly not found - compression disabled.");
return;
}
Assembly executingAssembly = Assembly.GetExecutingAssembly();
byte[] array;
using (Stream stream = executingAssembly.GetManifestResourceStream(ZSTD_DICT_RESOURCE_NAME))
{
if (stream == null)
{
LoggerOptions.LogError("Compression dictionary resource not found. Compression disabled.");
return;
}
array = new byte[stream.Length];
stream.Read(array, 0, array.Length);
}
compressor = Activator.CreateInstance(type, ZSTD_LEVEL);
type.GetMethod("LoadDictionary")?.Invoke(compressor, new object[1] { array });
decompressor = Activator.CreateInstance(type2);
type2.GetMethod("LoadDictionary")?.Invoke(decompressor, new object[1] { array });
LoggerOptions.LogInfo("ZSTD compression dictionary loaded successfully.");
}
catch (Exception arg)
{
LoggerOptions.LogError($"Failed to initialize compressor: {arg}");
}
}
private static void SetCompressionEnabledFromConfig()
{
bool value = ConfigCompressionEnabled.Value;
CompressionStatus.ourStatus.compressionEnabled = value;
LoggerOptions.LogMessage("Network compression: " + (value ? "Enabled" : "Disabled"));
SendCompressionEnabledStatusToAll();
}
[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
[HarmonyPostfix]
private static void OnNewConnection(ZNetPeer peer)
{
if (compressor != null)
{
CompressionStatus.AddPeer(peer.m_socket);
RegisterRPCs(peer);
SendCompressionVersion(peer);
}
}
[HarmonyPatch(typeof(ZNet), "Disconnect")]
[HarmonyPostfix]
private static void OnDisconnect(ZNetPeer peer)
{
CompressionStatus.RemovePeer(peer.m_socket);
}
private static void RegisterRPCs(ZNetPeer peer)
{
peer.m_rpc.Register<int>("FiresGhetto.CompressionVersion", (Action<ZRpc, int>)RPC_CompressionVersion);
peer.m_rpc.Register<bool>("FiresGhetto.CompressionEnabled", (Action<ZRpc, bool>)RPC_CompressionEnabled);
peer.m_rpc.Register<bool>("FiresGhetto.CompressedStarted", (Action<ZRpc, bool>)RPC_CompressionStarted);
}
private static void SendCompressionVersion(ZNetPeer peer)
{
peer.m_rpc.Invoke("FiresGhetto.CompressionVersion", new object[1] { CompressionStatus.ourStatus.version });
}
private static void RPC_CompressionVersion(ZRpc rpc, int version)
{
ZNetPeer val = FindPeerByRpc(rpc);
if (val != null)
{
CompressionStatus.SocketStatus status = CompressionStatus.GetStatus(val.m_socket);
if (status != null)
{
status.version = version;
}
if (version == CompressionStatus.ourStatus.version)
{
LoggerOptions.LogMessage("Compression compatible with " + GetPeerName(val));
}
else
{
LoggerOptions.LogWarning($"Compression version mismatch with {GetPeerName(val)} (them: {version}, us: {CompressionStatus.ourStatus.version})");
}
if (CompressionStatus.IsCompatible(val.m_socket))
{
SendCompressionEnabledStatus(val);
}
}
}
private static void SendCompressionEnabledStatusToAll()
{
if ((Object)(object)ZNet.instance == (Object)null)
{
return;
}
foreach (ZNetPeer peer in ZNet.instance.GetPeers())
{
if (CompressionStatus.IsCompatible(peer.m_socket))
{
SendCompressionEnabledStatus(peer);
}
}
}
private static void SendCompressionEnabledStatus(ZNetPeer peer)
{
peer.m_rpc.Invoke("FiresGhetto.CompressionEnabled", new object[1] { CompressionStatus.ourStatus.compressionEnabled });
bool started = CompressionStatus.ourStatus.compressionEnabled && (CompressionStatus.GetStatus(peer.m_socket)?.compressionEnabled ?? false);
SendCompressionStarted(peer, started);
}
private static void RPC_CompressionEnabled(ZRpc rpc, bool enabled)
{
ZNetPeer val = FindPeerByRpc(rpc);
if (val != null)
{
CompressionStatus.SocketStatus status = CompressionStatus.GetStatus(val.m_socket);
if (status != null)
{
status.compressionEnabled = enabled;
}
bool started = CompressionStatus.ourStatus.compressionEnabled && enabled;
SendCompressionStarted(val, started);
}
}
private static void SendCompressionStarted(ZNetPeer peer, bool started)
{
CompressionStatus.SocketStatus status = CompressionStatus.GetStatus(peer.m_socket);
if (status != null && status.sendingCompressed != started)
{
peer.m_rpc.Invoke("FiresGhetto.CompressedStarted", new object[1] { started });
Flush(peer);
status.sendingCompressed = started;
LoggerOptions.LogMessage("Compression " + (started ? "started" : "stopped") + " with " + GetPeerName(peer));
}
}
private static void Flush(ZNetPeer peer)
{
//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_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: 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_0010: Invalid comparison between Unknown and I4
OnlineBackendType onlineBackend = ZNet.m_onlineBackend;
OnlineBackendType val = onlineBackend;
if ((int)val != 0)
{
if ((int)val == 1)
{
}
}
else
{
peer.m_socket.Flush();
}
}
private static void RPC_CompressionStarted(ZRpc rpc, bool started)
{
ZNetPeer val = FindPeerByRpc(rpc);
if (val != null)
{
CompressionStatus.SocketStatus status = CompressionStatus.GetStatus(val.m_socket);
if (status != null)
{
status.receivingCompressed = started;
}
LoggerOptions.LogMessage("Receiving " + (started ? "compressed" : "uncompressed") + " data from " + GetPeerName(val));
}
}
internal static byte[] Compress(byte[] data)
{
if (compressor == null)
{
return data;
}
Type type = compressor.GetType();
MethodInfo methodInfo = type.GetMethod("Wrap", new Type[1] { typeof(byte[]) }) ?? type.GetMethod("Wrap");
object obj = methodInfo.Invoke(compressor, new object[1] { data });
if (obj is byte[] result)
{
return result;
}
MethodInfo methodInfo2 = obj?.GetType().GetMethod("ToArray", Type.EmptyTypes);
if (methodInfo2 != null)
{
return (byte[])methodInfo2.Invoke(obj, null);
}
return data;
}
internal static byte[] Decompress(byte[] data)
{
if (decompressor == null)
{
throw new Exception("Decompressor not initialized");
}
Type type = decompressor.GetType();
MethodInfo methodInfo = type.GetMethod("Unwrap", new Type[1] { typeof(byte[]) }) ?? type.GetMethod("Unwrap");
object obj = methodInfo.Invoke(decompressor, new object[1] { data });
if (obj is byte[] result)
{
return result;
}
MethodInfo methodInfo2 = obj?.GetType().GetMethod("ToArray", Type.EmptyTypes);
if (methodInfo2 != null)
{
return (byte[])methodInfo2.Invoke(obj, null);
}
throw new Exception("Failed to decompress data");
}
[HarmonyPatch(typeof(ZSteamSocket), "SendQueuedPackages")]
[HarmonyPrefix]
private static bool Steam_SendCompressed(ref Queue<byte[]> ___m_sendQueue, ZSteamSocket __instance)
{
if (compressor == null || !CompressionStatus.GetSendCompressionStarted((ISocket)(object)__instance))
{
return true;
}
___m_sendQueue = new Queue<byte[]>(___m_sendQueue.Select((byte[] p) => Compress(p)));
return true;
}
[HarmonyPatch(typeof(ZSteamSocket), "Recv")]
[HarmonyPostfix]
private static void Steam_RecvCompressed(ref ZPackage __result, ZSteamSocket __instance)
{
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Expected O, but got Unknown
if (__result == null || decompressor == null)
{
return;
}
CompressionStatus.SocketStatus status = CompressionStatus.GetStatus((ISocket)(object)__instance);
if (status == null || !status.receivingCompressed)
{
return;
}
try
{
__result = new ZPackage(Decompress(__result.GetArray()));
}
catch
{
LoggerOptions.LogWarning("Failed to decompress incoming Steamworks package - falling back to uncompressed");
status.receivingCompressed = false;
}
}
private static ZNetPeer FindPeerByRpc(ZRpc rpc)
{
try
{
if (rpc == null || ZRoutedRpc.instance == null)
{
return null;
}
return ((List<ZNetPeer>)AccessTools.Field(typeof(ZRoutedRpc), "m_peers").GetValue(ZRoutedRpc.instance))?.FirstOrDefault((Func<ZNetPeer, bool>)((ZNetPeer p) => p.m_rpc == rpc));
}
catch
{
return null;
}
}
private static string GetPeerName(ZNetPeer peer)
{
if (peer == null)
{
return "unknown";
}
try
{
if (peer.m_socket != null)
{
return peer.m_socket.GetEndPointString();
}
}
catch
{
}
return peer.m_uid.ToString();
}
}
[HarmonyPatch]
public static class DedicatedServerGroup
{
private static bool isDedicatedDetected;
public static void Init(ConfigFile config)
{
LoggerOptions.LogInfo("Dedicated server features initialized.");
isDedicatedDetected = ServerClientUtils.IsDedicatedServerDetected;
if (isDedicatedDetected)
{
LoggerOptions.LogInfo("Running as dedicated server (ServerClientUtils).");
}
else
{
LoggerOptions.LogInfo("Running as client/listen-server (ServerClientUtils).");
}
}
[HarmonyPatch(typeof(FejdStartup), "ParseServerArguments")]
[HarmonyPostfix]
private static void ApplyForceCrossplay()
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
if (isDedicatedDetected)
{
switch (FiresGhettoNetworkMod.ConfigForceCrossplay.Value)
{
case ForceCrossplayOptions.playfab:
ZNet.m_onlineBackend = (OnlineBackendType)1;
LoggerOptions.LogInfo("Forcing crossplay ENABLED (PlayFab backend).");
break;
case ForceCrossplayOptions.steamworks:
ZNet.m_onlineBackend = (OnlineBackendType)0;
LoggerOptions.LogInfo("Forcing crossplay DISABLED (Steamworks backend).");
break;
default:
LoggerOptions.LogInfo("Crossplay mode: vanilla (respecting command line).");
break;
}
}
}
[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> OverridePlayerLimit(IEnumerable<CodeInstruction> instructions)
{
//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
//IL_01bd: Invalid comparison between Unknown and I4
//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0208: Expected O, but got Unknown
if (!isDedicatedDetected)
{
return instructions;
}
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
bool flag = false;
for (int i = 0; i < list.Count; i++)
{
if (!(list[i].opcode == OpCodes.Call) || !(list[i].operand is MethodInfo methodInfo) || !(methodInfo.Name == "GetNrOfPlayers"))
{
continue;
}
for (int j = i + 1; j < list.Count; j++)
{
if (list[j].opcode == OpCodes.Ldc_I4_S || list[j].opcode == OpCodes.Ldc_I4 || list[j].opcode == OpCodes.Ldc_I4_0 || list[j].opcode == OpCodes.Ldc_I4_1 || list[j].opcode == OpCodes.Ldc_I4_2 || list[j].opcode == OpCodes.Ldc_I4_3 || list[j].opcode == OpCodes.Ldc_I4_4 || list[j].opcode == OpCodes.Ldc_I4_5 || list[j].opcode == OpCodes.Ldc_I4_6 || list[j].opcode == OpCodes.Ldc_I4_7 || list[j].opcode == OpCodes.Ldc_I4_8)
{
int num = FiresGhettoNetworkMod.ConfigPlayerLimit.Value;
if ((int)ZNet.m_onlineBackend == 1)
{
num++;
LoggerOptions.LogInfo("Applied +1 player limit for PlayFab backend.");
}
LoggerOptions.LogInfo($"Overriding player limit constant → {num}");
list[j] = new CodeInstruction(OpCodes.Ldc_I4, (object)num);
flag = true;
break;
}
}
if (flag)
{
break;
}
}
if (!flag)
{
LoggerOptions.LogWarning("Player limit constant not found in ZNet.RPC_PeerInfo. Patch skipped – possible game update or conflicting mod.");
}
return list;
}
}
public static class LoggerOptions
{
private static ManualLogSource logger;
public static void Init(ManualLogSource source)
{
logger = source;
}
public static void LogError(object data)
{
logger.LogError(data);
}
public static void LogWarning(object data)
{
logger.LogWarning(data);
}
public static void LogMessage(object data)
{
if (FiresGhettoNetworkMod.ConfigLogLevel != null && FiresGhettoNetworkMod.ConfigLogLevel.Value >= LogLevel.Message)
{
logger.LogMessage(data);
}
}
public static void LogInfo(object data)
{
if (FiresGhettoNetworkMod.ConfigLogLevel != null && FiresGhettoNetworkMod.ConfigLogLevel.Value >= LogLevel.Info)
{
logger.LogInfo(data);
}
}
}
[HarmonyPatch]
public static class MonsterAIPatches
{
private static readonly int PlayerPrefabHash = StringExtensionMethods.GetStableHashCode("Player");
private static readonly List<Player> s_tempPlayers = new List<Player>();
private static readonly Dictionary<int, float> s_eventDiagLastLogTime = new Dictionary<int, float>();
private const float EVENT_DIAG_INTERVAL = 30f;
private const float ZONE_PLAYER_EXTRA = 32f;
private static readonly FieldInfo _f_randomEvent = AccessTools.Field(typeof(RandEventSystem), "m_randomEvent");
private static readonly FieldInfo _f_forcedEvent = AccessTools.Field(typeof(RandEventSystem), "m_forcedEvent");
private static readonly FieldInfo _f_activeEvent = AccessTools.Field(typeof(RandEventSystem), "m_activeEvent");
private static readonly MethodInfo _m_setActiveEvent = AccessTools.Method(typeof(RandEventSystem), "SetActiveEvent", new Type[2]
{
typeof(RandomEvent),
typeof(bool)
}, (Type[])null);
private static readonly MethodInfo _m_isAnyPlayerIn = AccessTools.Method(typeof(RandEventSystem), "IsAnyPlayerInEventArea", new Type[1] { typeof(RandomEvent) }, (Type[])null);
[HarmonyPatch(typeof(BaseAI), "UpdateAI")]
[HarmonyPrefix]
public static bool BaseAI_UpdateAI_Prefix(BaseAI __instance)
{
if ((Object)(object)__instance.m_nview == (Object)null)
{
return false;
}
if (!__instance.m_nview.IsValid())
{
return false;
}
if (__instance.m_nview.GetZDO() == null)
{
return false;
}
if ((Object)(object)__instance.m_character == (Object)null)
{
return false;
}
return true;
}
[HarmonyPatch(typeof(SpawnSystem), "UpdateSpawning")]
[HarmonyPrefix]
private static bool UpdateSpawning_Prefix(SpawnSystem __instance, ZNetView ___m_nview, List<SpawnSystemList> ___m_spawnLists)
{
//IL_0140: Unknown result type (might be due to invalid IL or missing references)
//IL_0145: Unknown result type (might be due to invalid IL or missing references)
//IL_0154: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsDedicated())
{
return true;
}
if ((Object)(object)___m_nview == (Object)null || !___m_nview.IsValid() || !___m_nview.IsOwner())
{
return false;
}
RandomEvent val = (RandomEvent)(((Object)(object)RandEventSystem.instance != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
RandomEvent val2 = (RandomEvent)(((Object)(object)RandEventSystem.instance != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
bool flag = val != null || val2 != null;
bool flag2 = false;
if (flag)
{
int instanceID = ((Object)__instance).GetInstanceID();
float time = Time.time;
if (!s_eventDiagLastLogTime.TryGetValue(instanceID, out var value) || time - value >= 30f)
{
s_eventDiagLastLogTime[instanceID] = time;
flag2 = true;
}
}
s_tempPlayers.Clear();
GetPlayersInZone(__instance, s_tempPlayers);
if (s_tempPlayers.Count == 0)
{
if (flag2)
{
Vector3 position = ((Component)__instance).transform.position;
LoggerOptions.LogInfo($"[EventDiag] SpawnSystem@({position.x:F0},{position.z:F0}) SKIPPED: no players in zone. " + "ActiveEvent='" + ((val != null) ? val.m_name : "null") + "' RunningEvent='" + ((val2 != null) ? val2.m_name : "null") + "' " + $"TotalPlayers={Player.GetAllPlayers().Count} Peers={ZNet.instance.GetConnectedPeers().Count}");
}
return false;
}
SpawnSystem.m_tempNearPlayers.Clear();
SpawnSystem.m_tempNearPlayers.AddRange(s_tempPlayers);
DateTime time2 = ZNet.instance.GetTime();
foreach (SpawnSystemList ___m_spawnList in ___m_spawnLists)
{
if (___m_spawnList?.m_spawners != null)
{
__instance.UpdateSpawnList(___m_spawnList.m_spawners, time2, false);
}
}
if ((Object)(object)RandEventSystem.instance != (Object)null)
{
List<SpawnData> currentSpawners = RandEventSystem.instance.GetCurrentSpawners();
if (flag2)
{
Vector3 position2 = ((Component)__instance).transform.position;
int num = currentSpawners?.Count ?? (-1);
LoggerOptions.LogInfo($"[EventDiag] SpawnSystem@({position2.x:F0},{position2.z:F0}) RAN event path. " + "ActiveEvent='" + ((val != null) ? val.m_name : "null") + "' RunningEvent='" + ((val2 != null) ? val2.m_name : "null") + "' " + $"GetCurrentSpawners.Count={num} Players={s_tempPlayers.Count}");
}
if (currentSpawners != null)
{
__instance.UpdateSpawnList(currentSpawners, time2, true);
}
}
return false;
}
private static void GetPlayersInZone(SpawnSystem spawnSystem, List<Player> players)
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
foreach (Player allPlayer in Player.GetAllPlayers())
{
if ((Object)(object)allPlayer != (Object)null && InsideZone(spawnSystem, ((Component)allPlayer).transform.position, 32f))
{
players.Add(allPlayer);
}
}
}
private static bool InsideZone(SpawnSystem spawnSystem, Vector3 point, float extra = 0f)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: 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)
float num = 32f + extra;
Vector3 position = ((Component)spawnSystem).transform.position;
return point.x >= position.x - num && point.x <= position.x + num && point.z >= position.z - num && point.z <= position.z + num;
}
[HarmonyPatch(typeof(RandEventSystem), "FixedUpdate")]
[HarmonyPrefix]
private static void RandEventSystem_FixedUpdate_Prefix(RandEventSystem __instance)
{
if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsDedicated())
{
return;
}
object? value = _f_forcedEvent.GetValue(__instance);
RandomEvent val = (RandomEvent)((value is RandomEvent) ? value : null);
if (val == null)
{
object? value2 = _f_randomEvent.GetValue(__instance);
RandomEvent val2 = (RandomEvent)((value2 is RandomEvent) ? value2 : null);
if (val2 != null && (bool)_m_isAnyPlayerIn.Invoke(__instance, new object[1] { val2 }))
{
_f_activeEvent.SetValue(__instance, val2);
}
}
}
[HarmonyPatch(typeof(RandEventSystem), "SetActiveEvent")]
[HarmonyPrefix]
private static bool RandEventSystem_SetActiveEvent_Prefix(RandEventSystem __instance, RandomEvent ev)
{
if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsDedicated())
{
return true;
}
if (ev != null)
{
return true;
}
object? value = _f_forcedEvent.GetValue(__instance);
RandomEvent val = (RandomEvent)((value is RandomEvent) ? value : null);
if (val != null)
{
return true;
}
object? value2 = _f_randomEvent.GetValue(__instance);
RandomEvent val2 = (RandomEvent)((value2 is RandomEvent) ? value2 : null);
if (val2 == null)
{
return true;
}
return false;
}
[HarmonyPatch(typeof(RandEventSystem), "FixedUpdate")]
[HarmonyPostfix]
private static void RandEventSystem_FixedUpdate_Postfix(RandEventSystem __instance)
{
if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsDedicated())
{
return;
}
object? value = _f_forcedEvent.GetValue(__instance);
RandomEvent val = (RandomEvent)((value is RandomEvent) ? value : null);
if (val == null)
{
object? value2 = _f_randomEvent.GetValue(__instance);
RandomEvent val2 = (RandomEvent)((value2 is RandomEvent) ? value2 : null);
if (val2 != null)
{
bool flag = (bool)_m_isAnyPlayerIn.Invoke(__instance, new object[1] { val2 });
_m_setActiveEvent.Invoke(__instance, new object[2]
{
flag ? val2 : null,
false
});
}
else
{
_m_setActiveEvent.Invoke(__instance, new object[2] { null, false });
}
}
}
public static Player GetNearestPlayer(Vector3 position)
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
Player result = null;
float num = float.MaxValue;
foreach (Player allPlayer in Player.GetAllPlayers())
{
if ((Object)(object)allPlayer != (Object)null)
{
float num2 = Vector3.Distance(position, ((Component)allPlayer).transform.position);
if (num2 < num)
{
num = num2;
result = allPlayer;
}
}
}
return result;
}
public static bool IsAnyPlayerInActiveArea(Vector3 position)
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: 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_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)ZoneSystem.instance == (Object)null)
{
return false;
}
Vector2i zone = ZoneSystem.GetZone(position);
int activeArea = ZoneSystem.instance.m_activeArea;
foreach (Player allPlayer in Player.GetAllPlayers())
{
if ((Object)(object)allPlayer != (Object)null)
{
Vector2i zone2 = ZoneSystem.GetZone(((Component)allPlayer).transform.position);
if (ZNetScene.InActiveArea(zone, zone2, activeArea))
{
return true;
}
}
}
return false;
}
public static Player GetClosestPlayerInRange(Vector3 position, float maxDistance)
{
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
Player result = null;
float num = maxDistance;
foreach (Player allPlayer in Player.GetAllPlayers())
{
if ((Object)(object)allPlayer != (Object)null && !((Character)allPlayer).IsDead())
{
float num2 = Vector3.Distance(position, ((Component)allPlayer).transform.position);
if (num2 < num)
{
num = num2;
result = allPlayer;
}
}
}
return result;
}
public static bool IsPlayerZDO(ZDO zdo)
{
return zdo != null && zdo.m_prefab == PlayerPrefabHash;
}
}
[HarmonyPatch]
public static class NetworkingRatesGroup
{
public static void Init(ConfigFile config)
{
FiresGhettoNetworkMod.ConfigUpdateRate.SettingChanged += delegate
{
ApplyUpdateRate();
};
FiresGhettoNetworkMod.ConfigSendRateMin.SettingChanged += delegate
{
ApplySendRates();
};
FiresGhettoNetworkMod.ConfigSendRateMax.SettingChanged += delegate
{
ApplySendRates();
};
FiresGhettoNetworkMod.ConfigQueueSize.SettingChanged += delegate
{
LoggerOptions.LogInfo("Queue size changed - restart recommended.");
};
ApplyUpdateRate();
ApplySendRates();
}
private static void ApplyUpdateRate()
{
LoggerOptions.LogMessage($"Update rate set to {FiresGhettoNetworkMod.ConfigUpdateRate.Value}");
}
public static void ApplySendRates()
{
if (!((Object)(object)ZNet.instance == (Object)null))
{
int sendRateValue = GetSendRateValue(FiresGhettoNetworkMod.ConfigSendRateMin.Value);
int sendRateValue2 = GetSendRateValue(FiresGhettoNetworkMod.ConfigSendRateMax.Value);
SetSteamConfig("k_ESteamNetworkingConfig_SendRateMin", sendRateValue);
SetSteamConfig("k_ESteamNetworkingConfig_SendRateMax", sendRateValue2);
LoggerOptions.LogMessage($"Steam send rates applied: Min {sendRateValue / 1024} KB/s, Max {sendRateValue2 / 1024} KB/s");
}
}
private static int GetSendRateValue(object option)
{
string text = option.ToString();
if (1 == 0)
{
}
int result = text switch
{
"_1024KB" => 1048576,
"_768KB" => 786432,
"_512KB" => 524288,
"_256KB" => 262144,
_ => 153600,
};
if (1 == 0)
{
}
return result;
}
[HarmonyPatch(typeof(ZDOMan), "SendZDOToPeers2")]
[HarmonyPrefix]
private static void AdjustUpdateInterval(ref float dt)
{
switch (FiresGhettoNetworkMod.ConfigUpdateRate.Value)
{
case UpdateRateOptions._150:
dt *= 1.5f;
break;
case UpdateRateOptions._75:
dt *= 0.75f;
break;
case UpdateRateOptions._50:
dt *= 0.5f;
break;
case UpdateRateOptions._100:
break;
}
}
[HarmonyPatch(typeof(ZNet), "Start")]
[HarmonyPostfix]
private static void EnsureRatesOnStart()
{
ApplySendRates();
}
private static void SetSteamConfig(string enumMemberName, int value)
{
IntPtr intPtr = IntPtr.Zero;
try
{
IEnumerable<Type> source = AppDomain.CurrentDomain.GetAssemblies().SelectMany(delegate(Assembly a)
{
try
{
return a.GetTypes();
}
catch
{
return Array.Empty<Type>();
}
});
Type type = source.FirstOrDefault((Type t) => t.FullName == "Steamworks.ESteamNetworkingConfigValue");
Type type2 = source.FirstOrDefault((Type t) => t.FullName == "Steamworks.ESteamNetworkingConfigScope");
Type type3 = source.FirstOrDefault((Type t) => t.FullName == "Steamworks.ESteamNetworkingConfigDataType");
if (type == null || type2 == null || type3 == null)
{
LoggerOptions.LogWarning("Steamworks.NET types not found - send rate config skipped.");
return;
}
object obj = Enum.Parse(type, enumMemberName);
object obj2 = Enum.Parse(type2, "k_ESteamNetworkingConfig_Global");
object obj3 = Enum.Parse(type3, "k_ESteamNetworkingConfig_Int32");
intPtr = Marshal.AllocHGlobal(4);
Marshal.WriteInt32(intPtr, value);
Type type4 = ((Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsDedicated()) ? source.FirstOrDefault((Type t) => t.FullName == "Steamworks.SteamGameServerNetworkingUtils") : source.FirstOrDefault((Type t) => t.FullName == "Steamworks.SteamNetworkingUtils"));
if (type4 == null)
{
LoggerOptions.LogWarning("Steamworks utils type not found - send rate config skipped.");
return;
}
MethodInfo method = type4.GetMethod("SetConfigValue", BindingFlags.Static | BindingFlags.Public);
if (method == null)
{
LoggerOptions.LogWarning("SetConfigValue method not found - send rate config skipped.");
return;
}
method.Invoke(null, new object[5]
{
obj,
obj2,
IntPtr.Zero,
obj3,
intPtr
});
}
catch (Exception ex)
{
LoggerOptions.LogWarning("Failed to set Steam config " + enumMemberName + ": " + ex.Message);
}
finally
{
if (intPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(intPtr);
}
}
}
[HarmonyPatch(typeof(ZSteamSocket), "RegisterGlobalCallbacks")]
[HarmonyPostfix]
private static void ApplySendRatesOnConnect()
{
ApplySendRates();
}
[HarmonyPatch(typeof(ZDOMan), "SendZDOs")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> SendZDOs_QueueLimitTranspiler(IEnumerable<CodeInstruction> instructions)
{
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
int num = 0;
int configuredQueueLimit = GetConfiguredQueueLimit();
for (int i = 0; i < list.Count; i++)
{
if ((!(list[i].opcode == OpCodes.Ldc_I4) && !(list[i].opcode == OpCodes.Ldc_I4_S)) || !(list[i].operand is int num2) || num2 < 10240)
{
continue;
}
bool flag = false;
for (int j = Math.Max(0, i - 15); j < Math.Min(list.Count, i + 15); j++)
{
if (list[j].opcode == OpCodes.Callvirt && list[j].operand is MethodInfo methodInfo && methodInfo.Name == "GetSendQueueSize")
{
flag = true;
break;
}
}
if (flag)
{
LoggerOptions.LogInfo($"Overriding ZDOMan.SendZDOs queue limit #{num + 1}: original {num2} → {configuredQueueLimit} bytes");
list[i].opcode = OpCodes.Ldc_I4;
list[i].operand = configuredQueueLimit;
num++;
}
}
if (num == 0)
{
LoggerOptions.LogWarning("No queue limit constants found in ZDOMan.SendZDOs — queue size config not applied (game update may have changed IL).");
}
else
{
LoggerOptions.LogInfo($"Successfully patched {num} queue limit constant(s).");
}
return list.AsEnumerable();
}
private static int GetConfiguredQueueLimit()
{
QueueSizeOptions value = FiresGhettoNetworkMod.ConfigQueueSize.Value;
if (1 == 0)
{
}
int result = value switch
{
QueueSizeOptions._80KB => 81920,
QueueSizeOptions._64KB => 65536,
QueueSizeOptions._48KB => 49152,
QueueSizeOptions._32KB => 32768,
_ => 10240,
};
if (1 == 0)
{
}
return result;
}
}
[HarmonyPatch]
public static class PlayerPositionSyncPatches
{
private sealed class PlayerSyncData
{
public Vector3 networkPos;
public Vector3 prevNetworkPos;
public Quaternion networkRot;
public Quaternion prevNetworkRot;
public Vector3 velocity;
public Vector3 smoothedVelocity;
public float lastNetworkUpdateTime;
public float networkUpdateInterval;
public bool hasData;
public Vector3 renderPos;
public Quaternion renderRot;
public float lastFrameTime;
public Vector3 acceleration;
}
public static ConfigEntry<bool> ConfigEnablePlayerPositionBoost;
public static ConfigEntry<float> ConfigPlayerPositionUpdateMultiplier;
public static ConfigEntry<bool> ConfigEnableClientInterpolation;
public static ConfigEntry<bool> ConfigEnablePlayerPrediction;
public static ConfigEntry<float> ConfigSmoothingMinInterval;
public static ConfigEntry<float> ConfigSmoothingMaxInterval;
private static readonly int PlayerPrefabHash = StringExtensionMethods.GetStableHashCode("Player");
private static readonly Dictionary<long, PlayerSyncData> _syncData = new Dictionary<long, PlayerSyncData>();
public static void Init(ConfigFile config)
{
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Expected O, but got Unknown
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00bd: Expected O, but got Unknown
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
//IL_00f5: Expected O, but got Unknown
ConfigEnablePlayerPositionBoost = config.Bind<bool>("Player Sync", "Enable High-Frequency Position Updates", true, "Boosts server send priority for player ZDOs so they sync before terrain/object ZDOs.\nReduces the floaty delayed movement you see on other players.\nSERVER-ONLY — no effect on client.");
ConfigPlayerPositionUpdateMultiplier = config.Bind<float>("Player Sync", "Position Update Multiplier", 2.5f, new ConfigDescription("How aggressively player ZDOs are prioritized over other ZDOs (1.0 = vanilla, 2.5 = recommended).\nHigher values push player positions to the front of the send queue more strongly.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>()));
ConfigEnableClientInterpolation = config.Bind<bool>("Player Sync", "Enable Client-Side Interpolation", true, "Smooths other players' movement on your client by interpolating between received network positions.\nEliminates the snapping/teleporting caused by discrete 50ms network updates.\nCLIENT-ONLY — no server impact.");
ConfigEnablePlayerPrediction = config.Bind<bool>("Player Sync", "Enable Client-Side Prediction", false, "Extrapolates other players' positions forward between network updates using their last known velocity.\nCan help on high latency (>100ms) but may cause overshooting at low ping.\nDisabled by default — only enable if interpolation alone feels laggy.\nCLIENT-ONLY — no server impact.");
ConfigSmoothingMinInterval = config.Bind<float>("Player Sync", "Smoothing Min Interval (s)", 0.05f, new ConfigDescription("When a remote player's packets arrive faster than this interval (seconds),\nsmoothing is disabled entirely and vanilla movement renders directly.\nLower = trust the network more (use only on LAN / very fast servers).\nDefault 0.05s = 20Hz. Set to 0 to always smooth.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.2f), Array.Empty<object>()));
ConfigSmoothingMaxInterval = config.Bind<float>("Player Sync", "Smoothing Max Interval (s)", 0.2f, new ConfigDescription("When a remote player's packets arrive slower than this interval (seconds),\nsmoothing runs at full strength. Between Min and Max the strength fades\nin linearly so the handoff is invisible. Raise it for a more aggressive\nfade-in (less smoothing on borderline-laggy connections); lower it for a\nsnappier ramp to full smoothing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 0.5f), Array.Empty<object>()));
}
private static bool IsPlayerZDO(ZDO zdo)
{
return zdo != null && zdo.m_prefab == PlayerPrefabHash;
}
[HarmonyPatch(typeof(ZDO), "Deserialize")]
[HarmonyPostfix]
public static void ZDO_Deserialize_Postfix(ZDO __instance)
{
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_015f: Unknown result type (might be due to invalid IL or missing references)
//IL_0162: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: 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)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: 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_0103: Unknown result type (might be due to invalid IL or missing references)
//IL_0109: Unknown result type (might be due to invalid IL or missing references)
//IL_010e: Unknown result type (might be due to invalid IL or missing references)
//IL_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_0119: Unknown result type (might be due to invalid IL or missing references)
//IL_011f: Unknown result type (might be due to invalid IL or missing references)
//IL_0124: Unknown result type (might be due to invalid IL or missing references)
//IL_017b: Unknown result type (might be due to invalid IL or missing references)
//IL_0180: Unknown result type (might be due to invalid IL or missing references)
//IL_018a: Unknown result type (might be due to invalid IL or missing references)
//IL_018f: Unknown result type (might be due to invalid IL or missing references)
//IL_0198: Unknown result type (might be due to invalid IL or missing references)
//IL_019d: Unknown result type (might be due to invalid IL or missing references)
//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
//IL_01de: Unknown result type (might be due to invalid IL or missing references)
//IL_0304: Unknown result type (might be due to invalid IL or missing references)
//IL_0309: Unknown result type (might be due to invalid IL or missing references)
//IL_0312: Unknown result type (might be due to invalid IL or missing references)
//IL_0317: Unknown result type (might be due to invalid IL or missing references)
//IL_031e: Unknown result type (might be due to invalid IL or missing references)
//IL_031f: Unknown result type (might be due to invalid IL or missing references)
//IL_0326: Unknown result type (might be due to invalid IL or missing references)
//IL_0327: Unknown result type (might be due to invalid IL or missing references)
//IL_0226: Unknown result type (might be due to invalid IL or missing references)
//IL_0229: Unknown result type (might be due to invalid IL or missing references)
//IL_022e: Unknown result type (might be due to invalid IL or missing references)
//IL_0235: Unknown result type (might be due to invalid IL or missing references)
//IL_023a: Unknown result type (might be due to invalid IL or missing references)
//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
//IL_0257: Unknown result type (might be due to invalid IL or missing references)
//IL_025b: Unknown result type (might be due to invalid IL or missing references)
//IL_0260: Unknown result type (might be due to invalid IL or missing references)
//IL_0267: Unknown result type (might be due to invalid IL or missing references)
//IL_026c: Unknown result type (might be due to invalid IL or missing references)
//IL_0272: Unknown result type (might be due to invalid IL or missing references)
//IL_0277: Unknown result type (might be due to invalid IL or missing references)
//IL_027e: Unknown result type (might be due to invalid IL or missing references)
//IL_0283: Unknown result type (might be due to invalid IL or missing references)
//IL_028a: Unknown result type (might be due to invalid IL or missing references)
//IL_028f: Unknown result type (might be due to invalid IL or missing references)
//IL_0296: Unknown result type (might be due to invalid IL or missing references)
//IL_029b: Unknown result type (might be due to invalid IL or missing references)
//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
if (ConfigEnableClientInterpolation == null || ConfigEnablePlayerPrediction == null || (!ConfigEnableClientInterpolation.Value && !ConfigEnablePlayerPrediction.Value) || (Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer() || __instance == null || !IsPlayerZDO(__instance))
{
return;
}
long owner = __instance.GetOwner();
if (owner == ZNet.GetUID())
{
return;
}
Vector3 position = __instance.GetPosition();
Quaternion rotation = __instance.GetRotation();
rotation = Quaternion.Normalize(rotation);
float time = Time.time;
if (!_syncData.TryGetValue(owner, out var value))
{
_syncData[owner] = new PlayerSyncData
{
networkPos = position,
prevNetworkPos = position,
networkRot = rotation,
prevNetworkRot = rotation,
renderPos = position,
renderRot = rotation,
velocity = Vector3.zero,
smoothedVelocity = Vector3.zero,
acceleration = Vector3.zero,
networkUpdateInterval = 0.05f,
lastNetworkUpdateTime = time,
lastFrameTime = time,
hasData = true
};
return;
}
float num = time - value.lastNetworkUpdateTime;
if (position == value.networkPos)
{
value.velocity = Vector3.Lerp(value.velocity, Vector3.zero, 0.9f);
value.acceleration = Vector3.Lerp(value.acceleration, Vector3.zero, 0.9f);
if (((Vector3)(ref value.velocity)).magnitude < 0.05f)
{
value.velocity = Vector3.zero;
value.acceleration = Vector3.zero;
}
}
else if (num >= 0.005f && num <= 0.5f)
{
value.networkUpdateInterval = Mathf.Lerp(value.networkUpdateInterval, num, 0.15f);
Vector3 val = (position - value.networkPos) / num;
if (((Vector3)(ref val)).magnitude <= 30f)
{
Vector3 val2 = (val - value.velocity) / num;
value.acceleration = Vector3.Lerp(value.acceleration, val2, 0.25f);
Vector3 val3 = Vector3.Lerp(value.velocity, val, 0.5f);
value.velocity = Vector3.Lerp(value.velocity, val3, 0.7f);
value.smoothedVelocity = Vector3.Lerp(value.smoothedVelocity, value.velocity, 0.6f);
}
else
{
value.velocity = Vector3.zero;
value.smoothedVelocity = Vector3.zero;
value.acceleration = Vector3.zero;
}
}
value.prevNetworkPos = value.networkPos;
value.prevNetworkRot = value.networkRot;
value.networkPos = position;
value.networkRot = rotation;
value.lastNetworkUpdateTime = time;
value.hasData = true;
}
[HarmonyPatch(typeof(Player), "LateUpdate")]
[HarmonyPostfix]
public static void Player_LateUpdate_Postfix(Player __instance)
{
//IL_014f: Unknown result type (might be due to invalid IL or missing references)
//IL_0155: Unknown result type (might be due to invalid IL or missing references)
//IL_0169: Unknown result type (might be due to invalid IL or missing references)
//IL_016f: Unknown result type (might be due to invalid IL or missing references)
//IL_026f: Unknown result type (might be due to invalid IL or missing references)
//IL_0274: Unknown result type (might be due to invalid IL or missing references)
//IL_0231: Unknown result type (might be due to invalid IL or missing references)
//IL_0237: Unknown result type (might be due to invalid IL or missing references)
//IL_023e: Unknown result type (might be due to invalid IL or missing references)
//IL_0248: Unknown result type (might be due to invalid IL or missing references)
//IL_024d: Unknown result type (might be due to invalid IL or missing references)
//IL_0252: Unknown result type (might be due to invalid IL or missing references)
//IL_0255: Unknown result type (might be due to invalid IL or missing references)
//IL_025a: Unknown result type (might be due to invalid IL or missing references)
//IL_025e: Unknown result type (might be due to invalid IL or missing references)
//IL_0263: Unknown result type (might be due to invalid IL or missing references)
//IL_0268: Unknown result type (might be due to invalid IL or missing references)
//IL_0278: Unknown result type (might be due to invalid IL or missing references)
//IL_027d: Unknown result type (might be due to invalid IL or missing references)
//IL_0297: Unknown result type (might be due to invalid IL or missing references)
//IL_0299: Unknown result type (might be due to invalid IL or missing references)
//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
//IL_0336: Unknown result type (might be due to invalid IL or missing references)
//IL_033b: Unknown result type (might be due to invalid IL or missing references)
//IL_033f: Unknown result type (might be due to invalid IL or missing references)
//IL_0344: Unknown result type (might be due to invalid IL or missing references)
//IL_0351: Unknown result type (might be due to invalid IL or missing references)
//IL_0357: Unknown result type (might be due to invalid IL or missing references)
//IL_03cf: Unknown result type (might be due to invalid IL or missing references)
//IL_03d5: Unknown result type (might be due to invalid IL or missing references)
//IL_03dc: Unknown result type (might be due to invalid IL or missing references)
//IL_03ee: Unknown result type (might be due to invalid IL or missing references)
//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
//IL_0400: Unknown result type (might be due to invalid IL or missing references)
//IL_0397: Unknown result type (might be due to invalid IL or missing references)
//IL_039d: Unknown result type (might be due to invalid IL or missing references)
//IL_03ac: Unknown result type (might be due to invalid IL or missing references)
//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
//IL_03b8: Unknown result type (might be due to invalid IL or missing references)
//IL_03bd: Unknown result type (might be due to invalid IL or missing references)
//IL_03c2: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)__instance == (Object)null || (Object)(object)__instance == (Object)(object)Player.m_localPlayer || (Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer() || ConfigEnableClientInterpolation == null || !ConfigEnableClientInterpolation.Value)
{
return;
}
ZNetView nview = ((Character)__instance).m_nview;
if ((Object)(object)nview == (Object)null || !nview.IsValid())
{
return;
}
ZDO zDO = nview.GetZDO();
if (zDO == null)
{
return;
}
long owner = zDO.GetOwner();
if (!_syncData.TryGetValue(owner, out var value) || !value.hasData)
{
return;
}
float networkUpdateInterval = value.networkUpdateInterval;
float num = ConfigSmoothingMinInterval?.Value ?? 0.05f;
float num2 = Mathf.Max(num + 0.001f, ConfigSmoothingMaxInterval?.Value ?? 0.2f);
if (networkUpdateInterval < num)
{
return;
}
float num3 = Mathf.Clamp01((networkUpdateInterval - num) / (num2 - num));
bool flag = ((Vector3)(ref value.smoothedVelocity)).magnitude < 0.03f;
bool flag2 = Vector3.Distance(value.renderPos, value.networkPos) < 0.005f;
bool flag3 = Quaternion.Angle(value.renderRot, value.networkRot) < 0.05f;
if (flag && flag2 && flag3)
{
return;
}
float time = Time.time;
float num4 = time - value.lastFrameTime;
value.lastFrameTime = time;
float num5 = time - value.lastNetworkUpdateTime;
float num6 = 0f;
num6 = ((!ConfigEnablePlayerPrediction.Value || !(((Vector3)(ref value.smoothedVelocity)).magnitude > 0.2f)) ? (value.networkUpdateInterval * 0.4f) : Mathf.Min(num5 * 0.8f, value.networkUpdateInterval * 1.2f));
Vector3 val2;
if (((Vector3)(ref value.smoothedVelocity)).magnitude > 1f)
{
Vector3 val = value.smoothedVelocity + value.acceleration * num6 * 0.5f;
val2 = value.networkPos + val * num6;
}
else
{
val2 = value.networkPos;
}
float num7 = Vector3.Distance(value.renderPos, val2);
if (num7 > 5f)
{
value.renderPos = val2;
value.renderRot = Quaternion.Normalize(value.networkRot);
}
else
{
float num8 = Mathf.Clamp01(((Vector3)(ref value.smoothedVelocity)).magnitude / 8f);
float num9 = Mathf.Clamp01(num7 / 1.5f);
float num10 = Mathf.Lerp(15f, 30f, Mathf.Max(num8, num9));
if (num7 < 0.2f)
{
num10 *= 0.6f;
}
float num11 = Mathf.Clamp01(num4 * num10);
num11 = num11 * num11 * (3f - 2f * num11);
value.renderPos = Vector3.Lerp(value.renderPos, val2, num11);
float num12 = 25f;
float num13 = Quaternion.Angle(value.renderRot, value.networkRot);
if (num13 > 30f)
{
num12 = 40f;
}
else if (num13 < 5f)
{
num12 = 15f;
}
value.renderRot = Quaternion.Slerp(value.renderRot, value.networkRot, Mathf.Clamp01(num4 * num12));
value.renderRot = Quaternion.Normalize(value.renderRot);
}
((Component)__instance).transform.position = Vector3.Lerp(value.networkPos, value.renderPos, num3);
((Component)__instance).transform.rotation = Quaternion.Slerp(Quaternion.Normalize(value.networkRot), value.renderRot, num3);
}
}
public static class RoutedRpcManager
{
public static readonly Dictionary<int, string> HashCodeToMethodNameCache = new Dictionary<int, string>();
private static readonly Dictionary<int, List<RpcMethodHandler>> _rpcMethodHandlers = new Dictionary<int, List<RpcMethodHandler>>();
private static readonly RoutedRPCData _routedRpcData = new RoutedRPCData();
private static long _serverPeerId = 0L;
private static float _aoiRadiusOverride = -1f;
public static long ServerPeerId => _serverPeerId;
public static void SetAoIRadiusOverride(float radius)
{
_aoiRadiusOverride = radius;
}
public static void SetupServerPeer()
{
_serverPeerId = ZDOMan.GetSessionID();
LoggerOptions.LogInfo($"[RpcRouter] Server peer ID set to {_serverPeerId}");
}
public static void AddHandler(string methodName, RpcMethodHandler handler)
{
int stableHashCode = StringExtensionMethods.GetStableHashCode(methodName);
HashCodeToMethodNameCache[stableHashCode] = methodName;
LoggerOptions.LogInfo($"[RpcRouter] Registering handler for {methodName} ({stableHashCode}): {handler.GetType().Name}");
if (!_rpcMethodHandlers.TryGetValue(stableHashCode, out var value))
{
value = new List<RpcMethodHandler>();
_rpcMethodHandlers[stableHashCode] = value;
}
value.Add(handler);
}
public static void ProcessRoutedRPC(ZRoutedRpc routedRpc, ZRpc rpc, ZPackage package)
{
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
_routedRpcData.Deserialize(package);
long targetPeerID = _routedRpcData.m_targetPeerID;
long id = routedRpc.m_id;
if (targetPeerID == id || targetPeerID == 0)
{
routedRpc.HandleRoutedRPC(_routedRpcData);
}
if ((targetPeerID != id || targetPeerID == _serverPeerId) && ProcessHandlers(_routedRpcData))
{
if (targetPeerID == 0L && FiresGhettoNetworkMod.ConfigEnableRpcAoI.Value)
{
float radius = ((_aoiRadiusOverride > 0f) ? _aoiRadiusOverride : FiresGhettoNetworkMod.ConfigRpcAoIRadius.Value);
_aoiRadiusOverride = -1f;
if (!((ZDOID)(ref _routedRpcData.m_targetZDO)).IsNone())
{
SpawnedZonePositionHint.Clear();
RouteRPCWithAoI(routedRpc, _routedRpcData, radius);
}
else if (SpawnedZonePositionHint.HasHint)
{
Vector3 position = SpawnedZonePositionHint.Position;
SpawnedZonePositionHint.Clear();
RouteRPCWithAoIFromPosition(routedRpc, _routedRpcData, position, radius);
}
else
{
SpawnedZonePositionHint.Clear();
routedRpc.RouteRPC(_routedRpcData);
}
}
else
{
_aoiRadiusOverride = -1f;
SpawnedZonePositionHint.Clear();
routedRpc.RouteRPC(_routedRpcData);
}
}
else
{
_aoiRadiusOverride = -1f;
SpawnedZonePositionHint.Clear();
}
}
private static void RouteRPCWithAoIFromPosition(ZRoutedRpc routedRpc, RoutedRPCData rpcData, Vector3 worldPos, float radius)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Expected O, but got Unknown
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
float num = radius * radius;
ZPackage val = new ZPackage();
rpcData.Serialize(val);
foreach (ZNetPeer peer in routedRpc.m_peers)
{
if (rpcData.m_senderPeerID != peer.m_uid && peer.IsReady())
{
Vector3 refPos = peer.GetRefPos();
float num2 = refPos.x - worldPos.x;
float num3 = refPos.z - worldPos.z;
if (num2 * num2 + num3 * num3 <= num)
{
peer.m_rpc.Invoke("RoutedRPC", new object[1] { val });
}
}
}
}
private static void RouteRPCWithAoI(ZRoutedRpc routedRpc, RoutedRPCData rpcData, float radius)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Expected O, but got Unknown
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
if (!ZDOMan.instance.m_objectsByID.TryGetValue(rpcData.m_targetZDO, out var value))
{
routedRpc.RouteRPC(rpcData);
return;
}
Vector3 position = value.m_position;
float num = radius * radius;
ZPackage val = new ZPackage();
rpcData.Serialize(val);
int num2 = 0;
int num3 = 0;
foreach (ZNetPeer peer in routedRpc.m_peers)
{
if (rpcData.m_senderPeerID != peer.m_uid && peer.IsReady())
{
Vector3 refPos = peer.GetRefPos();
float num4 = refPos.x - position.x;
float num5 = refPos.z - position.z;
float num6 = num4 * num4 + num5 * num5;
if (num6 <= num)
{
peer.m_rpc.Invoke("RoutedRPC", new object[1] { val });
num2++;
}
else
{
num3++;
}
}
}
}
public static bool ProcessHandlers(RoutedRPCData routedRpcData)
{
if (!_rpcMethodHandlers.TryGetValue(routedRpcData.m_methodHash, out var value))
{
return true;
}
bool flag = true;
foreach (RpcMethodHandler item in value)
{
flag &= item.Process(routedRpcData);
}
return flag;
}
public static string MethodHashToString(int methodHash)
{
if (HashCodeToMethodNameCache.TryGetValue(methodHash, out var value))
{
return value;
}
return $"RPC_{methodHash}";
}
public static void Reset()
{
_rpcMethodHandlers.Clear();
HashCodeToMethodNameCache.Clear();
_serverPeerId = 0L;
}
}
public sealed class AddNoiseHandler : RpcMethodHandler
{
private static readonly AddNoiseHandler _instance = new AddNoiseHandler();
private AddNoiseHandler()
{
}
public static void Register()
{
RoutedRpcManager.AddHandler("AddNoise", _instance);
}
public override bool Process(RoutedRPCData routedRpcData)
{
ZPackage parameters = routedRpcData.m_parameters;
if (parameters == null || parameters.Size() < 4)
{
return true;
}
int pos = parameters.GetPos();
parameters.SetPos(0);
float num = parameters.ReadSingle();
parameters.SetPos(pos);
RoutedRpcManager.SetAoIRadiusOverride(num * 2f);
return true;
}
}
public sealed class DamageTextHandler : RpcMethodHandler
{
private static readonly DamageTextHandler _instance = new DamageTextHandler();
private DamageTextHandler()
{
}
public static void Register()
{
RoutedRpcManager.AddHandler("DamageText", _instance);
}
public override bool Process(RoutedRPCData routedRpcData)
{
return false;
}
}
public sealed class HealthChangedHandler : RpcMethodHandler
{
private static readonly HealthChangedHandler _instance = new HealthChangedHandler();
private HealthChangedHandler()
{
}
public static void Register()
{
RoutedRpcManager.AddHandler("RPC_HealthChanged", _instance);
}
public override bool Process(RoutedRPCData routedRpcData)
{
return false;
}
}
public sealed class SetTargetHandler : RpcMethodHandler
{
private static readonly SetTargetHandler _instance = new SetTargetHandler();
public static readonly int PlayerHashCode = StringExtensionMethods.GetStableHashCode("Player");
private SetTargetHandler()
{
}
public static void Register()
{
RoutedRpcManager.AddHandler("RPC_SetTarget", _instance);
}
public override bool Process(RoutedRPCData routedRpcData)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
ZPackage parameters = routedRpcData.m_parameters;
parameters.SetPos(0);
ZDOID val = parameters.ReadZDOID();
parameters.SetPos(0);
if (val == ZDOID.None)
{
return true;
}
if (!ZDOMan.instance.m_objectsByID.TryGetValue(val, out var value))
{
return true;
}
if (Utils.DistanceXZ(Vector3.zero, value.m_position) > 50000f)
{
LoggerOptions.LogWarning($"[RpcRouter] SetTarget suspicious — target ZDO at extreme distance ({value.m_position})");
return true;
}
if (value.m_prefab == PlayerHashCode || value.GetBool(ZDOVars.s_tamed, false))
{
parameters.Clear();
parameters.Write(ZDOID.None);
parameters.m_writer.Flush();
parameters.m_stream.Flush();
parameters.SetPos(0);
routedRpcData.m_senderPeerID = ZRoutedRpc.instance.m_id;
LoggerOptions.LogInfo("[RpcRouter] SetTarget cleared — target was player or tamed creature");
}
return true;
}
}
public sealed class SpawnedZoneHandler : RpcMethodHandler
{
private static readonly SpawnedZoneHandler _instance = new SpawnedZoneHandler();
private SpawnedZoneHandler()
{
}
public static void Register()
{
RoutedRpcManager.AddHandler("SpawnedZone", _instance);
}
public override bool Process(RoutedRPCData routedRpcData)
{
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: 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_0057: Unknown result type (might be due to invalid IL or missing references)
ZPackage parameters = routedRpcData.m_parameters;
if (parameters == null || parameters.Size() < 8)
{
return true;
}
int pos = parameters.GetPos();
parameters.SetPos(0);
int num = parameters.ReadInt();
int num2 = parameters.ReadInt();
parameters.SetPos(pos);
Vector3 zonePos = ZoneSystem.GetZonePos(new Vector2i(num, num2));
SpawnedZonePositionHint.Position = zonePos;
SpawnedZonePositionHint.HasHint = true;
RoutedRpcManager.SetAoIRadiusOverride(FiresGhettoNetworkMod.ConfigRpcAoIRadius.Value);
return true;
}
}
public static class SpawnedZonePositionHint
{
public static bool HasHint;
public static Vector3 Position;
public static void Clear()
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
HasHint = false;
Position = Vector3.zero;
}
}
public sealed class TalkerSayHandler : RpcMethodHandler
{
private static readonly TalkerSayHandler _instance = new TalkerSayHandler();
private TalkerSayHandler()
{
}
public static void Register()
{
RoutedRpcManager.AddHandler("Say", _instance);
}
public override bool Process(RoutedRPCData routedRpcData)
{
return true;
}
}
public sealed class TriggerAnimationHandler : RpcMethodHandler
{
private static readonly TriggerAnimationHandler _instance = new TriggerAnimationHandler();
private TriggerAnimationHandler()
{
}
public static void Register()
{
RoutedRpcManager.AddHandler("TriggerAnimation", _instance);
}
public override bool Process(RoutedRPCData routedRpcData)
{
return true;
}
}
public sealed class TriggerOnDeathHandler : RpcMethodHandler
{
private static readonly TriggerOnDeathHandler _instance = new TriggerOnDeathHandler();
private TriggerOnDeathHandler()
{
}
public static void Register()
{
RoutedRpcManager.AddHandler("OnDeath", _instance);
}
public override bool Process(RoutedRPCData routedRpcData)
{
return true;
}
}
public sealed class WNTHealthChangedHandler : RpcMethodHandler
{
private static readonly WNTHealthChangedHandler _instance = new WNTHealthChangedHandler();
private WNTHealthChangedHandler()
{
}
public static void Register()
{
RoutedRpcManager.AddHandler("RPC_WNTHealthChanged", _instance);
}
public override bool Process(RoutedRPCData routedRpcData)
{
return false;
}
}
public abstract class RpcMethodHandler
{
public abstract bool Process(RoutedRPCData routedRpcData);
}
[HarmonyPatch]
public static class RpcRouterPatches
{
[HarmonyPatch(typeof(ZNet), "Start")]
[HarmonyPostfix]
public static void ZNet_Start_Postfix()
{
if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated() && ZDOMan.instance != null)
{
RoutedRpcManager.SetupServerPeer();
}
}
[HarmonyPatch(typeof(ZRoutedRpc), "RPC_RoutedRPC")]
[HarmonyPrefix]
public static bool RPC_RoutedRPC_Prefix(ZRoutedRpc __instance, ZRpc rpc, ZPackage pkg)
{
if (__instance.m_server)
{
RoutedRpcManager.ProcessRoutedRPC(__instance, rpc, pkg);
return false;
}
return true;
}
}
[HarmonyPatch]
public static class ServerAuthorityPatches
{
private static readonly int DefaultActiveArea = 3;
private static readonly int DefaultDistantArea = 5;
private static readonly int PlayerPrefabHash = StringExtensionMethods.GetStableHashCode("Player");
[HarmonyPatch(typeof(ZoneSystem), "IsActiveAreaLoaded")]
[HarmonyPriority(800)]
[HarmonyPrefix]
public static bool IsActiveAreaLoaded_TeleportFix(ref bool __result)
{
if ((Object)(object)Player.m_localPlayer != (Object)null && ((Character)Player.m_localPlayer).IsTeleporting())
{
__result = true;
return false;
}
return true;
}
[HarmonyPatch(typeof(ZNetScene), "CreateDestroyObjects")]
[HarmonyPrefix]
public static bool CreateDestroyObjects_Prefix(ZNetScene __instance)
{
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: 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_00cc: Unknown result type (might be due to invalid IL or missing references)
if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsDedicated() || ZNet.instance.GetConnectedPeers().Count == 0)
{
return true;
}
try
{
int value = FiresGhettoNetworkMod.ConfigExtendedZoneRadius.Value;
int num = (ZoneSystem.instance?.m_activeArea ?? DefaultActiveArea) + value;
int num2 = (ZoneSystem.instance?.m_activeDistantArea ?? DefaultDistantArea) + value;
List<ZDO> list = new List<ZDO>();
List<ZDO> list2 = new List<ZDO>();
foreach (ZNetPeer connectedPeer in ZNet.instance.GetConnectedPeers())
{
if (connectedPeer.IsReady())
{
Vector3 refPos = connectedPeer.GetRefPos();
Vector2i zone = ZoneSystem.GetZone(refPos);
ZDOMan.instance.FindSectorObjects(zone, num, num2, list, list2);
}
}
List<ZDO> list3 = list.Where((ZDO zdo) => zdo != null && zdo.IsValid() && !((ZDOID)(ref zdo.m_uid)).IsNone()).Distinct().ToList();
List<ZDO> list4 = list2.Where((ZDO zdo) => zdo != null && zdo.IsValid() && !((ZDOID)(ref zdo.m_uid)).IsNone()).Distinct().ToList();
__instance.CreateObjects(list3, list4);
__instance.RemoveObjects(list3, list4);
return false;
}
catch (NullReferenceException ex)
{
LoggerOptions.LogWarning("CreateDestroyObjects encountered NRE (likely mod conflict), falling back to vanilla: " + ex.Message);
return true;
}
}
[HarmonyPatch(typeof(ZoneSystem), "IsActiveAreaLoaded")]
[HarmonyPrefix]
public static bool IsActiveAreaLoaded_Prefix(ref bool __result, ZoneSystem __instance)
{
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_010e: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsDedicated() || ZNet.instance.GetPeers().Count == 0)
{
return true;
}
int value = FiresGhettoNetworkMod.ConfigExtendedZoneRadius.Value;
int num = __instance.m_activeArea + value;
Dictionary<Vector2i, ZoneData> zones = __instance.m_zones;
if (zones == null)
{
return true;
}
foreach (ZNetPeer peer in ZNet.instance.GetPeers())
{
if (!peer.IsReady())
{
continue;
}
Vector2i zone = ZoneSystem.GetZone(peer.GetRefPos());
for (int i = zone.y - num; i <= zone.y + num; i++)
{
for (int j = zone.x - num; j <= zone.x + num; j++)
{
if (!zones.ContainsKey(new Vector2i(j, i)))
{
__result = false;
return false;
}
}
}
}
__result = true;
return false;
}
[HarmonyPatch(typeof(ZoneSystem), "Update")]
[HarmonyPostfix]
public static void ZoneSystem_Update_Postfix(ZoneSystem __instance)
{
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsDedicated() || ZNet.instance.GetPeers().Count == 0)
{
return;
}
foreach (ZNetPeer peer in ZNet.instance.GetPeers())
{
if (peer.IsReady())
{
__instance.CreateLocalZones(peer.GetRefPos());
}
}
}
private static bool IsPlayerZDO(ZDO zdo)
{
return zdo != null && zdo.m_prefab == PlayerPrefabHash;
}
private static bool IsPeerConnected(ZDOMan zdoMan, long uid)
{
if (uid == ZDOMan.GetSessionID())
{
return true;
}
foreach (ZNetPeer peer in ZNet.instance.GetPeers())
{
if (peer.m_uid == uid)
{
return true;
}
}
return false;
}
[HarmonyPatch(typeof(ZNetScene), "OutsideActiveArea", new Type[] { typeof(Vector3) })]
[HarmonyPrefix]
public static bool OutsideActiveArea_Prefix(ref bool __result, Vector3 point)
{
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsDedicated() || ZNet.instance.GetPeers().Count == 0)
{
return true;
}
int value = FiresGhettoNetworkMod.ConfigExtendedZoneRadius.Value;
int num = (ZoneSystem.instance?.m_activeArea ?? DefaultActiveArea) + value;
__result = true;
foreach (ZNetPeer peer in ZNet.instance.GetPeers())
{
if (peer.IsReady() && !ZNetScene.OutsideActiveArea(point, ZoneSystem.GetZone(peer.GetRefPos()), num))
{
__result = false;
break;
}
}
return false;
}
[HarmonyPatch(typeof(Tameable), "Awake")]
[HarmonyPrefix]
public static bool Tameable_Awake_Prefix()
{
return (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsDedicated();
}
[HarmonyPatch(typeof(Tameable), "Update")]