using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("WormtownTerrainSettings")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("WormtownTerrainSettings")] [assembly: AssemblyTitle("WormtownTerrainSettings")] [assembly: AssemblyVersion("1.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 WormtownTerrainSettings { [HarmonyPatch] public static class GroundClutterPatches { private sealed class RuntimeBaseline { public MapBuilder builder; public int fixed_crates; public int random_crates; public int random_trunks; public int diggables; } private sealed class LoaderBaseline { public MapLayoutPrefabLoader loader; public int spawns_per_frame; } private struct RankedIndex { public int index; public uint rank; public RankedIndex(int value, uint value_rank) { index = value; rank = value_rank; } } private sealed class OccupancyGrid { private readonly float cell_size; private readonly Dictionary> cells = new Dictionary>(); public OccupancyGrid(float size) { cell_size = size; } public void Add(Vector3 position) { //IL_0000: 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) //IL_0050: 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_005c: Unknown result type (might be due to invalid IL or missing references) int x = Mathf.FloorToInt(position.x / cell_size); int z = Mathf.FloorToInt(position.z / cell_size); long key = CellKey(x, z); if (!cells.TryGetValue(key, out var value)) { value = new List(); cells.Add(key, value); } value.Add(new Vector2(position.x, position.z)); } public bool IsFree(Vector3 position, float distance) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_008c: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.FloorToInt(position.x / cell_size); int num2 = Mathf.FloorToInt(position.z / cell_size); int num3 = Mathf.CeilToInt(distance / cell_size); float num4 = distance * distance; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(position.x, position.z); for (int i = -num3; i <= num3; i++) { for (int j = -num3; j <= num3; j++) { if (!cells.TryGetValue(CellKey(num + j, num2 + i), out var value)) { continue; } foreach (Vector2 item in value) { Vector2 val2 = item - val; if (((Vector2)(ref val2)).sqrMagnitude < num4) { return false; } } } } return true; } private static long CellKey(int x, int z) { return ((long)x << 32) ^ (uint)z; } } private const int MAX_STATIC_OBJECTS = 8000; private const int MAX_BUILDINGS = 256; private const int MAX_NETWORKED_ITEMS = 1000; private const int MAX_STATIC_SPAWNS_PER_FRAME = 100; private const int PLACEMENT_ATTEMPTS = 32; private const float TRAIN_CLEARANCE = 30f; private const float TOWN_CLEARANCE = 54f; private const float QUARRY_CLEARANCE = 44f; private const float CHURCH_CLEARANCE = 30f; private const float MESA_CLEARANCE = 26f; private const float STATIC_SPACING = 3f; private const float BUILDING_SPACING = 18f; private const int BOULDER_SEED = 101; private const int CACTUS_SEED = 211; private const int BUILDING_SEED = 307; private const int TRUNK_SEED = 401; private static readonly FieldInfo diggable_count_field = AccessTools.Field(typeof(MapBuilder), "numOfRandoDiggablesToSpawn"); private static readonly FieldInfo scatter_limit_field = AccessTools.Field(typeof(MapBuilder), "scatterObjectSetItemSpawnLimit"); private static readonly FieldInfo building_color_field = AccessTools.Field(typeof(CollapsibleBuilding), "dontRandomizeBuildingColors"); private static readonly Dictionary runtime_baselines = new Dictionary(); private static readonly Dictionary loader_baselines = new Dictionary(); private static int processed_layout_id; private static int layout_seed; private static int baseline_priority_trunks; private static int loader_spawns_per_frame; private static bool loading_tutorial; private static bool layout_loaded_without_snapshot; [HarmonyPatch(typeof(MapBuilder), "Start")] [HarmonyPostfix] public static void MapBuilder_Start_Postfix(MapBuilder __instance) { CaptureRuntimeBaseline(__instance); } [HarmonyPatch(typeof(MapLayoutPrefabLoader), "LoadMapLayout")] [HarmonyPrefix] public static void MapLayoutPrefabLoader_LoadMapLayout_Prefix(MapLayoutPrefabLoader __instance, bool _pardnerTutorialMap, bool _wormTutorialMap) { processed_layout_id = 0; baseline_priority_trunks = 0; layout_loaded_without_snapshot = false; loading_tutorial = _pardnerTutorialMap || _wormTutorialMap; loader_spawns_per_frame = GetLoaderBaseline(__instance); if ((Object)(object)__instance != (Object)null) { __instance.numberOfBuilderSetObjectsToSpawnPerFrame = loader_spawns_per_frame; } } [HarmonyPatch(typeof(MapLayoutPrefabLoader), "ChangeMapLoadState")] [HarmonyPrefix] public static void MapLayoutPrefabLoader_ChangeMapLoadState_Prefix(MapLayoutPrefabLoader __instance, int _stateIndex) { if (_stateIndex != 4 || (Object)(object)__instance == (Object)null || (Object)(object)__instance.activeMapLayout == (Object)null) { return; } MapLayout activeMapLayout = __instance.activeMapLayout; int instanceID = ((Object)activeMapLayout).GetInstanceID(); if (processed_layout_id == instanceID) { return; } processed_layout_id = instanceID; layout_seed = GetLayoutSeed(__instance); CapturePriorityTrunkBaseline(); NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton != (Object)null && singleton.IsListening && !singleton.IsHost && !TerrainSettingsSync.CanApplyGameplayPatches) { layout_loaded_without_snapshot = true; } if (loading_tutorial || IsTutorialActive() || !TerrainSettingsSync.CanApplyGameplayPatches || !TerrainSettings.HasGroundClutterEffect) { return; } try { ScaleBuildings(activeMapLayout); ScaleStaticSpawners(activeMapLayout); __instance.numberOfBuilderSetObjectsToSpawnPerFrame = Mathf.Max(loader_spawns_per_frame, ScaleCount(loader_spawns_per_frame, TerrainSettings.ground_clutter, 100)); } catch (Exception ex) { Plugin.log.LogError((object)$"ground clutter layout scaling failed: {ex}"); TerrainSettingsSync.ReportTerrainApplicationFailure(ex.Message); } } [HarmonyPatch(typeof(MapBuilder), "ChangeBuilderState")] [HarmonyPrefix] public static void MapBuilder_ChangeBuilderState_Prefix(MapBuilder __instance, int _stateIndex) { if (!ShouldScaleHostRuntime(__instance)) { return; } RuntimeBaseline runtimeBaseline = CaptureRuntimeBaseline(__instance); byte units = EffectiveClutterUnits(); switch (_stateIndex) { case 4: { int num = ScaleCount(runtimeBaseline.fixed_crates + runtimeBaseline.random_crates, units, 1000); __instance.numberOfCratesToSpawn = Mathf.Min(runtimeBaseline.fixed_crates, num); __instance.numberOfRandomWorldCratesToSpawn = Mathf.Max(0, num - __instance.numberOfCratesToSpawn); break; } case 13: if (diggable_count_field != null) { diggable_count_field.SetValue(__instance, ScaleCount(runtimeBaseline.diggables, units, 1000)); } break; } } [HarmonyPatch(typeof(MapBuilder), "ChangeBuilderState")] [HarmonyPostfix] public static void MapBuilder_ChangeBuilderState_Postfix(MapBuilder __instance, int _stateIndex) { if (_stateIndex == 5 && ShouldScaleHostRuntime(__instance) && __instance.priorityTrunkSpawnPoints != null) { RuntimeBaseline runtimeBaseline = CaptureRuntimeBaseline(__instance); int num = ScaleCount(baseline_priority_trunks + runtimeBaseline.random_trunks, EffectiveClutterUnits(), 1000); __instance.numberOfRandomWorldTrunksToSpawn = Mathf.Max(0, num - (__instance.priorityTrunkSpawnPoints = SelectPriorityTrunks(__instance.priorityTrunkSpawnPoints, Mathf.Min(num, __instance.priorityTrunkSpawnPoints.Count))).Count); } } [HarmonyPatch(typeof(MapBuilder), "SetupNextScatterObjectSet")] [HarmonyPostfix] public static void MapBuilder_SetupNextScatterObjectSet_Postfix(MapBuilder __instance) { if (ShouldScaleHostRuntime(__instance) && !(scatter_limit_field == null)) { int vanilla = (int)scatter_limit_field.GetValue(__instance); scatter_limit_field.SetValue(__instance, ScaleCount(vanilla, EffectiveClutterUnits(), 1000)); } } public static bool ValidateSynchronizedSnapshot() { if (layout_loaded_without_snapshot) { return !TerrainSettings.HasGroundClutterEffect; } return true; } public static void ResetRuntimeState() { foreach (RuntimeBaseline value in runtime_baselines.Values) { if (!((Object)(object)value.builder == (Object)null)) { value.builder.numberOfCratesToSpawn = value.fixed_crates; value.builder.numberOfRandomWorldCratesToSpawn = value.random_crates; value.builder.numberOfRandomWorldTrunksToSpawn = value.random_trunks; if (diggable_count_field != null) { diggable_count_field.SetValue(value.builder, value.diggables); } } } foreach (LoaderBaseline value2 in loader_baselines.Values) { if ((Object)(object)value2.loader != (Object)null) { value2.loader.numberOfBuilderSetObjectsToSpawnPerFrame = value2.spawns_per_frame; } } runtime_baselines.Clear(); loader_baselines.Clear(); processed_layout_id = 0; layout_seed = 0; baseline_priority_trunks = 0; loader_spawns_per_frame = 0; loading_tutorial = false; layout_loaded_without_snapshot = false; } private static void ScaleBuildings(MapLayout layout) { //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) if (layout.buildings == null || layout.buildings.Count == 0) { return; } List list = new List(); for (int i = 0; i < layout.buildings.Count; i++) { if (IsScalableBuilding(layout.buildings[i])) { list.Add(i); } } if (list.Count == 0) { return; } int num = ScaleCount(list.Count, TerrainSettings.ground_clutter, 256); int num2 = RequiredPlayerSpawnBuilding(layout, list); if (num2 >= 0) { num = Mathf.Max(1, num); } HashSet hashSet = SelectIndices(list, Mathf.Min(num, list.Count), 307, num2); List list2 = new List(); List list3 = new List(); for (int j = 0; j < layout.buildings.Count; j++) { CollapsibleBuilding val = layout.buildings[j]; if ((Object)(object)val == (Object)null) { continue; } if (!list.Contains(j) || hashSet.Contains(j)) { list2.Add(val); if (list.Contains(j)) { list3.Add(val); } } else { ((Component)val).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)val).gameObject); } } int num3 = Mathf.Max(0, num - list.Count); int num4 = 0; if (num3 > 0 && list3.Count > 0) { OccupancyGrid occupancyGrid = BuildBuildingOccupancy(layout, list2); Terrain terrain = (((Object)(object)MapBuilder.Singleton != (Object)null) ? MapBuilder.Singleton.GetTerrain() : null); for (int k = 0; k < num3; k++) { if (list2.Count >= 256) { break; } CollapsibleBuilding val2 = list3[(int)(StableHash(layout_seed, 307, k, 0) % (uint)list3.Count)]; if (!TryFindPlacement(terrain, ((Component)val2).transform.position, 18f, 36f, 7f, 2.5f, 307, k, occupancyGrid, out var position)) { continue; } Quaternion val3 = Quaternion.Euler(((Component)val2).transform.eulerAngles.x, UnitHash(layout_seed, 307, k, 91) * 360f, ((Component)val2).transform.eulerAngles.z); GameObject val4 = Object.Instantiate(((Component)val2).gameObject, position, val3, ((Component)layout).transform); ((Object)val4).name = ((Object)((Component)val2).gameObject).name + " Clutter Copy"; val4.transform.localScale = ((Component)val2).transform.localScale; CollapsibleBuilding component = val4.GetComponent(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val4); continue; } if (building_color_field != null) { building_color_field.SetValue(component, true); } list2.Add(component); occupancyGrid.Add(position); num4++; } } RebuildBuildingLists(layout, list2); Plugin.log.LogInfo((object)($"ground clutter buildings: vanilla={list.Count}, " + $"target={num}, active={list3.Count + num4}")); } private static void ScaleStaticSpawners(MapLayout layout) { if (layout.builderSetObjectSpawners == null || (Object)(object)MapBuilder.Singleton == (Object)null) { return; } List list = new List(layout.builderSetObjectSpawners); List list2 = new List(); List list3 = new List(); Dictionary dictionary = new Dictionary(); for (int i = 0; i < list.Count; i++) { if (TryClassifyStaticSpawner(list[i], out var cactus, out var cactus_count)) { if (cactus) { list3.Add(i); dictionary[i] = cactus_count; } else { list2.Add(i); } } } int num = ScaleCount(list2.Count, TerrainSettings.ground_clutter, 8000); int num2 = 0; foreach (int item in list3) { num2 += dictionary[item]; } int num3 = ScaleCount(num2, TerrainSettings.ground_clutter, 8000); if (TerrainSettings.ground_clutter <= 20) { num3 = num2; } HashSet hashSet = SelectIndices(list2, Mathf.Min(num, list2.Count), 101, -1); HashSet hashSet2 = SelectCactusIndices(list3, dictionary, Mathf.Min(num3, num2)); List list4 = new List(); for (int j = 0; j < list.Count; j++) { if ((!list2.Contains(j) && !list3.Contains(j)) || hashSet.Contains(j) || hashSet2.Contains(j)) { list4.Add(list[j]); } } OccupancyGrid occupancy = BuildStaticOccupancy(layout, list4); int num4 = AddSpawnerCopies(layout, list, list2, Mathf.Max(0, num - list2.Count), 101, occupancy, list4); int num5 = AddCactusCopies(layout, list, list3, dictionary, Mathf.Max(0, num3 - num2), occupancy, list4); layout.builderSetObjectSpawners = list4; Plugin.log.LogInfo((object)($"ground clutter static: boulders={hashSet.Count + num4}/" + $"{num}, cactuses={CountSelectedCactuses(hashSet2, dictionary) + num5}/" + $"{num3}, total={list4.Count}")); } private static int AddSpawnerCopies(MapLayout layout, List originals, List source_indices, int desired, int category_seed, OccupancyGrid occupancy, List output) { //IL_0047: 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) //IL_0088: Unknown result type (might be due to invalid IL or missing references) if (desired <= 0 || source_indices.Count == 0) { return 0; } Terrain terrain = MapBuilder.Singleton.GetTerrain(); int num = 0; for (int i = 0; i < desired; i++) { if (output.Count >= 8000) { break; } int index = source_indices[(int)(StableHash(layout_seed, category_seed, i, 0) % (uint)source_indices.Count)]; MapLayout_BuilderSetObject_Spawner val = originals[index]; if (TryFindPlacement(terrain, val.pos, 3f, 8f, 0f, float.MaxValue, category_seed, i, occupancy, out var position)) { MapLayout_BuilderSetObject_Spawner item = CreateSpawnerCopy(layout, val, position, category_seed, i); output.Add(item); occupancy.Add(position); num++; } } return num; } private static int AddCactusCopies(MapLayout layout, List originals, List source_indices, Dictionary cactus_counts, int desired_components, OccupancyGrid occupancy, List output) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) if (desired_components <= 0 || source_indices.Count == 0) { return 0; } Terrain terrain = MapBuilder.Singleton.GetTerrain(); int num = 0; int num2 = 0; while (num < desired_components && output.Count < 8000 && num2 < desired_components * 4) { int num3 = source_indices[(int)(StableHash(layout_seed, 211, num2, 0) % (uint)source_indices.Count)]; MapLayout_BuilderSetObject_Spawner val = originals[num3]; if (TryFindPlacement(terrain, val.pos, 3f, 8f, 0f, float.MaxValue, 211, num2, occupancy, out var position)) { output.Add(CreateSpawnerCopy(layout, val, position, 211, num2)); occupancy.Add(position); num += cactus_counts[num3]; } num2++; } return num; } private static MapLayout_BuilderSetObject_Spawner CreateSpawnerCopy(MapLayout layout, MapLayout_BuilderSetObject_Spawner source, Vector3 position, int category_seed, int copy) { //IL_0015: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_0057: Unknown result type (might be due to invalid IL or missing references) //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) GameObject val = new GameObject(((Object)((Component)source).gameObject).name + " Clutter Copy"); val.transform.SetParent(((Component)layout).transform, false); val.transform.position = position; MapLayout_BuilderSetObject_Spawner obj = val.AddComponent(); obj.SetIndex = source.SetIndex; obj.PrefabIndexWithinSet = source.PrefabIndexWithinSet; obj.pos = position; obj.rot = source.rot; obj.rot.y = UnitHash(layout_seed, category_seed, copy, 47) * 360f; obj.scale = source.scale; return obj; } private static bool TryClassifyStaticSpawner(MapLayout_BuilderSetObject_Spawner spawner, out bool cactus, out int cactus_count) { cactus = false; cactus_count = 0; GameObject val = ResolveBasePrefab(spawner); GameObject val2 = ResolveActivePrefab(spawner, val); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || ContainsForbiddenStaticContent(val2)) { return false; } switch (((Object)val).name) { case "Barrel Cactus": return true; case "Cactus 1": case "Cactus 2": cactus = true; cactus_count = val2.GetComponentsInChildren(true).Length; return cactus_count > 0; case "Boulder 1": case "Boulder 2": case "Boulder 3": case "Boulder 4": case "Boulder 5": return true; default: return false; } } private static GameObject ResolveBasePrefab(MapLayout_BuilderSetObject_Spawner spawner) { MapBuilder singleton = MapBuilder.Singleton; if ((Object)(object)spawner == (Object)null || (Object)(object)singleton == (Object)null || singleton.builderSets == null || spawner.SetIndex < 0 || spawner.SetIndex >= singleton.builderSets.Length) { return null; } BuilderSet val = singleton.builderSets[spawner.SetIndex]; if ((Object)(object)val == (Object)null || val.prefabs == null || spawner.PrefabIndexWithinSet < 0 || spawner.PrefabIndexWithinSet >= val.prefabs.Length) { return null; } return val.prefabs[spawner.PrefabIndexWithinSet]; } private static GameObject ResolveActivePrefab(MapLayout_BuilderSetObject_Spawner spawner, GameObject fallback) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected I4, but got Unknown BuilderSet val = MapBuilder.Singleton.builderSets[spawner.SetIndex]; GameObject[] array = null; ThemeOverride themeOverride = GameManager.Singleton.themeOverride; switch (themeOverride - 1) { case 0: array = val.themedPrefabs_Halloween; break; case 1: array = val.themedPrefabs_WinterHoliday; break; case 2: array = val.themedPrefabs_Aquarium; break; } int prefabIndexWithinSet = spawner.PrefabIndexWithinSet; if (array == null || prefabIndexWithinSet < 0 || prefabIndexWithinSet >= array.Length || !((Object)(object)array[prefabIndexWithinSet] != (Object)null)) { return fallback; } return array[prefabIndexWithinSet]; } private static bool ContainsForbiddenStaticContent(GameObject prefab) { Component[] componentsInChildren = prefab.GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } if (val is NetworkObject || val is NetworkBehaviour || val is CollapsibleBuilding || val is PropSpawner || val is TrunkSpawner || val is FarmSpawnPoint || val is PardnerObjective) { return true; } switch (((object)val).GetType().Name) { case "DestructibleTrain": case "BuildingInteriorSet": case "PardnerObjective": case "Diggable": case "PickUppable": case "LootTrunk": case "BrokenTrainTrackSegment": return true; } Type[] interfaces = ((object)val).GetType().GetInterfaces(); for (int j = 0; j < interfaces.Length; j++) { if (interfaces[j].Name == "IWorldUsable") { return true; } } } Transform[] componentsInChildren2 = prefab.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { if (IsEssentialTag(((Component)componentsInChildren2[i]).gameObject.tag)) { return true; } } return false; } private static bool IsScalableBuilding(CollapsibleBuilding building) { if ((Object)(object)building == (Object)null || building.isChurch || building.isWaterTower || building.isMiscStructure || building.isFarmHouse || (Object)(object)((Component)building).GetComponentInChildren(true) != (Object)null) { return false; } Component[] componentsInChildren = ((Component)building).GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } string name = ((object)val).GetType().Name; if (!(val is NetworkBehaviour) && !(val is FarmSpawnPoint) && !(val is PardnerObjective)) { switch (name) { case "DestructibleTrain": case "PardnerObjective": case "Diggable": case "PickUppable": case "LootTrunk": case "BrokenTrainTrackSegment": case "LadderSpawn": break; default: { Type[] interfaces = ((object)val).GetType().GetInterfaces(); for (int j = 0; j < interfaces.Length; j++) { if (interfaces[j].Name == "IWorldUsable") { return false; } } TrunkSpawner val2 = (TrunkSpawner)(object)((val is TrunkSpawner) ? val : null); if (val2 == null || !val2.onlySpawnEquipment_NoNormalLoot) { continue; } return false; } } } return false; } Transform[] componentsInChildren2 = ((Component)building).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { switch (((Component)componentsInChildren2[i]).gameObject.tag) { case "PlayerSpawnPoint": case "SafeSpawnPoint": case "CrateSpawnPoint": case "LadderSpawnPoint": case "PriorityLadderSpawnPoint": case "Train": case "DestructibleTrain": case "Dandylion": return false; } } return true; } private static int RequiredPlayerSpawnBuilding(MapLayout layout, List scalable_indices) { int num = 0; int num2 = -1; foreach (int scalable_index in scalable_indices) { int num3 = CountTag(((Component)layout.buildings[scalable_index]).gameObject, "PlayerSpawnPoint"); if (num3 > 0 && num2 < 0) { num2 = scalable_index; } num += num3; } if (GameObject.FindGameObjectsWithTag("PlayerSpawnPoint").Length - num <= 0) { return num2; } return -1; } private static void RebuildBuildingLists(MapLayout layout, List buildings) { layout.buildings = buildings; MapBuilder.Singleton.spawnedBuildings.Clear(); MapBuilder.Singleton.spawnedBuildings.AddRange(buildings); if ((Object)(object)MapLayoutPrefabCreator.Singleton != (Object)null) { MapLayoutPrefabCreator.Singleton.spawnedBuildings.Clear(); MapLayoutPrefabCreator.Singleton.spawnedBuildings.AddRange(buildings); } for (int i = 0; i < buildings.Count; i++) { buildings[i].buildingID = i; } } private static OccupancyGrid BuildBuildingOccupancy(MapLayout layout, List buildings) { //IL_0023: 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) OccupancyGrid occupancyGrid = new OccupancyGrid(3f); foreach (CollapsibleBuilding building in buildings) { occupancyGrid.Add(((Component)building).transform.position); } if (layout.builderSetObjectSpawners != null) { foreach (MapLayout_BuilderSetObject_Spawner builderSetObjectSpawner in layout.builderSetObjectSpawners) { if ((Object)(object)builderSetObjectSpawner != (Object)null) { occupancyGrid.Add(builderSetObjectSpawner.pos); } } } return occupancyGrid; } private static OccupancyGrid BuildStaticOccupancy(MapLayout layout, List spawners) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) OccupancyGrid occupancyGrid = new OccupancyGrid(3f); foreach (MapLayout_BuilderSetObject_Spawner spawner in spawners) { if ((Object)(object)spawner != (Object)null) { occupancyGrid.Add(spawner.pos); } } if (layout.buildings != null) { foreach (CollapsibleBuilding building in layout.buildings) { if ((Object)(object)building != (Object)null) { occupancyGrid.Add(((Component)building).transform.position); } } } return occupancyGrid; } private static bool TryFindPlacement(Terrain terrain, Vector3 source_position, float spacing, float margin, float slope_radius, float maximum_slope, int category_seed, int copy, OccupancyGrid occupancy, out Vector3 position) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) position = source_position; if ((Object)(object)terrain == (Object)null || (Object)(object)terrain.terrainData == (Object)null) { return false; } Vector3 position2 = ((Component)terrain).transform.position; Vector3 size = terrain.terrainData.size; float num = GroundY(terrain, source_position.x, source_position.z); float num2 = Mathf.Clamp(source_position.y - num, -2f, 5f); Vector3 val = default(Vector3); for (int i = 0; i < 32; i++) { float num3 = Mathf.Lerp(position2.x + margin, position2.x + size.x - margin, UnitHash(layout_seed, category_seed, copy, i * 2)); float num4 = Mathf.Lerp(position2.z + margin, position2.z + size.z - margin, UnitHash(layout_seed, category_seed, copy, i * 2 + 1)); ((Vector3)(ref val))..ctor(num3, GroundY(terrain, num3, num4) + num2, num4); if (!IsProtected(val) && occupancy.IsFree(val, spacing) && (!(slope_radius > 0f) || !(TerrainRelief(terrain, val, slope_radius) > maximum_slope))) { position = val; return true; } } return false; } private static bool IsProtected(Vector3 position) { //IL_0000: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) if (Mathf.Abs(position.z) < 30f) { return true; } MapBuilder singleton = MapBuilder.Singleton; if ((Object)(object)singleton == (Object)null) { return false; } if (Near(position, singleton.town, 54f) || Near(position, singleton.quarry, 44f) || Near(position, singleton.church, 30f)) { return true; } if (singleton.mesas != null) { GameObject[] mesas = singleton.mesas; foreach (GameObject target in mesas) { if (Near(position, target, 26f)) { return true; } } } return false; } private static bool Near(Vector3 position, GameObject target, float radius) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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_0030: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)target == (Object)null) { return false; } Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(position.x - target.transform.position.x, position.z - target.transform.position.z); return ((Vector2)(ref val)).sqrMagnitude < radius * radius; } private static float TerrainRelief(Terrain terrain, Vector3 position, float radius) { //IL_0015: 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) float num = float.MaxValue; float num2 = float.MinValue; for (int i = -1; i <= 1; i += 2) { for (int j = -1; j <= 1; j += 2) { float num3 = GroundY(terrain, position.x + (float)j * radius, position.z + (float)i * radius); num = Mathf.Min(num, num3); num2 = Mathf.Max(num2, num3); } } return num2 - num; } private static float GroundY(Terrain terrain, float x, float z) { //IL_0006: 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) return ((Component)terrain).transform.position.y + terrain.SampleHeight(new Vector3(x, 0f, z)); } private static HashSet SelectIndices(List indices, int target, int category_seed, int forced_index) { HashSet hashSet = new HashSet(); if (target <= 0) { return hashSet; } if (forced_index >= 0) { hashSet.Add(forced_index); } List list = new List(); foreach (int index in indices) { if (index != forced_index) { list.Add(new RankedIndex(index, StableHash(layout_seed, category_seed, index, 0))); } } list.Sort(delegate(RankedIndex left, RankedIndex right) { int num = left.rank.CompareTo(right.rank); return (num == 0) ? left.index.CompareTo(right.index) : num; }); foreach (RankedIndex item in list) { if (hashSet.Count >= target) { break; } hashSet.Add(item.index); } return hashSet; } private static HashSet SelectCactusIndices(List indices, Dictionary counts, int target_components) { HashSet hashSet = new HashSet(); if (target_components <= 0) { return hashSet; } List list = new List(); foreach (int index in indices) { list.Add(new RankedIndex(index, StableHash(layout_seed, 211, index, 0))); } list.Sort(delegate(RankedIndex left, RankedIndex right) { int num2 = left.rank.CompareTo(right.rank); return (num2 == 0) ? left.index.CompareTo(right.index) : num2; }); int num = 0; foreach (RankedIndex item in list) { hashSet.Add(item.index); num += counts[item.index]; if (num >= target_components) { break; } } return hashSet; } private static int CountSelectedCactuses(HashSet selected, Dictionary counts) { int num = 0; foreach (int item in selected) { num += counts[item]; } return num; } private static List SelectPriorityTrunks(List source, int target) { HashSet hashSet = new HashSet(); List list = new List(); for (int i = 0; i < source.Count; i++) { TrunkSpawner val = (((Object)(object)source[i] != (Object)null) ? source[i].GetComponent() : null); if ((Object)(object)val != (Object)null && val.onlySpawnEquipment_NoNormalLoot) { hashSet.Add(i); } else { list.Add(i); } } target = Mathf.Max(target, hashSet.Count); List list2 = new List(); foreach (int item in list) { list2.Add(new RankedIndex(item, StableHash(layout_seed, 401, item, 0))); } list2.Sort(delegate(RankedIndex left, RankedIndex right) { int num2 = left.rank.CompareTo(right.rank); return (num2 == 0) ? left.index.CompareTo(right.index) : num2; }); foreach (RankedIndex item2 in list2) { if (hashSet.Count >= target) { break; } hashSet.Add(item2.index); } List list3 = new List(); for (int num = 0; num < source.Count; num++) { if (hashSet.Contains(num)) { list3.Add(source[num]); } } return list3; } private static RuntimeBaseline CaptureRuntimeBaseline(MapBuilder builder) { int instanceID = ((Object)builder).GetInstanceID(); if (!runtime_baselines.TryGetValue(instanceID, out var value)) { value = new RuntimeBaseline { builder = builder, fixed_crates = builder.numberOfCratesToSpawn, random_crates = builder.numberOfRandomWorldCratesToSpawn, random_trunks = builder.numberOfRandomWorldTrunksToSpawn, diggables = ((diggable_count_field != null) ? ((int)diggable_count_field.GetValue(builder)) : 0) }; runtime_baselines.Add(instanceID, value); } return value; } private static int GetLoaderBaseline(MapLayoutPrefabLoader loader) { if ((Object)(object)loader == (Object)null) { return 1; } int instanceID = ((Object)loader).GetInstanceID(); if (!loader_baselines.TryGetValue(instanceID, out var value)) { value = new LoaderBaseline { loader = loader, spawns_per_frame = Mathf.Max(1, loader.numberOfBuilderSetObjectsToSpawnPerFrame) }; loader_baselines.Add(instanceID, value); } return value.spawns_per_frame; } private static void CapturePriorityTrunkBaseline() { baseline_priority_trunks = GameObject.FindGameObjectsWithTag("PriorityTrunkSpawnPoint").Length; } private static bool ShouldScaleHostRuntime(MapBuilder builder) { if ((Object)(object)builder != (Object)null && ((NetworkBehaviour)builder).IsHost && !IsTutorialActive()) { return TerrainSettingsSync.CanApplyGameplayPatches; } return false; } private static byte EffectiveClutterUnits() { if (!TerrainSettings.enabled) { return 20; } return TerrainSettings.ground_clutter; } private static int GetLayoutSeed(MapLayoutPrefabLoader loader) { MapBuilder singleton = MapBuilder.Singleton; if ((Object)(object)singleton != (Object)null && singleton.chosenMapLayoutIndexForJoinInProgPlayers != null && singleton.chosenMapLayoutIndexForJoinInProgPlayers.Value >= 0) { return singleton.chosenMapLayoutIndexForJoinInProgPlayers.Value; } return loader.mapLayoutIndexChosenByServer; } private static bool IsTutorialActive() { MenuToGameBridger singleton = MenuToGameBridger.Singleton; if ((Object)(object)singleton != (Object)null) { if (!singleton.isPardnerTutorial) { return singleton.isWormTutorial; } return true; } return false; } private static int ScaleCount(int vanilla, byte units, int maximum) { long num = (long)Mathf.Max(0, vanilla) * (long)units + 10; return Mathf.Min(maximum, (int)(num / 20)); } private static int CountTag(GameObject root, string tag) { int num = 0; Transform[] componentsInChildren = root.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if (((Component)componentsInChildren[i]).gameObject.tag == tag) { num++; } } return num; } private static bool IsEssentialTag(string tag) { switch (tag) { default: return tag == "Dandylion"; case "PlayerSpawnPoint": case "CrateSpawnPoint": case "PriorityTrunkSpawnPoint": case "TrunkSpawnPoint": case "LadderSpawnPoint": case "PriorityLadderSpawnPoint": case "PropSpawner": case "SafeSpawnPoint": case "SpawnBlocker": case "NonOverlap": case "WorldUsable": case "ClimbableLadder": case "Zipline": case "Train": case "CollapsibleBuilding": case "DestructibleTrain": case "PickUp": return true; } } private static uint StableHash(int a, int b, int c, int d) { return Mix(Mix(Mix(Mix((uint)(-2128831035 ^ a)) ^ (uint)b) ^ (uint)c) ^ (uint)d); } private static uint Mix(uint value) { value ^= value >> 16; value *= 2146121005; value ^= value >> 15; value *= 2221713035u; value ^= value >> 16; return value; } private static float UnitHash(int a, int b, int c, int d) { return (float)(StableHash(a, b, c, d) & 0xFFFFFF) / 16777215f; } } [BepInPlugin("com.wormtown.terrainsettings", "WormtownTerrainSettings", "0.5.0")] public sealed class Plugin : BaseUnityPlugin { public const string GUID = "com.wormtown.terrainsettings"; public const string NAME = "WormtownTerrainSettings"; public const string VERSION = "0.5.0"; public const byte VERSION_MAJOR = 0; public const byte VERSION_MINOR = 5; public const byte VERSION_PATCH = 0; public static Plugin instance; public static ManualLogSource log; public static bool terrain_patch_ready; public static bool ground_clutter_patch_ready; public static bool shovel_patch_ready; public static bool start_guard_patch_ready; private ConfigEntry enabled_config; private ConfigEntry hilliness_config; private ConfigEntry smoothness_config; private ConfigEntry elevation_config; private ConfigEntry ground_clutter_config; public static bool CriticalPatchesReady { get { if (terrain_patch_ready && ground_clutter_patch_ready && shovel_patch_ready) { return start_guard_patch_ready; } return false; } } private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown instance = this; log = ((BaseUnityPlugin)this).Logger; BindConfig(); Harmony val = new Harmony("com.wormtown.terrainsettings"); Type[] types = Assembly.GetExecutingAssembly().GetTypes(); foreach (Type type in types) { try { val.CreateClassProcessor(type).Patch(); if (type == typeof(TerrainPatches)) { terrain_patch_ready = true; } else if (type == typeof(GroundClutterPatches)) { ground_clutter_patch_ready = true; } else if (type == typeof(ShovelPatches)) { shovel_patch_ready = true; } else if (type == typeof(TerrainSettingsSyncPatches)) { start_guard_patch_ready = true; } } catch (Exception ex) { log.LogWarning((object)("patch class " + type.Name + " failed: " + ex.Message)); } } RestoreHostPreferences(); TerrainSettingsSync.EnsureAvailable(); if (!CriticalPatchesReady) { log.LogError((object)"critical patches failed; terrain modifications have been disabled"); } log.LogInfo((object)"WormtownTerrainSettings 0.5.0 loaded"); } public static void RestoreHostPreferences() { if (!((Object)(object)instance == (Object)null)) { if (!CriticalPatchesReady) { TerrainSettings.ResetToVanilla(); } else { TerrainSettings.Apply(instance.enabled_config.Value, ParseHilliness(instance.hilliness_config.Value), ParseSmoothness(instance.smoothness_config.Value), ParseElevation(instance.elevation_config.Value), ParseGroundClutter(instance.ground_clutter_config.Value)); } } } public static void SaveHostPreferences() { if (!((Object)(object)instance == (Object)null)) { instance.enabled_config.Value = TerrainSettings.enabled; instance.hilliness_config.Value = TerrainSettingsRules.HillinessMultiplier(TerrainSettings.hilliness).ToString("0.00", CultureInfo.InvariantCulture); instance.smoothness_config.Value = TerrainSettings.smoothness.ToString(CultureInfo.InvariantCulture); instance.elevation_config.Value = TerrainSettingsRules.ElevationMultiplier(TerrainSettings.elevation).ToString("0.00", CultureInfo.InvariantCulture); instance.ground_clutter_config.Value = TerrainSettingsRules.GroundClutterMultiplier(TerrainSettings.ground_clutter).ToString("0.00", CultureInfo.InvariantCulture); } } private void BindConfig() { enabled_config = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Enabled", false, "Enable synchronized custom terrain and ground clutter for hosted matches."); hilliness_config = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Hilliness", "1.00", "Terrain relief multiplier from 0.00 to 10.00 in 0.05 steps."); smoothness_config = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Smoothness", "0", "Additional deterministic smoothing passes from 0 to 16."); elevation_config = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Elevation", "1.00", "Overall terrain elevation multiplier from 0.00 to 10.00 in 0.05 steps."); ground_clutter_config = ((BaseUnityPlugin)this).Config.Bind("Terrain", "GroundClutter", "1.00", "Ground clutter multiplier from 0.00 to 10.00 in 0.05 steps."); } private static byte ParseHilliness(string value) { if (TryParseMultiplier(value, out var result)) { return result; } return (value ?? string.Empty).Trim() switch { "Flat" => TerrainSettingsRules.MultiplierToUnits(0.5f), "Gentle" => TerrainSettingsRules.MultiplierToUnits(0.75f), "Hilly" => TerrainSettingsRules.MultiplierToUnits(1.25f), "VeryHilly" => TerrainSettingsRules.MultiplierToUnits(1.5f), "Extreme" => TerrainSettingsRules.MultiplierToUnits(1.8f), "Mountainous" => TerrainSettingsRules.MultiplierToUnits(2.1f), "Towering" => TerrainSettingsRules.MultiplierToUnits(2.4f), "Absurd" => TerrainSettingsRules.MultiplierToUnits(2.7f), "Maximum" => TerrainSettingsRules.MultiplierToUnits(3f), _ => 20, }; } private static byte ParseSmoothness(string value) { if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return TerrainSettingsRules.ClampSmoothness(result); } return (value ?? string.Empty).Trim() switch { "Smooth" => 1, "Smoother" => 2, "Smoothest" => 4, "UltraSmooth" => 5, "Extreme" => 6, "NearFlat" => 7, "Maximum" => 8, _ => 0, }; } private static byte ParseElevation(string value) { if (TryParseMultiplier(value, out var result)) { return result; } return (value ?? string.Empty).Trim() switch { "Low" => TerrainSettingsRules.MultiplierToUnits(0.85f), "High" => TerrainSettingsRules.MultiplierToUnits(1.1f), "VeryHigh" => TerrainSettingsRules.MultiplierToUnits(1.2f), "Extreme" => TerrainSettingsRules.MultiplierToUnits(1.5f), "Towering" => TerrainSettingsRules.MultiplierToUnits(1.8f), "SkyHigh" => TerrainSettingsRules.MultiplierToUnits(2.1f), "Maximum" => TerrainSettingsRules.MultiplierToUnits(2.4f), _ => 20, }; } private static byte ParseGroundClutter(string value) { if (!TryParseMultiplier(value, out var result)) { return 20; } return TerrainSettingsRules.ClampGroundClutter(result); } private static bool TryParseMultiplier(string value, out byte result) { if (float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && !float.IsNaN(result2) && !float.IsInfinity(result2)) { result = TerrainSettingsRules.MultiplierToUnits(result2); return true; } result = 0; return false; } } [HarmonyPatch] public static class ShovelPatches { private struct EquipmentTypeScope { public PardnerEquipment_Shovel shovel; public EquipmentType previous_type; } private struct AimedUseScope { public bool active; public PardnerEquipment_Shovel shovel; public EquipmentType previous_type; public bool previous_requirement; public PardnerEquipment_Shovel previous_aimed_shovel; public Vector3 previous_aimed_position; public Rigidbody body; public PlayerMovement movement; public Vector3 velocity; public bool restore_velocity; public bool air_animation_registered; } private const float AIM_PLAYER_RANGE = 6f; private const float AIM_RAY_LENGTH = 15f; private const int VISIBLE_TERRAIN_MASK = 128; private const float SHOVEL_DIG_STRENGTH = 0.24f; private const int SHOVEL_DIG_RADIUS = 10; private const float SHOVEL_DIG_FALLOFF = 0.25f; private static readonly FieldInfo specific_use_field = AccessTools.Field(typeof(PardnerEquipment), "specificUseRequirementsMet_ThisFrame"); private static readonly FieldInfo use_buffer_field = AccessTools.Field(typeof(PardnerEquipment_Shovel), "useBuffer"); private static readonly HashSet airborne_shovel_animations = new HashSet(); [ThreadStatic] private static bool inside_shovel_deform; [ThreadStatic] private static PardnerEquipment_Shovel aimed_shovel; [ThreadStatic] private static Vector3 aimed_position; [HarmonyPatch(typeof(PardnerEquipment_Shovel), "DeformTerrain", new Type[] { typeof(Vector3), typeof(ulong) })] [HarmonyPrefix] private static void PardnerEquipment_Shovel_DeformTerrain_Prefix(out bool __state) { __state = inside_shovel_deform; inside_shovel_deform = true; } [HarmonyPatch(typeof(PardnerEquipment_Shovel), "DeformTerrain", new Type[] { typeof(Vector3), typeof(ulong) })] [HarmonyFinalizer] private static Exception PardnerEquipment_Shovel_DeformTerrain_Finalizer(Exception __exception, bool __state) { inside_shovel_deform = __state; return __exception; } [HarmonyPatch(typeof(TerrainDeformerManager), "LowerTerrain")] [HarmonyPrefix] public static bool TerrainDeformerManager_LowerTerrain_Prefix(TerrainDeformerManager __instance, Vector3 worldPosition) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (!inside_shovel_deform) { return true; } if (!TerrainSettingsSync.CanApplyGameplayPatches) { return !TerrainSettingsSync.ShouldDeferGameplayPatches; } __instance.LowerTerrainInCircle(worldPosition, 0.24f, 10, 0.25f); return false; } [HarmonyPatch(typeof(PlayerGrabber), "HandleUsingEquipment")] [HarmonyPrefix] private static void PlayerGrabber_HandleUsingEquipment_Prefix(PlayerGrabber __instance, out EquipmentTypeScope __state) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_005e: Invalid comparison between Unknown and I4 //IL_006a: 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) //IL_0076: Unknown result type (might be due to invalid IL or missing references) __state = default(EquipmentTypeScope); if (!((NetworkBehaviour)__instance).IsOwner || !TerrainSettingsSync.CanApplyGameplayPatches || (Object)(object)InputManager.Singleton == (Object)null) { return; } PardnerActionMapActions pardnerActionMap = InputManager.Singleton.inputActions.PardnerActionMap; if (((PardnerActionMapActions)(ref pardnerActionMap)).AimCameraMode.IsPressed()) { PardnerEquipment clientsideEquippedEquipment = __instance.clientsideEquippedEquipment; PardnerEquipment_Shovel val = (PardnerEquipment_Shovel)(object)((clientsideEquippedEquipment is PardnerEquipment_Shovel) ? clientsideEquippedEquipment : null); if (!((Object)(object)val == (Object)null) && (int)((PardnerEquipment)val).equipmentType == 3) { __state.shovel = val; __state.previous_type = ((PardnerEquipment)val).equipmentType; ((PardnerEquipment)val).equipmentType = (EquipmentType)1; } } } [HarmonyPatch(typeof(PlayerGrabber), "HandleUsingEquipment")] [HarmonyFinalizer] private static Exception PlayerGrabber_HandleUsingEquipment_Finalizer(Exception __exception, EquipmentTypeScope __state) { //IL_0015: 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) if ((Object)(object)__state.shovel != (Object)null) { ((PardnerEquipment)__state.shovel).equipmentType = __state.previous_type; } return __exception; } [HarmonyPatch(typeof(PardnerEquipment_Shovel), "OnUse")] [HarmonyPrefix] private static bool PardnerEquipment_Shovel_OnUse_Prefix(PardnerEquipment_Shovel __instance, out AimedUseScope __state) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) __state = default(AimedUseScope); if ((int)((PardnerEquipment)__instance).equipmentType == 1 && (Object)(object)InputManager.Singleton != (Object)null) { PardnerActionMapActions pardnerActionMap = InputManager.Singleton.inputActions.PardnerActionMap; if (((PardnerActionMapActions)(ref pardnerActionMap)).AimCameraMode.IsPressed()) { if (!TryPrepareAimedUse(__instance, ref __state)) { return false; } return true; } } return true; } [HarmonyPatch(typeof(PardnerEquipment_Shovel), "OnUse")] [HarmonyFinalizer] private static Exception PardnerEquipment_Shovel_OnUse_Finalizer(Exception __exception, AimedUseScope __state) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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) //IL_0069: Unknown result type (might be due to invalid IL or missing references) if (!__state.active) { return __exception; } specific_use_field.SetValue(__state.shovel, __state.previous_requirement); ((PardnerEquipment)__state.shovel).equipmentType = __state.previous_type; aimed_shovel = __state.previous_aimed_shovel; aimed_position = __state.previous_aimed_position; if (__state.restore_velocity && (Object)(object)__state.body != (Object)null) { __state.body.velocity = __state.velocity; } if (__exception != null && __state.air_animation_registered) { airborne_shovel_animations.Remove(__state.movement); } return __exception; } [HarmonyPatch(typeof(PardnerEquipment_Shovel), "WaitASecondAndThenDigAHole")] [HarmonyPrefix] public static void PardnerEquipment_Shovel_WaitForDig_Prefix(PardnerEquipment_Shovel __instance, ref Vector3 _digPos) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)aimed_shovel == (Object)(object)__instance) { _digPos = aimed_position; } } [HarmonyPatch(typeof(PlayerMovement), "ChangeAwayFromStaticAnimationState")] [HarmonyPostfix] public static void PlayerMovement_ChangeAwayFromStaticAnimationState_Postfix(PlayerMovement __instance) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (airborne_shovel_animations.Remove(__instance) && !__instance.grounded) { __instance.movementState = (MovementState)1; } } [HarmonyPatch(typeof(PlayerMovement), "AttemptToSurfaceClingInFrontOfUs")] [HarmonyPrefix] public static bool PlayerMovement_AttemptSurfaceCling_Prefix(PlayerMovement __instance) { return !IsAimingShovel(__instance); } [HarmonyPatch(typeof(PlayerMovement), "AttemptToGrabZipline")] [HarmonyPrefix] public static bool PlayerMovement_AttemptGrabZipline_Prefix(PlayerMovement __instance) { return !IsAimingShovel(__instance); } public static void ResetRuntimeState() { //IL_000c: 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) inside_shovel_deform = false; aimed_shovel = null; aimed_position = Vector3.zero; airborne_shovel_animations.Clear(); } private static bool TryPrepareAimedUse(PardnerEquipment_Shovel shovel, ref AimedUseScope state) { //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0164: 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_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Invalid comparison between Unknown and I4 //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_021d: 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) if (!TerrainSettingsSync.CanApplyGameplayPatches || specific_use_field == null || use_buffer_field == null || (bool)use_buffer_field.GetValue(shovel) || (Object)(object)((PardnerEquipment)shovel).grabberScriptOfWhoHasUsEquipped == (Object)null || !((NetworkBehaviour)((PardnerEquipment)shovel).grabberScriptOfWhoHasUsEquipped).IsOwner || ((PardnerEquipment)shovel).grabberScriptOfWhoHasUsEquipped.isHoldingAnObject || !((PardnerEquipment)shovel).GetIsCooldownReady()) { return false; } PlayerGrabber grabberScriptOfWhoHasUsEquipped = ((PardnerEquipment)shovel).grabberScriptOfWhoHasUsEquipped; Player component = ((Component)grabberScriptOfWhoHasUsEquipped).GetComponent(); PlayerMovement component2 = ((Component)grabberScriptOfWhoHasUsEquipped).GetComponent(); if ((Object)(object)component == (Object)null || !component.isAlive || (Object)(object)component2 == (Object)null || ((int)component2.movementState != 0 && (int)component2.movementState != 1)) { return false; } Camera val = (((Object)(object)GameManager.Singleton != (Object)null) ? GameManager.Singleton.activeCamera : null); RaycastHit val2 = default(RaycastHit); if ((Object)(object)val == (Object)null || !Physics.Raycast(new Ray(((Component)val).transform.position, ((Component)val).transform.forward), ref val2, 15f, 128, (QueryTriggerInteraction)1) || Vector3.Distance(((Component)grabberScriptOfWhoHasUsEquipped).transform.position, ((RaycastHit)(ref val2)).point) > 6f || !(((RaycastHit)(ref val2)).collider is TerrainCollider)) { return false; } state.active = true; state.shovel = shovel; state.previous_type = ((PardnerEquipment)shovel).equipmentType; state.previous_requirement = (bool)specific_use_field.GetValue(shovel); state.previous_aimed_shovel = aimed_shovel; state.previous_aimed_position = aimed_position; state.body = ((Component)component2).GetComponent(); state.movement = component2; state.restore_velocity = (int)component2.movementState == 1 && (Object)(object)state.body != (Object)null; state.velocity = (state.restore_velocity ? state.body.velocity : Vector3.zero); if (state.restore_velocity) { airborne_shovel_animations.Add(component2); state.air_animation_registered = true; } specific_use_field.SetValue(shovel, true); ((PardnerEquipment)shovel).equipmentType = (EquipmentType)3; aimed_shovel = shovel; aimed_position = ((RaycastHit)(ref val2)).point; ((PardnerEquipment)shovel).aimSpotOnUse = ((RaycastHit)(ref val2)).point; ((PardnerEquipment)shovel).cameraPositionOnUse = ((Component)val).transform.position; ((PardnerEquipment)shovel).playerPositionOnUse = ((Component)grabberScriptOfWhoHasUsEquipped).transform.position; return true; } private static bool IsAimingShovel(PlayerMovement movement) { //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) if (TerrainSettingsSync.CanApplyGameplayPatches && !((Object)(object)movement == (Object)null) && ((NetworkBehaviour)movement).IsOwner && !((Object)(object)InputManager.Singleton == (Object)null)) { PardnerActionMapActions pardnerActionMap = InputManager.Singleton.inputActions.PardnerActionMap; if (((PardnerActionMapActions)(ref pardnerActionMap)).AimCameraMode.IsPressed()) { PlayerGrabber component = ((Component)movement).GetComponent(); if ((Object)(object)component != (Object)null) { return component.clientsideEquippedEquipment is PardnerEquipment_Shovel; } return false; } } return false; } } [HarmonyPatch(typeof(TerrainManager), "SetTerrainHeights")] public static class TerrainPatches { private struct ProtectedArea { public Vector3 position; public float radius; public ProtectedArea(Vector3 area_position, float area_radius) { //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) position = area_position; radius = area_radius; } } private const int EDGE_BLEND_SAMPLES = 16; private const float TOWN_PROTECTION_RADIUS = 48f; private const float QUARRY_PROTECTION_RADIUS = 38f; private const float CHURCH_PROTECTION_RADIUS = 24f; private const float MESA_PROTECTION_RADIUS = 20f; private const float BUILDING_PROTECTION_RADIUS = 12f; private const float PROTECTION_BLEND_WIDTH = 12f; private const float TRAIN_CORRIDOR_HALF_WIDTH = 24f; private const float TRAIN_CORRIDOR_BLEND_WIDTH = 4f; private static TerrainManager captured_manager; private static float[,] vanilla_heights; private static float[,] applied_base_heights; private static ushort applied_revision; private static bool terrain_generation_seen; [HarmonyPostfix] public static void SetTerrainHeights_Postfix(TerrainManager __instance) { if (IsTutorial() || IsMapAuthoring()) { return; } terrain_generation_seen = true; try { if (!CaptureVanillaTerrain(__instance)) { if (TerrainSettings.HasNonVanillaEffect) { TerrainSettingsSync.ReportTerrainApplicationFailure("terrain data was unavailable after generation"); } } else { if (!TerrainSettingsSync.CanApplyTerrain) { return; } if (TerrainSettings.HasNonVanillaEffect) { if (!ApplyCapturedTerrain(TerrainSettingsSync.ActiveRevision, update_duplicate: false)) { TerrainSettingsSync.ReportTerrainApplicationFailure("the generated heightmap could not be committed"); } } else { applied_revision = TerrainSettingsSync.ActiveRevision; } } } catch (Exception ex) { Plugin.log.LogWarning((object)$"terrain settings failed; vanilla terrain retained: {ex}"); if (TerrainSettings.HasNonVanillaEffect) { TerrainSettingsSync.ReportTerrainApplicationFailure(ex.Message); } } } public static bool ApplySynchronizedSnapshot(ushort revision) { if (!terrain_generation_seen || applied_revision == revision || IsTutorial()) { return true; } if ((Object)(object)captured_manager == (Object)null || vanilla_heights == null) { return false; } try { bool num = ApplyCapturedTerrain(revision, update_duplicate: true); if (!num) { TerrainSettingsSync.ReportTerrainApplicationFailure("the late synchronized heightmap could not update worm collision"); } return num; } catch (Exception ex) { Plugin.log.LogWarning((object)$"late terrain synchronization failed: {ex}"); TerrainSettingsSync.ReportTerrainApplicationFailure(ex.Message); return false; } } public static void ResetSessionState() { ShovelPatches.ResetRuntimeState(); GroundClutterPatches.ResetRuntimeState(); captured_manager = null; vanilla_heights = null; applied_base_heights = null; applied_revision = 0; terrain_generation_seen = false; } private static bool CaptureVanillaTerrain(TerrainManager manager) { Terrain val = (((Object)(object)manager != (Object)null) ? manager.GetTerrain() : null); TerrainData val2 = (((Object)(object)val != (Object)null) ? val.terrainData : null); if ((Object)(object)val2 == (Object)null) { Plugin.log.LogWarning((object)"terrain settings skipped: terrain data unavailable"); return false; } int heightmapResolution = val2.heightmapResolution; captured_manager = manager; vanilla_heights = val2.GetHeights(0, 0, heightmapResolution, heightmapResolution); applied_base_heights = null; applied_revision = 0; return true; } private static bool ApplyCapturedTerrain(ushort revision, bool update_duplicate) { Terrain val = (((Object)(object)captured_manager != (Object)null) ? captured_manager.GetTerrain() : null); TerrainData val2 = (((Object)(object)val != (Object)null) ? val.terrainData : null); if ((Object)(object)val2 == (Object)null || vanilla_heights == null) { return false; } float[,] previous_base = applied_base_heights ?? vanilla_heights; float[,] array = (float[,])vanilla_heights.Clone(); if (TerrainSettings.HasNonVanillaEffect) { int num = TerrainSettingsRules.AdditionalSmoothingPasses(TerrainSettings.smoothness); for (int i = 0; i < num; i++) { array = SmoothHeightmap(array); } ApplyShape(array, TerrainSettingsRules.HillinessMultiplier(TerrainSettings.hilliness), TerrainSettingsRules.ElevationMultiplier(TerrainSettings.elevation)); ApplySafetyBlend(val, vanilla_heights, array, BuildProtectedAreas()); } float[,] array2 = (update_duplicate ? PreserveRuntimeDeformations(val2, previous_base, array) : array); val2.SetHeights(0, 0, array2); applied_base_heights = array; AlignFutureLayoutSpawns(val, previous_base, array); if (update_duplicate && !UpdateDuplicateTerrain(val2, array)) { return false; } applied_revision = revision; Plugin.log.LogInfo((object)(TerrainSettings.HasNonVanillaEffect ? ("terrain applied: hilliness=" + TerrainSettingsRules.HillinessName(TerrainSettings.hilliness) + ", smoothness=" + TerrainSettingsRules.SmoothnessName(TerrainSettings.smoothness) + ", elevation=" + TerrainSettingsRules.ElevationName(TerrainSettings.elevation)) : "terrain restored to the synchronized vanilla baseline")); return true; } private static float[,] PreserveRuntimeDeformations(TerrainData terrain_data, float[,] previous_base, float[,] new_base) { int length = new_base.GetLength(0); int length2 = new_base.GetLength(1); if (previous_base == null || previous_base.GetLength(0) != length || previous_base.GetLength(1) != length2) { return new_base; } float[,] heights = terrain_data.GetHeights(0, 0, length2, length); float[,] array = new float[length, length2]; for (int i = 0; i < length; i++) { for (int j = 0; j < length2; j++) { float num = heights[i, j] - previous_base[i, j]; array[i, j] = Mathf.Clamp01(new_base[i, j] + num); } } return array; } private static bool UpdateDuplicateTerrain(TerrainData visible_data, float[,] heights) { GameManager singleton = GameManager.Singleton; GameObject val = (((Object)(object)singleton != (Object)null) ? singleton.duplicateWormOnlyTerrain : null); if ((Object)(object)val == (Object)null) { return false; } Terrain component = val.GetComponent(); TerrainCollider component2 = val.GetComponent(); TerrainData val2 = (((Object)(object)component != (Object)null) ? component.terrainData : null); bool flag = (Object)(object)val2 == (Object)(object)visible_data; if (!flag && (Object)(object)val2 != (Object)null && val2.heightmapResolution == heights.GetLength(0)) { val2.SetHeights(0, 0, heights); flag = true; } TerrainData val3 = (((Object)(object)component2 != (Object)null) ? component2.terrainData : null); bool flag2 = (Object)(object)component2 != (Object)null && ((Object)(object)val3 == (Object)(object)visible_data || (flag && (Object)(object)val3 == (Object)(object)val2)); if (!flag2 && (Object)(object)val3 != (Object)null && (Object)(object)val3 != (Object)(object)val2 && val3.heightmapResolution == heights.GetLength(0)) { val3.SetHeights(0, 0, heights); flag2 = true; } return flag && flag2; } private static void ApplyShape(float[,] modified, float hilliness, float elevation) { int length = modified.GetLength(0); int length2 = modified.GetLength(1); double num = 0.0; for (int i = 0; i < length; i++) { for (int j = 0; j < length2; j++) { num += (double)modified[i, j]; } } float mean = (float)(num / (double)(length2 * length)); for (int k = 0; k < length; k++) { for (int l = 0; l < length2; l++) { modified[k, l] = RoundedHeight(modified[k, l], mean, hilliness, elevation); } } } private static void ApplySafetyBlend(Terrain terrain, float[,] original, float[,] modified, List protected_areas) { //IL_0016: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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_003e: Unknown result type (might be due to invalid IL or missing references) int length = modified.GetLength(0); int length2 = modified.GetLength(1); Vector3 position = ((Component)terrain).transform.position; Vector3 size = terrain.terrainData.size; for (int i = 0; i < length; i++) { float num = TrainCorridorBlend(position.z + (float)i / (float)(length - 1) * size.z); for (int j = 0; j < length2; j++) { float num2 = Mathf.Min(BorderBlend(j, i, length2, length), ProtectedAreaBlend(terrain, protected_areas, j, i, length2, length)); float num3 = ((modified[i, j] < original[i, j]) ? num2 : Mathf.Min(num, num2)); modified[i, j] = Mathf.Clamp01(Mathf.Lerp(original[i, j], modified[i, j], num3)); } } } private static float TrainCorridorBlend(float world_z) { float num = Mathf.Abs(world_z); float num2 = Mathf.InverseLerp(24f, 28f, num); return num2 * num2 * (3f - 2f * num2); } private static float RoundedHeight(float height, float mean, float hilliness, float elevation) { if (elevation <= 0f) { return 0f; } if (Mathf.Approximately(hilliness, 1f) && Mathf.Approximately(elevation, 1f)) { return Mathf.Clamp01(height); } float num = SoftElevationCenter(mean * elevation); float num2 = (height - mean) * hilliness * elevation; if (num2 >= 0f) { float num3 = 1f - num; if (!(num3 <= Mathf.Epsilon)) { return num + num3 * num2 / (num3 + num2); } return num; } float num4 = 0f - num2; if (!(num <= Mathf.Epsilon)) { return num - num * num4 / (num + num4); } return num; } private static float SoftElevationCenter(float value) { value = Mathf.Max(0f, value); if (value <= 0.8f) { return value; } float num = value - 0.8f; return 0.8f + 0.19999999f * num / (0.19999999f + num); } private static List BuildProtectedAreas() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: 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) List list = new List(); MapLayoutPrefabLoader singleton = MapLayoutPrefabLoader.Singleton; MapLayout val = (((Object)(object)singleton != (Object)null) ? singleton.activeMapLayout : null); if ((Object)(object)val != (Object)null) { list.Add(new ProtectedArea(val.town_POS, 48f)); list.Add(new ProtectedArea(val.quarry_POS, 38f)); list.Add(new ProtectedArea(val.church_POS, 24f)); if (val.mesa_Positions != null) { foreach (Vector3 mesa_Position in val.mesa_Positions) { list.Add(new ProtectedArea(mesa_Position, 20f)); } } if (val.buildings != null) { foreach (CollapsibleBuilding building in val.buildings) { AddProtectedBuilding(list, building); } } } MapBuilder singleton2 = MapBuilder.Singleton; if ((Object)(object)singleton2 == (Object)null) { return list; } AddProtectedObject(list, singleton2.town, 48f); AddProtectedObject(list, singleton2.quarry, 38f); AddProtectedObject(list, singleton2.church, 24f); AddProtectedObject(list, singleton2.waterTower, 12f); if (singleton2.mesas != null) { GameObject[] mesas = singleton2.mesas; foreach (GameObject scene_object in mesas) { AddProtectedObject(list, scene_object, 20f); } } if (singleton2.spawnedBuildings != null) { foreach (CollapsibleBuilding spawnedBuilding in singleton2.spawnedBuildings) { AddProtectedBuilding(list, spawnedBuilding); } } return list; } private static void AddProtectedObject(List areas, GameObject scene_object, float radius) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)scene_object != (Object)null) { areas.Add(new ProtectedArea(scene_object.transform.position, radius)); } } private static void AddProtectedBuilding(List areas, CollapsibleBuilding building) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)building != (Object)null) { areas.Add(new ProtectedArea(((Component)building).transform.position, 12f)); } } private static float ProtectedAreaBlend(Terrain terrain, List areas, int x, int y, int width, int height) { //IL_0020: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_0055: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)terrain == (Object)null || areas == null || areas.Count == 0) { return 1f; } Vector3 position = ((Component)terrain).transform.position; Vector3 size = terrain.terrainData.size; float num = position.x + (float)x / (float)(width - 1) * size.x; float num2 = position.z + (float)y / (float)(height - 1) * size.z; float num3 = 1f; foreach (ProtectedArea area in areas) { float num4 = num - area.position.x; float num5 = num2 - area.position.z; float num6 = area.radius + 12f; float num7 = num4 * num4 + num5 * num5; if (!(num7 >= num6 * num6)) { float num8 = Mathf.Sqrt(num7); float num9 = Mathf.InverseLerp(area.radius, num6, num8); num9 = num9 * num9 * (3f - 2f * num9); num3 = Mathf.Min(num3, num9); } } return num3; } private static void AlignFutureLayoutSpawns(Terrain terrain, float[,] previous_base, float[,] new_base) { //IL_0033: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_00cb: 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_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) MapLayoutPrefabLoader singleton = MapLayoutPrefabLoader.Singleton; MapLayout val = (((Object)(object)singleton != (Object)null) ? singleton.activeMapLayout : null); if ((Object)(object)terrain == (Object)null || (Object)(object)val == (Object)null || previous_base == null || new_base == null) { return; } Vector3 bones_POS = val.bones_POS; val.bones_POS = ShiftPosition(terrain, previous_base, new_base, val.bones_POS); MapBuilder singleton2 = MapBuilder.Singleton; if ((Object)(object)singleton2 != (Object)null && (Object)(object)singleton2.conductorBones != (Object)null && Mathf.Abs(singleton2.conductorBones.transform.position.x - bones_POS.x) < 0.1f && Mathf.Abs(singleton2.conductorBones.transform.position.z - bones_POS.z) < 0.1f) { Vector3 position = singleton2.conductorBones.transform.position; position.y += val.bones_POS.y - bones_POS.y; singleton2.conductorBones.transform.position = position; } if (val.builderSetObjectSpawners == null) { return; } foreach (MapLayout_BuilderSetObject_Spawner builderSetObjectSpawner in val.builderSetObjectSpawners) { if ((Object)(object)builderSetObjectSpawner != (Object)null) { builderSetObjectSpawner.pos = ShiftPosition(terrain, previous_base, new_base, builderSetObjectSpawner.pos); } } } private static Vector3 ShiftPosition(Terrain terrain, float[,] previous_base, float[,] new_base, Vector3 position) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_0031: Unknown result type (might be due to invalid IL or missing references) float num = SampleNormalizedHeight(terrain, previous_base, position); float num2 = SampleNormalizedHeight(terrain, new_base, position); position.y += (num2 - num) * terrain.terrainData.size.y; return position; } private static float SampleNormalizedHeight(Terrain terrain, float[,] heights, Vector3 world_position) { //IL_0016: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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_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) //IL_0043: 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_0050: Unknown result type (might be due to invalid IL or missing references) int length = heights.GetLength(0); int length2 = heights.GetLength(1); Vector3 position = ((Component)terrain).transform.position; Vector3 size = terrain.terrainData.size; float num = Mathf.Clamp01((world_position.x - position.x) / size.x); float num2 = Mathf.Clamp01((world_position.z - position.z) / size.z); float num3 = num * (float)(length2 - 1); float num4 = num2 * (float)(length - 1); int num5 = Mathf.FloorToInt(num3); int num6 = Mathf.FloorToInt(num4); int num7 = Mathf.Min(length2 - 1, num5 + 1); int num8 = Mathf.Min(length - 1, num6 + 1); float num9 = num3 - (float)num5; float num10 = num4 - (float)num6; float num11 = Mathf.Lerp(heights[num6, num5], heights[num6, num7], num9); float num12 = Mathf.Lerp(heights[num8, num5], heights[num8, num7], num9); return Mathf.Lerp(num11, num12, num10); } private static float[,] SmoothHeightmap(float[,] source) { int length = source.GetLength(0); int length2 = source.GetLength(1); float[,] array = new float[length, length2]; float[,] array2 = new float[length, length2]; for (int i = 0; i < length; i++) { for (int j = 0; j < length2; j++) { int num = Mathf.Max(0, j - 2); int num2 = Mathf.Max(0, j - 1); int num3 = Mathf.Min(length2 - 1, j + 1); int num4 = Mathf.Min(length2 - 1, j + 2); array[i, j] = (source[i, num] + source[i, num2] * 4f + source[i, j] * 6f + source[i, num3] * 4f + source[i, num4]) / 16f; } } for (int k = 0; k < length; k++) { int num5 = Mathf.Max(0, k - 2); int num6 = Mathf.Max(0, k - 1); int num7 = Mathf.Min(length - 1, k + 1); int num8 = Mathf.Min(length - 1, k + 2); for (int l = 0; l < length2; l++) { array2[k, l] = (array[num5, l] + array[num6, l] * 4f + array[k, l] * 6f + array[num7, l] * 4f + array[num8, l]) / 16f; } } return array2; } private static float BorderBlend(int x, int y, int width, int height) { float num = Mathf.Clamp01((float)Math.Min(Math.Min(x, width - 1 - x), Math.Min(y, height - 1 - y)) / 16f); return num * num * (3f - 2f * num); } private static bool IsTutorial() { MenuToGameBridger singleton = MenuToGameBridger.Singleton; if ((Object)(object)singleton != (Object)null) { if (!singleton.isWormTutorial) { return singleton.isPardnerTutorial; } return true; } return false; } private static bool IsMapAuthoring() { MapLayoutPrefabCreator singleton = MapLayoutPrefabCreator.Singleton; MapLayoutPrefabLoader singleton2 = MapLayoutPrefabLoader.Singleton; if ((Object)(object)singleton != (Object)null && ((Component)singleton).gameObject.activeInHierarchy) { if (!((Object)(object)singleton2 == (Object)null)) { return (Object)(object)singleton2.activeMapLayout == (Object)null; } return true; } return false; } } public static class TerrainSettings { public const byte DEFAULT_HILLINESS = 20; public const byte DEFAULT_SMOOTHNESS = 0; public const byte DEFAULT_ELEVATION = 20; public const byte DEFAULT_GROUND_CLUTTER = 20; public static bool enabled; public static byte hilliness = 20; public static byte smoothness = 0; public static byte elevation = 20; public static byte ground_clutter = 20; public static bool HasNonVanillaEffect { get { if (enabled) { if (hilliness == 20 && smoothness == 0) { return elevation != 20; } return true; } return false; } } public static bool HasGroundClutterEffect { get { if (enabled) { return ground_clutter != 20; } return false; } } public static bool Apply(bool new_enabled, byte new_hilliness, byte new_smoothness, byte new_elevation, byte new_ground_clutter) { new_hilliness = TerrainSettingsRules.ClampHilliness(new_hilliness); new_smoothness = TerrainSettingsRules.ClampSmoothness(new_smoothness); new_elevation = TerrainSettingsRules.ClampElevation(new_elevation); new_ground_clutter = TerrainSettingsRules.ClampGroundClutter(new_ground_clutter); bool result = enabled != new_enabled || hilliness != new_hilliness || smoothness != new_smoothness || elevation != new_elevation || ground_clutter != new_ground_clutter; enabled = new_enabled; hilliness = new_hilliness; smoothness = new_smoothness; elevation = new_elevation; ground_clutter = new_ground_clutter; return result; } public static bool ResetToVanilla() { return Apply(new_enabled: false, 20, 0, 20, 20); } } public static class TerrainSettingsRules { public const byte MULTIPLIER_UNITS_PER_ONE = 20; public const byte MAX_HILLINESS = 200; public const byte MAX_SMOOTHNESS = 16; public const byte MAX_ELEVATION = 200; public const byte MAX_GROUND_CLUTTER = 200; public static byte ClampHilliness(int value) { return ClampByte(value, 200); } public static byte ClampSmoothness(int value) { return ClampByte(value, 16); } public static byte ClampElevation(int value) { return ClampByte(value, 200); } public static byte ClampGroundClutter(int value) { return ClampByte(value, 200); } public static float HillinessMultiplier(byte value) { return (float)(int)ClampHilliness(value) / 20f; } public static int AdditionalSmoothingPasses(byte value) { return ClampSmoothness(value); } public static float ElevationMultiplier(byte value) { return (float)(int)ClampElevation(value) / 20f; } public static float GroundClutterMultiplier(byte value) { return (float)(int)ClampGroundClutter(value) / 20f; } public static string HillinessName(byte value) { return MultiplierName(ClampHilliness(value)); } public static string SmoothnessName(byte value) { byte b = ClampSmoothness(value); if (b != 1) { return $"{b} passes"; } return "1 pass"; } public static string ElevationName(byte value) { return MultiplierName(ClampElevation(value)); } public static string GroundClutterName(byte value) { return MultiplierName(ClampGroundClutter(value)); } public static byte MultiplierToUnits(float value) { return ClampByte((int)Math.Round(value * 20f, MidpointRounding.AwayFromZero), 200); } private static string MultiplierName(byte value) { return ((float)(int)value / 20f).ToString("0.00", CultureInfo.InvariantCulture) + "x"; } private static byte ClampByte(int value, byte maximum) { if (value <= 0) { return 0; } if (value >= maximum) { return maximum; } return (byte)value; } } public sealed class TerrainSettingsSync : MonoBehaviour { private const string REQUEST_MESSAGE = "com.wormtown.terrainsettings.request.v6"; private const string SNAPSHOT_MESSAGE = "com.wormtown.terrainsettings.snapshot.v6"; private const string ACK_MESSAGE = "com.wormtown.terrainsettings.ack.v6"; private const string SERVICE_OBJECT_NAME = "Wormtown Terrain Settings Service"; private const byte PROTOCOL_VERSION = 6; private const byte TERRAIN_ALGORITHM_VERSION = 10; private const int COMPATIBILITY_HEADER_SIZE = 5; private const int REQUEST_SIZE = 5; private const int SNAPSHOT_SIZE = 12; private const int ACK_SIZE = 7; private const float REQUEST_RETRY_INITIAL_SECONDS = 0.5f; private const float REQUEST_RETRY_MAX_SECONDS = 5f; private const float SNAPSHOT_RETRY_SECONDS = 1f; private const float LATE_JOIN_MAP_WAIT_SECONDS = 5f; private const float LATE_JOIN_COMPATIBILITY_GRACE_SECONDS = 3f; private static TerrainSettingsSync instance; private static int ui_revision; private readonly HashSet modded_clients = new HashSet(); private readonly Dictionary acknowledged_revisions = new Dictionary(); private readonly Dictionary compatibility_deadlines = new Dictionary(); private NetworkManager network_manager; private bool registered_as_host; private bool has_host_snapshot; private bool terrain_application_failed; private ushort active_revision; private float next_request_time; private float request_retry_seconds; private float next_snapshot_retry_time; private float allow_vanilla_late_join_time; public static int UiRevision => ui_revision; public static ushort ActiveRevision { get { if (!((Object)(object)instance != (Object)null)) { return 0; } return instance.active_revision; } } public static bool IsLocalHost { get { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton != (Object)null) { return singleton.IsHost; } return false; } } public static bool CanEdit { get { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 if (!IsLocalHost || !Plugin.CriticalPatchesReady) { return false; } GameManager singleton = GameManager.Singleton; if (!((Object)(object)singleton == (Object)null)) { return (int)singleton.gameState == 0; } return true; } } public static bool CanApplyTerrain { get { if (!Plugin.CriticalPatchesReady) { return false; } NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsListening || singleton.IsHost) { return true; } if ((Object)(object)instance != (Object)null) { return instance.has_host_snapshot; } return false; } } public static bool CanApplyGameplayPatches { get { if (!Plugin.CriticalPatchesReady) { return false; } NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsListening || (Object)(object)instance == (Object)null || (Object)(object)instance.network_manager != (Object)(object)singleton) { return false; } if (!singleton.IsHost) { return instance.has_host_snapshot; } if (instance.registered_as_host) { return !instance.terrain_application_failed; } return false; } } public static bool ShouldDeferGameplayPatches { get { NetworkManager singleton = NetworkManager.Singleton; if (Plugin.CriticalPatchesReady && (Object)(object)singleton != (Object)null && singleton.IsListening && !singleton.IsHost && (Object)(object)instance != (Object)null && (Object)(object)instance.network_manager == (Object)(object)singleton && !instance.has_host_snapshot) { return Time.unscaledTime < instance.allow_vanilla_late_join_time; } return false; } } public static int MissingClientCount { get { if ((Object)(object)instance == (Object)null || !instance.registered_as_host) { return 0; } return instance.CountMissingClients(); } } public static bool AreAllConnectedClientsReady { get { if ((Object)(object)instance == (Object)null || !instance.registered_as_host) { return false; } return instance.CountMissingClients() == 0; } } public static bool CanLoadLateJoinMap { get { if (!Plugin.CriticalPatchesReady) { return true; } NetworkManager singleton = NetworkManager.Singleton; GameManager singleton2 = GameManager.Singleton; if ((Object)(object)singleton == (Object)null || singleton.IsHost || (Object)(object)singleton2 == (Object)null || !singleton2.weJoinedInProg) { return true; } if ((Object)(object)instance == (Object)null || (Object)(object)instance.network_manager != (Object)(object)singleton) { return false; } if (!instance.has_host_snapshot) { return Time.unscaledTime >= instance.allow_vanilla_late_join_time; } return true; } } public static string PanelTitle { get { if (!Plugin.CriticalPatchesReady) { return "Terrain Settings (Unavailable)"; } if ((Object)(object)instance != (Object)null && instance.terrain_application_failed) { return "Terrain Settings (Failed)"; } if (!IsLocalHost && (Object)(object)instance != (Object)null && !instance.has_host_snapshot) { return "Terrain Settings (Syncing)"; } int missingClientCount = MissingClientCount; if (missingClientCount <= 0) { return "Terrain Settings"; } return $"Terrain Settings ({missingClientCount} Missing)"; } } public static bool IsSoloTestLobby(LobbyManager lobby_manager) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; MenuToGameBridger singleton2 = MenuToGameBridger.Singleton; GameManager singleton3 = GameManager.Singleton; int num = (((Object)(object)lobby_manager != (Object)null) ? ((lobby_manager.humanTeam?.Count ?? 0) + (lobby_manager.wormTeam?.Count ?? 0)) : 0); if ((Object)(object)singleton != (Object)null && singleton.IsHost && singleton.ConnectedClients.Count == 1 && (Object)(object)singleton2 != (Object)null && !singleton2.isQuickplayMatch && (Object)(object)singleton3 != (Object)null && (int)singleton3.gameState == 0) { return num == 1; } return false; } public static bool EnsureAvailable() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown if ((Object)(object)instance != (Object)null) { return true; } try { TerrainSettingsSync terrainSettingsSync = Object.FindObjectOfType(); GameObject val = (((Object)(object)terrainSettingsSync != (Object)null) ? ((Component)terrainSettingsSync).gameObject : GameObject.Find("Wormtown Terrain Settings Service")); if ((Object)(object)val == (Object)null) { val = new GameObject("Wormtown Terrain Settings Service"); Object.DontDestroyOnLoad((Object)(object)val); } terrainSettingsSync = val.GetComponent(); if ((Object)(object)terrainSettingsSync == (Object)null) { terrainSettingsSync = val.AddComponent(); } instance = terrainSettingsSync; return true; } catch (Exception ex) { Plugin.log.LogWarning((object)("terrain sync creation failed: " + ex.Message)); return false; } } private void Awake() { if ((Object)(object)instance != (Object)null && (Object)(object)instance != (Object)(object)this) { Object.Destroy((Object)(object)this); } else { instance = this; } } public static void SetEnabled(bool value) { if (CanEdit && TerrainSettings.Apply(value, TerrainSettings.hilliness, TerrainSettings.smoothness, TerrainSettings.elevation, TerrainSettings.ground_clutter)) { CommitHostChange(); } } public static void SetHilliness(byte value) { if (CanEdit && TerrainSettings.Apply(TerrainSettings.enabled, value, TerrainSettings.smoothness, TerrainSettings.elevation, TerrainSettings.ground_clutter)) { CommitHostChange(); } } public static void SetSmoothness(byte value) { if (CanEdit && TerrainSettings.Apply(TerrainSettings.enabled, TerrainSettings.hilliness, value, TerrainSettings.elevation, TerrainSettings.ground_clutter)) { CommitHostChange(); } } public static void SetElevation(byte value) { if (CanEdit && TerrainSettings.Apply(TerrainSettings.enabled, TerrainSettings.hilliness, TerrainSettings.smoothness, value, TerrainSettings.ground_clutter)) { CommitHostChange(); } } public static void SetGroundClutter(byte value) { if (CanEdit && TerrainSettings.Apply(TerrainSettings.enabled, TerrainSettings.hilliness, TerrainSettings.smoothness, TerrainSettings.elevation, value)) { CommitHostChange(); } } public static void ResendCurrentSnapshot() { if ((Object)(object)instance != (Object)null && instance.registered_as_host) { instance.SendSnapshotToModdedClients(); } } public static void ReportTerrainApplicationFailure(string reason) { Plugin.log.LogError((object)("synchronized terrain application failed: " + reason)); NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)instance != (Object)null) { instance.terrain_application_failed = true; TouchUi(); } if ((Object)(object)singleton == (Object)null || !singleton.IsListening) { return; } try { if (singleton.IsHost) { List list = new List(); foreach (ulong key in singleton.ConnectedClients.Keys) { if (key != singleton.LocalClientId) { list.Add(key); } } { foreach (ulong item in list) { singleton.DisconnectClient(item); } return; } } if (singleton.IsConnectedClient) { singleton.Shutdown(false); } } catch (Exception ex) { Plugin.log.LogError((object)("terrain failure disconnect failed: " + ex.Message)); } } private void Update() { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)network_manager != (Object)null && ((Object)(object)network_manager != (Object)(object)singleton || !network_manager.IsListening)) { UnregisterNetworkManager(); } if ((Object)(object)network_manager == (Object)null && (Object)(object)singleton != (Object)null && singleton.IsListening) { RegisterNetworkManager(singleton); } if ((Object)(object)network_manager == (Object)null) { return; } if (registered_as_host) { if (Time.unscaledTime >= next_snapshot_retry_time) { next_snapshot_retry_time = Time.unscaledTime + 1f; SendSnapshotToUnacknowledgedClients(); } EnforceLateJoinCompatibility(); } else { TryRequestSnapshot(); } } private void OnDestroy() { UnregisterNetworkManager(); if ((Object)(object)instance == (Object)(object)this) { instance = null; } } private void RegisterNetworkManager(NetworkManager manager) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown TerrainPatches.ResetSessionState(); network_manager = manager; registered_as_host = manager.IsHost; has_host_snapshot = registered_as_host; terrain_application_failed = false; modded_clients.Clear(); acknowledged_revisions.Clear(); compatibility_deadlines.Clear(); manager.CustomMessagingManager.RegisterNamedMessageHandler("com.wormtown.terrainsettings.request.v6", new HandleNamedMessageDelegate(ReceiveSnapshotRequest)); manager.CustomMessagingManager.RegisterNamedMessageHandler("com.wormtown.terrainsettings.snapshot.v6", new HandleNamedMessageDelegate(ReceiveSnapshot)); manager.CustomMessagingManager.RegisterNamedMessageHandler("com.wormtown.terrainsettings.ack.v6", new HandleNamedMessageDelegate(ReceiveSnapshotAck)); manager.OnClientConnectedCallback += OnClientConnected; manager.OnClientDisconnectCallback += OnClientDisconnected; if (registered_as_host) { Plugin.RestoreHostPreferences(); active_revision = NextRevision(active_revision); modded_clients.Add(manager.LocalClientId); acknowledged_revisions[manager.LocalClientId] = active_revision; next_snapshot_retry_time = Time.unscaledTime; } else { TerrainSettings.ResetToVanilla(); ResetSnapshotRequests(); allow_vanilla_late_join_time = Time.unscaledTime + 5f; TryRequestSnapshot(); } TouchUi(); } private void UnregisterNetworkManager() { if (!((Object)(object)network_manager == (Object)null)) { try { network_manager.CustomMessagingManager.UnregisterNamedMessageHandler("com.wormtown.terrainsettings.request.v6"); network_manager.CustomMessagingManager.UnregisterNamedMessageHandler("com.wormtown.terrainsettings.snapshot.v6"); network_manager.CustomMessagingManager.UnregisterNamedMessageHandler("com.wormtown.terrainsettings.ack.v6"); network_manager.OnClientConnectedCallback -= OnClientConnected; network_manager.OnClientDisconnectCallback -= OnClientDisconnected; } catch { } network_manager = null; registered_as_host = false; has_host_snapshot = false; terrain_application_failed = false; active_revision = 0; modded_clients.Clear(); acknowledged_revisions.Clear(); compatibility_deadlines.Clear(); TerrainPatches.ResetSessionState(); Plugin.RestoreHostPreferences(); TouchUi(); } } private void OnClientConnected(ulong client_id) { if (registered_as_host && terrain_application_failed && (Object)(object)network_manager != (Object)null && client_id != network_manager.LocalClientId) { network_manager.DisconnectClient(client_id); return; } if (!registered_as_host && (Object)(object)network_manager != (Object)null && client_id == network_manager.LocalClientId) { ResetSnapshotRequests(); allow_vanilla_late_join_time = Time.unscaledTime + 5f; TryRequestSnapshot(); } TouchUi(); } private void OnClientDisconnected(ulong client_id) { modded_clients.Remove(client_id); acknowledged_revisions.Remove(client_id); compatibility_deadlines.Remove(client_id); TouchUi(); } private void ResetSnapshotRequests() { has_host_snapshot = false; next_request_time = Time.unscaledTime; request_retry_seconds = 0.5f; } private static bool ReadCompatibilityHeader(ref FastBufferReader reader) { byte b = default(byte); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b); byte b2 = default(byte); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b2); byte b3 = default(byte); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b3); byte b4 = default(byte); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b4); byte b5 = default(byte); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b5); if (b == 6 && b2 == 0 && b3 == 5 && b4 == 0) { return b5 == 10; } return false; } private unsafe void TryRequestSnapshot() { //IL_007e: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.CriticalPatchesReady || has_host_snapshot || (Object)(object)network_manager == (Object)null || !network_manager.IsConnectedClient || Time.unscaledTime < next_request_time) { return; } try { FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(5, (Allocator)2, 5); try { ((FastBufferWriter)(ref val)).WriteByteSafe((byte)6); ((FastBufferWriter)(ref val)).WriteByteSafe((byte)0); ((FastBufferWriter)(ref val)).WriteByteSafe((byte)5); ((FastBufferWriter)(ref val)).WriteByteSafe((byte)0); ((FastBufferWriter)(ref val)).WriteByteSafe((byte)10); network_manager.CustomMessagingManager.SendNamedMessage("com.wormtown.terrainsettings.request.v6", 0uL, val, (NetworkDelivery)2); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } catch { } next_request_time = Time.unscaledTime + request_retry_seconds; request_retry_seconds = Mathf.Min(5f, request_retry_seconds * 2f); } private void ReceiveSnapshotRequest(ulong sender_client_id, FastBufferReader reader) { if (!Plugin.CriticalPatchesReady || !registered_as_host || terrain_application_failed || (Object)(object)network_manager == (Object)null || !network_manager.IsHost || !network_manager.ConnectedClients.ContainsKey(sender_client_id) || ((FastBufferReader)(ref reader)).Length < 5) { return; } try { if (!ReadCompatibilityHeader(ref reader)) { return; } } catch { return; } modded_clients.Add(sender_client_id); SendSnapshot(sender_client_id); TouchUi(); } private void ReceiveSnapshot(ulong sender_client_id, FastBufferReader reader) { if (!Plugin.CriticalPatchesReady || registered_as_host || (Object)(object)network_manager == (Object)null || sender_client_id != 0L || ((FastBufferReader)(ref reader)).Length < 12) { return; } byte b = default(byte); byte b2 = default(byte); byte b3 = default(byte); byte b4 = default(byte); byte b5 = default(byte); byte b6 = default(byte); byte b7 = default(byte); try { if (!ReadCompatibilityHeader(ref reader)) { return; } ((FastBufferReader)(ref reader)).ReadByteSafe(ref b); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b2); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b3); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b4); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b5); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b6); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b7); } catch { return; } if (b3 > 1 || b4 > 200 || b5 > 16 || b6 > 200 || b7 > 200) { return; } ushort num = (ushort)(b | (b2 << 8)); if (has_host_snapshot && num != active_revision && !IsNewerRevision(num, active_revision)) { SendAck(active_revision); return; } active_revision = num; TerrainSettings.Apply(b3 != 0, b4, b5, b6, b7); if (!GroundClutterPatches.ValidateSynchronizedSnapshot()) { ReportTerrainApplicationFailure("ground clutter loaded before the synchronized host snapshot"); } else if (!TerrainPatches.ApplySynchronizedSnapshot(active_revision)) { ResetSnapshotRequests(); TouchUi(); } else { has_host_snapshot = true; SendAck(active_revision); TouchUi(); } } private void ReceiveSnapshotAck(ulong sender_client_id, FastBufferReader reader) { if (!registered_as_host || (Object)(object)network_manager == (Object)null || !modded_clients.Contains(sender_client_id) || ((FastBufferReader)(ref reader)).Length < 7) { return; } byte b = default(byte); byte b2 = default(byte); try { if (!ReadCompatibilityHeader(ref reader)) { return; } ((FastBufferReader)(ref reader)).ReadByteSafe(ref b); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b2); } catch { return; } ushort num = (ushort)(b | (b2 << 8)); if (num == active_revision) { acknowledged_revisions[sender_client_id] = num; compatibility_deadlines.Remove(sender_client_id); TouchUi(); } } private unsafe void SendSnapshot(ulong client_id) { //IL_00ba: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)network_manager == (Object)null) { return; } try { FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(12, (Allocator)2, 12); try { ((FastBufferWriter)(ref val)).WriteByteSafe((byte)6); ((FastBufferWriter)(ref val)).WriteByteSafe((byte)0); ((FastBufferWriter)(ref val)).WriteByteSafe((byte)5); ((FastBufferWriter)(ref val)).WriteByteSafe((byte)0); ((FastBufferWriter)(ref val)).WriteByteSafe((byte)10); ((FastBufferWriter)(ref val)).WriteByteSafe((byte)(active_revision & 0xFF)); ((FastBufferWriter)(ref val)).WriteByteSafe((byte)(active_revision >> 8)); ((FastBufferWriter)(ref val)).WriteByteSafe(TerrainSettings.enabled ? ((byte)1) : ((byte)0)); ((FastBufferWriter)(ref val)).WriteByteSafe(TerrainSettings.hilliness); ((FastBufferWriter)(ref val)).WriteByteSafe(TerrainSettings.smoothness); ((FastBufferWriter)(ref val)).WriteByteSafe(TerrainSettings.elevation); ((FastBufferWriter)(ref val)).WriteByteSafe(TerrainSettings.ground_clutter); network_manager.CustomMessagingManager.SendNamedMessage("com.wormtown.terrainsettings.snapshot.v6", client_id, val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } catch { } } private unsafe void SendAck(ushort revision) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) try { FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(7, (Allocator)2, 7); try { ((FastBufferWriter)(ref val)).WriteByteSafe((byte)6); ((FastBufferWriter)(ref val)).WriteByteSafe((byte)0); ((FastBufferWriter)(ref val)).WriteByteSafe((byte)5); ((FastBufferWriter)(ref val)).WriteByteSafe((byte)0); ((FastBufferWriter)(ref val)).WriteByteSafe((byte)10); ((FastBufferWriter)(ref val)).WriteByteSafe((byte)(revision & 0xFF)); ((FastBufferWriter)(ref val)).WriteByteSafe((byte)(revision >> 8)); network_manager.CustomMessagingManager.SendNamedMessage("com.wormtown.terrainsettings.ack.v6", 0uL, val, (NetworkDelivery)2); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } catch { } } private void SendSnapshotToModdedClients() { if ((Object)(object)network_manager == (Object)null || !registered_as_host) { return; } foreach (ulong key in network_manager.ConnectedClients.Keys) { if (key != network_manager.LocalClientId && modded_clients.Contains(key)) { SendSnapshot(key); } } } private void SendSnapshotToUnacknowledgedClients() { if ((Object)(object)network_manager == (Object)null || !registered_as_host) { return; } foreach (ulong key in network_manager.ConnectedClients.Keys) { if (key != network_manager.LocalClientId && modded_clients.Contains(key) && (!acknowledged_revisions.TryGetValue(key, out var value) || value != active_revision)) { SendSnapshot(key); } } } private int CountMissingClients() { if ((Object)(object)network_manager == (Object)null || !registered_as_host) { return 0; } int num = 0; foreach (ulong key in network_manager.ConnectedClients.Keys) { if (key != network_manager.LocalClientId && (!modded_clients.Contains(key) || !acknowledged_revisions.TryGetValue(key, out var value) || value != active_revision)) { num++; } } return num; } private void EnforceLateJoinCompatibility() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) GameManager singleton = GameManager.Singleton; if ((Object)(object)network_manager == (Object)null || !registered_as_host || (Object)(object)singleton == (Object)null || (int)singleton.gameState == 0) { return; } List list = new List(); foreach (ulong key in network_manager.ConnectedClients.Keys) { if (key == network_manager.LocalClientId) { continue; } if (modded_clients.Contains(key) && acknowledged_revisions.TryGetValue(key, out var value) && value == active_revision) { compatibility_deadlines.Remove(key); continue; } if (!compatibility_deadlines.TryGetValue(key, out var value2)) { value2 = Time.unscaledTime + 3f; compatibility_deadlines[key] = value2; } if (Time.unscaledTime >= value2) { list.Add(key); } } foreach (ulong item in list) { compatibility_deadlines.Remove(item); Plugin.log.LogWarning((object)$"disconnecting incompatible late joiner {item} from modded match"); network_manager.DisconnectClient(item); } } private void AdvanceRevisionAndBroadcast() { active_revision = NextRevision(active_revision); if ((Object)(object)network_manager != (Object)null) { acknowledged_revisions[network_manager.LocalClientId] = active_revision; } SendSnapshotToModdedClients(); next_snapshot_retry_time = Time.unscaledTime + 1f; } private static ushort NextRevision(ushort revision) { revision++; if (revision != 0) { return revision; } return 1; } private static bool IsNewerRevision(ushort candidate, ushort current) { return (short)(candidate - current) > 0; } private static void CommitHostChange() { Plugin.SaveHostPreferences(); if ((Object)(object)instance != (Object)null && instance.registered_as_host) { instance.AdvanceRevisionAndBroadcast(); } MatchSettingsManager singleton = MatchSettingsManager.Singleton; if ((Object)(object)singleton != (Object)null) { singleton.settingsChanged_UnreadyAllPlayersInNextUpdate = true; } TouchUi(); Plugin.log.LogInfo((object)($"terrain settings: enabled={TerrainSettings.enabled}, " + "hilliness=" + TerrainSettingsRules.HillinessName(TerrainSettings.hilliness) + ", smoothness=" + TerrainSettingsRules.SmoothnessName(TerrainSettings.smoothness) + ", elevation=" + TerrainSettingsRules.ElevationName(TerrainSettings.elevation) + ", ground_clutter=" + TerrainSettingsRules.GroundClutterName(TerrainSettings.ground_clutter))); } private static void TouchUi() { ui_revision++; } } [HarmonyPatch] public static class TerrainSettingsSyncPatches { [HarmonyPatch(typeof(LobbyManager), "OnNetworkSpawn", new Type[] { })] [HarmonyPostfix] public static void LobbyManager_OnNetworkSpawn_Postfix() { TerrainSettingsSync.EnsureAvailable(); } [HarmonyPatch(typeof(LobbyManager), "AttemptToStartGame")] [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyBefore(new string[] { "com.wormtown.ai" })] public static void AttemptToStartGame_NormalizeSoloForce_Prefix(LobbyManager __instance, ref bool force) { if (TerrainSettingsSync.IsSoloTestLobby(__instance)) { force = false; } } [HarmonyPatch(typeof(LobbyManager), "AttemptToStartGame")] [HarmonyPrefix] [HarmonyPriority(0)] [HarmonyAfter(new string[] { "com.wormtown.ai" })] public static bool AttemptToStartGame_Prefix(LobbyManager __instance, ref bool force) { if (!TerrainSettingsSync.IsLocalHost) { return true; } if (!Plugin.CriticalPatchesReady) { Plugin.log.LogWarning((object)"match start blocked: critical terrain patches are unavailable"); return false; } if (!force && TerrainSettingsSync.IsSoloTestLobby(__instance)) { force = true; Plugin.log.LogInfo((object)"solo test lobby: forcing match start"); } TerrainSettingsSync.ResendCurrentSnapshot(); if (TerrainSettingsSync.AreAllConnectedClientsReady) { return true; } Plugin.log.LogWarning((object)("match start blocked: every connected player must install and synchronize the mod " + $"({TerrainSettingsSync.MissingClientCount} pending)")); return false; } [HarmonyPatch(typeof(MapLayoutPrefabLoader), "LoadMapLayout")] [HarmonyPrefix] public static bool MapLayoutPrefabLoader_LoadMapLayout_Prefix() { return TerrainSettingsSync.CanLoadLateJoinMap; } } public enum TerrainSettingKind { Hilliness, Smoothness, Elevation, GroundClutter } [HarmonyPatch] public static class TerrainSettingsUI { private const string PANEL_NAME = "Terrain Settings Panel"; private const string TOGGLE_BUTTON_NAME = "Toggle Button (ITS A BUTTON, Toggles are dumb)"; private const float PANEL_HEIGHT = 255f; private const float PANEL_GAP = 8f; private const float TITLE_Y = 110f; private const float TOGGLE_Y = 65f; private const float HILLINESS_Y = 23f; private const float SMOOTHNESS_Y = -19f; private const float ELEVATION_Y = -61f; private const float GROUND_CLUTTER_Y = -103f; private const float HEADER_SCALE = 1f; private const float ROW_SCALE = 1f; private const float ROW_LABEL_X = -160f; private const float SLIDER_X = 20f; private const float VALUE_LABEL_X = 170f; [HarmonyPatch(typeof(ConnectedPlayerLobbyPanel), "SetupPanel")] [HarmonyPostfix] public static void ConnectedPlayerLobbyPanel_SetupPanel_Postfix() { EnsurePanel(); } [HarmonyPatch(typeof(MatchSettingsManager), "OnNetworkSpawn")] [HarmonyPostfix] public static void MatchSettingsManager_OnNetworkSpawn_Postfix() { EnsurePanel(); } private static void EnsurePanel() { try { TerrainSettingsSync.EnsureAvailable(); TryAddPanel(); } catch (Exception ex) { Plugin.log.LogWarning((object)("terrain settings ui failed: " + ex.Message)); } } private static void TryAddPanel() { //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Expected O, but got Unknown //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_0279: 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_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: 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_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_0322: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_0367: Unknown result type (might be due to invalid IL or missing references) //IL_03c0: Unknown result type (might be due to invalid IL or missing references) //IL_03da: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: Unknown result type (might be due to invalid IL or missing references) //IL_044f: Unknown result type (might be due to invalid IL or missing references) //IL_0469: Unknown result type (might be due to invalid IL or missing references) //IL_0473: Unknown result type (might be due to invalid IL or missing references) //IL_04f8: Unknown result type (might be due to invalid IL or missing references) //IL_0502: Expected O, but got Unknown //IL_05dc: Unknown result type (might be due to invalid IL or missing references) MatchSettingsManager val = Object.FindObjectOfType(); if ((Object)(object)val == (Object)null) { return; } Transform val2 = FindObjectivesGroup(); Transform val3 = FindMapGroup(val); Transform val4 = (((Object)(object)val2 != (Object)null) ? val2.parent : null); if ((Object)(object)val2 == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)val4.Find("Terrain Settings Panel") != (Object)null) { return; } Transform val5 = val3.Find("Backer"); Transform val6 = val2.Find("Objectives Header") ?? FindHeader(val2); GameObject val7 = RefGameObject(val, "BalloonEnabled_CheckBox_CheckMarkImage"); if ((Object)(object)val6 == (Object)null || (Object)(object)val7 == (Object)null) { GameObject val8 = RefGameObject(val, "WormAbilityScream_CheckBox_CheckMarkImage"); Transform val9 = (((Object)(object)val8 != (Object)null) ? val8.transform.parent : null); Transform val10 = (((Object)(object)val9 != (Object)null) ? val9.parent : null); Transform val11 = (((Object)(object)val10 != (Object)null) ? val10.parent : null); if ((Object)(object)val6 == (Object)null && (Object)(object)val11 != (Object)null) { val6 = FindHeader(val11); } if ((Object)(object)val7 == (Object)null) { val7 = val8; } } Transform val12 = (((Object)(object)val7 != (Object)null) ? val7.transform.parent : null); Transform val13 = (((Object)(object)val12 != (Object)null) ? val12.parent : null); Component val14 = RefComponent(HudManager.Singleton, "matchSettings_Objectives_DifficultyText"); Transform val15 = (((Object)(object)val14 != (Object)null) ? FindDirectChildAncestor(val14.transform, val2) : null); Component val16 = (((Object)(object)val15 != (Object)null) ? FindFirstLabelExcept(((Component)val15).gameObject, val14) : null); Component obj = RefComponent(val, "cactusFruits_Custom_Slider"); Slider val17 = (Slider)(object)((obj is Slider) ? obj : null); Component val18 = RefComponent(val, "cactusFruits_Custom_ValueDisplay"); if ((Object)(object)val5 == (Object)null || (Object)(object)val6 == (Object)null || (Object)(object)val13 == (Object)null || (Object)(object)val16 == (Object)null || (Object)(object)val17 == (Object)null || (Object)(object)val18 == (Object)null) { Plugin.log.LogWarning((object)"terrain settings ui source objects not found"); return; } GameObject val19 = null; try { val19 = new GameObject("Terrain Settings Panel", new Type[1] { typeof(RectTransform) }); val19.transform.SetParent(val4, false); RectTransform component = val19.GetComponent(); RectTransform component2 = ((Component)val2).GetComponent(); RectTransform component3 = ((Component)val5).GetComponent(); if ((Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null) { throw new InvalidOperationException("objectives layout rects not found"); } Bounds val20 = RectTransformUtility.CalculateRelativeRectTransformBounds(val4, val2); float num = ((Bounds)(ref val20)).size.x; if (num < 1f) { num = RectWidth(component3); } component.anchorMin = new Vector2(0.5f, 0.5f); component.anchorMax = new Vector2(0.5f, 0.5f); component.pivot = new Vector2(0.5f, 0.5f); component.sizeDelta = new Vector2(num, 255f); ((Transform)component).localPosition = new Vector3(((Bounds)(ref val20)).center.x, ((Bounds)(ref val20)).min.y - 8f - 127.5f, ((Transform)component2).localPosition.z); ((Transform)component).localScale = Vector3.one; GameObject val21 = Object.Instantiate(((Component)val5).gameObject, val19.transform); ((Object)val21).name = "Backer"; PlaceChild(val21, Vector2.zero, (Vector2?)new Vector2(num, 255f)); Image component4 = val21.GetComponent(); if ((Object)(object)component4 != (Object)null) { ((Graphic)component4).raycastTarget = false; } GameObject obj2 = Object.Instantiate(((Component)val6).gameObject, val19.transform); ((Object)obj2).name = "Terrain Settings Header"; StripLocalizers(obj2); PlaceChild(obj2, new Vector2(0f, 110f), null); obj2.transform.localScale = Vector3.one * 1f; Component label = FindFirstLabel(obj2); SetText(label, TerrainSettingsSync.PanelTitle); val19.AddComponent().Initialize(label); GameObject obj3 = Object.Instantiate(((Component)val13).gameObject, val19.transform); ((Object)obj3).name = "Custom Terrain Toggle Group"; StripLocalizers(obj3); RemoveChild(obj3.transform, "Sub Label"); PlaceChild(obj3, new Vector2(0f, 65f), null); obj3.transform.localScale = Vector3.one * 1f; SetFirstLabel(obj3, "Custom Terrain"); Transform val22 = obj3.transform.Find("Toggle Button (ITS A BUTTON, Toggles are dumb)"); Button val23 = (((Object)(object)val22 != (Object)null) ? ((Component)val22).GetComponent