Пример #1
0
        /// <summary>
        /// Safely adds a new crafting node to the custom crafting tree of this fabricator.<para/>
        /// If the item has not been patched yet, its <see cref="Spawnable.Patch"/> method will first be invoked.
        /// </summary>
        /// <param name="item">The <see cref="Craftable"/> item to craft from this fabricator.</param>
        /// <param name="parentTabId">Optional. The parent tab of this craft node.<para/>
        /// When this value is null, the item's <see cref="Craftable.StepsToFabricatorTab"/> property will be checked instead.<para/>
        /// The craft node will be added to the root of the craft tree if both are null.</param>
        public void AddCraftNode(Craftable item, string parentTabId = null)
        {
            Logger.Debug($"'{item.ClassID}' will be added to the custom craft tree '{this.ClassID}'");
            OrderedCraftTreeActions.Add(() =>
            {
                if (item.TechType == TechType.None)
                {
                    Logger.Info($"'{item.ClassID} had to be patched early to obtain its TechType value for the custom craft tree '{this.ClassID}'");
                    item.Patch();
                }

                string[] stepsToParent = item.StepsToFabricatorTab;

                if (parentTabId == null)
                {
                    if (stepsToParent != null && stepsToParent.Length > 0)
                    {
                        int last    = stepsToParent.Length - 1;
                        parentTabId = stepsToParent[last];
                    }
                    else
                    {
                        parentTabId = RootNode;
                    }
                }

                ModCraftTreeLinkingNode parentTab = CraftTreeLinkingNodes[parentTabId];
                parentTab.AddCraftingNode(item.TechType);
            });
        }
        internal static void Patch(Harmony harmony)
        {
            harmony.Patch(AccessTools.Method(typeof(LootDistributionData), nameof(LootDistributionData.Initialize)),
                          postfix: new HarmonyMethod(AccessTools.Method(typeof(LootDistributionPatcher), nameof(LootDistributionPatcher.InitializePostfix))));

            Logger.Log("LootDistributionPatcher is done.", LogLevel.Debug);
        }
Пример #3
0
        internal void AddCompoundUnlock(TechType techType, List <TechType> compoundTechsForUnlock)
        {
            if (techType == TechType.None)
            {
                Logger.Error("Cannot Add Unlock to TechType.None!");
                return;
            }

            if (compoundTechsForUnlock.Contains(techType))
            {
                Logger.Error("Cannot Add Compound Unlock that contains itself!");
                return;
            }


            if (KnownTechPatcher.CompoundTech.TryGetValue(techType, out KnownTech.CompoundTech compoundTech))
            {
                Logger.Debug($"Compound Unlock already found for {techType.AsString()}, Overwriting.");
                compoundTech.dependencies = compoundTechsForUnlock;
            }
            else
            {
                Logger.Debug($"Adding Compound Unlock for {techType.AsString()}");
                KnownTechPatcher.CompoundTech.Add(techType, new KnownTech.CompoundTech()
                {
                    techType = techType, dependencies = compoundTechsForUnlock
                });
            }
        }
Пример #4
0
 internal void AddAnalysisTech(TechType techTypeToBeAnalysed, IEnumerable <TechType> techTypesToUnlock, string UnlockMessage = "NotificationBlueprintUnlocked", FMODAsset UnlockSound = null, UnityEngine.Sprite UnlockSprite = null)
 {
     if (techTypeToBeAnalysed != TechType.None)
     {
         if (KnownTechPatcher.AnalysisTech.TryGetValue(techTypeToBeAnalysed, out KnownTech.AnalysisTech existingEntry))
         {
             existingEntry.unlockMessage = existingEntry.unlockMessage ?? UnlockMessage;
             existingEntry.unlockSound   = existingEntry.unlockSound ?? UnlockSound;
             existingEntry.unlockPopup   = existingEntry.unlockPopup ?? UnlockSprite;
             existingEntry.unlockTechTypes.AddRange(techTypesToUnlock);
         }
         else
         {
             KnownTechPatcher.AnalysisTech.Add(techTypeToBeAnalysed, new KnownTech.AnalysisTech()
             {
                 techType        = techTypeToBeAnalysed,
                 unlockMessage   = UnlockMessage,
                 unlockSound     = UnlockSound,
                 unlockPopup     = UnlockSprite,
                 unlockTechTypes = new List <TechType>(techTypesToUnlock)
             });
         }
     }
     else
     {
         Logger.Error("Cannot Add Unlock to TechType.None!");
     }
 }
