diff --git a/FastTrack/CritterPatches/ThreatAndCrowdPatches.cs b/FastTrack/CritterPatches/ThreatAndCrowdPatches.cs index 84038545..324614fa 100644 --- a/FastTrack/CritterPatches/ThreatAndCrowdPatches.cs +++ b/FastTrack/CritterPatches/ThreatAndCrowdPatches.cs @@ -17,7 +17,6 @@ */ using HarmonyLib; -using PeterHan.PLib.Core; #if DEBUG using PeterHan.PLib.Core; #endif diff --git a/FastTrack/FastTrack.csproj b/FastTrack/FastTrack.csproj index b80719b7..38efb855 100644 --- a/FastTrack/FastTrack.csproj +++ b/FastTrack/FastTrack.csproj @@ -2,11 +2,11 @@ Fast Track - 0.13.6.0 + 0.14.0.0 PeterHan.FastTrack Optimizes Oxygen Not Included to improve performance. - 0.14.0.0 - 596100 + 0.15.0.0 + 616718 Vanilla;Mergedown true true diff --git a/FastTrack/UIPatches/DetailsPanelWrapper.cs b/FastTrack/UIPatches/DetailsPanelWrapper.cs index a4f53a43..36a90b53 100644 --- a/FastTrack/UIPatches/DetailsPanelWrapper.cs +++ b/FastTrack/UIPatches/DetailsPanelWrapper.cs @@ -82,19 +82,15 @@ private static string GetCodexLink(GameObject go, CellSelectionObject cso) { codexText = FormatLinkID(building.Def.PrefabID); else if (go.TryGetComponent(out KPrefabID id)) { string prefabID = id.PrefabTag.ToString(); + PlantBranch.Instance smi; if (id.HasTag(GameTags.Creature)) codexText = FormatLinkID(prefabID, "BABY", ""); else if (id.HasTag(GameTags.Plant)) codexText = FormatLinkID(prefabID, "SEED", ""); - else if (go.TryGetComponent(out BudUprootedMonitor monitor)) { - KPrefabID parent; - BuddingTrunk trunk; - if ((parent = monitor.parentObject.Get()) != null) - codexText = FormatLinkID(parent.PrefabTag.ToString()); - else if (go.TryGetComponent(out TreeBud bud) && (trunk = bud.buddingTrunk. - Get()) != null) - // Special case for trees? - codexText = FormatLinkID(trunk.PrefabID().ToString()); + else if ((smi = go.GetSMI()) != null) { + var parent = smi.trunk; + if (parent != null && (id = parent.GetComponent()) != null) + codexText = FormatLinkID(id.PrefabTag.ToString()); else codexText = FormatLinkID(prefabID); } else @@ -361,7 +357,7 @@ internal static bool Prefix(DetailsScreen __instance, string newName) { /// /// Applied to DetailsScreen to make opening the codex entry much faster! /// - [HarmonyPatch(typeof(DetailsScreen), nameof(DetailsScreen.OpenCodexEntry))] + [HarmonyPatch(typeof(DetailsScreen), nameof(DetailsScreen.CodexEntryButton_OnClick))] internal static class OpenCodexEntry_Patch { internal static bool Prepare() => FastTrackOptions.Instance.SideScreenOpts; diff --git a/MooReproduction/MooReproduction.csproj b/MooReproduction/MooReproduction.csproj index 60833b93..73132820 100644 --- a/MooReproduction/MooReproduction.csproj +++ b/MooReproduction/MooReproduction.csproj @@ -2,7 +2,7 @@ Moo Reproduction - 2.8.0.0 + 2.9.0.0 PeterHan.MooReproduction Allows Gassy Moos to reproduce, giving live birth like mammals should. 2.2.0.0 diff --git a/MoreAchievements/AchievementStateComponent.cs b/MoreAchievements/AchievementStateComponent.cs index 42c5fa79..e60ce053 100644 --- a/MoreAchievements/AchievementStateComponent.cs +++ b/MoreAchievements/AchievementStateComponent.cs @@ -57,11 +57,11 @@ public static void OnCritterKilled() { /// The cause of death. public static void OnDeath(Death cause) { var asc = Instance; - var instance = GameClock.Instance; + var gc = GameClock.Instance; if (cause != null) { Trigger(DeathFromCause.PREFIX + cause.Id); - if (instance != null) - asc.LastDeath = instance.GetCycle(); + if (gc != null) + asc.LastDeath = gc.GetCycle(); } } @@ -79,7 +79,7 @@ public static void OnGeneShuffleComplete() { /// /// The rating of the overloaded wire. public static void OnOverload(Wire.WattageRating rating) { - Trigger(OverloadWire.PREFIX + rating.ToString()); + Trigger(OverloadWire.PREFIX + rating); } /// @@ -87,7 +87,9 @@ public static void OnOverload(Wire.WattageRating rating) { /// /// The destination of the mission. public static void OnVisit(int destination) { - Instance?.PlanetsVisited?.Add(destination); + var asc = Instance; + if (asc != null) + asc.PlanetsVisited?.Add(destination); } /// @@ -95,11 +97,12 @@ public static void OnVisit(int destination) { /// /// The requirement ID to trigger. public static void Trigger(string achievement) { - if (!string.IsNullOrEmpty(achievement)) { + var asc = Instance; + if (!string.IsNullOrEmpty(achievement) && asc != null) { #if DEBUG PUtil.LogDebug("Achievement requirement triggered: " + achievement); #endif - var te = Instance?.TriggerEvents; + var te = asc.TriggerEvents; if (te != null) te[achievement] = true; } @@ -230,9 +233,9 @@ public AchievementStateComponent() { private void InitGrimReaper() { // Look for the last dip in Duplicant count float lastValue = -1.0f; - RetiredColonyData.RetiredColonyStatistic[] stats; try { var data = RetireColonyUtility.GetCurrentColonyRetiredColonyData(); + RetiredColonyData.RetiredColonyStatistic[] stats; if ((stats = data?.Stats) != null && data.cycleCount > 0) { var liveDupes = new SortedList(stats.Length); // Copy and sort the values @@ -253,9 +256,11 @@ private void InitGrimReaper() { liveDupes.Clear(); } } catch (Exception e) { + var gc = GameClock.Instance; PUtil.LogWarning("Unable to determine the last date of death:"); PUtil.LogExcWarn(e); - LastDeath = GameClock.Instance?.GetCycle() ?? 0; + if (gc != null) + LastDeath = gc.GetCycle(); } } @@ -302,7 +307,7 @@ protected override void OnSpawn() { if (LastDeath <= 0) InitGrimReaper(); var dbAttr = Db.Get().Attributes; - VarietyAttributes = new Klei.AI.Attribute[] { dbAttr.Art, dbAttr.Athletics, + VarietyAttributes = new[] { dbAttr.Art, dbAttr.Athletics, dbAttr.Botanist, dbAttr.Caring, dbAttr.Construction, dbAttr.Cooking, dbAttr.Digging, dbAttr.Learning, dbAttr.Machinery, dbAttr.Ranching, dbAttr.Strength }; @@ -315,11 +320,11 @@ protected override void OnSpawn() { PlanetsRequired = ClusterManager.Instance.worldCount; else { // VANILLA STARMAP - var dest = SpacecraftManager.instance?.destinations; - if (dest != null) { + var si = SpacecraftManager.instance; + if (si != null && si.destinations != null) { int count = 0; // Exclude unreachable destinations (earth) but include temporal tear - foreach (var destination in dest) + foreach (var destination in si.destinations) if (destination.GetDestinationType()?.visitable == true) count++; if (count > 0) @@ -336,8 +341,8 @@ public void Sim1000ms(float dt) { int have = 0; // Count artifacts discovered foreach (var pair in ArtifactConfig.artifactItems) - foreach (string name in pair.Value) - if (DiscoveredResources.Instance.IsDiscovered(Assets.GetPrefab(name). + foreach (string artName in pair.Value) + if (DiscoveredResources.Instance.IsDiscovered(Assets.GetPrefab(artName). PrefabID())) have++; ArtifactsObtained = have; diff --git a/MoreAchievements/MoreAchievementsAPI.cs b/MoreAchievements/MoreAchievementsAPI.cs index 397d580e..8e19af58 100644 --- a/MoreAchievements/MoreAchievementsAPI.cs +++ b/MoreAchievements/MoreAchievementsAPI.cs @@ -37,25 +37,43 @@ public sealed class MoreAchievementsAPI : PForwardedComponent { /// /// The version of this component. /// - internal static readonly Version VERSION = new Version(1, 0, 0, 0); + internal static readonly Version VERSION = new Version(1, 1, 0, 0); + + private static void FilterAchievements_Postfix( + Dictionary ___achievementEntries) { + var inst = Instance; + if (inst != null) + foreach (var pair in ___achievementEntries) { + var obj = pair.Value; + string id = pair.Key; + var info = inst.GetAchievement(id); + if (obj != null && obj.TryGetComponent(out MultiToggle toggle) && + info != null && info.Hidden) + // Hide achievements that have never been achieved + obj.SetActive(toggle.CurrentState != 2); + } + } private static void UpdateAchievementData_Postfix(string[] newlyAchieved, Dictionary ___achievementEntries) { - var newly = HashSetPool.Allocate(); - // Achievements just obtained should always be shown - if (newlyAchieved != null) - foreach (string achieved in newlyAchieved) - newly.Add(achieved); - foreach (var pair in ___achievementEntries) { - var obj = pair.Value; - string id = pair.Key; - var info = Instance?.GetAchievement(id); - if (obj != null && obj.TryGetComponent(out MultiToggle toggle) && - info != null && info.Hidden) - // Hide achievements that have never been achieved - obj.SetActive(toggle.CurrentState != 2 || newly.Contains(id)); + var inst = Instance; + if (inst != null) { + var newly = HashSetPool.Allocate(); + // Achievements just obtained should always be shown + if (newlyAchieved != null) + foreach (string achieved in newlyAchieved) + newly.Add(achieved); + foreach (var pair in ___achievementEntries) { + var obj = pair.Value; + string id = pair.Key; + var info = inst.GetAchievement(id); + if (obj != null && obj.TryGetComponent(out MultiToggle toggle) && + info != null && info.Hidden) + // Hide achievements that have never been achieved + obj.SetActive(toggle.CurrentState != 2 || newly.Contains(id)); + } + newly.Recycle(); } - newly.Recycle(); } public override Version Version => VERSION; @@ -105,27 +123,28 @@ public void AddAchievementInformation(string id, string category, /// The achievement ID to look up. /// The extra information about that achievement. internal AchievementInfo GetAchievement(string id) { - if (!allAchievements.TryGetValue(id, out AchievementInfo info)) + if (!allAchievements.TryGetValue(id, out var info)) info = null; return info; } public override void Initialize(Harmony plibInstance) { Instance = this; - foreach (var achievementProvider in PRegistry.Instance.GetAllComponents(ID)) - if (achievementProvider != null) { - var toAdd = achievementProvider.GetInstanceDataSerialized>(); - if (toAdd != null) - foreach (var achievement in toAdd) { - allAchievements[achievement.ID] = achievement; + foreach (var achievementProvider in PRegistry.Instance.GetAllComponents(ID)) { + var toAdd = achievementProvider?.GetInstanceDataSerialized>(); + if (toAdd != null) + foreach (var achievement in toAdd) { + allAchievements[achievement.ID] = achievement; #if DEBUG - PUtil.LogDebug("Added data for achievement " + achievement.ID); + PUtil.LogDebug("Added data for achievement " + achievement.ID); #endif - } - } + } + } plibInstance.Patch(typeof(RetiredColonyInfoScreen), "UpdateAchievementData", postfix: PatchMethod(nameof(UpdateAchievementData_Postfix))); + plibInstance.Patch(typeof(RetiredColonyInfoScreen), "FilterAchievements", + postfix: PatchMethod(nameof(FilterAchievements_Postfix))); } /// diff --git a/MoreAchievements/MoreAchievementsPatches.cs b/MoreAchievements/MoreAchievementsPatches.cs index fbf88f43..7b168fc5 100644 --- a/MoreAchievements/MoreAchievementsPatches.cs +++ b/MoreAchievements/MoreAchievementsPatches.cs @@ -136,6 +136,32 @@ public override void OnLoad(Harmony harmony) { true); } + /// + /// Applied to BuildingHP to check for damage from overloading wires. + /// + [HarmonyPatch(typeof(BuildingHP), "OnDoBuildingDamage")] + public static class BuildingHP_OnDoBuildingDamage_Patch { + /// + /// Applied after DoDamage runs. + /// + internal static void Postfix(BuildingHP __instance, object data) { + if (__instance != null && data is BuildingHP.DamageSourceInfo source && + (source.source == STRINGS.BUILDINGS.DAMAGESOURCES.CIRCUIT_OVERLOADED || + source.takeDamageEffect == SpawnFXHashes.BuildingSpark)) { + var obj = __instance.gameObject; +#if DEBUG + PUtil.LogDebug("Wire overloaded: " + obj.name); +#endif + if (obj.TryGetComponent(out Wire wire)) + // Wire is overloading + AchievementStateComponent.OnOverload(wire.GetMaxWattageRating()); + else if (obj.TryGetComponent(out WireUtilityNetworkLink bridge)) + // Wire bridge is overloading + AchievementStateComponent.OnOverload(bridge.GetMaxWattageRating()); + } + } + } + /// /// Applied to BuildingComplete to update the maximum building temperature seen. /// @@ -163,32 +189,6 @@ internal static void Postfix(PrimaryElement ___primaryElement) { } } - /// - /// Applied to BuildingHP to check for damage from overloading wires. - /// - [HarmonyPatch(typeof(BuildingHP), "OnDoBuildingDamage")] - public static class BuildingHP_DoDamage_Patch { - /// - /// Applied after DoDamage runs. - /// - internal static void Postfix(BuildingHP __instance, object data) { - if (__instance != null && data is BuildingHP.DamageSourceInfo source && - (source.source == STRINGS.BUILDINGS.DAMAGESOURCES.CIRCUIT_OVERLOADED || - source.takeDamageEffect == SpawnFXHashes.BuildingSpark)) { - var obj = __instance.gameObject; -#if DEBUG - PUtil.LogDebug("Wire overloaded: " + obj.name); -#endif - if (obj.TryGetComponent(out Wire wire)) - // Wire is overloading - AchievementStateComponent.OnOverload(wire.GetMaxWattageRating()); - else if (obj.TryGetComponent(out WireUtilityNetworkLink bridge)) - // Wire bridge is overloading - AchievementStateComponent.OnOverload(bridge.GetMaxWattageRating()); - } - } - } - /// /// Applied to Butcherable to count dying critters if they die at a young age. /// @@ -275,7 +275,7 @@ internal static void Postfix(bool ___isDigComplete, Diggable __instance) { /// Applied to DiscoveredResources to grant an achievement upon discovering items. /// [HarmonyPatch(typeof(DiscoveredResources), nameof(DiscoveredResources.Discover), - typeof(Tag))] + typeof(Tag), typeof(Tag))] public static class DiscoveredResources_Discover_Patch { /// /// Applied after Discover runs. diff --git a/PLib/PLib.csproj b/PLib/PLib.csproj index f539df6b..f89eff28 100644 --- a/PLib/PLib.csproj +++ b/PLib/PLib.csproj @@ -15,7 +15,7 @@ PLib - Peter Han's library used for creating mods for Oxygen Not Included, a simulation game by Klei Entertainment. Contains methods aimed at improving cross-mod compatibility, in-game user interfaces, and game-wide functions such as Actions and Lighting. An easy-to-use Mod Options menu is also included. - Add compatibility methods to ease porting to U51-595713. + Add compatibility methods to ease porting to U52-622509. PeterHan.PLib $(PLibVersion) false diff --git a/PLibCore/PTranspilerTools.cs b/PLibCore/PTranspilerTools.cs index 6f094087..5712fcfe 100644 --- a/PLibCore/PTranspilerTools.cs +++ b/PLibCore/PTranspilerTools.cs @@ -173,10 +173,13 @@ private static bool GenerateBasicLoad(ILGenerator generator, Type type, object v else if (type == typeof(double)) // double generator.Emit(OpCodes.Ldc_R8, (value is double dVal) ? dVal : 0.0); - else if (type == typeof(string)) + else if (type == typeof(string)) { // string - generator.Emit(OpCodes.Ldstr, (value is string sVal) ? sVal : ""); - else if (type.IsPointer) + if (value == null) + generator.Emit(OpCodes.Ldnull); + else + generator.Emit(OpCodes.Ldstr, (value is string sVal) ? sVal : ""); + } else if (type.IsPointer) // All pointers generator.Emit(OpCodes.Ldc_I4_0); else if (!type.IsValueType) diff --git a/PLibDatabase/PColonyAchievement.cs b/PLibDatabase/PColonyAchievement.cs index 48cb6198..bf614ff6 100644 --- a/PLibDatabase/PColonyAchievement.cs +++ b/PLibDatabase/PColonyAchievement.cs @@ -148,7 +148,7 @@ public PColonyAchievement(string id) { /// public void AddAchievement() { if (Requirements == null) - throw new ArgumentNullException("No colony achievement requirements specified"); + throw new ArgumentNullException(nameof(Requirements)); var achieve = NEW_COLONY_ACHIEVEMENT.Invoke(ID, "", Name, Description, IsVictory, Requirements, VictoryTitle, VictoryMessage, VictoryVideoData, VictoryVideoLoop, OnVictory);