Decompiled source of LethalContentFilter v1.0.0

LethalContentFilter.dll

Decompiled 19 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("LethalContentFilter")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("LethalContentFilter")]
[assembly: AssemblyTitle("LethalContentFilter")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LethalContentFilter
{
	[HarmonyPatch(typeof(RoundManager))]
	internal class RoundManagerPatches
	{
		private static IntWithRarity[] _originalDungeonFlows;

		[HarmonyPatch("GenerateNewFloor")]
		[HarmonyPrefix]
		[HarmonyPriority(600)]
		private static void FilterInteriors_Prefix(RoundManager __instance)
		{
			HashSet<string> excludedSet = Plugin.GetExcludedSet(Plugin.ExcludedInteriors);
			if (excludedSet.Count == 0)
			{
				return;
			}
			excludedSet = Plugin.GetNormalizedInteriorNames(excludedSet);
			SelectableLevel currentLevel = __instance.currentLevel;
			if (currentLevel?.dungeonFlowTypes == null || currentLevel.dungeonFlowTypes.Length == 0)
			{
				Plugin.Log.LogDebug((object)"No dungeon flow types found for current level.");
				return;
			}
			_originalDungeonFlows = currentLevel.dungeonFlowTypes.ToArray();
			List<IntWithRarity> list = new List<IntWithRarity>();
			for (int i = 0; i < currentLevel.dungeonFlowTypes.Length; i++)
			{
				IntWithRarity val = currentLevel.dungeonFlowTypes[i];
				string dungeonFlowName = GetDungeonFlowName(val.id);
				if (string.IsNullOrEmpty(dungeonFlowName))
				{
					list.Add(val);
					Plugin.Log.LogDebug((object)$"Could not determine name for dungeon flow id {val.id}, keeping it.");
				}
				else if (excludedSet.Contains(dungeonFlowName.ToLowerInvariant()))
				{
					Plugin.Log.LogInfo((object)$"Filtering out interior: {dungeonFlowName} (id: {val.id})");
				}
				else
				{
					list.Add(val);
				}
			}
			if (list.Count > 0)
			{
				currentLevel.dungeonFlowTypes = list.ToArray();
				Plugin.Log.LogDebug((object)$"Interior pool: {list.Count}/{_originalDungeonFlows.Length} options remaining.");
			}
			else
			{
				Plugin.Log.LogWarning((object)"All interiors were filtered! Keeping original list to prevent crash.");
			}
		}

		[HarmonyPatch("GenerateNewFloor")]
		[HarmonyPostfix]
		private static void FilterInteriors_Postfix(RoundManager __instance)
		{
			if (_originalDungeonFlows != null && (Object)(object)__instance.currentLevel != (Object)null)
			{
				__instance.currentLevel.dungeonFlowTypes = _originalDungeonFlows;
				_originalDungeonFlows = null;
			}
		}

		private static string GetDungeonFlowName(int flowId)
		{
			return flowId switch
			{
				0 => "Level1Flow", 
				1 => "HauntedMansionFlow", 
				2 => "Level3Flow", 
				_ => $"UnknownFlow_{flowId}", 
			};
		}
	}
	[HarmonyPatch(typeof(StartOfRound))]
	internal class StartOfRoundPatches
	{
		[HarmonyPatch("SetPlanetsWeather")]
		[HarmonyPostfix]
		private static void FilterWeather_Postfix(StartOfRound __instance)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			HashSet<string> excludedSet = Plugin.GetExcludedSet(Plugin.ExcludedWeather);
			if (excludedSet.Count == 0)
			{
				return;
			}
			SelectableLevel[] levels = __instance.levels;
			foreach (SelectableLevel val in levels)
			{
				if (!((Object)(object)val == (Object)null))
				{
					string item = ((object)(LevelWeatherType)(ref val.currentWeather)).ToString().ToLowerInvariant();
					if (excludedSet.Contains(item))
					{
						Plugin.Log.LogInfo((object)$"Changing weather on {val.PlanetName} from {val.currentWeather} to None");
						val.currentWeather = (LevelWeatherType)(-1);
					}
				}
			}
		}

		[HarmonyPatch("ChangeLevelServerRpc")]
		[HarmonyPrefix]
		private static bool PreventExcludedMoonTravel_Prefix(int levelID, StartOfRound __instance)
		{
			HashSet<string> excludedSet = Plugin.GetExcludedSet(Plugin.ExcludedMoons);
			if (excludedSet.Count == 0)
			{
				return true;
			}
			if (levelID < 0 || levelID >= __instance.levels.Length)
			{
				return true;
			}
			SelectableLevel val = __instance.levels[levelID];
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			string item = NormalizeMoonName(val.PlanetName);
			if (excludedSet.Contains(item))
			{
				Plugin.Log.LogInfo((object)("Blocked travel to excluded moon: " + val.PlanetName));
				if ((Object)(object)HUDManager.Instance != (Object)null)
				{
					HUDManager.Instance.DisplayTip("Moon Restricted", val.PlanetName + " has been disabled by Lethal Content Filter.", true, false, "LC_Tip1");
				}
				return false;
			}
			return true;
		}

		private static string NormalizeMoonName(string planetName)
		{
			if (string.IsNullOrEmpty(planetName))
			{
				return "";
			}
			return Regex.Replace(planetName, "^\\d+\\s*", "").Trim().ToLowerInvariant();
		}
	}
	[BepInPlugin("com.yourname.lethalcontentfilter", "Lethal Content Filter", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string ModGUID = "com.yourname.lethalcontentfilter";

		public const string ModName = "Lethal Content Filter";

		public const string ModVersion = "1.0.0";

		internal static ManualLogSource Log;

		private readonly Harmony _harmony = new Harmony("com.yourname.lethalcontentfilter");

		public static ConfigEntry<string> ExcludedInteriors;

		public static ConfigEntry<string> ExcludedMoons;

		public static ConfigEntry<string> ExcludedWeather;

		public static Plugin Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			InitConfig();
			_harmony.PatchAll(typeof(RoundManagerPatches));
			_harmony.PatchAll(typeof(StartOfRoundPatches));
			Log.LogInfo((object)"Lethal Content Filter v1.0.0 loaded!");
			LogCurrentConfig();
		}

		private void InitConfig()
		{
			ExcludedInteriors = ((BaseUnityPlugin)this).Config.Bind<string>("Filtering", "ExcludedInteriors", "Mineshaft", "Comma-separated list of interior names to exclude.\nValid vanilla names: Mineshaft, Level3Flow, Manor, HauntedMansionFlow, Factory, Level1Flow\nFor modded interiors, use their DungeonFlow name.");
			ExcludedMoons = ((BaseUnityPlugin)this).Config.Bind<string>("Filtering", "ExcludedMoons", "", "Comma-separated list of moon names to exclude (e.g., 'Dine,Rend,Titan').\nUse the moon name without the number prefix.");
			ExcludedWeather = ((BaseUnityPlugin)this).Config.Bind<string>("Filtering", "ExcludedWeather", "", "Comma-separated list of weather types to exclude.\nValid types: None, Rainy, Stormy, Foggy, Flooded, Eclipsed, DustClouds");
		}

		private void LogCurrentConfig()
		{
			HashSet<string> excludedSet = GetExcludedSet(ExcludedInteriors);
			HashSet<string> excludedSet2 = GetExcludedSet(ExcludedMoons);
			HashSet<string> excludedSet3 = GetExcludedSet(ExcludedWeather);
			if (excludedSet.Count > 0)
			{
				Log.LogInfo((object)("Excluded interiors: " + string.Join(", ", excludedSet)));
			}
			if (excludedSet2.Count > 0)
			{
				Log.LogInfo((object)("Excluded moons: " + string.Join(", ", excludedSet2)));
			}
			if (excludedSet3.Count > 0)
			{
				Log.LogInfo((object)("Excluded weather: " + string.Join(", ", excludedSet3)));
			}
		}

		public static HashSet<string> GetExcludedSet(ConfigEntry<string> config)
		{
			if (string.IsNullOrWhiteSpace(config.Value))
			{
				return new HashSet<string>();
			}
			return (from s in config.Value.Split(',')
				select s.Trim().ToLowerInvariant() into s
				where !string.IsNullOrEmpty(s)
				select s).ToHashSet();
		}

		public static HashSet<string> GetNormalizedInteriorNames(HashSet<string> userInput)
		{
			HashSet<string> hashSet = new HashSet<string>();
			foreach (string item in userInput)
			{
				hashSet.Add(item);
				switch (item)
				{
				case "cave":
				case "mine":
				case "mineshaft":
					hashSet.Add("level3flow");
					hashSet.Add("mineshaft");
					break;
				case "mansion":
				case "manor":
					hashSet.Add("hauntedmansionflow");
					hashSet.Add("manor");
					break;
				case "factory":
				case "facility":
					hashSet.Add("level1flow");
					hashSet.Add("factory");
					break;
				}
			}
			return hashSet;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "LethalContentFilter";

		public const string PLUGIN_NAME = "LethalContentFilter";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}