Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ChunkLoader v1.0.5
plugins/ChunkLoader.dll
Decompiled 13 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("ChunkLoader")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ChunkLoader")] [assembly: AssemblyTitle("ChunkLoader")] [assembly: AssemblyVersion("1.0.5.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ChunkLoader { public class ChunkLoaderComponent : MonoBehaviour, Hoverable { private ZNetView _nview; private Piece _piece; private void Awake() { _nview = ((Component)this).GetComponent<ZNetView>(); _piece = ((Component)this).GetComponent<Piece>(); } private void Start() { if ((Object)(object)_nview != (Object)null && _nview.IsValid()) { LoaderRegistry.Register(_nview.GetZDO()); } } public string GetHoverText() { int value = Plugin.LoadRadiusZones.Value; int num = (value * 2 + 1) * 64; string text = (Plugin.Enabled.Value ? "<color=#C080FF>Active</color>" : "<color=#FF6060>Disabled by config</color>"); return $"{GetHoverName()}\n{text}\nKeeps a {num}x{num} m area loaded ({value * 2 + 1}x{value * 2 + 1} zones)"; } public string GetHoverName() { if (!((Object)(object)_piece != (Object)null)) { return "Chunk Loader"; } return Localization.instance.Localize(_piece.m_name); } public float GetHoverOffset() { return 0f; } } internal static class ChunkLoaderPrefab { private static readonly string[] ColorProps = new string[4] { "_Color", "_TintColor", "_EmissionColor", "_MainColor" }; private static readonly Dictionary<Material, Material> _matCache = new Dictionary<Material, Material>(); private static readonly Dictionary<Texture, Texture2D> _texCache = new Dictionary<Texture, Texture2D>(); public static void Configure(GameObject prefab, Color glow) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) Renderer val = LoaderPresentation.FindWardModel(prefab); float hue = default(float); float num = default(float); float num2 = default(float); Color.RGBToHSV(glow, ref hue, ref num, ref num2); StripWard(prefab); Recolor(prefab, hue); if (!((Object)(object)val == (Object)null)) { LoaderPresentation.SetEmission(val, glow); } LoaderPresentation.ReplaceWardGuide(prefab); if ((Object)(object)prefab.GetComponent<ChunkLoaderComponent>() == (Object)null) { prefab.AddComponent<ChunkLoaderComponent>(); } } private static void StripWard(GameObject prefab) { PrivateArea[] componentsInChildren = prefab.GetComponentsInChildren<PrivateArea>(true); foreach (PrivateArea val in componentsInChildren) { if ((Object)(object)val.m_enabledEffect != (Object)null) { val.m_enabledEffect.SetActive(false); } if ((Object)(object)val.m_areaMarker != (Object)null) { Object.DestroyImmediate((Object)(object)((Component)val.m_areaMarker).gameObject); } if ((Object)(object)val.m_model != (Object)null) { _ = val.m_model; } Object.DestroyImmediate((Object)(object)val); } EffectArea[] componentsInChildren2 = prefab.GetComponentsInChildren<EffectArea>(true); foreach (EffectArea val2 in componentsInChildren2) { if ((Object)(object)val2 == (Object)null) { continue; } if ((Object)(object)((Component)val2).gameObject != (Object)(object)prefab) { Object.DestroyImmediate((Object)(object)((Component)val2).gameObject); continue; } Collider[] components = prefab.GetComponents<Collider>(); foreach (Collider val3 in components) { if (val3.isTrigger) { Object.DestroyImmediate((Object)(object)val3); } } Object.DestroyImmediate((Object)(object)val2); } } private static void Recolor(GameObject prefab, float hue) { //IL_0010: 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_003a: 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) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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_006e: 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) Light[] componentsInChildren = prefab.GetComponentsInChildren<Light>(true); foreach (Light obj in componentsInChildren) { obj.color = Shift(obj.color, hue); } ParticleSystem[] componentsInChildren2 = prefab.GetComponentsInChildren<ParticleSystem>(true); foreach (ParticleSystem obj2 in componentsInChildren2) { MainModule main = obj2.main; ((MainModule)(ref main)).startColor = Shift(((MainModule)(ref main)).startColor, hue); ColorOverLifetimeModule colorOverLifetime = obj2.colorOverLifetime; if (((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled) { ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = Shift(((ColorOverLifetimeModule)(ref colorOverLifetime)).color, hue); } } Renderer[] componentsInChildren3 = prefab.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren3) { Material[] sharedMaterials = val.sharedMaterials; bool flag = false; for (int j = 0; j < sharedMaterials.Length; j++) { if ((Object)(object)sharedMaterials[j] == (Object)null) { continue; } Material val2 = CloneMat(sharedMaterials[j]); string[] colorProps = ColorProps; foreach (string text in colorProps) { if (val2.HasProperty(text)) { val2.SetColor(text, ShiftHdr(val2.GetColor(text), hue)); } } if (val2.HasProperty("_EmissionMap")) { Texture2D val3 = ShiftTexture(val2.GetTexture("_EmissionMap"), hue); if ((Object)(object)val3 != (Object)null) { val2.SetTexture("_EmissionMap", (Texture)(object)val3); } } if (val is ParticleSystemRenderer && val2.HasProperty("_MainTex")) { Texture2D val4 = ShiftTexture(val2.GetTexture("_MainTex"), hue); if ((Object)(object)val4 != (Object)null) { val2.SetTexture("_MainTex", (Texture)(object)val4); } } sharedMaterials[j] = val2; flag = true; } if (flag) { val.sharedMaterials = sharedMaterials; } } } private static Material CloneMat(Material src) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown if (_matCache.ContainsValue(src)) { return src; } if (!_matCache.TryGetValue(src, out var value)) { value = new Material(src) { name = ((Object)src).name + "_chunkloader" }; _matCache[src] = value; } return value; } private static Color Shift(Color c, float hue) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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) float num = default(float); float num2 = default(float); float num3 = default(float); Color.RGBToHSV(c, ref num, ref num2, ref num3); if (num2 < 0.15f) { return c; } Color result = Color.HSVToRGB(hue, num2, num3, true); result.a = c.a; return result; } private static Color ShiftHdr(Color c, float hue) { //IL_0018: 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_0028: 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_0036: 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) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) float maxColorComponent = ((Color)(ref c)).maxColorComponent; if (maxColorComponent <= 1f) { return Shift(c, hue); } Color val = Shift(new Color(c.r / maxColorComponent, c.g / maxColorComponent, c.b / maxColorComponent, c.a), hue); return new Color(val.r * maxColorComponent, val.g * maxColorComponent, val.b * maxColorComponent, c.a); } private static Gradient Shift(Gradient g, float hue) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown if (g == null) { return null; } GradientColorKey[] colorKeys = g.colorKeys; for (int i = 0; i < colorKeys.Length; i++) { colorKeys[i].color = Shift(colorKeys[i].color, hue); } Gradient val = new Gradient { mode = g.mode }; val.SetKeys(colorKeys, g.alphaKeys); return val; } private static MinMaxGradient Shift(MinMaxGradient g, float hue) { //IL_0002: 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_0022: Expected I4, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //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) ParticleSystemGradientMode mode = ((MinMaxGradient)(ref g)).mode; switch ((int)mode) { case 0: return new MinMaxGradient(Shift(((MinMaxGradient)(ref g)).color, hue)); case 2: return new MinMaxGradient(Shift(((MinMaxGradient)(ref g)).colorMin, hue), Shift(((MinMaxGradient)(ref g)).colorMax, hue)); case 1: return new MinMaxGradient(Shift(((MinMaxGradient)(ref g)).gradient, hue)); case 3: return new MinMaxGradient(Shift(((MinMaxGradient)(ref g)).gradientMin, hue), Shift(((MinMaxGradient)(ref g)).gradientMax, hue)); case 4: { MinMaxGradient result = default(MinMaxGradient); ((MinMaxGradient)(ref result))..ctor(Shift(((MinMaxGradient)(ref g)).gradient, hue)); ((MinMaxGradient)(ref result)).mode = (ParticleSystemGradientMode)4; return result; } default: return g; } } private static Texture2D ShiftTexture(Texture src, float hue) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown //IL_008b: 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_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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: 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_00e2: 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) if ((Object)(object)src == (Object)null || (int)SystemInfo.graphicsDeviceType == 4) { return null; } if (_texCache.TryGetValue(src, out var value)) { return value; } Texture2D val = null; RenderTexture active = RenderTexture.active; RenderTexture val2 = null; try { int width = src.width; int height = src.height; val2 = RenderTexture.GetTemporary(width, height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2); Graphics.Blit(src, val2); RenderTexture.active = val2; val = new Texture2D(width, height, (TextureFormat)4, true) { name = ((Object)src).name + "_chunkloader" }; val.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), 0, 0); Color32[] pixels = val.GetPixels32(); for (int i = 0; i < pixels.Length; i++) { Color c = Color32.op_Implicit(pixels[i]); pixels[i] = Color32.op_Implicit(Shift(c, hue)); } val.SetPixels32(pixels); ((Texture)val).wrapMode = src.wrapMode; ((Texture)val).filterMode = src.filterMode; val.Apply(true, true); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not recolor texture '" + ((Object)src).name + "': " + ex.Message)); val = null; } finally { RenderTexture.active = active; if ((Object)(object)val2 != (Object)null) { RenderTexture.ReleaseTemporary(val2); } } _texCache[src] = val; return val; } } internal static class LoaderRegistry { private const float PokeInterval = 0.5f; private const float OwnershipInterval = 2f; private const float RescanInterval = 10f; private const int ScanCallsPerFrame = 16; private static readonly HashSet<Vector2i> _loadedZones = new HashSet<Vector2i>(); private static readonly List<Vector2i> _loadedZoneList = new List<Vector2i>(); private static readonly List<ZDO> _loaders = new List<ZDO>(); private static readonly List<ZDO> _scanResult = new List<ZDO>(); private static readonly List<ZDO> _tmp = new List<ZDO>(); private static bool _scanning; private static int _scanIndex; private static float _rescanTimer = 10f; private static float _pokeTimer; private static float _ownershipTimer; private static int _appliedRadius = -1; private static int _appliedMax = -1; private static MethodInfo _pokeLocalZone; private static bool _pokeLookupDone; public static bool Active { get { if (_loadedZones.Count > 0 && Plugin.Enabled.Value && (Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsServer(); } return false; } } public static IReadOnlyList<Vector2i> LoadedZones => _loadedZoneList; public static bool IsInLoadedArea(Vector3 point) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (Active) { return _loadedZones.Contains(RuntimeSupport.GetZone(point)); } return false; } public static bool IsZoneLoadedByLoader(Vector2i zone) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (Active) { return _loadedZones.Contains(zone); } return false; } public static void Register(ZDO zdo) { if (zdo != null && !((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && !_loaders.Contains(zdo)) { _loaders.Add(zdo); RebuildZones(); } } public static void Tick(float dt) { if ((Object)(object)ZNet.instance == (Object)null || ZDOMan.instance == null || (Object)(object)ZoneSystem.instance == (Object)null || !ZNet.instance.IsServer()) { Reset(); return; } if (!Plugin.Enabled.Value) { if (_loadedZones.Count > 0) { _loadedZones.Clear(); _loadedZoneList.Clear(); } return; } if (_appliedRadius != Plugin.LoadRadiusZones.Value || _appliedMax != Plugin.MaxLoaders.Value) { RebuildZones(); } ScanStep(dt); if (_loadedZones.Count != 0) { _pokeTimer += dt; if (_pokeTimer >= 0.5f) { _pokeTimer = 0f; KeepZonesAlive(); } _ownershipTimer += dt; if (_ownershipTimer >= 2f) { _ownershipTimer = 0f; ClaimOwnership(); } } } private static void Reset() { if (_loaders.Count != 0 || _loadedZones.Count != 0 || _scanning) { _loaders.Clear(); _loadedZones.Clear(); _loadedZoneList.Clear(); _scanResult.Clear(); _scanning = false; _scanIndex = 0; _rescanTimer = 10f; _appliedRadius = -1; _appliedMax = -1; } } private static void ScanStep(float dt) { if (!_scanning) { _rescanTimer += dt; if (_rescanTimer < 10f) { return; } _rescanTimer = 0f; _scanning = true; _scanIndex = 0; _scanResult.Clear(); } for (int i = 0; i < 16; i++) { if (!ZDOMan.instance.GetAllZDOsWithPrefabIterative("piece_chunkloader", _scanResult, ref _scanIndex)) { continue; } _scanning = false; _loaders.Clear(); foreach (ZDO item in _scanResult) { if (item != null && item.IsValid() && !_loaders.Contains(item)) { _loaders.Add(item); } } _scanResult.Clear(); RebuildZones(); break; } } private static void RebuildZones() { //IL_00b9: 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_00c3: 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) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) _appliedRadius = Plugin.LoadRadiusZones.Value; _appliedMax = Plugin.MaxLoaders.Value; _loaders.RemoveAll((ZDO z) => z == null || !z.IsValid()); _loaders.Sort((ZDO a, ZDO b) => ((ZDOID)(ref a.m_uid)).CompareTo(b.m_uid)); int num = ((_appliedMax > 0) ? Mathf.Min(_appliedMax, _loaders.Count) : _loaders.Count); int appliedRadius = _appliedRadius; _loadedZones.Clear(); for (int num2 = 0; num2 < num; num2++) { Vector2i zone = RuntimeSupport.GetZone(_loaders[num2].GetPosition()); for (int num3 = zone.y - appliedRadius; num3 <= zone.y + appliedRadius; num3++) { for (int num4 = zone.x - appliedRadius; num4 <= zone.x + appliedRadius; num4++) { _loadedZones.Add(new Vector2i(num4, num3)); } } } _loadedZoneList.Clear(); _loadedZoneList.AddRange(_loadedZones); Plugin.Debug($"[ChunkLoader] {_loaders.Count} loader(s) found, {num} active, {_loadedZones.Count} zone(s) kept loaded."); } private static void KeepZonesAlive() { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) if (!_pokeLookupDone) { _pokeLookupDone = true; _pokeLocalZone = AccessTools.Method(typeof(ZoneSystem), "PokeLocalZone", new Type[1] { typeof(Vector2s) }, (Type[])null); if (_pokeLocalZone == null) { Plugin.Log.LogError((object)"ZoneSystem.PokeLocalZone not found - zones around loaders cannot be kept loaded (game update changed the API?)."); } } if (_pokeLocalZone == null) { return; } ZoneSystem instance = ZoneSystem.instance; object[] array = new object[1]; bool flag = false; foreach (Vector2i loadedZone in _loadedZoneList) { if (!(!instance.IsZoneLoaded(new Vector2s(loadedZone)) && flag)) { array[0] = (object)new Vector2s(loadedZone); if ((bool)_pokeLocalZone.Invoke(instance, array)) { flag = true; Plugin.Debug($"[ChunkLoader] Created local zone {loadedZone.x},{loadedZone.y}"); } } } } private static void ClaimOwnership() { //IL_001a: 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_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) long sessionID = ZDOMan.GetSessionID(); int num = 0; foreach (Vector2i loadedZone in _loadedZoneList) { _tmp.Clear(); RuntimeSupport.FindZoneObjects(ZDOMan.instance, loadedZone, _tmp); foreach (ZDO item in _tmp) { if (item.Persistent) { long owner = item.GetOwner(); if (owner != sessionID && (owner == 0L || !RuntimeSupport.OwnerIsNearby(item.GetPosition(), owner))) { item.SetOwner(sessionID); num++; } } } } _tmp.Clear(); if (num > 0) { Plugin.Debug($"[ChunkLoader] Server took ownership of {num} unattended object(s)."); } } } internal static class Patches { private static readonly List<ZDO> _tmp = new List<ZDO>(); [ThreadStatic] private static int _spawnerDepth; public static void Apply(Harmony h) { Type typeFromHandle = typeof(Patches); Patch(h, AccessTools.Method(typeof(ZNetScene), "CreateObjects", new Type[2] { typeof(List<ZDO>), typeof(List<ZDO>) }, (Type[])null), typeFromHandle.GetMethod("CreateObjects_Prefix", BindingFlags.Static | BindingFlags.NonPublic)); Patch(h, AccessTools.Method(typeof(ZNetScene), "OutsideActiveArea", new Type[1] { typeof(Vector3) }, (Type[])null), null, typeFromHandle.GetMethod("OutsideActiveArea_Postfix", BindingFlags.Static | BindingFlags.NonPublic)); MethodInfo method = typeFromHandle.GetMethod("SpawnerEnter", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo method2 = typeFromHandle.GetMethod("SpawnerExit", BindingFlags.Static | BindingFlags.NonPublic); Patch(h, AccessTools.Method(typeof(SpawnArea), "UpdateSpawn", (Type[])null, (Type[])null), method, null, method2); Patch(h, AccessTools.Method(typeof(CreatureSpawner), "UpdateSpawner", (Type[])null, (Type[])null), method, null, method2); MethodInfo method3 = typeFromHandle.GetMethod("IsPlayerInRange_Postfix", BindingFlags.Static | BindingFlags.NonPublic); int num = 0; MethodInfo[] methods = typeof(Player).GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (!(methodInfo.Name != "IsPlayerInRange") && !(methodInfo.ReturnType != typeof(bool))) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length >= 2 && parameters[0].ParameterType == typeof(Vector3) && parameters[1].ParameterType == typeof(float) && (parameters.Length == 2 || (parameters.Length == 3 && parameters[2].ParameterType == typeof(float)))) { Patch(h, methodInfo, null, method3); num++; } } } if (num == 0) { Plugin.Log.LogError((object)"Player.IsPlayerInRange not found - spawners in loaded areas will stay idle without a player nearby."); } } private static void Patch(Harmony h, MethodBase target, MethodInfo prefix = null, MethodInfo postfix = null, MethodInfo finalizer = null) { //IL_004b: 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_0072: Unknown result type (might be due to invalid IL or missing references) if (target == null) { Plugin.Log.LogError((object)("Patch target not found for " + (prefix ?? postfix ?? finalizer)?.Name + ". That feature is disabled (game update?).")); return; } try { h.Patch(target, (!(prefix != null)) ? ((HarmonyMethod)null) : new HarmonyMethod(prefix), (!(postfix != null)) ? ((HarmonyMethod)null) : new HarmonyMethod(postfix), (HarmonyMethod)null, (!(finalizer != null)) ? ((HarmonyMethod)null) : new HarmonyMethod(finalizer), (HarmonyMethod)null); } catch (Exception arg) { Plugin.Log.LogError((object)$"Failed to patch {target.DeclaringType?.Name}.{target.Name}: {arg}"); } } private static void CreateObjects_Prefix(List<ZDO> __0) { if (__0 != null && LoaderRegistry.Active) { try { RuntimeSupport.CollectLoadedObjects(__0, LoaderRegistry.LoadedZones, _tmp); } catch (Exception ex) { Plugin.Log.LogError((object)ex); } } } private static void OutsideActiveArea_Postfix(Vector3 __0, ref bool __result) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) if (__result && LoaderRegistry.IsInLoadedArea(__0)) { __result = false; } } private static void SpawnerEnter() { _spawnerDepth++; } private static Exception SpawnerExit(Exception __exception) { if (_spawnerDepth > 0) { _spawnerDepth--; } return __exception; } private static void IsPlayerInRange_Postfix(Vector3 __0, ref bool __result) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (!__result && _spawnerDepth > 0 && Plugin.SimulatePlayerForSpawners.Value && LoaderRegistry.IsInLoadedArea(__0)) { __result = true; } } } [BepInPlugin("com.chunkloader.valheim", "ChunkLoader", "1.0.5")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "com.chunkloader.valheim"; public const string PluginName = "ChunkLoader"; public const string PluginVersion = "1.0.5"; public const string PiecePrefabName = "piece_chunkloader"; public const string VanillaBasePrefab = "guard_stone"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<int> LoadRadiusZones; internal static ConfigEntry<int> MaxLoaders; internal static ConfigEntry<bool> SimulatePlayerForSpawners; internal static ConfigEntry<Color> GlowColor; internal static ConfigEntry<bool> DebugLogging; private Harmony _harmony; private void Awake() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; BindConfig(); _harmony = new Harmony("com.chunkloader.valheim"); Patches.Apply(_harmony); PrefabManager.OnVanillaPrefabsAvailable += RegisterPiece; Log.LogInfo((object)"ChunkLoader 1.0.5 loaded."); } private void BindConfig() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Expected O, but got Unknown //IL_00ff: Unknown result type (might be due to invalid IL or missing references) ConfigurationManagerAttributes val = new ConfigurationManagerAttributes { IsAdminOnly = true }; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, new ConfigDescription("Master switch. When false, placed chunk loaders do nothing (the piece can still be built/removed).", (AcceptableValueBase)null, new object[1] { val })); LoadRadiusZones = ((BaseUnityPlugin)this).Config.Bind<int>("General", "LoadRadiusZones", 1, new ConfigDescription("Radius kept loaded around each chunk loader, in zones (1 zone = 64x64 m). 0 = only the loader's own zone (64x64 m), 1 = 3x3 zones (192x192 m), 2 = 5x5 zones (320x320 m, same as vanilla player area). Larger values cost server CPU.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 3), new object[1] { val })); MaxLoaders = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxLoaders", 10, new ConfigDescription("Maximum number of chunk loaders that are active world-wide (oldest win). 0 = unlimited.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), new object[1] { val })); SimulatePlayerForSpawners = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SimulatePlayerForSpawners", true, new ConfigDescription("Spawner objects (creature nests, spawner pieces, camp spawn points) only spawn while a player is within their trigger distance. When true, spawners inside a loaded area behave as if a player were nearby. Without this, loaded areas are simulated but spawners stay idle.", (AcceptableValueBase)null, new object[1] { val })); GlowColor = ((BaseUnityPlugin)this).Config.Bind<Color>("Visual", "GlowColor", new Color(0.62f, 0.2f, 1f, 1f), "Color the ward glow is re-tinted to (hue is what matters). Requires a game restart."); DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLogging", false, "Log loader scans and zone/ownership activity."); } private void RegisterPiece() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown //IL_00b8: Unknown result type (might be due to invalid IL or missing references) PrefabManager.OnVanillaPrefabsAvailable -= RegisterPiece; try { PieceConfig val = new PieceConfig(); val.Name = "Chunk Loader"; val.Description = "A purple-glowing stone that keeps the surrounding area loaded so spawners and farms keep running while you are away."; val.PieceTable = PieceTables.Hammer; val.Category = PieceCategories.Misc; val.CraftingStation = CraftingStations.Workbench; val.Requirements = (RequirementConfig[])(object)new RequirementConfig[2] { new RequirementConfig("FineWood", 10, 0, true), new RequirementConfig("Wisp", 1, 0, true) }; PieceConfig val2 = val; CustomPiece val3 = new CustomPiece("piece_chunkloader", "guard_stone", val2); if ((Object)(object)val3.PiecePrefab == (Object)null) { Log.LogError((object)"Could not clone 'guard_stone'. Chunk Loader piece not registered."); return; } ChunkLoaderPrefab.Configure(val3.PiecePrefab, GlowColor.Value); PieceManager.Instance.AddPiece(val3); Log.LogInfo((object)"Registered piece 'piece_chunkloader' (Hammer > Misc, needs Workbench, 10 FineWood + 1 Wisp)."); } catch (Exception arg) { Log.LogError((object)$"Failed to register Chunk Loader piece: {arg}"); } } private void Update() { LoaderRegistry.Tick(Time.unscaledDeltaTime); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } internal static void Debug(string msg) { if (DebugLogging != null && DebugLogging.Value) { Log.LogInfo((object)msg); } } } internal static class RuntimeSupport { private static readonly HashSet<ZDO> Seen = new HashSet<ZDO>(); internal static Vector2i GetZone(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //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_0009: Unknown result type (might be due to invalid IL or missing references) Vector2s zone = ZoneSystem.GetZone(position); return ((Vector2s)(ref zone)).ToVector2i(); } internal static void FindZoneObjects(ZDOMan manager, Vector2i zone, List<ZDO> objects) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) manager.FindSectorObjects(new Vector2s(zone), new SimulationDistance(0, 0, false), objects, (List<ZDO>)null); } internal static bool OwnerIsNearby(Vector3 position, long owner) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) ZNetPeer peer = ZNet.instance.GetPeer(owner); if (peer != null) { return ZNetScene.InActiveArea(position, peer.GetRefPos()); } return false; } internal static void CollectLoadedObjects(List<ZDO> current, IReadOnlyList<Vector2i> zones, List<ZDO> scratch) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) ZoneSystem instance = ZoneSystem.instance; ZDOMan instance2 = ZDOMan.instance; if ((Object)(object)instance == (Object)null || instance2 == null) { return; } Seen.UnionWith(current); try { Vector2s val = default(Vector2s); for (int i = 0; i < zones.Count; i++) { ((Vector2s)(ref val))..ctor(zones[i]); if (!instance.IsZoneLoaded(val)) { continue; } scratch.Clear(); instance2.FindSectorObjects(val, new SimulationDistance(0, 0, false), scratch, (List<ZDO>)null); foreach (ZDO item in scratch) { if (Seen.Add(item)) { current.Add(item); } } } } finally { scratch.Clear(); Seen.Clear(); } } } internal static class LoaderPresentation { private const float RuneGlow = default(float); internal static Renderer FindWardModel(GameObject prefab) { PrivateArea componentInChildren = prefab.GetComponentInChildren<PrivateArea>(true); if (!((Object)(object)componentInChildren != (Object)null)) { return null; } return (Renderer)(object)componentInChildren.m_model; } internal static void ReplaceWardGuide(GameObject prefab) { LoaderPerch loaderPerch = prefab.AddComponent<LoaderPerch>(); GuidePoint[] componentsInChildren = prefab.GetComponentsInChildren<GuidePoint>(true); foreach (GuidePoint val in componentsInChildren) { GameObject ravenPrefab = val.m_ravenPrefab; if ((Object)(object)ravenPrefab != (Object)null && (Object)(object)loaderPerch.MuninModel == (Object)null) { Raven[] componentsInChildren2 = ravenPrefab.GetComponentsInChildren<Raven>(true); foreach (Raven val2 in componentsInChildren2) { if (val2.m_isMunin && (Object)(object)val2.m_visual != (Object)null) { loaderPerch.Perch = ((Component)val).transform; loaderPerch.MuninModel = val2.m_visual; break; } } } Object.DestroyImmediate((Object)(object)val); } GameObject prefab2 = PrefabManager.Instance.GetPrefab("piece_wisplure"); WispSpawner val3 = (((Object)(object)prefab2 != (Object)null) ? prefab2.GetComponent<WispSpawner>() : null); GameObject val4 = (((Object)(object)val3 != (Object)null) ? val3.m_wispPrefab : null); if ((Object)(object)val4 != (Object)null) { Transform val5 = val4.transform.Find("demister_ball"); if ((Object)(object)val5 != (Object)null) { loaderPerch.WispModel = ((Component)val5).gameObject; } } } internal static void SetEmission(Renderer renderer, Color glow) { //IL_002b: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_0079: Unknown result type (might be due to invalid IL or missing references) Material[] sharedMaterials = renderer.sharedMaterials; foreach (Material val in sharedMaterials) { if ((Object)(object)val != (Object)null && val.HasProperty("_EmissionColor")) { Color color = val.GetColor("_EmissionColor"); if (((Color)(ref color)).maxColorComponent > 0f) { val.EnableKeyword("_EMISSION"); val.SetColor("_EmissionColor", new Color(glow.r * 0.6f, glow.g * 0.6f, glow.b * 0.6f, 1f)); } } } } } public sealed class LoaderPerch : MonoBehaviour, IPlaced { private const int IdleState = default(int); private const int TeleportInState = default(int); private const float OrbitRadius = default(float); private const float OrbitSpeed = default(float); public Transform Perch; public GameObject MuninModel; public GameObject WispModel; private bool _justPlaced; private Transform _wisp; private Vector3 _orbitCenter; public void OnPlaced() { _justPlaced = true; } private void Start() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 //IL_005f: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) ZNetView component = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || (int)SystemInfo.graphicsDeviceType == 4) { ((Behaviour)this).enabled = false; return; } if ((Object)(object)WispModel != (Object)null) { _orbitCenter = (((Object)(object)Perch != (Object)null) ? (Perch.localPosition + Vector3.up) : (Vector3.up * 2.45f)); _wisp = Object.Instantiate<GameObject>(WispModel, ((Component)this).transform, false).transform; Transform wisp = _wisp; wisp.localScale *= 1.4f; ((Component)_wisp).gameObject.SetActive(true); Update(); } if ((Object)(object)MuninModel != (Object)null && (Object)(object)Perch != (Object)null) { SpawnMunin(); } ((Behaviour)this).enabled = (Object)(object)_wisp != (Object)null; } private void Update() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) float num = Time.time * 1.45f; _wisp.localPosition = _orbitCenter + new Vector3(Mathf.Cos(num) * 0.55f, 0.04f * Mathf.Sin(num * 2f), Mathf.Sin(num) * 0.55f); } private void SpawnMunin() { GameObject val = Object.Instantiate<GameObject>(MuninModel, Perch, false); Light[] componentsInChildren = val.GetComponentsInChildren<Light>(true); for (int i = 0; i < componentsInChildren.Length; i++) { ((Component)componentsInChildren[i]).gameObject.SetActive(false); } ParticleSystem[] componentsInChildren2 = val.GetComponentsInChildren<ParticleSystem>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { ((Component)componentsInChildren2[i]).gameObject.SetActive(false); } Transform val2 = val.transform.Find("collider"); if ((Object)(object)val2 == (Object)null) { Object.Destroy((Object)(object)val); return; } LoaderRaven loaderRaven = ((Component)val2).gameObject.AddComponent<LoaderRaven>(); loaderRaven.Bird = val; loaderRaven.Animator = val.GetComponentInChildren<Animator>(true); val.SetActive(true); if ((Object)(object)loaderRaven.Animator != (Object)null) { loaderRaven.Animator.Play(_justPlaced ? (-7850611) : 1432961145, 0, 0f); } } } public sealed class LoaderRaven : MonoBehaviour, Hoverable, Interactable { private const int TalkTrigger = default(int); private const int FlyAwayTrigger = default(int); private const float FlightCleanupDelay = default(float); internal GameObject Bird; internal Animator Animator; private bool _talking; private bool _leaving; public string GetHoverName() { return Localization.instance.Localize("$npc_munin"); } public string GetHoverText() { return Localization.instance.Localize("$npc_munin\n[<color=yellow><b>$KEY_Use</b></color>] $raven_interact"); } public float GetHoverOffset() { return 0f; } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) Chat instance = Chat.instance; if (hold || alt || _leaving || (Object)(object)instance == (Object)null || (Object)(object)Bird == (Object)null) { return false; } if (_talking) { FlyAway(); return true; } _talking = true; instance.SetNpcText(Bird, Vector3.up, float.PositiveInfinity, 0f, "$npc_munin", "<color=orange>Chunk Loader</color>\nAttracts a wisp that keeps the area active.", true); if ((Object)(object)Animator != (Object)null) { Animator.SetTrigger(-1624975941); } return true; } private void FlyAway() { if (!_leaving && !((Object)(object)Bird == (Object)null)) { _leaving = true; if ((Object)(object)Chat.instance != (Object)null) { Chat.instance.ClearNpcText(Bird); } Collider component = ((Component)this).GetComponent<Collider>(); if ((Object)(object)component != (Object)null) { component.enabled = false; } if ((Object)(object)Animator == (Object)null) { Object.Destroy((Object)(object)Bird); return; } Animator.ResetTrigger(-1624975941); Animator.SetTrigger(2045089523); Object.Destroy((Object)(object)Bird, 7f); } } public bool UseItem(Humanoid user, ItemData item) { return false; } } }