Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of CustomInteriorRate v1.0.1
plugins/com.eigeen.lethal.CustomInteriorRate.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Plugin.Configuration; using Plugin.Interior; using Plugin.Utils; 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("com.eigeen.lethal.CustomInteriorRate")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1+da77b38156859ca52c67d6c95f22c71518454287")] [assembly: AssemblyProduct("CustomInteriorRate")] [assembly: AssemblyTitle("com.eigeen.lethal.CustomInteriorRate")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.1.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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 Plugin { public class CombinedMap { private static Dictionary<string, List<InteriorConfig>> combinedConfigs = new Dictionary<string, List<InteriorConfig>>(); public string MapName { get; set; } public List<InteriorConfig>? InteriorConfigs { get; set; } public List<InteriorWeightData>? InteriorWeightDatas { get; set; } public CombinedMap(string name) { MapName = name; } public List<InteriorConfig>? GetCached() { if (combinedConfigs.TryGetValue(MapName, out List<InteriorConfig> value)) { return value; } return null; } public List<InteriorConfig>? GetConfigs() { List<InteriorConfig> cached = GetCached(); if (cached != null) { return cached; } return Merge(); } public int? SampleOneInteriorId(Random? random = null) { List<InteriorConfig> configs = GetConfigs(); if (configs == null) { return null; } if (random == null) { random = new Random(); } double num = random.NextDouble(); double num2 = 0.0; foreach (InteriorConfig item in configs) { num2 += item.Rate; if (num2 >= num) { return item.Id; } } return null; } private List<InteriorConfig>? Merge() { if (InteriorConfigs == null || InteriorWeightDatas == null || InteriorConfigs.Count == 0 || InteriorWeightDatas.Count == 0) { return null; } List<InteriorConfig> combined = new List<InteriorConfig>(); HashSet<int> originalMapIds = new HashSet<int>(InteriorWeightDatas.Select((InteriorWeightData it) => it.Id)); List<InteriorConfig> list = InteriorConfigs.Where((InteriorConfig it) => originalMapIds.Contains(it.Id)).ToList(); double num = list.Sum((InteriorConfig it) => it.Rate); HashSet<int> other = new HashSet<int>(list.Select((InteriorConfig it) => it.Id)); HashSet<int> diff = new HashSet<int>(originalMapIds); diff.ExceptWith(other); List<InteriorWeightData> list2 = InteriorWeightDatas.Where((InteriorWeightData it) => diff.Contains(it.Id)).ToList(); if (list2.Count == 0 && list.Count > 0) { if (list.Sum((InteriorConfig it) => it.Rate) != 1.0) { Plugin.Logger.LogWarning((object)"Sum of configured interior rates not equal to 1.0, rebalancing..."); } double[] array = ZoomRatesInto(list.Select((InteriorConfig it) => it.Rate).ToArray(), 1.0); for (int i = 0; i < array.Length; i++) { combined.Add(new InteriorConfig { Id = list[i].Id, Rate = array[i] }); } Plugin.Logger.LogInfo((object)("Proxied interior rates: [" + string.Join(", ", combined) + "]")); combinedConfigs[MapName] = combined; return combined; } list.ForEach(delegate(InteriorConfig it) { combined.Add(it); }); if (list2.Count > 0) { double[] array2 = ZoomRatesInto(((IEnumerable<InteriorWeightData>)list2).Select((Func<InteriorWeightData, double>)((InteriorWeightData it) => it.Weight)).ToArray(), 1.0 - num); for (int j = 0; j < array2.Length; j++) { combined.Add(new InteriorConfig { Id = list2[j].Id, Rate = array2[j] }); } } Plugin.Logger.LogInfo((object)("Proxied interior rates: [" + string.Join(", ", combined) + "]")); combinedConfigs[MapName] = combined; return combined; } private static double[] ZoomRatesInto(double[] rates, double target) { if (rates == null || rates.Length == 0) { throw new ArgumentException("Rates cannot be null or empty."); } double num = rates.Sum(); double[] array = new double[rates.Length]; if (num == 0.0) { if (target != 0.0) { throw new InvalidOperationException("Cannot normalize when the sum of rates is zero and target is non-zero."); } Array.Fill(array, 0.0); } else { for (int i = 0; i < rates.Length; i++) { array[i] = rates[i] * (target / num); } } return array; } public override string ToString() { List<InteriorConfig> cached = GetCached(); string text = "null"; if (cached != null) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("["); List<string> list = new List<string>(); foreach (InteriorConfig item in cached) { list.Add($"InteriorConfig {{ Id={item.Id}, Rate={item.Rate} }}"); } stringBuilder.Append(string.Join(", ", list)); stringBuilder.Append("]"); text = stringBuilder.ToString(); } return "MapName=" + MapName + ", CachedData=" + text; } } [BepInPlugin("com.eigeen.lethal.CustomInteriorRate", "CustomInteriorRate", "1.0.1")] public class Plugin : BaseUnityPlugin { public static Plugin Instance { get; private set; } public static ManualLogSource Logger { get; private set; } internal static Harmony? Harmony { get; set; } public static PluginConfig Config { get; private set; } public HashSet<string> MapWhitelist { get; private set; } private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; Instance = this; Config = new PluginConfig(); Logger.LogInfo((object)"com.eigeen.lethal.CustomInteriorRate v1.0.1 has loaded!"); if (Config.GeneralEnable.Value) { Patch(); } } internal static void Patch() { //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) //IL_0017: Expected O, but got Unknown if (Harmony == null) { Harmony = new Harmony("com.eigeen.lethal.CustomInteriorRate"); } Logger.LogDebug((object)"Patching..."); Harmony.PatchAll(); } internal static void Unpatch() { Logger.LogDebug((object)"Unpatching..."); Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "com.eigeen.lethal.CustomInteriorRate"; public const string PLUGIN_NAME = "CustomInteriorRate"; public const string PLUGIN_VERSION = "1.0.1"; } } namespace Plugin.Utils { public class StringUtils { public static string TrimStart(string source, string toTrim) { if (source.StartsWith(toTrim)) { int length = toTrim.Length; return source.Substring(length, source.Length - length); } return source; } public static string TrimEnd(string source, string toTrim) { if (source.EndsWith(toTrim)) { int length = toTrim.Length; return source.Substring(0, source.Length - length); } return source; } } } namespace Plugin.Patches { [HarmonyPatch(typeof(StartOfRound), "ChooseNewRandomMapSeed")] public class ChooseNewRandomMapSeedPatch { private static void Postfix(StartOfRound __instance) { PluginConfig config = Plugin.Config; string name = ((Object)__instance.currentLevel).name; MapConfig mapConfigByLevelName = config.GetMapConfigByLevelName(name); if (mapConfigByLevelName == null || !mapConfigByLevelName.Enable) { Plugin.Logger.LogInfo((object)("Level " + name + " config set to disable. Ignore.")); return; } int randomMapSeed = __instance.randomMapSeed; RoundManager instance = RoundManager.Instance; CombinedMap combinedMap = new CombinedMap(mapConfigByLevelName.MapName) { InteriorConfigs = mapConfigByLevelName.InteriorConfigs, InteriorWeightDatas = TransWeightData(__instance.currentLevel) }; int? num; try { num = combinedMap.SampleOneInteriorId(); } catch (Exception arg) { Plugin.Logger.LogError((object)$"Accidental error: Failed to get target interior id: {arg}"); return; } if (!num.HasValue) { Plugin.Logger.LogWarning((object)"Got null target interior id, ignored. Maybe set empty configuration values?"); return; } string text = global::Plugin.Interior.Interior.ParseName(num.Value); Plugin.Logger.LogInfo((object)("Target interior: " + text)); Plugin.Logger.LogDebug((object)$"CombindMap: {combinedMap}"); int? num2 = CalcInteriorId(randomMapSeed, instance); if (!num2.HasValue) { Plugin.Logger.LogError((object)"Unexpected calc interior id: null"); return; } if (num2 == num) { Plugin.Logger.LogInfo((object)$"Detected the current map seed ({randomMapSeed}) will generate {text} interior, pass."); return; } Plugin.Logger.LogInfo((object)"Unmatching interior type. Try to regenerate."); for (int i = 0; i < 2000; i++) { randomMapSeed = NewMapSeed(); num2 = CalcInteriorId(randomMapSeed, instance); if (!num2.HasValue) { Plugin.Logger.LogWarning((object)"Detected unknown interior type. Ignore."); return; } text = global::Plugin.Interior.Interior.ParseName(num2.Value); Plugin.Logger.LogDebug((object)$"Trying No.{i + 1} (Seed {randomMapSeed}) Interior: {text}"); if (num2 == num) { __instance.randomMapSeed = randomMapSeed; Plugin.Logger.LogInfo((object)$"Generated new map seed ({randomMapSeed}) after {i + 1} retries."); return; } } Plugin.Logger.LogWarning((object)"Regenerate failed after 2000 retries."); } private static List<InteriorWeightData>? TransWeightData(SelectableLevel level) { IntWithRarity[] dungeonFlowTypes = level.dungeonFlowTypes; if (dungeonFlowTypes == null) { return null; } List<InteriorWeightData> list = new List<InteriorWeightData>(); IntWithRarity[] array = dungeonFlowTypes; foreach (IntWithRarity val in array) { if (val.rarity != 0) { list.Add(new InteriorWeightData { Id = val.id, Weight = val.rarity }); } } return list; } private static int? CalcInteriorId(int mapSeed, RoundManager roundManager) { Random random = new Random(mapSeed); if (roundManager.currentLevel.dungeonFlowTypes == null || roundManager.currentLevel.dungeonFlowTypes.Length == 0) { return null; } List<int> list = roundManager.currentLevel.dungeonFlowTypes.Select((IntWithRarity flowType) => flowType.rarity).ToList(); Plugin.Logger.LogDebug((object)("Original List: " + string.Join(", ", list))); int randomWeightedIndex = roundManager.GetRandomWeightedIndex(list.ToArray(), random); Plugin.Logger.LogDebug((object)$"randomWeightedIndex: {randomWeightedIndex}"); int id = roundManager.currentLevel.dungeonFlowTypes[randomWeightedIndex].id; Plugin.Logger.LogDebug((object)$"interiorId: {id}"); return id; } private static global::Plugin.Interior.Interior.InteriorEnum? CalcInteriorType(int mapSeed, RoundManager roundManager) { int? num = CalcInteriorId(mapSeed, roundManager); if (!num.HasValue) { return null; } return global::Plugin.Interior.Interior.ParseEnumFromId(num.Value) ?? null; } private static int NewMapSeed() { return Random.Range(1, 100000000); } } } namespace Plugin.Interior { public class Interior { public enum InteriorEnum { Factory = 0, Manor = 1, Mineshaft = 4 } public static string? ParseName(int id) { if (Enum.IsDefined(typeof(InteriorEnum), id)) { InteriorEnum interiorEnum = (InteriorEnum)id; return interiorEnum.ToString(); } return null; } public static int? ParseId(string name) { if (string.IsNullOrEmpty(name)) { return null; } if (Enum.TryParse(typeof(InteriorEnum), name, out object result)) { return (int)result; } return null; } public static InteriorEnum? ParseEnumFromId(int id) { if (Enum.IsDefined(typeof(InteriorEnum), id)) { return (InteriorEnum)id; } return null; } } public class InteriorWeightData { public int Id { get; set; } public string? Name { get { return Interior.ParseName(Id); } set { if (value != null) { int? num = Interior.ParseId(value); if (num.HasValue) { Id = num.Value; } } } } public int Weight { get; set; } } } namespace Plugin.Configuration { public class InteriorConfig { public int Id { get; set; } public string? Name { get { return global::Plugin.Interior.Interior.ParseName(Id); } set { if (value != null) { int? num = global::Plugin.Interior.Interior.ParseId(value); if (num.HasValue) { Id = num.Value; } } } } public double Rate { get; set; } public override string ToString() { return $"InteriorConfig{{ Id = {Id}, Name = {Name}, Rate = {Rate} }}"; } } public class MapConfig { public string MapName { get; private set; } public bool Enable { get; set; } public List<InteriorConfig> InteriorConfigs { get; set; } public MapConfig(string mapName, bool enable) { MapName = mapName; Enable = enable; InteriorConfigs = new List<InteriorConfig>(); } public override string ToString() { return $"MapName={MapName}, Enable={Enable}, InteriorConfigs={InteriorConfigs}"; } } public class PluginConfig { private ConfigFile _configFile; private Dictionary<string, MapConfig> _mapConfigs; public ConfigEntry<bool> GeneralEnable { get; private set; } public PluginConfig() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown _configFile = new ConfigFile(Path.Combine(Paths.ConfigPath, "com.eigeen.lethal.CustomInteriorRate.cfg"), true); BindAll(); foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in _configFile) { Plugin.Logger.LogDebug((object)$"Section={item.Key.Section}, Key={item.Key.Key}, Value={item.Value.BoxedValue}"); } _mapConfigs = new Dictionary<string, MapConfig>(); ICollection<ConfigDefinition> keys = _configFile.Keys; foreach (ConfigDefinition item2 in keys) { string[] array = item2.Section.Split('.'); if (array.Length == 2 && array[0] == "Map") { string text = array[1]; MapConfig mapConfig = (_mapConfigs.ContainsKey(text) ? _mapConfigs[text] : new MapConfig(text, enable: false)); ConfigEntryBase val = _configFile[item2]; if (item2.Key == "Enable") { mapConfig.Enable = (bool)val.BoxedValue; _mapConfigs[text] = mapConfig; } else if (item2.Key.EndsWith("Rate")) { string name = StringUtils.TrimEnd(item2.Key, "Rate"); mapConfig.InteriorConfigs.Add(new InteriorConfig { Name = name, Rate = (double)val.BoxedValue }); _mapConfigs[text] = mapConfig; } } } foreach (KeyValuePair<string, MapConfig> mapConfig2 in _mapConfigs) { string key = mapConfig2.Key; MapConfig value = mapConfig2.Value; if (value == null) { _mapConfigs.Remove(key); continue; } _mapConfigs[key].InteriorConfigs = value.InteriorConfigs.Where((InteriorConfig item) => item.Rate > 0.0).ToList(); double num = value.InteriorConfigs.Select((InteriorConfig item) => item.Rate).Sum(); if (num > 1.0 || num < 0.0) { Plugin.Logger.LogError((object)$"Total rate of map {key} is invalid: expect [0.0, 1.0], found {num}"); _mapConfigs.Remove(key); } } LogMapConfigs(_mapConfigs); } private static void LogMapConfigs(Dictionary<string, MapConfig> mapConfigs) { if (mapConfigs == null || mapConfigs.Count == 0) { Plugin.Logger.LogDebug((object)"mapConfigs is empty!"); return; } foreach (KeyValuePair<string, MapConfig> mapConfig in mapConfigs) { Plugin.Logger.LogDebug((object)("Map: " + mapConfig.Key + ", Config: " + mapConfig.Value.ToString())); } } public MapConfig? GetMapConfigByLevelName(string levelName) { if (_mapConfigs.TryGetValue(GetMapNameByLevelName(levelName), out MapConfig value)) { return value; } return null; } private static string GetMapNameByLevelName(string levelName) { return StringUtils.TrimEnd(levelName, "Level"); } private void BindAll() { GeneralEnable = _configFile.Bind<bool>("General", "Enable", true, "Enable plugin features."); _configFile.Bind<bool>("Map.Adamance", "Enable", false, "Enable the modification on map Vow."); _configFile.Bind<double>("Map.Adamance", "FactoryRate", -1.0, "Override the rate of Factory interior. If set to -1, keep the original rate."); _configFile.Bind<double>("Map.Adamance", "ManorRate", -1.0, "Override the rate of Manor interior. If set to -1, keep the original rate."); _configFile.Bind<double>("Map.Adamance", "MineshaftRate", -1.0, "Override the rate of Mineshaft interior. If set to -1, keep the original rate."); _configFile.Bind<bool>("Map.Artifice", "Enable", false, (ConfigDescription)null); _configFile.Bind<double>("Map.Artifice", "FactoryRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Artifice", "ManorRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Artifice", "MineshaftRate", -1.0, (ConfigDescription)null); _configFile.Bind<bool>("Map.Assurance", "Enable", false, (ConfigDescription)null); _configFile.Bind<double>("Map.Assurance", "FactoryRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Assurance", "ManorRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Assurance", "MineshaftRate", -1.0, (ConfigDescription)null); _configFile.Bind<bool>("Map.Dine", "Enable", false, (ConfigDescription)null); _configFile.Bind<double>("Map.Dine", "FactoryRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Dine", "ManorRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Dine", "MineshaftRate", -1.0, (ConfigDescription)null); _configFile.Bind<bool>("Map.Embrion", "Enable", false, (ConfigDescription)null); _configFile.Bind<double>("Map.Embrion", "FactoryRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Embrion", "ManorRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Embrion", "MineshaftRate", -1.0, (ConfigDescription)null); _configFile.Bind<bool>("Map.Experimentation", "Enable", false, (ConfigDescription)null); _configFile.Bind<double>("Map.Experimentation", "FactoryRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Experimentation", "ManorRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Experimentation", "MineshaftRate", -1.0, (ConfigDescription)null); _configFile.Bind<bool>("Map.Liquidation", "Enable", false, (ConfigDescription)null); _configFile.Bind<double>("Map.Liquidation", "FactoryRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Liquidation", "ManorRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Liquidation", "MineshaftRate", -1.0, (ConfigDescription)null); _configFile.Bind<bool>("Map.March", "Enable", false, (ConfigDescription)null); _configFile.Bind<double>("Map.March", "FactoryRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.March", "ManorRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.March", "MineshaftRate", -1.0, (ConfigDescription)null); _configFile.Bind<bool>("Map.Offense", "Enable", false, (ConfigDescription)null); _configFile.Bind<double>("Map.Offense", "FactoryRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Offense", "ManorRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Offense", "MineshaftRate", -1.0, (ConfigDescription)null); _configFile.Bind<bool>("Map.Rend", "Enable", false, (ConfigDescription)null); _configFile.Bind<double>("Map.Rend", "FactoryRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Rend", "ManorRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Rend", "MineshaftRate", -1.0, (ConfigDescription)null); _configFile.Bind<bool>("Map.Titan", "Enable", false, (ConfigDescription)null); _configFile.Bind<double>("Map.Titan", "FactoryRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Titan", "ManorRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Titan", "MineshaftRate", -1.0, (ConfigDescription)null); _configFile.Bind<bool>("Map.Vow", "Enable", false, (ConfigDescription)null); _configFile.Bind<double>("Map.Vow", "FactoryRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Vow", "ManorRate", -1.0, (ConfigDescription)null); _configFile.Bind<double>("Map.Vow", "MineshaftRate", -1.0, (ConfigDescription)null); } } }