Пример #5
0
        internal void RemoveAnalysisTechEntry(TechType targetTechType)
        {
            foreach (KnownTech.AnalysisTech tech in KnownTechPatcher.AnalysisTech.Values)
            {
                if (tech.unlockTechTypes.Contains(targetTechType))
                {
                    Logger.Debug($"Removed {targetTechType.AsString()} from {tech.techType.AsString()} unlocks that was added by another mod!");
                    tech.unlockTechTypes.Remove(targetTechType);
                }
            }

            if (KnownTechPatcher.CompoundTech.TryGetValue(targetTechType, out var types))
            {
                Logger.Debug($"Removed Compound Unlock for {targetTechType.AsString()} that was added by another mod!");
                KnownTechPatcher.CompoundTech.Remove(targetTechType);
            }

            if (KnownTechPatcher.UnlockedAtStart.Contains(targetTechType))
            {
                Logger.Debug($"Removed UnlockedAtStart for {targetTechType.AsString()} that was added by another mod!");
                KnownTechPatcher.UnlockedAtStart.Remove(targetTechType);
            }

            if (!KnownTechPatcher.RemovalTechs.Contains(targetTechType))
            {
                KnownTechPatcher.RemovalTechs.Add(targetTechType);
            }
        }
Пример #6
0
 /// <summary>
 /// Adds a new crafting node to the custom crafting tree of this fabricator.
 /// </summary>
 /// <param name="techType">The item to craft.</param>
 /// <param name="parentTabId">Optional. The parent tab of this craft node.<para/>
 /// When this value is null, the craft node will be added to the root of the craft tree.</param>
 public void AddCraftNode(TechType techType, string parentTabId = null)
 {
     Logger.Debug($"'{techType.AsString()}' will be added to the custom craft tree '{this.ClassID}'");
     OrderedCraftTreeActions.Add(() =>
     {
         ModCraftTreeLinkingNode parentTab = CraftTreeLinkingNodes[parentTabId ?? RootNode];
         parentTab.AddCraftingNode(techType);
     });
 }
Пример #7
0
        private static void AddPrefabInternal(GameObject prefab, bool autoremove)
        {
            if (autoremove)
            {
                prefabs.Add(Tuple.Create(Time.time, prefab));
            }

            Logger.Debug($"ModPrefabCache: adding prefab {prefab}");
        }
Пример #8
0
        public static void Patch(Harmony harmony)
        {
            Type creatureType = typeof(Creature);
            Type thisType     = typeof(FishPatcher);

            harmony.Patch(AccessTools.Method(typeof(Creature), nameof(Creature.Start)),
                          postfix: new HarmonyMethod(typeof(FishPatcher), nameof(FishPatcher.CreatureStart_Postfix)));

            Logger.Debug("CustomFishPatcher is done.");
        }
Пример #9
0
        internal static void Patch(HarmonyInstance harmony)
        {
            harmony.Patch(AccessTools.Method(typeof(PrefabDatabase), nameof(PrefabDatabase.LoadPrefabDatabase)),
                          postfix: new HarmonyMethod(AccessTools.Method(typeof(PrefabDatabasePatcher), nameof(PrefabDatabasePatcher.LoadPrefabDatabase_Postfix))));

            harmony.Patch(AccessTools.Method(typeof(PrefabDatabase), nameof(PrefabDatabase.GetPrefabForFilename)),
                          prefix: new HarmonyMethod(AccessTools.Method(typeof(PrefabDatabasePatcher), nameof(PrefabDatabasePatcher.GetPrefabForFilename_Prefix))));

            harmony.Patch(AccessTools.Method(typeof(PrefabDatabase), nameof(PrefabDatabase.GetPrefabAsync)),
                          prefix: new HarmonyMethod(AccessTools.Method(typeof(PrefabDatabasePatcher), nameof(PrefabDatabasePatcher.GetPrefabAsync_Prefix))));

            Logger.Log("PrefabDatabasePatcher is done.", LogLevel.Debug);
        }
