Decompiled source of GoonLagoon Expanded Biome Fix v1.0.0

BepInEx/plugins/GoonLagoon.ExpandedBiomeFix.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using ExpandWorldSize;
using HarmonyLib;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.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 GoonLagoon.ExpandedBiomeFix
{
	[BepInPlugin("goonlagoon.expandedbiomefix", "GoonLagoon Expanded Biome Fix", "1.0.0")]
	[BepInDependency("expand_world_size", "1.33")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Id = "goonlagoon.expandedbiomefix";

		internal static ManualLogSource Log;

		private static int gridSize = 2048;

		private static float radius = 10500f;

		private static string cacheTag = "uninitialized";

		private static Type biomeType;

		private Harmony harmony;

		private void Awake()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				biomeType = AccessTools.TypeByName("AltBiomeWorldData");
				if (biomeType == null)
				{
					throw new InvalidOperationException("AltBiomeWorldData not found; this fix targets the Valheim 1.0 biome generator.");
				}
				Type type = AccessTools.TypeByName("World");
				harmony = new Harmony("goonlagoon.expandedbiomefix");
				harmony.Patch((MethodBase)Require("VerifyBiomeData", type), HM("Refresh"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)Require("MapSpaceToWorldSpace", typeof(float)), (HarmonyMethod)null, (HarmonyMethod)null, HM("PatchHalfWidth"), (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)Require("WorldSpaceToMapSpace", typeof(float)), (HarmonyMethod)null, (HarmonyMethod)null, HM("PatchHalfWidth"), (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)Require("GenerateBiomePoints", type), HM("Refresh"), (HarmonyMethod)null, HM("PatchGrid"), (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)Require("GetFilePath", typeof(string)), (HarmonyMethod)null, HM("CachePath"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)Require("GenerateSectors"), (HarmonyMethod)null, HM("Coverage"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Expanded biome compatibility patch installed: grid extent, sampling radius, and separate cache. Native location placement remains enabled.");
			}
			catch (Exception ex)
			{
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
				((BaseUnityPlugin)this).Logger.LogError((object)("Expanded biome patch could not be installed. Do not use this world until resolved. " + ex));
				throw;
			}
		}

		private static MethodInfo Require(string name, params Type[] args)
		{
			return AccessTools.Method(biomeType, name, args, (Type[])null) ?? throw new MissingMethodException(biomeType.FullName, name);
		}

		private static HarmonyMethod HM(string name)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			return new HarmonyMethod(typeof(Plugin), name, (Type[])null);
		}

		public static int GridSize()
		{
			return gridSize;
		}

		public static float HalfWidth()
		{
			return (float)gridSize / 2f;
		}

		public static float RadiusSquared()
		{
			return radius * radius;
		}

		private static void Refresh()
		{
			radius = Configuration.WorldTotalRadius;
			gridSize = GridMath.Dimension(radius);
			string text = "v1|" + gridSize + "|" + radius.ToString("R", CultureInfo.InvariantCulture);
			string[] array = new string[16]
			{
				"WorldRadius", "WorldEdgeSize", "WorldStretch", "BiomeStretch", "AltitudeMultiplier", "AltitudeDelta", "WaterDepthMultiplier", "Seed", "HeightSeed", "OffsetX",
				"OffsetY", "RestrictAshlands", "AshlandsGap", "DeepNorthGap", "AshlandsWidthRestriction", "AshlandsLengthRestriction"
			};
			foreach (string text2 in array)
			{
				PropertyInfo property = typeof(Configuration).GetProperty(text2, BindingFlags.Static | BindingFlags.Public);
				object obj = ((property != null) ? property.GetValue(null) : typeof(Configuration).GetField(text2, BindingFlags.Static | BindingFlags.Public)?.GetValue(null));
				text = text + "|" + text2 + "=" + Convert.ToString(obj, CultureInfo.InvariantCulture);
			}
			using (SHA256 sHA = SHA256.Create())
			{
				cacheTag = BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(text))).Replace("-", "").Substring(0, 16);
			}
			Log.LogInfo((object)("Biome grid " + gridSize + " x " + gridSize + "; cell size 12 m; sampled radius " + radius.ToString(CultureInfo.InvariantCulture) + " m; cache " + cacheTag + "."));
		}

		private static void CachePath(ref string __result)
		{
			if (cacheTag == "uninitialized")
			{
				Refresh();
			}
			__result = __result + ".goonlagoon-v1-" + cacheTag;
		}

		public static IEnumerable<CodeInstruction> PatchHalfWidth(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			int num = 0;
			foreach (CodeInstruction item in list)
			{
				if (item.opcode == OpCodes.Ldc_R4 && item.operand is float num2 && num2 == 1024f)
				{
					item.opcode = OpCodes.Call;
					item.operand = typeof(Plugin).GetMethod("HalfWidth");
					num++;
				}
			}
			if (num != 1)
			{
				throw new InvalidOperationException("Unexpected biome coordinate IL: expected one half-width constant; found " + num);
			}
			return list;
		}

		public static IEnumerable<CodeInstruction> PatchGrid(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			int num = 0;
			int num2 = 0;
			foreach (CodeInstruction item in list)
			{
				if (item.opcode == OpCodes.Ldc_I4 && item.operand is int num3 && num3 == 2048)
				{
					item.opcode = OpCodes.Call;
					item.operand = typeof(Plugin).GetMethod("GridSize");
					num++;
				}
				else if (item.opcode == OpCodes.Ldc_R4 && item.operand is float num4 && num4 == 110250000f)
				{
					item.opcode = OpCodes.Call;
					item.operand = typeof(Plugin).GetMethod("RadiusSquared");
					num2++;
				}
			}
			if (num != 3 || num2 != 1)
			{
				throw new InvalidOperationException("Unexpected biome generation IL: expected 3 grid constants and 1 radius; found " + num + "/" + num2);
			}
			return list;
		}

		private static void Coverage(object __instance)
		{
			IDictionary obj = AccessTools.Field(biomeType, "Biomes").GetValue(__instance) as IDictionary;
			List<string> list = new List<string>();
			foreach (DictionaryEntry item in obj)
			{
				object value = item.Value;
				ICollection collection = AccessTools.Field(value.GetType(), "AllPoints").GetValue(value) as ICollection;
				ICollection collection2 = AccessTools.Field(value.GetType(), "AllPointsAboveSeaLevel").GetValue(value) as ICollection;
				list.Add(item.Key?.ToString() + "=" + (collection?.Count ?? 0) + "/" + (collection2?.Count ?? 0));
			}
			Log.LogInfo((object)("Biome coverage (all/above water): " + string.Join(", ", list)));
		}
	}
	public static class GridMath
	{
		public static int Dimension(float totalRadius)
		{
			if (float.IsNaN(totalRadius) || float.IsInfinity(totalRadius) || totalRadius < 1000f || totalRadius > 30000f)
			{
				throw new ArgumentOutOfRangeException("totalRadius", "Supported total world radius: 1000–30000 meters.");
			}
			return (Math.Max(2048, (int)Math.Ceiling(2048.0 * (double)totalRadius / 10500.0)) + 1) & -2;
		}
	}
}