Decompiled source of ForwindzCustomCornerstones v1.0.0
ForwindzCustomPerksMod.dll
Decompiled a day 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.Services; 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 ForwindzCustomPerks.Scripts.Framework.Utils.Extend; 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.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+0dc3075784e55ef5f6b5c6ad2e8ecc863c024f9b")] [assembly: AssemblyProduct("ForwindzCustomPerksMod")] [assembly: AssemblyTitle("ForwindzCustomPerksMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ForwindzCustomPerks { public static class PluginInfo { public const string PLUGIN_GUID = "ForwindzCustomPerksMod"; public const string PLUGIN_NAME = "ForwindzCustomPerksMod"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace ForwindzCustomPerks.Scripts.Framework.Utils.Extend { 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 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"); 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 DynamicTraderInfoService : GameService, IDynamicTraderInfoService, IService { [ModSerializedField(SaveLoadType.Unknown, "")] internal DynamicTraderInfoData stateData = new DynamicTraderInfoData(); private IDisposable traderArriveListener = null; private MethodInfo methodUpdateNextVisit = null; public DynamicTraderInfoData DynamicTraderState => stateData; 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!"); } 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 > "); FLog.Info($"Sell Perks Count: {stateData.effectsSellValue.Count} | Force List: {stateData.forceTraderNameList.Count}"); } private void OnTraderArrive(TraderVisitState visitState) { FLog.Info("Trader [" + visitState.trader + "] Arrived! Process its effect price!"); 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."); foreach (KeyValuePair<string, bool> effect in newVisitState.effects) { FLog.Info($"Check {effect}"); string key = effect.Key; if (!effect.Value) { FLog.Info($"{traderGlobalEffects.chanceToFreeEffect} free chance for {effect}"); if (RNG.Roll(traderGlobalEffects.chanceToFreeEffect)) { stateData.effectsSellValue.Add(key, 0f); FLog.Info("Set " + key + " as free"); } } } } 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); 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!"); return; } FLog.Info("Remove Force Trader: " + name); ResetNextTrader(); } public void RemoveAssaultTrader(string name) { FLog.Info("Remove Assaulted Trader Record: " + name); Serviceable.StateService.Trade.assaultedTraders.Remove(name); } public void ResetNextTrader() { if (!Serviceable.TradeService.IsMainTraderInTheVillage()) { FLog.Info("Reset Next Trader"); 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."); } 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}"); } [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); __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}"); __result = num; } } } } 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.0.0"; } [BepInPlugin("Forwindz.CustomCornerstones", "f9's cornerstones", "1.0.0")] [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); 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); CustomServiceManager.GetService<BuildingMonitorService>().OnBuildingCompleted(__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}"); 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!"); } 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!"); } 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}"); 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}"); 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."); } FLog.Info("Find enum field: " + fieldInfo.FieldType.Name + " " + fieldInfo.Name); 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 + ">"); } } } public static class FLog { public static ManualLogSource logger = Logger.CreateLogSource("f9"); public static void Debug(params object[] objs) { logger.LogDebug((object)objs); } public static void Debug(object obj) { logger.LogDebug(obj); } public static void Info(params object[] objs) { logger.LogInfo((object)objs); } public static void Info(object obj) { logger.LogInfo(obj); } public static void Warning(params object[] objs) { logger.LogWarning((object)objs); } public static void Warning(object obj) { logger.LogWarning(obj); } public static void Error(params object[] objs) { logger.LogError((object)objs); } public static void Error(object obj) { logger.LogError(obj); } public static void ErrorAndThrow(object obj) { logger.LogError(obj); throw new Exception("Throw Exception:" + obj.ToString()); } public static void Fatal(params object[] objs) { logger.LogFatal((object)objs); } public static void Fatal(object obj) { logger.LogFatal(obj); } public static void FatalAndThrow(object obj) { logger.LogFatal(obj); throw new Exception("Throw Exception:" + obj.ToString()); } public static void Message(params object[] objs) { logger.LogMessage((object)objs); } public static void Message(object obj) { logger.LogMessage(obj); } public static void Assert(bool result, object message) { if (!result) { logger.LogError((object)"Assert failed!"); logger.LogError(message); throw new Exception("Assert Failed :" + message.ToString()); } } public static void AssertNotNull<T>(T obj) where T : class { if (obj == null) { logger.LogError((object)("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) { if (!obj.GetType().Equals(typeof(T))) { logger.LogError((object)("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); } } } 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); 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); 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}"); 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); } 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); } return fieldInfo; } } public class CompositeEffectBuilder : EffectBuilder<CompositeEffectModel> { public EffectModel[] Effects { get { return base.m_effectModel.rewards; } set { SetEffects(value); } } public CompositeEffectBuilder(string guid, string name, string iconPath) : base(guid, name, iconPath) { base.m_effectModel.anyNestedToFit = false; base.m_effectModel.rewards = Array.Empty<EffectModel>(); } public void AddEffect(EffectModel effect) { ArrayExtension.ForceAdd<EffectModel>(base.m_effectModel.rewards, effect); } public void AddEffects(IEnumerable<EffectModel> effects) { List<EffectModel> list = base.m_effectModel.rewards.ToList(); list.AddRange(effects.ToList()); base.m_effectModel.rewards = list.ToArray(); } public void AddEffects(EffectModel[] effects) { List<EffectModel> list = base.m_effectModel.rewards.ToList(); list.AddRange(effects.ToList()); base.m_effectModel.rewards = list.ToArray(); } public void SetEffect(EffectModel effect) { base.m_effectModel.rewards = (EffectModel[])(object)new EffectModel[1] { effect }; } public void SetEffects(IEnumerable<EffectModel> effects) { base.m_effectModel.rewards = effects.ToArray(); } public void SetEffects(EffectModel[] effects) { base.m_effectModel.rewards = effects; } public void ClearEffects() { base.m_effectModel.rewards = Array.Empty<EffectModel>(); } public void SetDescriptionArgs(params (TextArgType type, int sourceIndex)[] args) { ((EffectModel)base.m_effectModel).formatDescription = true; base.m_effectModel.dynamicDescriptionArgs = args.ToTextArgArray(); } public void SetAnyNestedToFit(bool value) { base.m_effectModel.anyNestedToFit = value; } public void SetNestedPreviewIndex(int index) { if (index < 0) { base.m_effectModel.hasNestedPreview = false; return; } base.m_effectModel.hasNestedPreview = true; base.m_effectModel.nestedPreviewIndex = index; } public void SetNestedRetroactivePreviewIndex(int index) { if (index < 0) { base.m_effectModel.hasNestedRetroactivePreview = false; return; } base.m_effectModel.hasNestedRetroactivePreview = true; base.m_effectModel.nestedRetroactivePreviewEffectIndex = index; } public void SetNestedStatePreviewIndex(int index) { if (index < 0) { base.m_effectModel.hasNestedStatePreview = false; return; } base.m_effectModel.hasNestedStatePreview = true; base.m_effectModel.nestedStatePreviewEffectIndex = index; } public void SetNestedAmountIndex(int index) { if (index < 0) { base.m_effectModel.hasNestedAmount = false; return; } base.m_effectModel.hasNestedAmount = true; base.m_effectModel.nestedAmountEffectIndex = index; } public void SetNestedIntAmountIndex(int index) { if (index < 0) { base.m_effectModel.hasNestedIntAmount = false; return; } base.m_effectModel.hasNestedIntAmount = true; base.m_effectModel.nestedIntAmountEffectIndex = index; } public void SetNestedFloatAmountIndex(int index) { if (index < 0) { base.m_effectModel.hasNestedFloatAmount = false; return; } base.m_effectModel.hasNestedFloatAmount = true; base.m_effectModel.nestedFloatAmountEffectIndex = index; } public void SetShowEffectAsPerks(bool value) { base.m_effectModel.showEffectsAsPerks = value; } } public class EffectAvailability { public static List<IEffectBuilder> RegularCornerstones; static EffectAvailability() { RegularCornerstones = new List<IEffectBuilder>(); PatchesManager.RegPatch<EffectAvailability>(); } private static void SetAvailableBasedOnRarity(List<IEffectBuilder> effectModelBuilders) { //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Invalid comparison between Unknown and I4 //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Expected O, but got Unknown //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Invalid comparison between Unknown and I4 //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Expected O, but got Unknown Settings settings = SO.Settings; BiomeModel[] biomes = settings.biomes; HashSet<EffectsTable> hashSet = new HashSet<EffectsTable>(); 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}"); } } 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}"); } } val2.effectsTable.effects = list.ToArray(); } } } [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 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 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_0068: 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) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: 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); 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)$"{val} [{item.Key}]:{item.Value}", (Object)null); } 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 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) { int num = Array.IndexOf(source, item); if (num < 0) { return source; } T[] array = new T[source.Length - 1]; if (num > 0) { Array.Copy(source, 0, array, 0, num); } if (num < source.Length - 1) { Array.Copy(source, num + 1, array, num, source.Length - num - 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); } } } } } 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"); 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"); 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"); 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"); metaServices = new WeakReference<List<IService>>(__instance.allServices); } private static void CreateServiceToList(List<IService> allServices, Type serviceType) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown FLog.Info("Try to create service " + serviceType.FullName); FLog.AssertNotNull(allServices); FLog.AssertNotNull(customServices); FLog.AssertNotNull(serviceType); ConstructorInfo nonParameterConstructor = ReflectUtils.GetNonParameterConstructor(serviceType); FLog.AssertNotNull(nonParameterConstructor); IService val = null; try { val = (IService)nonParameterConstructor.Invoke(null); } catch (Exception obj) { FLog.Error("Failed to create service!"); FLog.Error(obj); } FLog.AssertNotNull<IService>(val); 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); } } allServices.Add(val); } } internal class DecorationModelInfo { public DecorationTier tier; public int decorationScore; public DecorationModelInfo(DecorationModel decorationModel) { decorationScore = decorationModel.decorationScore; tier = decorationModel.tier; } public void Apply(DecorationModel decorationModel) { decorationModel.decorationScore = decorationScore; decorationModel.tier = tier; } } public class DynamicDecorationStateInfo { public float decorationPercent = 1f; } internal class DynamicBuildingState { [JsonIgnore] public Dictionary<string, DecorationModelInfo> originalDecorations = new Dictionary<string, DecorationModelInfo>(); 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 DecorationModelInfo(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) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown DynamicDecorationStateInfo dynamicDecorationStateInfo = decorationStates[decoName]; DecorationModelInfo decorationModelInfo = originalDecorations[decoName]; DecorationModel val = (DecorationModel)MB.Settings.GetBuilding(decoName); val.decorationScore = (int)((float)decorationModelInfo.decorationScore * dynamicDecorationStateInfo.decorationPercent); } public void DestoryRestore() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown foreach (string key in decorationStates.Keys) { DecorationModelInfo decorationModelInfo = originalDecorations[key]; DecorationModel val = (DecorationModel)MB.Settings.GetBuilding(key); val.decorationScore = decorationModelInfo.decorationScore; } } } public class DynamicBuildingStateService : GameService, IDynamicBuildingStateService, IService { [ModSerializedField(SaveLoadType.Unknown, "")] private DynamicBuildingState state = new DynamicBuildingState(); private FieldInfo fieldInfo_decorationTypeOwning = null; private FieldInfo fieldInfo_monitor = null; 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() { CustomServiceManager.RegGameService<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!"); 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); } } 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"); 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"); 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"); 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()); state.ApplyState(GetGoodModel()); } public void RemoveState() { if (!isOriginalState) { FLog.Info("-State " + ToString()); 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; } } public class ModifyGoodTypeStatesTracker { [JsonProperty] private Dictionary<string, ModifyGoodTypeInfo> duplicateTracker = new Dictionary<string, ModifyGoodTypeInfo>(); 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}"); 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}"); existingInfo.RemoveState(); } existingInfo.duplicateTimes--; } public void RemoveAllState() { FLog.Info("remove all dynamic good states"); 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}"); 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"); } catch (Exception obj) { FLog.Error(obj); FLog.Error("Failed to restore :("); } } } 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) FLog.Info("Load Dynamic Good State!"); modifyGoodState.RestoreState(); cacheMethod = AccessTools.Method(((object)Serviceable.GoodsService).GetType(), "Cache", (Type[])null, (Type[])null); FLog.AssertNotNull(cacheMethod); 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}"); modifyGoodState.AddState(new ModifyGoodTypeInfo(goodName, ModifyGoodTypeState.GenSetEdiable(state))); RecomputeCache(); } public void GoodAddTag(string goodName, string tagName) { FLog.Info("Add Tag " + goodName + " " + tagName); modifyGoodState.AddState(new ModifyGoodTypeInfo(goodName, ModifyGoodTypeState.GenAddTag(tagName))); RecomputeCache(); } public void GoodRemoveTag(string goodName, string tagName) { FLog.Info("Remove Tag " + goodName + " " + tagName); modifyGoodState.AddState(new ModifyGoodTypeInfo(goodName, ModifyGoodTypeState.GenRemoveTag(tagName))); RecomputeCache(); } } internal class DynamicHearthState { [JsonIgnore] public HubTier[] originalHubTiers = null; public float hubPopRequirePercent = 1f; public int hubPopRequireCount = 0; public void InitGame() { originalHubTiers = MB.Settings.hubsTiers.DeepClone<HubTier>(); } public void ApplyStates() { HubTier[] hubsTiers = MB.Settings.hubsTiers; for (int i = 0; i < hubsTiers.Length; i++) { hubsTiers[i].minPopulation = (int)Mathf.Max((float)originalHubTiers[i].minPopulation * hubPopRequirePercent + (float)hubPopRequireCount, 0f); } IEnumerable<Hearth> enumerable = LinqExtensions.FilterCast<Hearth>((IEnumerable)Serviceable.BuildingsService.Buildings.Values); foreach (Hearth item in enumerable) { ((Building)item).SlowUpdate(); } } public void DestoryRestore() { HubTier[] hubsTiers = MB.Settings.hubsTiers; for (int i = 0; i < hubsTiers.Length; i++) { hubsTiers[i].minPopulation = originalHubTiers[i].minPopulation; } } } 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(); } public void AddHearthRequirePopCount(int v) { state.hubPopRequireCount += v; state.ApplyStates(); } } public class ExtraStateService : GameService, IExtraStateService, IService { private class SaveInformation { [JsonProperty] public object obj; public Type type; public string name; public SaveInformation(object obj, Type type, string name) { this.obj = obj; this.type = type; this.name = name; } public void TryRecover() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (obj != null) { FLog.AssertType<JObject>(obj); obj = ((JToken)(JObject)obj).ToObject(type); } } } private class SaveInformations { public string versionName = ""; public Dictionary<string, SaveInformation> extraStates = new Dictionary<string, SaveInformation>(); public void OnSave() { versionName = Assembly.GetExecutingAssembly().GetName().Version.ToString(); } public void OnDestory() { extraStates.Clear(); versionName = ""; } public static SaveInformations CreateNew() { return new SaveInformations(); } } private class TrackedField { public string saveName; public object owner; public FieldInfo field; public TrackedField(string saveName, object owner, FieldInfo field) { this.saveName = saveName; this.owner = owner; this.field = field; } public void ApplyValue(object obj) { field.SetValue(owner, obj); } public object GetValue() { return field.GetValue(owner); } } [CompilerGenerated] private sealed class <LoadAllStates>d__13 : IAsyncStateMachine { public int <>1__state; public AsyncUniTaskMethodBuilder <>t__builder; public ExtraStateService <>4__this; private string <fullFilePath>5__1; private SaveInformations <>s__2; private Exception <e>5__3; private Dictionary<string, SaveInformation>.ValueCollection.Enumerator <>s__4; private SaveInformation <saveInfo>5__5; private Exception <e>5__6; private List<TrackedField>.Enumerator <>s__7; private TrackedField <trackedField>5__8; private Exception <e>5__9; private Awaiter<SaveInformations> <>u__1; private void MoveNext() { //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; try { if (num == 0) { goto IL_00a5; } if (MB.GameSaveService.IsNewGame()) { FLog.Info("ExtraStateService: New Game, do not load!"); <>4__this.saveInformations = SaveInformations.CreateNew(); } else { <fullFilePath>5__1 = Path.Combine(Serviceable.ProfilesService.GetProfileFolderPath(), SAVE_PATH); if (File.Exists(<fullFilePath>5__1)) { goto IL_00a5; } FLog.Error("The Save not exists : " + <fullFilePath>5__1); FLog.Warning("We generate a new one instead"); <>4__this.saveInformations = SaveInformations.CreateNew(); } goto end_IL_0007; IL_00a5: try { Awaiter<SaveInformations> awaiter; if (num != 0) { awaiter = Serviceable.SavesIOService.Get<SaveInformations>(Path.Combine(Serviceable.ProfilesService.GetProfileFolderPath(), SAVE_PATH), "MOD_FORWINDZ_SAVE_GAME").GetAwaiter(); if (!awaiter.IsCompleted) { num = (<>1__state = 0); <>u__1 = awaiter; <LoadAllStates>d__13 <LoadAllStates>d__ = this; ((AsyncUniTaskMethodBuilder)(ref <>t__builder)).AwaitUnsafeOnCompleted<Awaiter<SaveInformations>, <LoadAllStates>d__13>(ref awaiter, ref <LoadAllStates>d__); return; } } else { awaiter = <>u__1; <>u__1 = default(Awaiter<SaveInformations>); num = (<>1__state = -1); } <>s__2 = awaiter.GetResult(); <>4__this.saveInformations = <>s__2; <>s__2 = null; } catch (Exception ex) { <e>5__3 = ex; Log.Error((object)"Failed to load extra state", (Object)null); Log.Error((object)<e>5__3, (Object)null); Log.Warning((object)"We create a new one instead!", (Object)null); <>4__this.saveInformations = SaveInformations.CreateNew(); goto end_IL_0007; } <>s__4 = <>4__this.saveInformations.extraStates.Values.GetEnumerator(); try { while (<>s__4.MoveNext()) { <saveInfo>5__5 = <>s__4.Current; try { <saveInfo>5__5.TryRecover(); } catch (Exception ex) { <e>5__6 = ex; Log.Error((object)("Failed to load extra state " + <saveInfo>5__5.name), (Object)null); Log.Error((object)<e>5__6, (Object)null); } <saveInfo>5__5 = null; } } finally { if (num < 0) { ((IDisposable)<>s__4).Dispose(); } } <>s__4 = default(Dictionary<string, SaveInformation>.ValueCollection.Enumerator); <>s__7 = <>4__this.trackFieldList.GetEnumerator(); try { while (<>s__7.MoveNext()) { <trackedField>5__8 = <>s__7.Current; try { <trackedField>5__8.ApplyValue(<>4__this.saveInformations.extraStates[<trackedField>5__8.saveName].obj); } catch (Exception ex) { <e>5__9 = ex; Log.Error((object)("Failed to load & apply extra state " + <trackedField>5__8.saveName + " to field"), (Object)null); Log.Error((object)<e>5__9, (Object)null); } <trackedField>5__8 = null; } } finally { if (num < 0) { ((IDisposable)<>s__7).Dispose(); } } <>s__7 = default(List<TrackedField>.Enumerator); end_IL_0007:; } catch (Exception ex) { <>1__state = -2; <fullFilePath>5__1 = null; ((AsyncUniTaskMethodBuilder)(ref <>t__builder)).SetException(ex); return; } <>1__state = -2; <fullFilePath>5__1 = null; ((AsyncUniTaskMethodBuilder)(ref <>t__builder)).SetResult(); } void IAsyncStateMachine.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext this.MoveNext(); } [DebuggerHidden] private void SetStateMachine(IAsyncStateMachine stateMachine) { } void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine) { //ILSpy generated this explicit interface implementation from .override directive in SetStateMachine this.SetStateMachine(stateMachine); } } [CompilerGenerated] private sealed class <OnLoading>d__10 : IAsyncStateMachine { public int <>1__state; public AsyncUniTaskMethodBuilder <>t__builder; public ExtraStateService <>4__this; private Awaiter <>u__1; private void MoveNext() { //IL_0068: 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) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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) //IL_004e: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; try { Awaiter awaiter; if (num != 0) { FLog.Info("Load Extra States!"); <>4__this.ScanAttributes(); UniTask val = <>4__this.LoadAllStates(); awaiter = ((UniTask)(ref val)).GetAwaiter(); if (!((Awaiter)(ref awaiter)).IsCompleted) { num = (<>1__state = 0); <>u__1 = awaiter; <OnLoading>d__10 <OnLoading>d__ = this; ((AsyncUniTaskMethodBuilder)(ref <>t__builder)).AwaitUnsafeOnCompleted<Awaiter, <OnLoading>d__10>(ref awaiter, ref <OnLoading>d__); return; } } else { awaiter = <>u__1; <>u__1 = default(Awaiter); num = (<>1__state = -1); } ((Awaiter)(ref awaiter)).GetResult(); } catch (Exception exception) { <>1__state = -2; ((AsyncUniTaskMethodBuilder)(ref <>t__builder)).SetException(exception); return; } <>1__state = -2; ((AsyncUniTaskMethodBuilder)(ref <>t__builder)).SetResult(); } void IAsyncStateMachine.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext this.MoveNext(); } [DebuggerHidden] private void SetStateMachine(IAsyncStateMachine stateMachine) { } void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine) { //ILSpy generated this explicit interface implementation from .override directive in SetStateMachine this.SetStateMachine(stateMachine); } } public static string SAVE_PATH; public const string SAVE_KEY_INFO = "MOD_FORWINDZ_SAVE_GAME"; private SaveInformations saveInformations; private List<TrackedField> trackFieldList = new List<TrackedField>(); static ExtraStateService() { SAVE_PATH = "f9_mod\\ModGameSave.save"; CustomServiceManager.RegGameService<ExtraStateService>(); PatchesManager.RegPatch(typeof(ExtraStateService)); } public override IService[] GetDependencies() { return (IService[])(object)new IService[3] { (IService)Serviceable.StateService, (IService)Serviceable.GameSaveService, (IService)Serviceable.SavesIOService }; } [AsyncStateMachine(typeof(<OnLoading>d__10))] [DebuggerStepThrough] public override UniTask OnLoading() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) <OnLoading>d__10 <OnLoading>d__ = new <OnLoading>d__10(); <OnLoading>d__.<>t__builder = AsyncUniTaskMethodBuilder.Create(); <OnLoading>d__.<>4__this = this; <OnLoading>d__.<>1__state = -1; ((AsyncUniTaskMethodBuilder)(ref <OnLoading>d__.<>t__builder)).Start<<OnLoading>d__10>(ref <OnLoading>d__); return ((AsyncUniTaskMethodBuilder)(ref <OnLoading>d__.<>t__builder)).Task; } public override void OnDestroy() { trackFieldList.Clear(); saveInformations.OnDestory(); ((Service)this).OnDestroy(); } private void ScanAttributes() { IReadOnlyList<IService> gameServicesList = CustomServiceManager.GameServicesList; foreach (IService item in gameServicesList) { FieldInfo[] fields = ((object)item).GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { ModSerializedFieldAttribute customAttribute = fieldInfo.GetCustomAttribute<ModSerializedFieldAttribute>(); if (customAttribute != null && (customAttribute.SLType == SaveLoadType.Game || customAttribute.SLType == SaveLoadType.Unknown)) { object value = fieldInfo.GetValue(item); string text = customAttribute.SaveName; if (text == null || text.Length == 0) { string input = ((object)item).GetType().FullName + "#" + fieldInfo.FieldType.FullName + "#" + fieldInfo.Name; text = ((object)item).GetType().Name + "." + fieldInfo.Name + "_" + Forwindz.Framework.Utils.Utils.GetMd5Hash(input); } trackFieldList.Add(new TrackedField(text, item, fieldInfo)); } } } } [AsyncStateMachine(typeof(<LoadAllStates>d__13))] [DebuggerStepThrough] public UniTask LoadAllStates() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) <LoadAllStates>d__13 <LoadAllStates>d__ = new <LoadAllStates>d__13(); <LoadAllStates>d__.<>t__builder = AsyncUniTaskMethodBuilder.Create(); <LoadAllStates>d__.<>4__this = this; <LoadAllStates>d__.<>1__state = -1; ((AsyncUniTaskMethodBuilder)(ref <LoadAllStates>d__.<>t__builder)).Start<<LoadAllStates>d__13>(ref <LoadAllStates>d__); return ((AsyncUniTaskMethodBuilder)(ref <LoadAllStates>d__.<>t__builder)).Task; } public void SaveAllStates() { FLog.Info("Try to save extra states"); saveInformations.OnSave(); foreach (TrackedField trackField in trackFieldList) { saveInformations.extraStates[trackField.saveName] = new SaveInformation(trackField.GetValue(), trackField.field.FieldType, trackField.saveName); } Serviceable.SavesIOService.SaveToFile((object)saveInformations, SAVE_PATH, (SaveLocation)1); FLog.Info("Saved extra states!"); } public T GetStateSafe<T>(string name) { if (saveInformations.extraStates.TryGetValue(name, out var value)) { if (value.obj is T result) { return result; } FLog.Warning("SafeGetState: Unable to convert " + value.obj.GetType().Name + " " + name + " to " + typeof(T).Name); } else { FLog.Warning("SafeGetState: Unable to find " + name + ", type <" + typeof(T).Name + ">"); } return default(T); } public T GetState<T>(string name) { return (T)saveInformations.extraStates[name].obj; } [HarmonyPatch(typeof(GameSaveService), "SaveState")] [HarmonyPostfix] private static void GameSaveService_SaveState_PostPatch(GameService __instance, ref UniTask __result) { IExtraStateService service = CustomServiceManager.GetService<IExtraStateService>(); service.SaveAllStates(); } [HarmonyPatch(typeof(GameSaveService), "ForceSaveState")] [HarmonyPostfix] private static void GameSaveService_ForceSaveState_PostPatch(GameService __instance) { IExtraStateService service = CustomServiceManager.GetService<IExtraStateService>(); service.SaveAllStates(); } } public interface IDynamicBuildingStateService { void AddDecorationPercent(string decorationName, float percent); void AddAllDecorationPercent(float percent); float GetDecorationPercent(string decorationName); int GetDecorationAmount(DecorationTier tier); } public interface IDynamicGoodTypeService { ModifyGoodTypeStatesTracker GetStateTracker { get; } void GoodRemoveTag(string goodName, string tagName); void GoodAddTag(string goodName, string tagName); void GoodSetEatable(string goodName, bool state); } public interface IDynamicHearthService { void AddHearthRequirePopPercent(float v); void AddHearthRequirePopCount(int v); } public interface IDynamicTraderInfoService { DynamicTraderInfoData DynamicTraderState { get; } TraderModel GetForceTrader(); void AddForceTrader(string name); void RemoveForceTrader(string name); void RemoveAssaultTrader(string name); void ResetNextTrader(); void SetEffectFreeChance(string traderName, float chance); void AddEffectFreeChance(string traderName, float chance); } public interface IExtraStateService { T GetState<T>(string name); T GetStateSafe<T>(string name); void SaveAllStates(); UniTask LoadAllStates(); } public enum SaveLoadType { Game, App, Meta, World, Unknown } [AttributeUsage(AttributeTargets.Field)] public class ModSerializedFieldAttribute : Attribute { public SaveLoadType SLType { get; } public string SaveName { get; } public ModSerializedFieldAttribute(SaveLoadType type = SaveLoadType.Unknown, string saveName = "") { SLType = type; SaveName = saveName; } } } namespace Forwindz.Framework.Hooks { public class CustomHookedEffectsController { private static CustomHookedEffectsController instance; private Dictionary<HookLogicType, IHookMonitor> typeMonitorMapping = new Dictionary<HookLogicType, IHookMonitor>(); public static CustomHookedEffectsController Instance => instance; static CustomHookedEffectsController() { instance = new CustomHookedEffectsController(); PatchesManager.RegPatch<CustomHookedEffectsController>(); } public static T Register<T>(HookLogicType hookLogicType) where T : IHookMonitor, new() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) T val = new T(); Register(hookLogicType, (IHookMonitor)(object)val); return val; } public static void Register(HookLogicType hookLogicType, IHookMonitor monitor) { //IL_000d: 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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) Dictionary<HookLogicType, IHookMonitor> dictionary = Instance.typeMonitorMapping; if (dictionary.ContainsKey(hookLogicType)) { FLog.Error($"Already Registered HookLogicType {hookLogicType}! This will overwrite the previous reg!"); } dictionary[hookLogicType] = monitor; FLog.Info($"Reg enum {hookLogicType} = {((object)monitor).GetType().Name}"); } [HarmonyPatch(typeof(HookedEffectsController), "OnDestroy")] [HarmonyPostfix] private static void HookedEffectsController_OnDestroy_PostPatch(HookedEffectsController __instance) { Dictionary<HookLogicType, IHookMonitor> dictionary = Instance.typeMonitorMapping; foreach (IHookMonitor value in dictionary.Values) { value.Dispose(); } } [HarmonyPatch(typeof(HookedEffectsController), "GetMonitorFor")] [HarmonyPrefix] private static bool HookedEffectsController_GetMonitorFor_PrePatch(HookLogicType type, ref IHookMonitor __result) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) Dictionary<HookLogicType, IHookMonitor> dictionary = Instance.typeMonitorMapping; if (dictionary.TryGetValue(type, out var value)) { __result = value; return false; } return true; } } public class BuildingCompletedHook : HookLogic { [NewCustomEnum(null, null)] public static readonly HookLogicType EnumBuildingComplete; [Min(0f)] public int amount = 1; public bool ignoreDecorationBuildings = true; public bool ignoreRoads = true; public override HookLogicType Type => EnumBuildingComplete; static BuildingCompletedHook() { CustomIntEnumManager<HookLogicType>.ScanAndAssignEnumValues<BuildingCompletedHook>(); } public override bool CanBeDrawn() { return true; } public override string GetAmountText() { return amount.ToString(); } public override int GetIntAmount() { return amount; } public override bool HasImpactOn(BuildingModel building) { return false; } } public class BuildingCompletedMonitor : HookMonitor<BuildingCompletedHook, BuildingCompletedTracker> { static BuildingCompletedMonitor() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) CustomHookedEffectsController.Register<BuildingCompletedMonitor>(BuildingCompletedHook.EnumBuildingComplete); } public override void AddHandle(BuildingCompletedTracker tracker) { ((HookTracker<BuildingCompletedHook>)tracker).handle.Add(ObservableExtensions.Subscribe<Building>(CustomServiceManager.GetService<BuildingMonitorService>().OnBuildingConstructionFinished, (Action<Building>)tracker.Update)); } public override BuildingCompletedTracker CreateTracker(HookState state, BuildingCompletedHook model, HookedEffectModel effectModel, HookedEffectState effectState) { return new BuildingCompletedTracker(state, model, effectModel, effectState); } public override void InitValue(BuildingCompletedTracker tracker) { tracker.SetAmount(((HookMonitor<BuildingCompletedHook, BuildingCompletedTracker>)this).GetInitValueFor(((HookTracker<BuildingCompletedHook>)tracker).model)); } public override int GetInitValueFor(BuildingCompletedHook model) { BuildingMonitorService service = CustomServiceManager.GetService<BuildingMonitorService>(); int num = service.state.buildingsCompleted; if (model.ignoreDecorationBuildings) { num -= service.state.decorationBuildingsCompleted; } if (model.ignoreRoads) { num -= service.state.roadsCompleted; } return num; } public override int GetInitProgressFor(BuildingCompletedHook model) { return ((HookMonitor<BuildingCompletedHook, BuildingCompletedTracker>)this).GetInitValueFor(model) % model.amount; } public override int GetFiredAmountPreviewFor(BuildingCompletedHook model) { return ((HookMonitor<BuildingCompletedHook, BuildingCompletedTracker>)this).GetInitValueFor(model) / model.amount; } } public class BuildingCompletedTracker : HookTracker<BuildingCompletedHook> { public BuildingCompletedTracker(HookState hookState, BuildingCompletedHook model, HookedEffectModel effectModel, HookedEffectState effectState) : base(hookState, model, effectModel, effectState) { } public void Update(Building building) { string name = ((Object)building.BuildingModel.category).name; Debug.Log((object)("Building has category " + name)); if ((!base.model.ignoreDecorationBuildings || !BuildingHelper.IsDecorationBuilding(building)) && (!base.model.ignoreRoads || !BuildingHelper.IsRoad(building))) { Update(1); } } public void SetAmount(int amount) { Update(amount - base.hookState.totalAmount); } private void Update(int amount) { HookState hookState = base.hookState; hookState.totalAmount += amount; HookState hookState2 = base.hookState; hookState2.currentAmount += amount; while (base.hookState.currentAmount >= base.model.amount) { base.Fire(); HookState hookState3 = base.hookState; hookState3.currentAmount -= base.model.amount; } } } public class DecorationHook : HookLogic { [NewCustomEnum(null, null)] public static readonly HookLogicType EnumDecorationPoints; public DecorationTier decorationTier; public int amount; public override HookLogicType Type => EnumDecorationPoints; public override string FormatedDescription => ((Serviceable)this).TryFormat(base.description.Text, (object)((LabelModel)decorationTier).displayName.Text, (object)amount); public override string GetDescriptionInfo => "{0} - decoration tier, {1} - value"; static DecorationHook() { CustomIntEnumManager<HookLogicType>.ScanAndAssignEnumValues<DecorationHook>(); } public override string GetAmountText() { return amount.ToString(); } public override int GetIntAmount() { return amount; } public override bool HasImpactOn(BuildingModel building) { return false; } } public class DecorationMonitor : HookMonitor<DecorationHook, DecorationTracker> { static DecorationMonitor() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) CustomHookedEffectsController.Register<DecorationMonitor>(DecorationHook.EnumDecorationPoints); } public override void AddHandle(DecorationTracker tracker) { BuildingMonitorService service = CustomServiceManager.GetService<BuildingMonitorService>(); ((HookTracker<DecorationHook>)tracker).handle.Add(ObservableExtensions.Subscribe<Building>(service.OnBuildingConstructionFinished, (Action<Building>)tracker.OnAddBuilding)); ((HookTracker<DecorationHook>)tracker).handle.Add(ObservableExtensions.Subscribe<Building>(service.OnBuildingRemovedFinished, (Action<Building>)tracker.OnRemoveBuilding)); DynamicBuildingStateService service2 = CustomServiceManager.GetService<DynamicBuildingStateService>(); ((HookTracker<DecorationHook>)tracker).handle.Add(ObservableExtensions.Subscribe<Dictionary<string, DynamicDecorationStateInfo>>(service2.OnDecorationValueChange, (Action<Dictionary<string, DynamicDecorationStateInfo>>)delegate { tracker.Recalculate(); })); } public override DecorationTracker CreateTracker(HookState state, DecorationHook model, HookedEffectModel effectModel, HookedEffectState effectState) { return new DecorationTracker(state, model, effectModel, effectState); } public override void InitValue(DecorationTracker tracker) { tracker.Recalculate(); } public override int GetInitValueFor(DecorationHook model) { return BuildingHelper.CountDecorationValue(model.decorationTier); } public override int GetInitProgressFor(DecorationHook model) { return ((HookMonitor<DecorationHook, DecorationTracker>)this).GetInitValueFor(model) % model.amount; } public override int GetFiredAmountPreviewFor(DecorationHook model) { return ((HookMonitor<DecorationHook, DecorationTracker>)this).GetInitValueFor(model) / model.amount; } } public class DecorationTracker : HookTracker<DecorationHook> { public DecorationTracker(HookState hookState, DecorationHook model, HookedEffectModel effectModel, HookedEffectState effectState) : base(hookState, model, effectModel, effectState) { Recalculate(); } public void OnAddBuilding(Building building) { Decoration val = (Decoration)(object)((building is Decoration) ? building : null); if (!((Object)(object)val == (Object)null) && val.model.hasDecorationTier && (Object)(object)val.model.tier == (Object)(object)base.model.decorationTier) { Recalculate(); } } public void OnRemoveBuilding(Building building) { Decoration val = (Decoration)(object)((building is Decoration) ? building : null); if (!((Object)(object)val == (Object)null) && val.model.hasDecorationTier && (Object)(object)val.model.tier == (Object)(object)base.model.decorationTier) { Recalculate(); } } public void Recalculate() { int num = BuildingHelper.CountDecorationValue(base.model.decorationTier); FLog.Info($"Decoration Tracker: {((Object)base.model.decorationTier).name} > CurNum={base.hookState.totalAmount} > {base.hookState.currentAmount} | UpdateToNum={num} | curFireCount={base.hookState.firedAmount}"); UpdateTo(num); } private void UpdateTo(int amount) { Update(amount - base.hookState.totalAmount); } private void Update(int amount) { HookState hookState = base.hookState; hookState.totalAmount += amount; HookState hookState2 = base.hookState; hookState2.currentAmount += amount; while (base.hookState.currentAmount >= base.model.amount) { base.Fire(); HookState hookState3 = base.hookState; hookState3.currentAmount -= base.model.amount; } while (base.hookState.currentAmount < 0) { base.Revert(); HookState hookState4 = base.hookState; hookState4.currentAmount += base.model.amount; } } } } namespace Forwindz.Framework.Ef