Пример #10
0
        internal static void PrePatch(Harmony harmony)
        {
            PatchUtils.PatchClass(harmony);

#if !SUBNAUTICA_STABLE
            // patching iterator method ProtobufSerializer.DeserializeObjectsAsync
            MethodInfo DeserializeObjectsAsync = typeof(ProtobufSerializer).GetMethod(
                nameof(ProtobufSerializer.DeserializeObjectsAsync), BindingFlags.NonPublic | BindingFlags.Instance);
            harmony.Patch(PatchUtils.GetIteratorMethod(DeserializeObjectsAsync), transpiler:
                          new HarmonyMethod(AccessTools.Method(typeof(PrefabDatabasePatcher), nameof(DeserializeObjectsAsync_Transpiler))));
#endif
            Logger.Log("PrefabDatabasePatcher is done.", LogLevel.Debug);
        }
Пример #11
0
            public void Update()
            {
                for (int i = prefabs.Count - 1; i >= 0; i--)
                {
                    if (Time.time < prefabs[i].Item1 + cleanDelay || Builder.prefab == prefabs[i].Item2)
                    {
                        continue;
                    }

                    Logger.Debug($"ModPrefabCache: removing prefab {prefabs[i].Item2}");

                    Destroy(prefabs[i].Item2);
                    prefabs.RemoveAt(i);
                }
            }
Пример #12
0
 /// <summary>
 /// Safely attempts to add a new crafting node to the custom crafting tree of this fabricator.<para/>
 /// If the modded TechType is not found, the craft node will not be added.
 /// </summary>
 /// <param name="moddedTechType">The modded item to craft.</param>
 /// <param name="parentTabId">Optional. The parent tab of this craft node.<para/>
 /// When this value is null, the craft node will be added to the root of the craft tree.</param>
 public void AddCraftNode(string moddedTechType, string parentTabId = null)
 {
     Logger.Debug($"'{moddedTechType}' will be added to the custom craft tree '{this.ClassID}'");
     OrderedCraftTreeActions.Add(() =>
     {
         if (this.TechTypeHandler.TryGetModdedTechType(moddedTechType, out TechType techType))
         {
             ModCraftTreeLinkingNode parentTab = CraftTreeLinkingNodes[parentTabId ?? RootNode];
             parentTab.AddCraftingNode(techType);
         }
         else
         {
             Logger.Info($"Did not find a TechType value for '{moddedTechType}' to add to the custom craft tree '{this.ClassID}'");
         }
     });
 }
Пример #13
0
        private void Update()
        {
            if (!initalized)
            {
                time       = Time.time + 1f;
                initalized = true;
            }

            var prefab = (GameObject)BuilderPrefab.GetValue(null);

            if (transform.position == new Vector3(-5000, -5000, -5000) && gameObject != prefab && Time.time > time)
            {
                Logger.Debug("Destroying object: " + gameObject);
                Destroy(gameObject);
            }
        }
        internal static void PrePatch(Harmony harmony)
        {
            PatchUtils.PatchClass(harmony);

            var obsoleteInstantiatePrefabAsync = AccessTools.Method(typeof(ProtobufSerializer), nameof(ProtobufSerializer.InstantiatePrefabAsync),
                                                                    new[] { typeof(ProtobufSerializer.GameObjectData) });

            if (obsoleteInstantiatePrefabAsync == null) // it means that we have async-only prefabs now, otherwise patch will fail
            {
                // patching iterator method ProtobufSerializer.DeserializeObjectsAsync
                MethodInfo DeserializeObjectsAsync = typeof(ProtobufSerializer).GetMethod(
                    nameof(ProtobufSerializer.DeserializeObjectsAsync), BindingFlags.NonPublic | BindingFlags.Instance);
                harmony.Patch(PatchUtils.GetIteratorMethod(DeserializeObjectsAsync), transpiler:
                              new HarmonyMethod(AccessTools.Method(typeof(PrefabDatabasePatcher), nameof(DeserializeObjectsAsync_Transpiler))));
            }

            Logger.Log("PrefabDatabasePatcher is done.", LogLevel.Debug);
        }
