/// <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); }
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 }); } }
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!"); } }
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); } }
/// <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); }); }
private static void AddPrefabInternal(GameObject prefab, bool autoremove) { if (autoremove) { prefabs.Add(Tuple.Create(Time.time, prefab)); } Logger.Debug($"ModPrefabCache: adding prefab {prefab}"); }
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."); }
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); }
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); }
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); } }
/// <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}'"); } }); }
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); }
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); }
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)); }
/// <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); }