Decompiled source of ForwindzCustomCornerstones v1.2.2
ForwindzCustomPerksMod.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; 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.Cryptography; using System.Security.Permissions; using System.Text; using System.Threading; using System.Threading.Tasks; using ATS_API.Biomes; using ATS_API.Effects; using ATS_API.Helpers; using ATS_API.Localization; using BepInEx; using BepInEx.Logging; using Cysharp.Threading.Tasks; using Cysharp.Threading.Tasks.CompilerServices; using Eremite; using Eremite.Buildings; using Eremite.Controller; using Eremite.Controller.Effects; using Eremite.Model; using Eremite.Model.Effects; using Eremite.Model.Effects.Hooked; using Eremite.Model.Orders; using Eremite.Model.State; using Eremite.Model.Trade; using Eremite.Model.ViewsConfigurations; using Eremite.Services; using Eremite.Services.Monitors; using Eremite.Services.Orders; using Eremite.Services.World; using Eremite.WorldMap; using Forwindz.Content; using Forwindz.Framework.Effects; using Forwindz.Framework.Hooks; using Forwindz.Framework.Services; using Forwindz.Framework.Utils; using Forwindz.Framework.Utils.Extend; using Forwindz.Scripts.Framework.Services; using Forwindz.Scripts.Framework.Utils; using ForwindzCustomPerks.Framework.Services; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Sirenix.Utilities; using UniRx; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: AssemblyCompany("ForwindzCustomPerksMod")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("My First Mod for Against The Storm - by Forwindz")] [assembly: AssemblyFileVersion("1.2.2.0")] [assembly: AssemblyInformationalVersion("1.2.2+ba5bc310e22427e3dd43a69993f0e34b14661a33")] [assembly: AssemblyProduct("ForwindzCustomPerksMod")] [assembly: AssemblyTitle("ForwindzCustomPerksMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.2.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 ForwindzCustomPerks { public static class PluginInfo { public const string PLUGIN_GUID = "ForwindzCustomPerksMod"; public const string PLUGIN_NAME = "ForwindzCustomPerksMod"; public const string PLUGIN_VERSION = "1.2.2"; } } namespace ForwindzCustomPerks.Framework.Services { public class DynamicTraderExtraState { public float chanceToFreeEffect = 0f; } public class DynamicTraderInfoData { public List<string> forceTraderNameList = new List<string>(); [JsonProperty] private Dictionary<string, DynamicTraderExtraState> traderGlobalStates = new Dictionary<string, DynamicTraderExtraState>(); public Dictionary<string, float> effectsSellValue = new Dictionary<string, float>(); public DynamicTraderExtraState GetTraderGlobalEffects(string traderName) { if (!traderGlobalStates.TryGetValue(traderName, out var value)) { FLog.Info("[" + traderName + "] does not have extra states, create it", "GetTraderGlobalEffects", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicTraderInfoService.cs", 44); value = new DynamicTraderExtraState(); traderGlobalStates[traderName] = value; } return value; } public bool GetEffectModifiedSellValue(string effectName, out float modifiedValue) { if (effectsSellValue.TryGetValue(effectName, out modifiedValue)) { return true; } modifiedValue = 0f; return false; } } public class TradeDealInfo { public TraderVisitState visit; public TradingOffer villageOffer; public TradingOffer traderOffer; } public class DynamicTraderInfoService : GameService, IDynamicTraderInfoService, IService { [ModSerializedField(SaveLoadType.Unknown, "")] internal DynamicTraderInfoData stateData = new DynamicTraderInfoData(); private IDisposable traderArriveListener = null; public Subject<TradeDealInfo> onTradeCompleteSubject = new Subject<TradeDealInfo>(); private MethodInfo methodUpdateNextVisit = null; public DynamicTraderInfoData DynamicTraderState => stateData; public IObservable<TradeDealInfo> OnTradeCompleteEvent => (IObservable<TradeDealInfo>)onTradeCompleteSubject; static DynamicTraderInfoService() { CustomServiceManager.RegGameService<DynamicTraderInfoService>(); PatchesManager.RegPatch<DynamicTraderInfoService>(); } public override IService[] GetDependencies() { return (IService[])(object)new IService[2] { (IService)Serviceable.TradeService, CustomServiceManager.GetAsIService<IExtraStateService>() }; } public void UpdateNextVisit() { if (methodUpdateNextVisit == null) { FLog.Error("Cannot invoke UpdateNextVisit()! The trader state cannot be update!", "UpdateNextVisit", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicTraderInfoService.cs", 105); } else { methodUpdateNextVisit.Invoke(Serviceable.TradeService, null); } } public override void OnDestroy() { traderArriveListener.Dispose(); ((Service)this).OnDestroy(); } public override UniTask OnLoading() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) methodUpdateNextVisit = AccessTools.Method(typeof(TradeService), "UpdateNextVisit", (Type[])null, (Type[])null); traderArriveListener = ObservableExtensions.Subscribe<TraderVisitState>(Serviceable.TradeService.OnTraderArrived, (Action<TraderVisitState>)OnTraderArrive); RestoreData(); return UniTask.CompletedTask; } private void RestoreData() { FLog.Info("Restored DynamicTraderStateInfo > ", "RestoreData", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicTraderInfoService.cs", 128); FLog.Info($"Sell Perks Count: {stateData.effectsSellValue.Count} | Force List: {stateData.forceTraderNameList.Count}", "RestoreData", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicTraderInfoService.cs", 129); } private void OnTraderArrive(TraderVisitState visitState) { FLog.Info("Trader [" + visitState.trader + "] Arrived! Process its effect price!", "OnTraderArrive", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicTraderInfoService.cs", 134); ApplyEffectsToVisitState(visitState); } private void ApplyEffectsToVisitState(TraderVisitState newVisitState) { stateData.effectsSellValue.Clear(); DynamicTraderExtraState traderGlobalEffects = stateData.GetTraderGlobalEffects(newVisitState.trader); if (!(traderGlobalEffects.chanceToFreeEffect > 0f)) { return; } FLog.Info($"{newVisitState.trader} has {traderGlobalEffects.chanceToFreeEffect} free chance.", "ApplyEffectsToVisitState", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicTraderInfoService.cs", 150); foreach (KeyValuePair<string, bool> effect in newVisitState.effects) { FLog.Info($"Check {effect}", "ApplyEffectsToVisitState", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicTraderInfoService.cs", 153); string key = effect.Key; if (!effect.Value) { FLog.Info($"{traderGlobalEffects.chanceToFreeEffect} free chance for {effect}", "ApplyEffectsToVisitState", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicTraderInfoService.cs", 158); if (StableRNG.StableRoll(traderGlobalEffects.chanceToFreeEffect)) { stateData.effectsSellValue.Add(key, 0f); FLog.Info("Set " + key + " as free", "ApplyEffectsToVisitState", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicTraderInfoService.cs", 162); } } } } public TraderModel GetForceTrader() { if (stateData.forceTraderNameList.Count == 0) { return null; } string text = stateData.forceTraderNameList.Where((string x) => !Serviceable.StateService.Trade.assaultedTraders.Contains(x)).FirstOrDefault(); if (text == null || text.Length == 0) { return null; } return Serviceable.Settings.GetTrader(text); } public void AddForceTrader(string name) { FLog.Info("Add Force Trader: " + name, "AddForceTrader", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicTraderInfoService.cs", 200); RemoveAssaultTrader(name); stateData.forceTraderNameList.Add(name); ResetNextTrader(); } public void RemoveForceTrader(string name) { if (!stateData.forceTraderNameList.Remove(name)) { FLog.Warning("Cannot remove forced trader [" + name + "]. It not exists in forced list!", "RemoveForceTrader", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicTraderInfoService.cs", 214); return; } FLog.Info("Remove Force Trader: " + name, "RemoveForceTrader", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicTraderInfoService.cs", 218); ResetNextTrader(); } public void RemoveAssaultTrader(string name) { FLog.Info("Remove Assaulted Trader Record: " + name, "RemoveAssaultTrader", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicTraderInfoService.cs", 225); Serviceable.StateService.Trade.assaultedTraders.Remove(name); } public void ResetNextTrader() { if (!Serviceable.TradeService.IsMainTraderInTheVillage()) { FLog.Info("Reset Next Trader", "ResetNextTrader", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicTraderInfoService.cs", 237); float travelStartTime = -1f; bool flag = false; if (Serviceable.StateService.Trade.visit != null) { flag = true; travelStartTime = Serviceable.StateService.Trade.visit.travelStartTime; } Serviceable.StateService.Trade.visit = null; UpdateNextVisit(); if (Serviceable.StateService.Trade.visit != null && flag) { Serviceable.StateService.Trade.visit.travelStartTime = travelStartTime; } } } public void SetEffectFreeChance(string traderName, float chance) { DynamicTraderExtraState traderGlobalEffects = stateData.GetTraderGlobalEffects(traderName); traderGlobalEffects.chanceToFreeEffect = chance; FLog.Info($"{traderName} set {chance} free effects chance.", "SetEffectFreeChance", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicTraderInfoService.cs", 261); } public void AddEffectFreeChance(string traderName, float chance) { DynamicTraderExtraState traderGlobalEffects = stateData.GetTraderGlobalEffects(traderName); traderGlobalEffects.chanceToFreeEffect += chance; FLog.Info($"{traderName} add {chance} free effects chance, now it is {traderGlobalEffects.chanceToFreeEffect}", "AddEffectFreeChance", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicTraderInfoService.cs", 268); } [HarmonyPatch(typeof(TradeService), "UpdateNextVisit")] [HarmonyPrefix] private static bool TradeService_UpdateNextVisit_PrePatch(TradeService __instance) { if (__instance.State.visit != null) { return true; } DynamicTraderInfoService service = CustomServiceManager.GetService<DynamicTraderInfoService>(); TraderModel forceTrader = service.GetForceTrader(); if ((Object)(object)forceTrader != (Object)null) { FLog.Info("Force to set trader as " + ((SO)forceTrader).Name, "TradeService_UpdateNextVisit_PrePatch", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicTraderInfoService.cs", 288); __instance.State.visit = __instance.CreateVisit(forceTrader, 0); return false; } return true; } [HarmonyPatch(typeof(TradeService), "GetValueInCurrency", new Type[] { typeof(EffectModel) })] [HarmonyPostfix] private static void TradeService_GetValueInCurrency_Effect_PostPatch(TradeService __instance, ref float __result, EffectModel effect) { DynamicTraderInfoService service = CustomServiceManager.GetService<DynamicTraderInfoService>(); if (service.stateData.GetEffectModifiedSellValue(((Object)effect).name, out var modifiedValue) && effect.tradingBuyValue != 0) { float num = __result * modifiedValue / (float)effect.tradingBuyValue; FLog.Info($"Change effect price from {__result} to {num}", "TradeService_GetValueInCurrency_Effect_PostPatch", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicTraderInfoService.cs", 311); __result = num; } } [HarmonyPatch(typeof(TradeService), "CompleteTrade", new Type[] { typeof(TraderVisitState), typeof(TradingOffer), typeof(TradingOffer) })] [HarmonyPostfix] private static void TradeService_CompleteTrade_PostPatch(TradeService __instance, TraderVisitState visit, TradingOffer villageOffer, TradingOffer traderOffer) { DynamicTraderInfoService service = CustomServiceManager.GetService<DynamicTraderInfoService>(); TradeDealInfo tradeDealInfo = new TradeDealInfo { visit = visit, villageOffer = villageOffer, traderOffer = traderOffer }; service.onTradeCompleteSubject.OnNext(tradeDealInfo); } } } namespace Forwindz { public static class PluginInfo { public const string PLUGIN_GUID = "Forwindz.CustomCornerstones"; public const string PLUGIN_NAME = "f9's cornerstones"; public const string PLUGIN_VERSION = "1.2.2"; } [BepInPlugin("Forwindz.CustomCornerstones", "f9's cornerstones", "1.2.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public static Plugin Instance; private void Awake() { Instance = this; ReflectUtils.InitializeAllStatics(typeof(Plugin).Assembly); PatchesManager.RegPatch<Plugin>(); PatchesManager.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin Forwindz.CustomCornerstones is loaded!"); } [HarmonyPatch(typeof(MainController), "InitReferences")] [HarmonyPostfix] private static void PostSetupMainController() { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)"Initializing post Init References in MainController"); LocalizationLoader.LoadLocalization("assets/lang"); CustomCornerstones.CreateNewCornerstones(); } } } namespace Forwindz.Scripts.Framework.Utils { public static class BuildingHelper { public static int CountDecorationValue(DecorationTier tier) { int num = 0; foreach (Decoration value in GameMB.BuildingsService.Decorations.Values) { if (((Building)value).IsFinished() && value.model.hasDecorationTier && (Object)(object)value.model.tier == (Object)(object)tier) { num += value.model.decorationScore; } } return num; } public static int CountProductionBuildingArea() { //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) int num = 0; foreach (ProductionBuilding productionBuilding in GameMB.BuildingsService.ProductionBuildings) { if (((Building)productionBuilding).IsFinished()) { Vector2Int size = ((Building)productionBuilding).Size; num += ((Vector2Int)(ref size)).x * ((Vector2Int)(ref size)).y; } } return num; } public static bool IsDecorationBuilding(Building building) { string name = ((Object)building.BuildingModel.category).name; return name.Equals("Decorations"); } public static bool IsRoad(Building building) { string name = ((Object)building.BuildingModel.category).name; return name.Equals("Roads"); } } public static class Debug { static Debug() { PatchesManager.RegPatch(typeof(Debug)); } } } namespace Forwindz.Scripts.Framework.Services { public class BuildingMonitorState { public int buildingsCompleted = 0; public int decorationBuildingsCompleted = 0; public int roadsCompleted = 0; public int buildingsRemoved = 0; public int decorationBuildingsRemoved = 0; public int roadsRemoved = 0; } public class BuildingMonitorService : GameService, IService { [ModSerializedField(SaveLoadType.Unknown, "")] public BuildingMonitorState state = new BuildingMonitorState(); public readonly Subject<Building> buildingConstructionFinishedSubject = new Subject<Building>(); public readonly Subject<Building> buildingRemovedSubject = new Subject<Building>(); public IObservable<Building> OnBuildingConstructionFinished => (IObservable<Building>)buildingConstructionFinishedSubject; public IObservable<Building> OnBuildingRemovedFinished => (IObservable<Building>)buildingRemovedSubject; static BuildingMonitorService() { CustomServiceManager.RegGameService<BuildingMonitorService>(); PatchesManager.RegPatch<BuildingMonitorService>(); } public override IService[] GetDependencies() { return (IService[])(object)new IService[4] { (IService)Serviceable.BuildingsService, CustomServiceManager.GetAsIService<IExtraStateService>(), CustomServiceManager.GetAsIService<IDynamicBuildingStateService>(), CustomServiceManager.GetAsIService<IDynamicHearthService>() }; } public override void OnDestroy() { ((Service)this).OnDestroy(); } public override UniTask OnLoading() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) return UniTask.CompletedTask; } protected void OnBuildingCompleted(Building building) { state.buildingsCompleted++; if (BuildingHelper.IsDecorationBuilding(building)) { state.decorationBuildingsCompleted++; } if (BuildingHelper.IsRoad(building)) { state.roadsCompleted++; } buildingConstructionFinishedSubject.OnNext(building); } protected void OnBuildingRemoved(Building building) { state.buildingsRemoved++; if (BuildingHelper.IsDecorationBuilding(building)) { state.decorationBuildingsRemoved++; } if (BuildingHelper.IsRoad(building)) { state.roadsRemoved++; } buildingRemovedSubject.OnNext(building); } [HarmonyPatch(typeof(Building), "FinishConstruction")] [HarmonyPostfix] private static void Building_FinishConstruction_Postfix(Building __instance) { FLog.Info("Building finish: " + ((Object)__instance).name + " ||\t Category: " + ((Object)__instance.BuildingModel.category).name, "Building_FinishConstruction_Postfix", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\BuildingMonitorService.cs", 105); CustomServiceManager.GetService<BuildingMonitorService>().OnBuildingCompleted(__instance); } [HarmonyPatch(typeof(Building), "MakeBuildingCompleted")] [HarmonyPostfix] private static void Building_MakeBuildingCompleted_Postfix(Building __instance) { FLog.Info("Make building complete: " + ((Object)__instance).name + " ||\t Category: " + ((Object)__instance.BuildingModel.category).name, "Building_MakeBuildingCompleted_Postfix", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\BuildingMonitorService.cs", 113); CustomServiceManager.GetService<BuildingMonitorService>().OnBuildingCompleted(__instance); } [HarmonyPatch(typeof(Building), "Remove")] [HarmonyPostfix] private static void Building_Remove_Postfix(Building __instance) { FLog.Info("Building remove: " + ((Object)__instance).name + " ||\t Category: " + ((Object)__instance.BuildingModel.category).name, "Building_Remove_Postfix", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\BuildingMonitorService.cs", 121); CustomServiceManager.GetService<BuildingMonitorService>().OnBuildingRemoved(__instance); } } } namespace Forwindz.Framework.Utils { public static class AsyncUtils { public static async Task WaitForConditionAsync(Func<bool> condition, int checkInterval = 100, CancellationToken cancellationToken = default(CancellationToken)) { while (!condition()) { if (cancellationToken.IsCancellationRequested) { throw new TaskCanceledException(); } await Task.Delay(checkInterval, cancellationToken); } } } public class CustomField<ObjectType, FieldType> where ObjectType : class where FieldType : class { private readonly ConditionalWeakTable<ObjectType, FieldType> customFields = new ConditionalWeakTable<ObjectType, FieldType>(); private readonly Func<ObjectType, FieldType> initFieldFunc = (ObjectType inst) => null; public FieldType GetField(ObjectType instance) { if (customFields.TryGetValue(instance, out var value)) { return value; } throw new Exception($"Try to get field {typeof(FieldType).FullName} from {typeof(ObjectType).FullName}, but instance {instance.GetHashCode()} haven't created field"); } public void SetField(ObjectType instance, FieldType fieldContent) { customFields.Add(instance, fieldContent); } public void CreateField(ObjectType instance) { customFields.Add(instance, initFieldFunc(instance)); } public void RemoveField(ObjectType instance) { customFields.Remove(instance); } public CustomField(Func<ObjectType, FieldType> initFieldFunc) { this.initFieldFunc = initFieldFunc; PatchUtils.InjectConstructorPostPatch<ObjectType>(CreateField); } } public struct CustomIntEnum<T> where T : Enum { public int value; public CustomIntEnum(int value) { this.value = value; } public static implicit operator T(CustomIntEnum<T> enumObj) { return (T)Enum.ToObject(typeof(T), enumObj.value); } public static implicit operator CustomIntEnum<T>(T enumObjOrg) { return new CustomIntEnum<T>((int)(object)enumObjOrg); } public static T GetMaxOriginalEnum() { return Enum.GetValues(typeof(T)).Cast<T>().Max(); } public static int GetMaxOriginalEnumValue() { return (int)(object)Enum.GetValues(typeof(T)).Cast<T>().Max(); } } [AttributeUsage(AttributeTargets.Field)] public class NewCustomEnumAttribute : Attribute { public string Name { get; } public object PredefinedValue { get; } public NewCustomEnumAttribute(string name = null, object predefinedValue = null) { Name = name; PredefinedValue = predefinedValue; } } public class CustomIntEnumManager<T> where T : Enum { private static Dictionary<string, CustomIntEnum<T>> nameEnumMapping = new Dictionary<string, CustomIntEnum<T>>(); private static int curMaxIndex = CustomIntEnum<T>.GetMaxOriginalEnumValue(); private static Dictionary<int, string> valueNameMapping = new Dictionary<int, string>(); public static int CurrentMaxIndex => curMaxIndex; public static IReadOnlyDictionary<string, CustomIntEnum<T>> NameEnumMapping => nameEnumMapping; public static IReadOnlyDictionary<int, string> ValueNameMapping => valueNameMapping; public static CustomIntEnum<T> AddEnum(string name) { do { curMaxIndex++; } while (valueNameMapping.ContainsKey(curMaxIndex)); CustomIntEnum<T> customIntEnum = new CustomIntEnum<T>(curMaxIndex); nameEnumMapping.Add(name, customIntEnum); valueNameMapping.Add(customIntEnum.value, name); FLog.Info($"Add enum {name}={customIntEnum.value} to {typeof(T).Name}", "AddEnum", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\Base\\CustomIntEnum.cs", 80); return customIntEnum; } public static CustomIntEnum<T> AddPredefinedEnum(string name, int value) { if (value < curMaxIndex) { FLog.Error($"Try to add enum {name}={value} to {typeof(T).Name}, but the predefined value is already used. This may overwrite the previous enum!", "AddPredefinedEnum", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\Base\\CustomIntEnum.cs", 88); } else if (valueNameMapping.ContainsKey(value)) { FLog.Error($"Try to add enum {name}={value} to {typeof(T).Name}, but the predefined value is already used by other predefinitions. This will overwrite the previous enum!", "AddPredefinedEnum", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\Base\\CustomIntEnum.cs", 92); } CustomIntEnum<T> customIntEnum = new CustomIntEnum<T>(value); nameEnumMapping.Add(name, customIntEnum); valueNameMapping.Add(customIntEnum.value, name); FLog.Info($"Add predefined enum {name}={customIntEnum.value} to {typeof(T).Name}", "AddPredefinedEnum", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\Base\\CustomIntEnum.cs", 97); return customIntEnum; } public static void ScanAndAssignEnumValues<C>() { Type typeFromHandle = typeof(C); FieldInfo[] fields = typeFromHandle.GetFields(); FLog.Info($"{typeof(CustomIntEnum<T>).Name}: Scan enum values for {typeof(C).Name}, static fields count {fields.Length}", "ScanAndAssignEnumValues", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\Base\\CustomIntEnum.cs", 105); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { NewCustomEnumAttribute customAttribute = fieldInfo.GetCustomAttribute<NewCustomEnumAttribute>(); if (customAttribute == null) { continue; } string name = customAttribute.Name ?? fieldInfo.Name; if (!fieldInfo.IsInitOnly) { FLog.Warning("Enum field " + typeFromHandle.Name + "." + fieldInfo.Name + " is not readonly. New enum should be inmutable.", "ScanAndAssignEnumValues", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\Base\\CustomIntEnum.cs", 116); } FLog.Info("Find enum field: " + fieldInfo.FieldType.Name + " " + fieldInfo.Name, "ScanAndAssignEnumValues", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\Base\\CustomIntEnum.cs", 118); Type fieldType = fieldInfo.FieldType; if (fieldType == typeof(CustomIntEnum<T>)) { if (customAttribute.PredefinedValue == null) { fieldInfo.SetValue(null, AddEnum(name)); } else { fieldInfo.SetValue(null, AddPredefinedEnum(name, (int)customAttribute.PredefinedValue)); } continue; } if (fieldType == typeof(T)) { if (customAttribute.PredefinedValue == null) { fieldInfo.SetValue(null, (T)AddEnum(name)); } else { fieldInfo.SetValue(null, (T)AddPredefinedEnum(name, (int)customAttribute.PredefinedValue)); } continue; } FLog.Error(typeFromHandle.Name + "." + fieldInfo.Name + " has incorrect type, it should be CustomEnum<" + typeof(T).Name + "," + typeFromHandle.Name + ">", "ScanAndAssignEnumValues", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\Base\\CustomIntEnum.cs", 145); } } } public static class FLog { public static ManualLogSource logger = Logger.CreateLogSource("f9"); public static void Debug(object obj, [CallerMemberName] string memberName = "", [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0) { logger.LogDebug((object)(ProcessMetaInfo(memberName, filePath, lineNumber) + obj)); } public static void Info(object obj, [CallerMemberName] string memberName = "", [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0) { logger.LogInfo((object)(ProcessMetaInfo(memberName, filePath, lineNumber) + obj)); } public static void Warning(object obj, [CallerMemberName] string memberName = "", [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0) { logger.LogWarning((object)(ProcessMetaInfo(memberName, filePath, lineNumber) + obj)); } public static void Error(object obj, [CallerMemberName] string memberName = "", [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0) { logger.LogError((object)(ProcessMetaInfo(memberName, filePath, lineNumber) + obj)); } public static void ErrorAndThrow(object obj, [CallerMemberName] string memberName = "", [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0) { logger.LogError((object)(ProcessMetaInfo(memberName, filePath, lineNumber) + obj)); throw new Exception("Throw Exception:" + obj.ToString()); } public static void Fatal(object obj, [CallerMemberName] string memberName = "", [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0) { logger.LogFatal((object)(ProcessMetaInfo(memberName, filePath, lineNumber) + obj)); } public static void FatalAndThrow(object obj, [CallerMemberName] string memberName = "", [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0) { logger.LogFatal((object)(ProcessMetaInfo(memberName, filePath, lineNumber) + obj)); throw new Exception("Throw Exception:" + obj.ToString()); } public static void Message(object obj, [CallerMemberName] string memberName = "", [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0) { logger.LogMessage((object)(ProcessMetaInfo(memberName, filePath, lineNumber) + obj)); } public static void Assert(bool result, object message, [CallerMemberName] string memberName = "", [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0) { if (!result) { logger.LogError((object)(ProcessMetaInfo(memberName, filePath, lineNumber) + "Assert failed!")); logger.LogError(message); throw new Exception("Assert Failed :" + message.ToString()); } } public static void AssertNotNull<T>(T obj, [CallerMemberName] string memberName = "", [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0) where T : class { if (obj == null) { logger.LogError((object)(ProcessMetaInfo(memberName, filePath, lineNumber) + "Not null Assert failed! " + typeof(T).FullName)); throw new Exception("Not null Assert Failed for " + typeof(T).FullName); } } public static void AssertType<T>(object obj, [CallerMemberName] string memberName = "", [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0) { if (!obj.GetType().Equals(typeof(T))) { logger.LogError((object)(ProcessMetaInfo(memberName, filePath, lineNumber) + " Type Assert failed! Get <" + obj.GetType().FullName + "> Expect <" + typeof(T).FullName + ">")); string text = obj?.ToString(); if (text == null) { text = "null"; } throw new Exception("Type Assert Failed :" + text); } } private static string ProcessMetaInfo(string memberName, string filePath, int lineNumber) { return $"[@{Path.GetFileNameWithoutExtension(filePath)}.{memberName}:{lineNumber}] "; } } public static class PatchesManager { private static Dictionary<Type, Harmony> patchTypes = new Dictionary<Type, Harmony>(); public static Harmony harmony = new Harmony("Forwindz"); private static bool dirty = true; public static void RegPatch<T>() { patchTypes[typeof(T)] = null; dirty = true; } public static void RegPatch(Type type) { patchTypes[type] = null; dirty = true; } public static void PatchAll() { if (!dirty) { return; } Dictionary<Type, Harmony> dictionary = new Dictionary<Type, Harmony>(); foreach (KeyValuePair<Type, Harmony> patchType in patchTypes) { Type key = patchType.Key; Harmony value = patchType.Value; if (value == null) { FLog.Info("Try to Patch " + key.Namespace + " > " + key.Name, "PatchAll", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\Base\\PatchesManager.cs", 42); dictionary[key] = Harmony.CreateAndPatchAll(key, (string)null); } else { dictionary[key] = value; } } patchTypes = dictionary; dirty = false; } } public static class PatchUtils { public static void InjectConstructorPostPatch(Type injectClassType, MethodInfo methodInfo) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown ConstructorInfo[] constructors = injectClassType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); ConstructorInfo[] array = constructors; foreach (ConstructorInfo constructorInfo in array) { PatchesManager.harmony.Patch((MethodBase)constructorInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } public static void InjectConstructorPostPatch<T>(Action<T> action) { InjectConstructorPostPatch(typeof(T), ReflectUtils.GetMethodInfo(action)); } } public static class ReflectUtils { public static MethodInfo GetMethodInfo(Action action) { return action.Method; } public static MethodInfo GetMethodInfo<T>(Action<T> action) { return action.Method; } public static MethodInfo GetMethodInfo<T, U>(Action<T, U> action) { return action.Method; } public static MethodInfo GetMethodInfo<TResult>(Func<TResult> fun) { return fun.Method; } public static MethodInfo GetMethodInfo<T, TResult>(Func<T, TResult> fun) { return fun.Method; } public static MethodInfo GetMethodInfo<T, U, TResult>(Func<T, U, TResult> fun) { return fun.Method; } public static MethodInfo GetMethodInfo(Delegate del) { return del.Method; } public static List<Type> GetAllBaseTypes(Type type) { List<Type> list = new List<Type>(); Type baseType = type.BaseType; while (baseType != null) { list.Add(baseType); baseType = baseType.BaseType; } return list; } public static List<Type> GetAllBaseTypesAndInterfaces(Type type) { List<Type> list = new List<Type>(); Type baseType = type.BaseType; while (baseType != null) { list.Add(baseType); baseType = baseType.BaseType; } list.AddRange(type.GetInterfaces()); return list; } public static void InitializeAllStatics(Assembly assembly) { Type[] types = assembly.GetTypes(); foreach (Type type in types) { if (type.TypeInitializer != null) { RuntimeHelpers.RunClassConstructor(type.TypeHandle); } } } public static ConstructorInfo GetNonParameterConstructor(Type type) { ConstructorInfo[] constructors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FLog.Info("Try to search non parameter constructor " + type.Name, "GetNonParameterConstructor", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\Base\\PatchUtils.cs", 87); ConstructorInfo[] array = constructors; foreach (ConstructorInfo constructorInfo in array) { ParameterInfo[] parameters = constructorInfo.GetParameters(); Type declaringType = constructorInfo.DeclaringType; FLog.Info($"Detect {constructorInfo.Name} > {parameters} > {declaringType.Name} > Private {constructorInfo.IsPrivate}", "GetNonParameterConstructor", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\Base\\PatchUtils.cs", 92); if ((parameters == null || parameters.Length == 0) && !constructorInfo.IsStatic && declaringType.Equals(type)) { return constructorInfo; } } return null; } public static FieldInfo GetDeclaredField<T>(string fieldName) where T : class { FieldInfo fieldInfo = AccessTools.DeclaredField(typeof(T), fieldName); if (fieldInfo == null) { FLog.Error("Cannot find declared field: " + typeof(T).Namespace + "." + typeof(T).Name + "." + fieldName, "GetDeclaredField", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\Base\\PatchUtils.cs", 106); } return fieldInfo; } public static FieldInfo GetField<T>(string fieldName) where T : class { FieldInfo fieldInfo = AccessTools.Field(typeof(T), fieldName); if (fieldInfo == null) { FLog.Error("Cannot find declared field: " + typeof(T).Namespace + "." + typeof(T).Name + "." + fieldName, "GetField", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\Base\\PatchUtils.cs", 116); } return fieldInfo; } } public class BroadcastCallback : IBroadcaster { public Action focusAction; public Action dismissAction; public BroadcastCallback(Action forcusAction, Action dismissAction) { focusAction = forcusAction; this.dismissAction = dismissAction; } public BroadcastCallback(Action forcusAction) { focusAction = forcusAction; dismissAction = delegate { }; } public void Dismiss() { dismissAction(); } public void Focus() { focusAction(); } } public class BroadcastCallbackTranslateCameraToPos : IBroadcaster { public Vector2Int field; public BroadcastCallbackTranslateCameraToPos(Vector2Int field) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) this.field = field; } public void Dismiss() { } public void Focus() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) SO.GameBlackboardService.OnFocusRequested.OnNext(field); } } public interface IDynamicValue<T> { T BaseValue { get; } T CurrentValue { get; set; } void RestoreOriginalValue(); } public class DynamicValueFloat : IDynamicValue<float> { private readonly float baseValue; private float cacheValue; private readonly Func<float> getter; private readonly Action<float> adder; public float BaseValue => baseValue; public float CurrentValue { get { return cacheValue; } set { SetNewValue(value); } } public float RealValue => getter(); public DynamicValueFloat(Func<float> getter, Action<float> adder) { this.getter = getter; this.adder = adder; cacheValue = (baseValue = this.getter()); } public void SetNewValue(float newValue) { adder(newValue - cacheValue); cacheValue = newValue; } public void RestoreOriginalValue() { adder(baseValue - getter()); cacheValue = baseValue; } } public class DynamicValueInt : IDynamicValue<int> { private readonly int baseValue; private int cacheValue; private readonly Func<int> getter; private readonly Action<int> adder; public int BaseValue => baseValue; public int CurrentValue { get { return cacheValue; } set { SetNewValue(value); } } public int RealValue => getter(); public DynamicValueInt(Func<int> getter, Action<int> adder) { this.getter = getter; this.adder = adder; cacheValue = (baseValue = this.getter()); } public void SetNewValue(int newValue) { adder(newValue - cacheValue); cacheValue = newValue; } public void RestoreOriginalValue() { adder(baseValue - getter()); cacheValue = baseValue; } } public class DynamicValueArray<T> : IDynamicValue<T[]> { private readonly T[] baseValue; private readonly Func<T[]> getter; private readonly Action<T[]> setter; public T[] BaseValue => baseValue; public T[] CurrentValue { get { return getter(); } set { setter(value); } } public T[] RealValue => getter(); public DynamicValueArray(Func<T[]> getter, Action<T[]> setter) { this.getter = getter; this.setter = setter; T[] array = this.getter(); baseValue = new T[array.Length]; array.CopyTo(baseValue, 0); } public void AddNewValue(T newValue) { setter(ArrayExtension.ForceAdd<T>(getter(), newValue)); } public void Remove(int index) { setter(getter().ForceRemove(index)); } public void RestoreOriginalValue() { setter(baseValue); } } public class EffectAvailability { public static List<IEffectBuilder> RegularCornerstones; private static List<IEffectBuilder> AlreadyAddedCornerstones; static EffectAvailability() { RegularCornerstones = new List<IEffectBuilder>(); AlreadyAddedCornerstones = new List<IEffectBuilder>(); PatchesManager.RegPatch<EffectAvailability>(); } private static void SetAvailableBasedOnRarity(List<IEffectBuilder> effectModelBuilders) { //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: 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_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Invalid comparison between Unknown and I4 //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Expected O, but got Unknown //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Invalid comparison between Unknown and I4 //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Expected O, but got Unknown Settings settings = SO.Settings; BiomeModel[] biomes = settings.biomes; HashSet<EffectsTable> hashSet = new HashSet<EffectsTable>(); AlreadyAddedCornerstones.AddRange(RegularCornerstones); BiomeModel[] array = biomes; foreach (BiomeModel val in array) { int count = val.seasons.SeasonRewards.Count; for (int j = 0; j < count; j++) { SeasonRewardModel val2 = val.seasons.SeasonRewards[j]; int year = val2.year; bool flag = year == 2 || year == 4 || year == 6; EffectsTable effectsTable = val2.effectsTable; if (hashSet.Contains(effectsTable)) { continue; } hashSet.Add(effectsTable); EffectsTableEntity[] effects = val2.effectsTable.effects; List<EffectsTableEntity> list = new List<EffectsTableEntity>(effects); if (val2.effectsTable.effects.Length == 0) { continue; } foreach (IEffectBuilder effectModelBuilder in effectModelBuilders) { EffectModel model = effectModelBuilder.Model; EffectRarity rarity = model.rarity; EffectRarity val3 = rarity; if ((int)val3 != 4) { if ((int)val3 == 5 && flag) { EffectsTableEntity val4 = new EffectsTableEntity(); val4.chance = 100; val4.effect = model; list.Add(val4); FLog.Info($"{((SO)val).Name} Legendary Availability: Add <{((SO)model).Name}> to Year <{year}>, Weight={val4.chance} | {list.Count}", "SetAvailableBasedOnRarity", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\EffectAvailability.cs", 78); } } else if (!flag) { EffectsTableEntity val5 = new EffectsTableEntity(); val5.chance = 100; val5.effect = model; list.Add(val5); FLog.Info($"{((SO)val).Name} Epic Availability: Add <{((SO)model).Name}> to Year <{year}>, Weight={val5.chance} | {list.Count}", "SetAvailableBasedOnRarity", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\EffectAvailability.cs", 68); } } val2.effectsTable.effects = list.ToArray(); } } RegularCornerstones.Clear(); } [HarmonyPatch(typeof(BiomeManager), "SyncBiomes")] [HarmonyPostfix] private static void API_BiomeManager_SyncBiomes_PostPatch() { SetAvailableBasedOnRarity(RegularCornerstones); } } public static class EffectFactoryExtend { public static T CreateEffect<T>() where T : EffectModel { T val = ScriptableObject.CreateInstance<T>(); ((EffectModel)val).blockedBy = Array.Empty<EffectModel>(); ((EffectModel)val).usabilityTags = Array.Empty<ModelTag>(); return val; } public static T CreateEffect<T>(CompositeEffectBuilder builder) where T : EffectModel { T val = ScriptableObject.CreateInstance<T>(); ((EffectModel)val).description = ((EffectBuilder<CompositeEffectModel>)(object)builder).Model.description; ((EffectModel)val).displayName = ((EffectBuilder<CompositeEffectModel>)(object)builder).Model.displayName; ((EffectModel)val).label = ((EffectBuilder<CompositeEffectModel>)(object)builder).Model.label; ((EffectModel)val).blockedBy = Array.Empty<EffectModel>(); ((EffectModel)val).usabilityTags = Array.Empty<ModelTag>(); return val; } public static T CreateEffect<T>(HookedEffectBuilder builder) where T : EffectModel { return EffectFactory.NewHookedEffect<T>((IEffectBuilder)(object)builder); } public static ChanceForNoConsumptionEffectModel AddHookedEffect_ChanceForNoConsumptionEffectModel(IEffectBuilder effectBuilder, float amount) { ChanceForNoConsumptionEffectModel val = EffectFactory.NewHookedEffect<ChanceForNoConsumptionEffectModel>(effectBuilder); val.amount = amount; return val; } public static GoodEdibleEffectModel AddHookedEffect_GoodEdibleEffectModel(IEffectBuilder effectBuilder, GoodModel goodModel, bool ediable) { GoodEdibleEffectModel goodEdibleEffectModel = EffectFactory.NewHookedEffect<GoodEdibleEffectModel>(effectBuilder); goodEdibleEffectModel.good = goodModel; goodEdibleEffectModel.eatable = ediable; return goodEdibleEffectModel; } public static AddTraderFreeEffectChanceEffectModel AddHookedEffect_AddTraderFreeEffectChanceEffectModel(IEffectBuilder effectBuilder, TraderModel traderModel, float chance) { AddTraderFreeEffectChanceEffectModel addTraderFreeEffectChanceEffectModel = EffectFactory.NewHookedEffect<AddTraderFreeEffectChanceEffectModel>(effectBuilder); addTraderFreeEffectChanceEffectModel.trader = traderModel; addTraderFreeEffectChanceEffectModel.chance = chance; return addTraderFreeEffectChanceEffectModel; } public static OnlyTraderEffectModel AddHookedEffect_OnlyTraderEffectModel(IEffectBuilder effectBuilder, TraderModel traderModel) { OnlyTraderEffectModel onlyTraderEffectModel = EffectFactory.NewHookedEffect<OnlyTraderEffectModel>(effectBuilder); onlyTraderEffectModel.trader = traderModel; return onlyTraderEffectModel; } public static TraderIntervalEffectModel AddHookedEffect_TraderIntervalEffectModel(IEffectBuilder effectBuilder, float amount) { TraderIntervalEffectModel val = EffectFactory.NewHookedEffect<TraderIntervalEffectModel>(effectBuilder); val.amount = amount; return val; } public static HearthPopPercentEffectModel AddHookedEffect_HearthPopPercentEffectModel(IEffectBuilder effectBuilder, float percent) { HearthPopPercentEffectModel hearthPopPercentEffectModel = EffectFactory.NewHookedEffect<HearthPopPercentEffectModel>(effectBuilder); hearthPopPercentEffectModel.percent = percent; return hearthPopPercentEffectModel; } public static DecorationPercentEffectModel AddHookedEffect_DecorationPercentEffectModel(IEffectBuilder effectBuilder, float percent) { DecorationPercentEffectModel decorationPercentEffectModel = EffectFactory.NewHookedEffect<DecorationPercentEffectModel>(effectBuilder); decorationPercentEffectModel.percent = percent; return decorationPercentEffectModel; } public static VillagersBreakTimeRateEffectModel AddHookedEffect_VillagersBreakTimeRateEffectModel(IEffectBuilder effectBuilder, float percent) { VillagersBreakTimeRateEffectModel val = EffectFactory.NewHookedEffect<VillagersBreakTimeRateEffectModel>(effectBuilder); val.amount = percent; return val; } public static GlobalProductionRateEffectModel AddHookedEffect_GlobalProductionRateEffectModel(IEffectBuilder effectBuilder, float percent) { GlobalProductionRateEffectModel val = EffectFactory.NewHookedEffect<GlobalProductionRateEffectModel>(effectBuilder); val.amount = percent; return val; } public static HarvestingRateEffectModel AddHookedEffect_HarvestingRateEffectModel(IEffectBuilder effectBuilder, float percent) { HarvestingRateEffectModel val = EffectFactory.NewHookedEffect<HarvestingRateEffectModel>(effectBuilder); val.amount = percent; return val; } public static VillagersSpeedEffectModel AddHookedEffect_VillagersSpeedEffectModel(IEffectBuilder effectBuilder, VillagerSpeedRewardType type, float percent) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) VillagersSpeedEffectModel val = EffectFactory.NewHookedEffect<VillagersSpeedEffectModel>(effectBuilder); val.type = type; val.amount = percent; return val; } public static GlobalExtraProductionChanceEffectModel AddHookedEffect_GlobalExtraProductionChanceEffectModel(IEffectBuilder effectBuilder, float percent) { GlobalExtraProductionChanceEffectModel val = EffectFactory.NewHookedEffect<GlobalExtraProductionChanceEffectModel>(effectBuilder); ((BaseRateAmountEffectModel)val).amount = percent; return val; } } public static class GUIDManagerExtend { public static T Get<T>(string guid, string name) { return GUIDManager.Get<T>("Forwindz.CustomCornerstones", typeof(T).FullName + "." + name); } } public static class HookFactoryExtend { public static GoodProducedHook Create_GoodProducedHook(GoodRef goodRef, bool cycles) { return new GoodProducedHook { good = goodRef, cycles = cycles }; } public static DecorationHook Create_DecorationHook(DecorationTier tier, int amount) { return new DecorationHook { decorationTier = tier, amount = amount }; } } public class LocalizationLoader { public static void LoadLocalization(string folderPath = "lang") { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); FLog.Info("f9 cornerstone plugin patcher path " + directoryName, "LoadLocalization", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\LocalizationLoader.cs", 23); string path = Path.Combine(directoryName, folderPath); try { string[] files = Directory.GetFiles(path, "*.json", SearchOption.AllDirectories); string[] array = files; foreach (string text in array) { try { string text2 = File.ReadAllText(text); Dictionary<string, string> dictionary = JSON.FromJson<Dictionary<string, string>>(text2); string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text); SystemLanguage val = LocalizationManager.CodeToLanguage(fileNameWithoutExtension); foreach (KeyValuePair<string, string> item in dictionary) { LocalizationManager.AddString(item.Key, item.Value, val); } Log.Info((object)$"Load {dictionary.Count} entries for {val} language, from {text}", (Object)null); } catch (Exception ex) { Log.Error((object)("Error while processing localization file: " + text), (Object)null); Log.Error((object)ex, (Object)null); } } } catch (Exception ex2) { Log.Error((object)ex2, (Object)null); } } } public class StableRNG { private static float expectChance = 0f; private static float hitCount = 0f; private const float tolerateGap = 1f; private static float feelUnlucky = 0f; private static float unluckyTimes = 0.1f; private const float tolerateUnluckyGap = 10f; private const float unluckyBonusRatio = 0.02f; private const float luckyReduceFactor = 0.1f; private static float lastFeelUnluckyTime = -1f; private const float regardAsUnluckyInterval = 5f; public static bool StableRoll(float chance, float weight, bool isPositive) { if (chance <= 0f) { return false; } if (isPositive) { return StableRoll(chance, weight); } return !StableRoll(1f - chance, weight); } public static bool StableRoll(float chance, float weight = 1f) { float num = Mathf.Max(expectChance - hitCount - 1f, 0f) + Mathf.Max(0.02f * (feelUnlucky - 10f), 0f) + 1f; bool flag = RNG.Roll(num * chance); if (flag) { hitCount += weight; feelUnlucky *= 0.1f; unluckyTimes *= 0.1f; } else { if (CheckUnluckyInterval()) { unluckyTimes += weight; } feelUnlucky += weight * unluckyTimes; } expectChance += chance * weight; FLog.Info($"RNG Roll: {chance * 100f:F2}% * {num * 100f:F2}% | Exp: {(expectChance - hitCount) * 100f:F2}% | Unlucky: {feelUnlucky:F3}, Times: {unluckyTimes:F3}", "StableRoll", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\StableRNG.cs", 82); return flag; } public static float StableRandom(Vector2 range, float weight = 1f, bool higherIsPositive = true) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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) float num = Mathf.Max(expectChance - hitCount - 1f, 0f) + Mathf.Max(0.02f * (feelUnlucky - 10f), 0f); float num2 = Mathf.Min(RNG.Float(0f, 1f) * (1f + RNG.Float(0f, num)), 1f); float result = (range.y - range.x) * num2 + range.x; if (higherIsPositive) { StableRandomAdjustState(num2, weight); } else { StableRandomAdjustState(1f - num2, weight); } FLog.Info($"RNG Range: {num2 * 100f:F2}% + {num * 100f:F2}% | Exp: {(expectChance - hitCount) * 100f:F2}% | Unlucky: {feelUnlucky:F3}, Times: {unluckyTimes:F3}", "StableRandom", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\StableRNG.cs", 102); return result; } public static int StableCritialTimes(float chance, float weight = 1f, bool higherIsPositive = true) { int num = (int)chance; if (StableRoll(chance - (float)num, weight / (float)(num + 1), higherIsPositive)) { num++; } return num; } private static void StableRandomAdjustState(float rngResult, float weight) { if (rngResult < 0.5f) { if (CheckUnluckyInterval()) { unluckyTimes += weight; } feelUnlucky += (1f - rngResult * rngResult) * weight * unluckyTimes; } else if (rngResult > 0.7f) { float num = Mathf.Max(1.01f, 1.1f) - rngResult; num *= num; feelUnlucky *= num; unluckyTimes *= num; } hitCount += rngResult * weight; expectChance += 0.5f * weight; } private static bool CheckUnluckyInterval() { float unscaledTime = Time.unscaledTime; if (lastFeelUnluckyTime < 0f) { FLog.Info($"RNG New Time: {unscaledTime}", "CheckUnluckyInterval", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\StableRNG.cs", 143); lastFeelUnluckyTime = unscaledTime; return false; } if (unscaledTime - lastFeelUnluckyTime > 5f) { FLog.Info($"RNG Time gap: {unscaledTime - lastFeelUnluckyTime}, New Unlucky Event!", "CheckUnluckyInterval", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Utils\\StableRNG.cs", 151); lastFeelUnluckyTime = unscaledTime; return true; } return false; } } public static class Utils { public static string GetMd5Hash(string input) { using MD5 mD = MD5.Create(); byte[] array = mD.ComputeHash(Encoding.UTF8.GetBytes(input)); StringBuilder stringBuilder = new StringBuilder(); byte[] array2 = array; foreach (byte b in array2) { stringBuilder.Append(b.ToString("x2")); } return stringBuilder.ToString(); } public static T GetValue<T>(this WeakReference<T> instance) where T : class { if (instance.TryGetTarget(out var target)) { return target; } return null; } public static void SetSeasonsTime(float drizzleTime, float clearanceTime, float stormTime, SeasonQuarter firstCornerstoneTime = 1) { //IL_004b: 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) BiomeModel[] biomes = MB.Settings.biomes; foreach (BiomeModel val in biomes) { val.seasons.DrizzleTime = drizzleTime; val.seasons.ClearanceTime = clearanceTime; val.seasons.StormTime = stormTime; val.seasons.SeasonRewards[0].quarter = firstCornerstoneTime; } } public static string GetGoodIconAndName(GoodModel good) { string text = ((SO)good).Name; int num = text.LastIndexOf("]"); if (num != -1) { text = text.Substring(num + 1); } else if (text.Contains("_Meta")) { text = text.Substring("_Meta".Length + 1); } text = text.Trim(); return "<sprite name=\"" + ((SO)good).Name.ToLowerInvariant() + "\"> " + text; } } } namespace Forwindz.Framework.Utils.Extend { public static class ArrayExt { public static T[] ForceAdd<T>(this T[] source, T item) { T[] array = new T[source.Length + 1]; source.CopyTo(array, 0); array[^1] = item; return array; } public static void ForceAdd<T>(ref T[] source, T item) { source = source.ForceAdd(item); } public static T[] ForceRemove<T>(this T[] source, T item) { return source.ForceRemove(Array.IndexOf(source, item)); } public static T[] ForceRemove<T>(this T[] source, int index) { if (index < 0) { return source; } T[] array = new T[source.Length - 1]; if (index > 0) { Array.Copy(source, 0, array, 0, index); } if (index < source.Length - 1) { Array.Copy(source, index + 1, array, index, source.Length - index - 1); } return array; } public static void ForceRemove<T>(ref T[] source, T item) { source = source.ForceRemove(item); } } public static class GoodModelExt { public static bool ContainTag(this GoodModel goodModel, string name) { ModelTag[] tags = goodModel.tags; foreach (ModelTag val in tags) { if (((SO)val).Name.Equals(name)) { return true; } } return false; } } public static class SOExtend { public static List<T> DeepClone<T>(this List<T> objs) where T : SO { List<T> list = new List<T>(); list.Capacity = objs.Count; for (int i = 0; i < objs.Count; i++) { list.Add(((SO)(object)objs[i]).DeepClone<T>()); } return list; } public static T[] DeepClone<T>(this T[] objs) where T : SO { T[] array = new T[objs.Length]; for (int i = 0; i < objs.Length; i++) { array[i] = ((SO)(object)objs[i]).DeepClone<T>(); } return array; } public static T Clone<T>(this T original) where T : SO { if ((Object)(object)original == (Object)null) { return default(T); } return Object.Instantiate<T>(original); } public static SO DeepClone(this SO original) { if ((Object)(object)original == (Object)null) { return null; } SO val = Object.Instantiate<SO>(original); SODeepCopyFields(original, val); return val; } public static T DeepClone<T>(this SO original) where T : SO { return (T)(object)original.DeepClone(); } private static void SODeepCopyFields(object source, object destination) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown FieldInfo[] fields = source.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { if (!fieldInfo.IsNotSerialized && fieldInfo.FieldType.IsSubclassOf(typeof(SO))) { SO val = (SO)fieldInfo.GetValue(source); SO value = (((Object)(object)val != (Object)null) ? val.DeepClone() : null); fieldInfo.SetValue(destination, value); } } } } public static class TextArgExt { public static TextArg[] ToTextArgArray(this (TextArgType type, int sourceIndex)[] args) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown TextArg[] array = (TextArg[])(object)new TextArg[args.Length]; for (int i = 0; i < args.Length; i++) { array[i] = new TextArg { sourceIndex = args[i].sourceIndex, type = args[i].type }; } return array; } public static TextArg ToTextArg(this (TextArgType type, int sourceIndex) arg) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown TextArg val = new TextArg(); (val.type, val.sourceIndex) = arg; return val; } } } namespace Forwindz.Framework.Services { public static class CustomServiceManager { private static readonly List<Type> appExtraServiceTypes; private static readonly List<Type> gameExtraServiceTypes; private static readonly List<Type> metaExtraServiceTypes; private static readonly List<Type> worldExtraServiceTypes; private static Dictionary<Type, WeakReference<IService>> customServices; private static WeakReference<List<IService>> gameServices; private static WeakReference<List<IService>> metaServices; private static WeakReference<List<IService>> appServices; private static WeakReference<List<IService>> worldServices; public static IReadOnlyList<IService> GameServicesList => gameServices.GetValue(); public static IReadOnlyList<IService> MetaServicesList => metaServices.GetValue(); public static IReadOnlyList<IService> AppServicesList => appServices.GetValue(); public static IReadOnlyList<IService> WorldServicesList => worldServices.GetValue(); static CustomServiceManager() { appExtraServiceTypes = new List<Type>(); gameExtraServiceTypes = new List<Type>(); metaExtraServiceTypes = new List<Type>(); worldExtraServiceTypes = new List<Type>(); customServices = new Dictionary<Type, WeakReference<IService>>(); gameServices = null; metaServices = null; appServices = null; worldServices = null; PatchesManager.RegPatch(typeof(CustomServiceManager)); } public static void RegAppService<T>() where T : IService { appExtraServiceTypes.Add(typeof(T)); } public static void RegGameService<T>() where T : IService { gameExtraServiceTypes.Add(typeof(T)); } public static void RegMetaService<T>() where T : IService { metaExtraServiceTypes.Add(typeof(T)); } public static void RegWorldService<T>() where T : IService { worldExtraServiceTypes.Add(typeof(T)); } public static T GetService<T>() { if (customServices[typeof(T)].TryGetTarget(out var target)) { return (T)(object)target; } return default(T); } public static IService GetAsIService<T>() { if (customServices[typeof(T)].TryGetTarget(out var target)) { return target; } return null; } public static IService GetService(Type type) { if (customServices[type].TryGetTarget(out var target)) { return target; } return null; } public static IService GetServiceSafe(Type type) { if (customServices.TryGetValue(type, out var value) && value.TryGetTarget(out var target)) { return target; } return null; } public static T GetServiceSafe<T>() where T : IService { if (customServices.TryGetValue(typeof(T), out var value) && value.TryGetTarget(out var target) && target is T result) { return result; } return default(T); } [HarmonyPatch(typeof(WorldServices), "CreateServices")] [HarmonyPrefix] private static void WorldServicesCreate_PrePatch(WorldServices __instance) { foreach (Type worldExtraServiceType in worldExtraServiceTypes) { CreateServiceToList(__instance.allServices, worldExtraServiceType); } FLog.Info($"Try to create {worldExtraServiceTypes.Count} services in WorldServices", "WorldServicesCreate_PrePatch", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\Base\\CustomServiceManager.cs", 155); worldServices = new WeakReference<List<IService>>(__instance.allServices); } [HarmonyPatch(typeof(AppServices), "CreateServices")] [HarmonyPrefix] private static void AppServicesCreate_PrePatch(AppServices __instance) { foreach (Type appExtraServiceType in appExtraServiceTypes) { CreateServiceToList(__instance.allServices, appExtraServiceType); } FLog.Info($"Try to create {appExtraServiceTypes.Count} services in AppServices", "AppServicesCreate_PrePatch", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\Base\\CustomServiceManager.cs", 168); appServices = new WeakReference<List<IService>>(__instance.allServices); } [HarmonyPatch(typeof(GameServices), "CreateServices")] [HarmonyPostfix] private static void GameServicesCreate_PostPatch(GameServices __instance) { foreach (Type gameExtraServiceType in gameExtraServiceTypes) { CreateServiceToList(__instance.allServices, gameExtraServiceType); } FLog.Info($"Try to create {gameExtraServiceTypes.Count} services in GameServices", "GameServicesCreate_PostPatch", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\Base\\CustomServiceManager.cs", 181); gameServices = new WeakReference<List<IService>>(__instance.allServices); } [HarmonyPatch(typeof(MetaServices), "CreateServices")] [HarmonyPrefix] private static void MetaServicesCreate_PrePatch(MetaServices __instance) { foreach (Type metaExtraServiceType in metaExtraServiceTypes) { CreateServiceToList(__instance.allServices, metaExtraServiceType); } FLog.Info($"Try to create {metaExtraServiceTypes.Count} services in MetaServices", "MetaServicesCreate_PrePatch", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\Base\\CustomServiceManager.cs", 194); metaServices = new WeakReference<List<IService>>(__instance.allServices); } private static void CreateServiceToList(List<IService> allServices, Type serviceType) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown FLog.Info("Try to create service " + serviceType.FullName, "CreateServiceToList", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\Base\\CustomServiceManager.cs", 200); FLog.AssertNotNull(allServices, "CreateServiceToList", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\Base\\CustomServiceManager.cs", 201); FLog.AssertNotNull(customServices, "CreateServiceToList", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\Base\\CustomServiceManager.cs", 202); FLog.AssertNotNull(serviceType, "CreateServiceToList", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\Base\\CustomServiceManager.cs", 203); ConstructorInfo nonParameterConstructor = ReflectUtils.GetNonParameterConstructor(serviceType); FLog.AssertNotNull(nonParameterConstructor, "CreateServiceToList", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\Base\\CustomServiceManager.cs", 205); IService val = null; try { val = (IService)nonParameterConstructor.Invoke(null); } catch (Exception obj) { FLog.Error("Failed to create service!", "CreateServiceToList", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\Base\\CustomServiceManager.cs", 213); FLog.Error(obj, "CreateServiceToList", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\Base\\CustomServiceManager.cs", 214); } FLog.AssertNotNull<IService>(val, "CreateServiceToList", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\Base\\CustomServiceManager.cs", 217); List<Type> list = new List<Type>(); list.AddRange(serviceType.GetInterfaces()); list.Add(serviceType); list.AddRange(TypeExtensions.GetBaseTypes(serviceType, false)); List<Type> list2 = list; foreach (Type item in list2) { if (!(item == null) && GetServiceSafe(item) == null) { customServices[item] = new WeakReference<IService>(val); FLog.Info("Add Service " + serviceType.Name + " as " + item.Name, "CreateServiceToList", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\Base\\CustomServiceManager.cs", 230); } } allServices.Add(val); } } internal class DecorationModelDelegate { public DynamicValueInt decorationScoreDynamic; public DecorationModelDelegate(DecorationModel decorationModel) { decorationScoreDynamic = new DynamicValueInt(() => decorationModel.decorationScore, delegate(int delta) { DecorationModel obj = decorationModel; obj.decorationScore += delta; }); } public void RestoreToOriginal() { decorationScoreDynamic.RestoreOriginalValue(); } } public class DynamicDecorationStateInfo { public float decorationPercent = 1f; } internal class DynamicBuildingState { [JsonIgnore] public Dictionary<string, DecorationModelDelegate> originalDecorations = new Dictionary<string, DecorationModelDelegate>(); public Dictionary<string, DynamicDecorationStateInfo> decorationStates = new Dictionary<string, DynamicDecorationStateInfo>(); public void InitGame() { List<DecorationModel> list = LinqExtensions.FilterCast<DecorationModel>((IEnumerable)MB.Settings.Buildings).ToList(); foreach (DecorationModel item in list) { originalDecorations[((SO)item).Name] = new DecorationModelDelegate(item); } ApplyStates(); } public void AddDecorationPercent(string decoName, float percent) { if (decorationStates.TryGetValue(decoName, out var value)) { value.decorationPercent += percent; return; } value = new DynamicDecorationStateInfo(); value.decorationPercent += percent; decorationStates[decoName] = value; } public float GetDecorationPercent(string decoName) { if (decorationStates.TryGetValue(decoName, out var value)) { return value.decorationPercent; } return 1f; } public void ApplyStates() { foreach (string key in decorationStates.Keys) { ApplyDecorationState(key); } } public void ApplyDecorationState(string decoName) { DynamicDecorationStateInfo dynamicDecorationStateInfo = decorationStates[decoName]; DecorationModelDelegate decorationModelDelegate = originalDecorations[decoName]; DynamicValueInt decorationScoreDynamic = decorationModelDelegate.decorationScoreDynamic; decorationScoreDynamic.SetNewValue((int)((float)decorationModelDelegate.decorationScoreDynamic.BaseValue * dynamicDecorationStateInfo.decorationPercent)); } public void DestoryRestore() { foreach (string key in decorationStates.Keys) { DecorationModelDelegate decorationModelDelegate = originalDecorations[key]; decorationModelDelegate.RestoreToOriginal(); } } } public class DynamicBuildingStateService : GameService, IDynamicBuildingStateService, IService { [ModSerializedField(SaveLoadType.Unknown, "")] private DynamicBuildingState state = new DynamicBuildingState(); private FieldInfo fieldInfo_decorationTypeOwning = null; private FieldInfo fieldInfo_monitor = null; internal static float MIN_DECO_RATIO; public readonly Subject<Dictionary<string, DynamicDecorationStateInfo>> decorationValueChangeSubject = new Subject<Dictionary<string, DynamicDecorationStateInfo>>(); public IObservable<Dictionary<string, DynamicDecorationStateInfo>> OnDecorationValueChange => (IObservable<Dictionary<string, DynamicDecorationStateInfo>>)decorationValueChangeSubject; public OrdersMonitor Reflect_OrderService_monitor => (OrdersMonitor)(fieldInfo_monitor?.GetValue(Serviceable.OrdersService)); public Dictionary<ObjectiveState, DecorationTypeOwningLogic> Reflect_OrderMonitor_decorationTypeOwning { get { OrdersMonitor reflect_OrderService_monitor = Reflect_OrderService_monitor; if (reflect_OrderService_monitor == null) { return null; } return (Dictionary<ObjectiveState, DecorationTypeOwningLogic>)(fieldInfo_decorationTypeOwning?.GetValue(reflect_OrderService_monitor)); } } static DynamicBuildingStateService() { MIN_DECO_RATIO = 0.1f; CustomServiceManager.RegGameService<DynamicBuildingStateService>(); PatchesManager.RegPatch<DynamicBuildingStateService>(); } public override IService[] GetDependencies() { return (IService[])(object)new IService[4] { (IService)Serviceable.BuildingsService, (IService)Serviceable.RecipesService, (IService)Serviceable.OrdersService, CustomServiceManager.GetAsIService<IExtraStateService>() }; } public override void OnDestroy() { state.DestoryRestore(); ((Service)this).OnDestroy(); } public override UniTask OnLoading() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) fieldInfo_monitor = ReflectUtils.GetDeclaredField<OrdersService>("monitor"); fieldInfo_decorationTypeOwning = ReflectUtils.GetDeclaredField<OrdersMonitor>("decorationTypeOwning"); state.InitGame(); UpdateDecorationOrder(); return UniTask.CompletedTask; } private void UpdateDecorationOrder() { Dictionary<ObjectiveState, DecorationTypeOwningLogic> reflect_OrderMonitor_decorationTypeOwning = Reflect_OrderMonitor_decorationTypeOwning; if (reflect_OrderMonitor_decorationTypeOwning == null) { FLog.Error("Failed to get decoration orders, the decoration order info cannot be refreshed!", "UpdateDecorationOrder", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicBuildingStateService.cs", 207); return; } foreach (KeyValuePair<ObjectiveState, DecorationTypeOwningLogic> item in reflect_OrderMonitor_decorationTypeOwning) { ObjectiveState key = item.Key; DecorationTypeOwningLogic value = item.Value; ((OrderLogic)value).InitState(key); } } public void AddDecorationPercent(string decorationName, float percent) { AddDecorationPercentWithoutUpdate(decorationName, percent); decorationValueChangeSubject.OnNext(state.decorationStates); UpdateDecorationInfo(); } private void AddDecorationPercentWithoutUpdate(string decorationName, float percent) { state.AddDecorationPercent(decorationName, percent); state.ApplyDecorationState(decorationName); } public void AddAllDecorationPercent(float percent) { foreach (string key in state.originalDecorations.Keys) { AddDecorationPercentWithoutUpdate(key, percent); state.ApplyDecorationState(key); } UpdateDecorationInfo(); } private void UpdateDecorationInfo() { decorationValueChangeSubject.OnNext(state.decorationStates); UpdateDecorationOrder(); } public float GetDecorationPercent(string decorationName) { return state.GetDecorationPercent(decorationName); } public int GetDecorationAmount(DecorationTier tier) { return Serviceable.BuildingsService.Decorations.Values.Sum((Decoration d) => (((Building)d).IsFinished() && d.model.hasDecorationTier && (Object)(object)d.model.tier == (Object)(object)tier) ? d.model.decorationScore : 0); } [HarmonyPatch(typeof(ConstructionService), "GetConstructionCostFor")] [HarmonyPostfix] private static void ConstructionService_GetConstructionCostFor_PostPatch(ConstructionService __instance, BuildingModel building) { DecorationModel val = (DecorationModel)(object)((building is DecorationModel) ? building : null); if (val == null) { return; } DynamicBuildingStateService service = CustomServiceManager.GetService<DynamicBuildingStateService>(); if (service == null) { FLog.Error("Service is not inited!", "ConstructionService_GetConstructionCostFor_PostPatch", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicBuildingStateService.cs", 283); return; } float decorationPercent = service.state.GetDecorationPercent(((SO)val).Name); if (decorationPercent != 1f) { decorationPercent = Mathf.Max(MIN_DECO_RATIO, decorationPercent); float num = 1f / decorationPercent; Good[] requiredGoods = building.GetRequiredGoods(__instance.GetCurrentCostsRate() * num); } } } internal class DynamicCornerstoneState { public int noYearlyCornerstone = 0; } public class DynamicCornerstoneService : GameService, IDynamicCornerstoneService, IService { [ModSerializedField(SaveLoadType.Unknown, "")] internal DynamicCornerstoneState state = new DynamicCornerstoneState(); static DynamicCornerstoneService() { CustomServiceManager.RegGameService<DynamicCornerstoneService>(); PatchesManager.RegPatch<DynamicCornerstoneService>(); } public override IService[] GetDependencies() { return (IService[])(object)new IService[1] { CustomServiceManager.GetAsIService<IExtraStateService>() }; } public override UniTask OnLoading() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) return ((Service)this).OnLoading(); } public override void OnDestroy() { ((Service)this).OnDestroy(); } public void SetNoCornerstone(bool v) { state.noYearlyCornerstone += (v ? 1 : (-1)); } public bool GetNoCornerstone() { return state.noYearlyCornerstone > 0; } [HarmonyPatch(typeof(CornerstonesService), "CheckForPick")] [HarmonyPrefix] private static bool CornerstonesService_CheckForPick_PrePatch(CornerstonesService __instance) { DynamicCornerstoneService service = CustomServiceManager.GetService<DynamicCornerstoneService>(); if (service == null) { return true; } if (service.GetNoCornerstone()) { return false; } return true; } } public class ModifyGoodTypeState { public enum OperationType { SetEdiable, SetBurnable, SetTag } [JsonProperty] public readonly OperationType op; [JsonProperty] public readonly string content; [JsonProperty] public readonly bool boolState; private ModifyGoodTypeState() { } private ModifyGoodTypeState(OperationType op, string content, bool boolState) { this.op = op; this.content = content; this.boolState = boolState; } public static ModifyGoodTypeState GenAddTag(string tagName) { return new ModifyGoodTypeState(OperationType.SetTag, tagName, boolState: true); } public static ModifyGoodTypeState GenRemoveTag(string tagName) { return new ModifyGoodTypeState(OperationType.SetTag, tagName, boolState: false); } public static ModifyGoodTypeState GenSetEdiable(bool ediable) { return new ModifyGoodTypeState(OperationType.SetEdiable, null, ediable); } public static ModifyGoodTypeState GenSetBurnable(bool burnable) { return new ModifyGoodTypeState(OperationType.SetBurnable, null, burnable); } public bool IsAlreadyApplied(GoodModel goodModel) { switch (op) { case OperationType.SetEdiable: return goodModel.eatable == boolState; case OperationType.SetBurnable: return goodModel.canBeBurned = boolState; case OperationType.SetTag: if (boolState) { return goodModel.ContainTag(content); } return !goodModel.ContainTag(content); default: FLog.Warning($"Unknown enum values {op} in ModifyGoodTypeState", "IsAlreadyApplied", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 89); return false; } } public void ApplyState(GoodModel goodModel) { switch (op) { case OperationType.SetEdiable: goodModel.eatable = boolState; if (boolState) { Serviceable.StateService.Actors.rawFoodConsumptionPermits[((SO)goodModel).Name] = true; } else { Serviceable.StateService.Actors.rawFoodConsumptionPermits.Remove(((SO)goodModel).Name); } break; case OperationType.SetBurnable: goodModel.canBeBurned = boolState; Serviceable.HearthService.SetCanBeBurned(((SO)goodModel).Name, boolState); break; case OperationType.SetTag: if (boolState) { ArrayExt.ForceAdd(ref goodModel.tags, Serviceable.Settings.GetTag(content)); } else { ArrayExt.ForceRemove(ref goodModel.tags, Serviceable.Settings.GetTag(content)); } break; default: FLog.Warning($"Unknown enum values {op} in ModifyGoodTypeState", "ApplyState", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 126); break; } } public void RemoveState(GoodModel goodModel) { switch (op) { case OperationType.SetEdiable: goodModel.eatable = !boolState; break; case OperationType.SetBurnable: goodModel.canBeBurned = !boolState; break; case OperationType.SetTag: if (!boolState) { ArrayExt.ForceAdd(ref goodModel.tags, Serviceable.Settings.GetTag(content)); } else { ArrayExt.ForceRemove(ref goodModel.tags, Serviceable.Settings.GetTag(content)); } break; default: FLog.Warning($"Unknown enum values {op} in ModifyGoodTypeState", "RemoveState", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 153); break; } } public ModifyGoodTypeState GenerateInverseState() { return new ModifyGoodTypeState(op, content, !boolState); } public override bool Equals(object obj) { if (obj is ModifyGoodTypeState modifyGoodTypeState) { if (modifyGoodTypeState.op == op) { switch (op) { case OperationType.SetEdiable: case OperationType.SetBurnable: return modifyGoodTypeState.boolState == boolState; case OperationType.SetTag: return modifyGoodTypeState.boolState == boolState && modifyGoodTypeState.content.Equals(content); } } return false; } return base.Equals(obj); } public override int GetHashCode() { uint num = (boolState ? 1u : 0u); uint num2 = ((op == OperationType.SetTag) ? ((uint)EqualityComparer<string>.Default.GetHashCode(content)) : 0u); uint hashCode = (uint)op.GetHashCode(); return (int)((num << 31) | ((hashCode & 3) << 29)) | ((int)num2 & -1); } public override string ToString() { int num = (boolState ? 1 : 0); string text = $"{num}_{op.ToString()}"; if (op == OperationType.SetTag) { text = text + "_" + content; } return text; } public string ToInvString() { int num = ((!boolState) ? 1 : 0); string text = $"{num}_{op.ToString()}"; if (op == OperationType.SetTag) { text = text + "_" + content; } return text; } } public class ModifyGoodTypeInfo { [JsonProperty] private string goodName; [JsonProperty] private ModifyGoodTypeState state; [JsonProperty] private readonly bool isOriginalState; [JsonProperty] internal int duplicateTimes = 0; [JsonIgnore] public string GoodName => goodName; [JsonIgnore] public ModifyGoodTypeState State => state; [JsonIgnore] public bool IsOriginalState => isOriginalState; public ModifyGoodTypeInfo() { } public ModifyGoodTypeInfo(string goodName, ModifyGoodTypeState state) { this.goodName = goodName; this.state = state; isOriginalState = state.IsAlreadyApplied(GetGoodModel()); } public GoodModel GetGoodModel() { return Serviceable.Settings.GetGood(goodName); } public void ApplyState() { FLog.Info("+State " + ToString(), "ApplyState", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 255); state.ApplyState(GetGoodModel()); } public void RemoveState() { if (!isOriginalState) { FLog.Info("-State " + ToString(), "RemoveState", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 266); state.RemoveState(GetGoodModel()); } } public ModifyGoodTypeInfo GenerateInverseInfo() { return new ModifyGoodTypeInfo(goodName, state.GenerateInverseState()); } public override string ToString() { return state.ToString() + "_" + goodName; } public string ToInvString() { return state.ToInvString() + "_" + goodName; } } [Serializable] public class FluctuationInfo { [JsonProperty] public Vector2 range; [JsonProperty] private float totalValue = 0f; [JsonProperty] private int triggerTimes = 0; [JsonProperty] private string goodName; [JsonIgnore] private GoodModel goodModel; [JsonIgnore] public float TotalValue => totalValue; [JsonIgnore] public float TriggerTimes => triggerTimes; [JsonIgnore] public string GoodName => goodName; [JsonIgnore] public GoodModel GoodModel => goodModel; public FluctuationInfo(Vector2 range, string goodName) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) this.range = range; this.goodName = goodName; goodModel = MB.Settings.GetGood(goodName); } public void Restore() { goodModel = MB.Settings.GetGood(goodName); } public void TriggerEffect(int times = 1) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) float num = 0f; for (int i = 0; i < times; i++) { num += StableRNG.StableRandom(range); if (totalValue + num < -1f) { num = 0f - (totalValue + 1f); } } totalValue += num; triggerTimes += times; SO.EffectsService.GrantTraderSellPriceRate(goodName, num); FLog.Info($"Trigger Fluctuation: {goodName} | Range={range} | {times} times | Change Delta = {num}", "TriggerEffect", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 335); } public void RemoveEffect() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) FLog.Info($"Remove Fluctuation: {goodName} | Range={range} | {triggerTimes} times | Total Change = {totalValue}", "RemoveEffect", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 340); SO.EffectsService.GrantTraderSellPriceRate(goodName, 0f - totalValue); totalValue = 0f; triggerTimes = 0; } } public class ModifyGoodTypeStatesTracker { [JsonProperty] private Dictionary<string, ModifyGoodTypeInfo> duplicateTracker = new Dictionary<string, ModifyGoodTypeInfo>(); [JsonProperty] private Dictionary<string, Dictionary<int, FluctuationInfo>> fluctuationInfo = new Dictionary<string, Dictionary<int, FluctuationInfo>>(); public void AddFluctuationDefine(string goodName, Vector2 range) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) if (!fluctuationInfo.TryGetValue(goodName, out var value)) { Dictionary<int, FluctuationInfo> dictionary2 = (fluctuationInfo[goodName] = new Dictionary<int, FluctuationInfo>()); value = dictionary2; } int hashCode = ((object)(Vector2)(ref range)).GetHashCode(); if (!value.TryGetValue(hashCode, out var value2)) { value2 = new FluctuationInfo(range, goodName); value[hashCode] = value2; } } public void TriggerFluctuation(string goodName, Vector2 range, int times = 1) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) if (!this.fluctuationInfo.TryGetValue(goodName, out var value)) { Dictionary<int, FluctuationInfo> dictionary2 = (this.fluctuationInfo[goodName] = new Dictionary<int, FluctuationInfo>()); value = dictionary2; } int hashCode = ((object)(Vector2)(ref range)).GetHashCode(); if (!value.TryGetValue(hashCode, out var value2)) { value2 = (value[hashCode] = new FluctuationInfo(range, goodName)); } value2.TriggerEffect(times); } public void RemoveFluctuationDefine(string goodName, Vector2 range) { if (fluctuationInfo.TryGetValue(goodName, out var value)) { int hashCode = ((object)(Vector2)(ref range)).GetHashCode(); if (value.TryGetValue(hashCode, out var value2)) { value2.RemoveEffect(); value.Remove(hashCode); } } } public float GetFluctuation(string goodName, Vector2 range) { if (fluctuationInfo.TryGetValue(goodName, out var value)) { int hashCode = ((object)(Vector2)(ref range)).GetHashCode(); if (value.TryGetValue(hashCode, out var value2)) { return value2.TotalValue; } } return 0f; } public ModifyGoodTypeInfo GetExistingInfo(ModifyGoodTypeInfo info) { ModifyGoodTypeInfo value = null; string key = info.ToString(); if (!duplicateTracker.TryGetValue(key, out value)) { value = info; duplicateTracker[key] = value; } return value; } public ModifyGoodTypeInfo GetExistingInvInfo(ModifyGoodTypeInfo info) { ModifyGoodTypeInfo value = null; string key = info.ToInvString(); if (!duplicateTracker.TryGetValue(key, out value)) { value = info; duplicateTracker[key] = value.GenerateInverseInfo(); } return value; } public void AddState(ModifyGoodTypeInfo stateInfo) { ModifyGoodTypeInfo existingInfo = GetExistingInfo(stateInfo); ModifyGoodTypeInfo existingInvInfo = GetExistingInvInfo(stateInfo); if (existingInfo.duplicateTimes == existingInvInfo.duplicateTimes) { FLog.Info($"Apply state {stateInfo}", "AddState", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 451); existingInfo.ApplyState(); } existingInfo.duplicateTimes++; } public void RemoveState(ModifyGoodTypeInfo stateInfo) { ModifyGoodTypeInfo existingInfo = GetExistingInfo(stateInfo); ModifyGoodTypeInfo existingInvInfo = GetExistingInvInfo(stateInfo); if (existingInfo.duplicateTimes == existingInvInfo.duplicateTimes) { FLog.Info($"Remove state {stateInfo}", "RemoveState", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 465); existingInfo.RemoveState(); } existingInfo.duplicateTimes--; } public void RemoveAllState() { FLog.Info("remove all dynamic good states", "RemoveAllState", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 474); foreach (ModifyGoodTypeInfo value in duplicateTracker.Values) { ModifyGoodTypeInfo modifyGoodTypeInfo = duplicateTracker[value.ToInvString()]; if (value.duplicateTimes > modifyGoodTypeInfo.duplicateTimes) { value.RemoveState(); } } duplicateTracker.Clear(); } public void RestoreState() { try { FLog.Info($"restore dynamic good states, total states type: {duplicateTracker.Count}", "RestoreState", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 490); foreach (ModifyGoodTypeInfo value in duplicateTracker.Values) { ModifyGoodTypeInfo modifyGoodTypeInfo = duplicateTracker[value.ToInvString()]; if (value.duplicateTimes > modifyGoodTypeInfo.duplicateTimes) { value.ApplyState(); } } FLog.Info("finish restore dynamic good states", "RestoreState", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 499); } catch (Exception obj) { FLog.Error(obj, "RestoreState", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 502); FLog.Error("Failed to restore :(", "RestoreState", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 503); } } } public class DynamicGoodTypeService : GameService, IDynamicGoodTypeService, IService { [ModSerializedField(SaveLoadType.Unknown, "")] protected ModifyGoodTypeStatesTracker modifyGoodState = new ModifyGoodTypeStatesTracker(); private MethodInfo cacheMethod; public ModifyGoodTypeStatesTracker GetStateTracker => modifyGoodState; static DynamicGoodTypeService() { CustomServiceManager.RegGameService<DynamicGoodTypeService>(); } private void RecomputeCache() { cacheMethod.Invoke(Serviceable.GoodsService, null); } public override UniTask OnLoading() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) FLog.Info("Load Dynamic Good State!", "OnLoading", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 532); modifyGoodState.RestoreState(); cacheMethod = AccessTools.Method(((object)Serviceable.GoodsService).GetType(), "Cache", (Type[])null, (Type[])null); FLog.AssertNotNull(cacheMethod, "OnLoading", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 535); RecomputeCache(); return UniTask.CompletedTask; } public override void OnDestroy() { modifyGoodState.RemoveAllState(); ((Service)this).OnDestroy(); } public override IService[] GetDependencies() { return (IService[])(object)new IService[2] { (IService)Serviceable.GoodsService, CustomServiceManager.GetAsIService<IExtraStateService>() }; } public void GoodSetEatable(string goodName, bool state) { FLog.Info($"Set Ediable {goodName} {state}", "GoodSetEatable", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 558); modifyGoodState.AddState(new ModifyGoodTypeInfo(goodName, ModifyGoodTypeState.GenSetEdiable(state))); RecomputeCache(); } public void GoodAddTag(string goodName, string tagName) { FLog.Info("Add Tag " + goodName + " " + tagName, "GoodAddTag", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 569); modifyGoodState.AddState(new ModifyGoodTypeInfo(goodName, ModifyGoodTypeState.GenAddTag(tagName))); RecomputeCache(); } public void GoodRemoveTag(string goodName, string tagName) { FLog.Info("Remove Tag " + goodName + " " + tagName, "GoodRemoveTag", "D:\\dev\\projects\\game_mod\\against_storm\\try_modding\\AtS-my-first-mod\\Scripts\\Framework\\Services\\DynamicGoodTypeService.cs", 580); modifyGoodState.AddState(new ModifyGoodTypeInfo(goodName, ModifyGoodTypeState.GenRemoveTag(tagName))); RecomputeCache(); } public void AddGoodPriceFluctuationDefine(string goodName, Vector2 range) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) modifyGoodState.AddFluctuationDefine(goodName, range); } public void TriggerGoodPriceFluctuation(string goodName, Vector2 range, int times = 1) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) modifyGoodState.TriggerFluctuation(goodName, range, times); } public void RemoveGoodPriceFluctuationDefine(string goodName, Vector2 range) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) modifyGoodState.RemoveFluctuationDefine(goodName, range); } public float GetGoodPriceFluctuation(string goodName, Vector2 range) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) return modifyGoodState.GetFluctuation(goodName, range); } } public class HubTierDelegate { public DynamicValueInt hubPop; public HubTierDelegate(HubTier hub) { hubPop = new DynamicValueInt(() => hub.minPopulation, delegate(int delta) { HubTier obj = hub; obj.minPopulation += delta; }); } public void RestoreToOriginal() { hubPop.RestoreOriginalValue(); } } internal class DynamicHearthState { [JsonIgnore] public List<HubTierDelegate> hubTierDelegates = new List<HubTierDelegate>(); public float hubPopRequirePercent = 1f; public int hubPopRequireCount = 0; public void InitGame() { HubTier[] hubsTiers = MB.Settings.hubsTiers; foreach (HubTier hub in hubsTiers) { hubTierDelegates.Add(new HubTierDelegate(hub)); } } public void ApplyStates() { HubTier[] hubsTiers = MB.Settings.hubsTiers; foreach (HubTierDelegate hubTierDelegate in hubTierDelegates) { hubTierDelegate.hubPop.SetNewValue((int)((float)hubTierDelegate.hubPop.BaseValue * hubPopRequirePercent + (float)hubPopRequireCount)); } IEnumerable<Hearth> enumerable = LinqExtensions.FilterCast<Hearth>((IEnumerable)Serviceable.BuildingsService.Buildings.Values); foreach (Hearth item in enumerable) { ((Building)item).SlowUpdate(); } } public void DestoryRestore() { foreach (HubTierDelegate hubTierDelegate in hubTierDelegates) { hubTierDelegate.RestoreToOriginal(); } } } public class DynamicHearthService : GameService, IDynamicHearthService, IService { [ModSerializedField(SaveLoadType.Unknown, "")] private DynamicHearthState state = new DynamicHearthState(); static DynamicHearthService() { CustomServiceManager.RegGameService<DynamicHearthService>(); } public override IService[] GetDependencies() { return (IService[])(object)new IService[2] { (IService)Serviceable.HearthService, CustomServiceManager.GetAsIService<IExtraStateService>() }; } public override void OnDestroy() { state.DestoryRestore(); ((Service)this).OnDestroy(); } public override UniTask OnLoading() { //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_0021: Unknown result type (might be due to invalid IL or missing references) state.InitGame(); state.ApplyStates(); return UniTask.CompletedTask; } public void AddHearthRequirePopPercent(float v) { state.hubPopRequirePercent += v; state.ApplyStates(); } publi