Пример #15
0
        internal static void Patch(HarmonyInstance harmony)
        {
            Type       prefabDatabaseType   = typeof(PrefabDatabase);
            MethodInfo loadPrefabDatabase   = prefabDatabaseType.GetMethod("LoadPrefabDatabase", BindingFlags.Public | BindingFlags.Static);
            MethodInfo getPrefabForFilename = prefabDatabaseType.GetMethod("GetPrefabForFilename", BindingFlags.Public | BindingFlags.Static);
            MethodInfo getPrefabAsync       = prefabDatabaseType.GetMethod("GetPrefabAsync", BindingFlags.Public | BindingFlags.Static);

            harmony.Patch(loadPrefabDatabase, null,
                          new HarmonyMethod(typeof(PrefabDatabasePatcher).GetMethod("LoadPrefabDatabase_Postfix", BindingFlags.NonPublic | BindingFlags.Static)));

            harmony.Patch(getPrefabForFilename,
                          new HarmonyMethod(typeof(PrefabDatabasePatcher).GetMethod("GetPrefabForFilename_Prefix", BindingFlags.Static | BindingFlags.NonPublic)), null);

            harmony.Patch(getPrefabAsync,
                          new HarmonyMethod(typeof(PrefabDatabasePatcher).GetMethod("GetPrefabAsync_Prefix", BindingFlags.Static | BindingFlags.NonPublic)), null);

            Logger.Log("PrefabDatabasePatcher is done.", LogLevel.Debug);
        }
Пример #16
0
        private void Update()
        {
            if (!initalized)
            {
                time       = Time.time + 1f;
                initalized = true;
            }

            if (Time.time > time && this.gameObject != Builder.prefab)
            {
                if (this.transform.position.y < -4500)
                {
                    Logger.Debug("Destroying object: " + this.gameObject);
                    Destroy(this.gameObject);
                }
                else
                {
                    Logger.Debug("Destroying Fixer for object: " + this.gameObject);
                    Destroy(this);
                }
            }
        }
        private static IPrefabRequest GetModPrefabAsync(string classId)
        {
            if (!ModPrefab.TryGetFromClassId(classId, out ModPrefab prefab))
            {
                return(null);
            }

            try
            {
                // trying sync method first
                if (prefab.GetGameObjectInternal() is GameObject go)
                {
                    return(new LoadedPrefabRequest(go));
                }
            }
            catch (Exception e)
            {
                Logger.Debug($"Caught exception while calling GetGameObject for {classId}, trying GetGameObjectAsync now. {Environment.NewLine}{e}");
            }

            return(new ModPrefabRequest(prefab));
        }
Пример #18
0
        /// <summary>
        /// Creates a new <see cref="Texture2D" /> from an image file.
        /// </summary>
        /// <param name="filePathToImage">The path to the image file.</param>
        /// <param name="format">
        /// <para>The texture format. By default, this uses <see cref="TextureFormat.BC7" />.</para>
        /// <para>https://docs.unity3d.com/ScriptReference/TextureFormat.BC7.html</para>
        /// <para>Don't change this unless you really know what you're doing.</para>
        /// </param>
        /// <returns>Will return a new <see cref="Texture2D"/> instance if the file exists; Otherwise returns null.</returns>
        /// <remarks>
        /// Ripped from: https://github.com/RandyKnapp/SubnauticaModSystem/blob/master/SubnauticaModSystem/Common/Utility/ImageUtils.cs
        /// </remarks>
        public static Texture2D LoadTextureFromFile(string filePathToImage, TextureFormat format = TextureFormat.BC7)
        {
            if (File.Exists(filePathToImage))
            {
                byte[]    imageBytes = File.ReadAllBytes(filePathToImage);
                Texture2D texture2D  = new Texture2D(2, 2, format, false);
                if (texture2D.LoadImage(imageBytes))
                {
                    return(texture2D);
                }
                else
                {
                    Logger.Log("Error on LoadTextureFromFile call. Texture cannot be loaded: " + filePathToImage, LogLevel.Error);
                }
            }
            else
            {
                Logger.Log("Error on LoadTextureFromFile call. File not found at " + filePathToImage, LogLevel.Error);
            }

            return(null);
        }
        internal static void PostPatch(Harmony harmony)
        {
            PatchUtils.PatchClass(harmony, typeof(PostPatches));

            Logger.Log("PrefabDatabasePostPatcher is done.", LogLevel.Debug);
        }