From 04a4e0d073c5c2757a8faa72b1f640de4a4dc40b Mon Sep 17 00:00:00 2001 From: zelzmiy <51797223+zelzmiy@users.noreply.github.com> Date: Mon, 9 Sep 2024 19:37:56 -0500 Subject: [PATCH 01/10] WIP CustomSeed / CustomCropManager --- .../CustomCrops/CustomCropManager.cs | 125 ++++++++++++++++++ .../CustomInventory/CustomCrops/CustomSeed.cs | 38 ++++++ .../Patches/CropControllerPatches.cs | 76 +++++++++++ 3 files changed, 239 insertions(+) create mode 100644 COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs create mode 100644 COTL_API/CustomInventory/CustomCrops/CustomSeed.cs create mode 100644 COTL_API/CustomInventory/CustomCrops/Patches/CropControllerPatches.cs diff --git a/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs b/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs new file mode 100644 index 0000000..154b2cb --- /dev/null +++ b/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs @@ -0,0 +1,125 @@ +using COTL_API.Guid; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.Bindings; +using UnityEngine.Rendering; +using Object = UnityEngine.Object; + +namespace COTL_API.CustomInventory; + +public static partial class CustomItemManager +{ + public static Dictionary CustomCropList { get; } = []; + + public static Dictionary CustomCropControllers { get; } = []; + + public static InventoryItem.ITEM_TYPE Add(CustomSeed seed) + { + var item = Add(seed as CustomInventoryItem); + seed.StructureType = + GuidManager.GetEnumValue(CustomItemList[item].ModPrefix, seed.InternalName); + + CustomCropList.Add(item, seed); + CustomCropControllers.Add(item, CreateCropController(seed)); + + return item; + } + + #region Custom CropControllers + + private static CropController ControllerPrefab; + + private static CropController CreateCropController(CustomSeed seed) + { + if (!ControllerPrefab) + { + ControllerPrefab = CreateGenericController(); + } + + var holderObject = new GameObject(); + holderObject.SetActive(false); + + var customController = + Object.Instantiate(ControllerPrefab, null, instantiateInWorldSpace: false) as CropController; + + customController.transform.SetParent(holderObject.transform); + + customController.SeedType = seed.ItemType; + + var cropStage = customController.CropStates[0]; + var finalCrop = customController.CropStates[customController.CropStates.Count - 1]; + + customController.CropStates = []; + + for (var i = 0; i < seed.CropStates.Count - 1; i++) + { + var sprite = seed.CropStates[i]; + var newObj = Object.Instantiate(cropStage, null, instantiateInWorldSpace: false) as GameObject; + newObj?.transform.SetParent(customController.transform); + Object.DontDestroyOnLoad(newObj); + customController.CropStates.Add(newObj); + customController.CropStates[i].GetComponent().sprite = sprite; + } + + var newFinalCrop = Object.Instantiate(finalCrop, null, instantiateInWorldSpace: false) as GameObject; + newFinalCrop?.transform.SetParent(customController.transform); + finalCrop.GetComponent().sprite = seed.CropStates[seed.CropStates.Count-1]; + Object.DontDestroyOnLoad(newFinalCrop); + customController.CropStates.Add(newFinalCrop); + + customController.CropStates[customController.CropStates.Count - 1] + .GetComponentInChildren() + .sprite = seed.CropStates[seed.CropStates.Count - 1]; + + customController.CropStates[customController.CropStates.Count - 1].GetComponent().Type = + seed.StructureType; + + Object.DontDestroyOnLoad(customController); + return customController; + } + + private static CropController CreateGenericController() + { + var cropController = new GameObject("Custom Crop").AddComponent(); + + var cropState = new GameObject("Crop"); + cropState.AddComponent(); + + var finalCropState = new GameObject("Harvest"); + finalCropState.AddComponent(); + finalCropState.AddComponent(); + //var interactionBerries = finalCropState.AddComponent(); + var structure = finalCropState.AddComponent(); + finalCropState.AddComponent(); + + var playerPosLeft = new GameObject("PlayerPositionLeft"); + var playerPosRight = new GameObject("PlayerPositionRight"); + playerPosLeft.transform.SetParent(finalCropState.transform); + playerPosRight.transform.SetParent(finalCropState.transform); + + var bush = new GameObject("bush"); + bush.AddComponent(); + var toShake = new GameObject("ToShake"); + var gameObj = new GameObject("GamObject"); + var stump = new GameObject("Stump"); + bush.transform.SetParent(toShake.transform); + toShake.transform.SetParent(gameObj.transform); + stump.transform.SetParent(gameObj.transform); + gameObj.transform.SetParent(finalCropState.transform); + + + // interactionBerries.berryToShake = toShake; + // interactionBerries.berryBush_Normal = gameObj; + // interactionBerries.Structure = structure; + // interactionBerries.PlayerPositionLeft = playerPosLeft; + // interactionBerries.PlayerPositionRight = playerPosRight; + // interactionBerries.berryToShake = stump; + + cropController.CropStates.Add(cropState); + cropController.CropStates.Add(finalCropState); + + return cropController; + } + + #endregion +} \ No newline at end of file diff --git a/COTL_API/CustomInventory/CustomCrops/CustomSeed.cs b/COTL_API/CustomInventory/CustomCrops/CustomSeed.cs new file mode 100644 index 0000000..081b2a3 --- /dev/null +++ b/COTL_API/CustomInventory/CustomCrops/CustomSeed.cs @@ -0,0 +1,38 @@ +using UnityEngine; + +namespace COTL_API.CustomInventory; + +public abstract class CustomSeed : CustomInventoryItem +{ + internal StructureBrain.TYPES StructureType { get; set; } + internal int CropStatesCount => CropStates.Count; + public sealed override bool IsPlantable { get; } = true; + public sealed override bool IsSeed { get; } = true; + + /// + /// The States of this crop, the last state should be the fully grown state. + /// + public virtual List CropStates { get; } = []; + + public virtual float CropGrowthTime => 9f; + + /// + /// How many resources this will drop upon collecting + /// + public virtual Vector2Int HarvestsPerSeedRange => new(2, 5); + + /// + /// The Items, (and probabilities) dropped when harvesting this crop + /// + public virtual DropMultipleLootOnDeath.ItemAndProbability[] HarvestResult => []; + + /// s + /// TODO: Find out what this does, it's probably how long it takes to break but that's an odd name for it + /// + public virtual int ProgressTarget => 10; + + /// + /// TODO: Find out what this does, it's probably how many of the item drops, but then what's HarvestsPerSeedRange? + /// + public virtual Vector2Int CropCountToDropRange => new(3, 4); +} \ No newline at end of file diff --git a/COTL_API/CustomInventory/CustomCrops/Patches/CropControllerPatches.cs b/COTL_API/CustomInventory/CustomCrops/Patches/CropControllerPatches.cs new file mode 100644 index 0000000..7e88a81 --- /dev/null +++ b/COTL_API/CustomInventory/CustomCrops/Patches/CropControllerPatches.cs @@ -0,0 +1,76 @@ +using HarmonyLib; +using UnityEngine; + +namespace COTL_API.CustomInventory; + +[HarmonyPatch] +public static partial class CustomItemManager +{ + [HarmonyPatch(typeof(CropController), nameof(CropController.CropStatesForSeedType))] + [HarmonyPostfix] + private static void CropController_CropStatesForSeedType(InventoryItem.ITEM_TYPE seedType, ref int __result) + { + if (!CustomCropList.TryGetValue(seedType, out var item)) return; + + __result = item.CropStatesCount; + } + + [HarmonyPatch(typeof(CropController), nameof(CropController.CropGrowthTimes))] + [HarmonyPostfix] + private static void CropController_CropGrowthTimes(InventoryItem.ITEM_TYPE seedType, ref float __result) + { + if (!CustomCropList.TryGetValue(seedType, out var item)) return; + + __result = item.CropGrowthTime; + } + + [HarmonyPatch(typeof(CropController), nameof(CropController.GetHarvestsPerSeedRange))] + [HarmonyPostfix] + private static void CropController_GetHarvestsPerSeedRange(InventoryItem.ITEM_TYPE seedType, + ref Vector2Int __result) + { + if (!CustomCropList.TryGetValue(seedType, out var item)) return; + + __result = item.HarvestsPerSeedRange; + } + + [HarmonyPatch(typeof(FarmPlot), nameof(FarmPlot.Awake))] + [HarmonyPrefix] + private static void FarmPlot_Awake(FarmPlot __instance) + { + foreach (var key in CustomCropControllers.Values) + { + __instance.CropPrefabs.Add(key); + } + } + + [HarmonyPatch(typeof(StructuresData), nameof(StructuresData.GetInfoByType))] + [HarmonyPostfix] + private static void StructureData_GetInfoByType(StructureBrain.TYPES Type, ref StructuresData __result) + { + if (CustomCropList.Values.All(x => x.StructureType != Type)) return; + + var crop = CustomCropList.Values.First(x => x.StructureType == Type); + + __result = new StructuresData + { + PrefabPath = "Prefabs/Structures/Other/BerryBush", + DontLoadMe = true, + ProgressTarget = crop.ProgressTarget, + MultipleLootToDrop = crop.HarvestResult.Select(item => item.Type).ToList(), + MultipleLootToDropChance = crop.HarvestResult.Select(item => item.Probability).ToList(), + LootCountToDropRange = crop.CropCountToDropRange, + CropLootCountToDropRange = crop.CropCountToDropRange + }; + __result.Type = crop.StructureType; + } + + [HarmonyPatch(typeof(StructureBrain), nameof(StructureBrain.CreateBrain))] + [HarmonyPostfix] + private static void StructureBrain_CreateBrain(StructuresData data, ref StructureBrain __result) + { + if (CustomCropList.Values.All(x => x.StructureType != data.Type)) return; + + __result = new Structures_BerryBush(); + } +} \ No newline at end of file From 531c9665a9968fccfa601fc2f61f49ef6f6a4538 Mon Sep 17 00:00:00 2001 From: zelzmiy <51797223+zelzmiy@users.noreply.github.com> Date: Mon, 2 Dec 2024 19:35:15 -0600 Subject: [PATCH 02/10] idefk anymore i passed out behind the keyboard --- .../{CustomSeed.cs => CustomCrop.cs} | 10 +- .../CustomCrops/CustomCropManager.cs | 181 +++++++++--------- ...trollerPatches.cs => CustomCropPatches.cs} | 48 +++-- 3 files changed, 123 insertions(+), 116 deletions(-) rename COTL_API/CustomInventory/CustomCrops/{CustomSeed.cs => CustomCrop.cs} (84%) rename COTL_API/CustomInventory/CustomCrops/{Patches/CropControllerPatches.cs => CustomCropPatches.cs} (80%) diff --git a/COTL_API/CustomInventory/CustomCrops/CustomSeed.cs b/COTL_API/CustomInventory/CustomCrops/CustomCrop.cs similarity index 84% rename from COTL_API/CustomInventory/CustomCrops/CustomSeed.cs rename to COTL_API/CustomInventory/CustomCrops/CustomCrop.cs index 081b2a3..2c897fb 100644 --- a/COTL_API/CustomInventory/CustomCrops/CustomSeed.cs +++ b/COTL_API/CustomInventory/CustomCrops/CustomCrop.cs @@ -2,8 +2,9 @@ namespace COTL_API.CustomInventory; -public abstract class CustomSeed : CustomInventoryItem +public abstract class CustomCrop : CustomInventoryItem { + internal InventoryItem.ITEM_TYPE ItemType; internal StructureBrain.TYPES StructureType { get; set; } internal int CropStatesCount => CropStates.Count; public sealed override bool IsPlantable { get; } = true; @@ -14,8 +15,11 @@ public abstract class CustomSeed : CustomInventoryItem /// public virtual List CropStates { get; } = []; + /// + /// The time it takes for this crop to grow, in game ticks. + /// public virtual float CropGrowthTime => 9f; - + /// /// How many resources this will drop upon collecting /// @@ -26,7 +30,7 @@ public abstract class CustomSeed : CustomInventoryItem /// public virtual DropMultipleLootOnDeath.ItemAndProbability[] HarvestResult => []; - /// s + /// /// TODO: Find out what this does, it's probably how long it takes to break but that's an odd name for it /// public virtual int ProgressTarget => 10; diff --git a/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs b/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs index 154b2cb..2092215 100644 --- a/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs +++ b/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs @@ -1,125 +1,122 @@ using COTL_API.Guid; using UnityEngine; using UnityEngine.AddressableAssets; -using UnityEngine.Bindings; -using UnityEngine.Rendering; -using Object = UnityEngine.Object; +using UnityEngine.ResourceManagement.AsyncOperations; +using static UnityEngine.Object; namespace COTL_API.CustomInventory; public static partial class CustomItemManager { - public static Dictionary CustomCropList { get; } = []; + private static GameObject CropPrefab; - public static Dictionary CustomCropControllers { get; } = []; + public static Dictionary CustomCropList { get; } = []; + internal static Dictionary CropObjectList { get; } = []; - public static InventoryItem.ITEM_TYPE Add(CustomSeed seed) + private static readonly List s_toRegister = []; + + public static InventoryItem.ITEM_TYPE Add(CustomCrop crop) { - var item = Add(seed as CustomInventoryItem); - seed.StructureType = - GuidManager.GetEnumValue(CustomItemList[item].ModPrefix, seed.InternalName); + var item = Add(crop as CustomInventoryItem); + crop.ItemType = item; + crop.StructureType = + GuidManager.GetEnumValue(CustomItemList[item].ModPrefix, crop.InternalName); - CustomCropList.Add(item, seed); - CustomCropControllers.Add(item, CreateCropController(seed)); + CustomCropList.Add(item, crop); + CropObjectList.Add(item, CreateCropObject(crop)); return item; } - #region Custom CropControllers - - private static CropController ControllerPrefab; - - private static CropController CreateCropController(CustomSeed seed) + private static GameObject CreateCropObject(CustomCrop crop) { - if (!ControllerPrefab) - { - ControllerPrefab = CreateGenericController(); - } + if (CropPrefab == null) + GetCropAsset(); - var holderObject = new GameObject(); - holderObject.SetActive(false); + if (CropPrefab == null) + throw new NullReferenceException(":/ Send a bug report"); - var customController = - Object.Instantiate(ControllerPrefab, null, instantiateInWorldSpace: false) as CropController; + var duplicate = Instantiate(CropPrefab); - customController.transform.SetParent(holderObject.transform); + if (duplicate == null) + throw new NullReferenceException("Somehow, the Crop Prefab could not be instantiated, send a bug report"); - customController.SeedType = seed.ItemType; + duplicate.hideFlags = HideFlags.HideAndDontSave; + duplicate.name = $"{crop.Name()} Crop"; - var cropStage = customController.CropStates[0]; - var finalCrop = customController.CropStates[customController.CropStates.Count - 1]; + var cropController = duplicate.GetComponent(); - customController.CropStates = []; + cropController.CropStates = []; + cropController.SeedType = crop.ItemType; - for (var i = 0; i < seed.CropStates.Count - 1; i++) - { - var sprite = seed.CropStates[i]; - var newObj = Object.Instantiate(cropStage, null, instantiateInWorldSpace: false) as GameObject; - newObj?.transform.SetParent(customController.transform); - Object.DontDestroyOnLoad(newObj); - customController.CropStates.Add(newObj); - customController.CropStates[i].GetComponent().sprite = sprite; - } + Destroy(duplicate.transform.GetChild(1)); // Stage 2 + Destroy(duplicate.transform.GetChild(1)); // Stage 3 + Destroy(duplicate.transform.GetChild(1)); // Stage 4 - var newFinalCrop = Object.Instantiate(finalCrop, null, instantiateInWorldSpace: false) as GameObject; - newFinalCrop?.transform.SetParent(customController.transform); - finalCrop.GetComponent().sprite = seed.CropStates[seed.CropStates.Count-1]; - Object.DontDestroyOnLoad(newFinalCrop); - customController.CropStates.Add(newFinalCrop); + /* + * DEV NOTE: this is insane, why are you like this game? why the fuck are there two of them? why do they have + * identical scripts? Harvest is what happens if a crop grows out without fertilizer, and BumperHarvest is with + * fertilizer. the only difference seems to be a tiny sign... + * it also skips stage 2 of the crop states, it goes 1,3,4, (Bumper)Harvest. WHY? why is stage 2 there? + */ - customController.CropStates[customController.CropStates.Count - 1] - .GetComponentInChildren() - .sprite = seed.CropStates[seed.CropStates.Count - 1]; + // "Harvest" object + var harvest = duplicate.transform.GetChild(1); + // "bush1" -> sprite of the final harvest crop bush + // "Harvest"/"GameObject (2)/"To Shake(2)"/"Bush1"/ + var bush1 = harvest.GetChild(2).GetChild(0).GetChild(0); - customController.CropStates[customController.CropStates.Count - 1].GetComponent().Type = - seed.StructureType; + // "Bumper Harvest" object + var bumperHarvest = duplicate.transform.GetChild(2); + // "bumperBush1" -> the final stage that gets activated with fertilizer + // "BumperHarvest"/"GameObject (2)/"To Shake(2)"/"Bush1"/ + var bumperBush1 = bumperHarvest.GetChild(3).GetChild(0).GetChild(0); - Object.DontDestroyOnLoad(customController); - return customController; + bush1.GetComponent().sprite = crop.CropStates.Last(); + bumperBush1.GetComponent().sprite = crop.CropStates.Last(); + + var cropState = duplicate.transform.GetChild(0); + cropState.GetComponent().sprite = crop.CropStates[0]; + cropController.CropStates.Add(cropState.gameObject); + foreach (var sprite in crop.CropStates) + { + var newState = Instantiate(cropState, duplicate.transform); + newState.GetComponent().sprite = sprite; + cropController.CropStates.Add(newState.gameObject); + } + + cropController.CropStates.Add(harvest.gameObject); + + return duplicate; } - private static CropController CreateGenericController() + private static void GetCropAsset() { - var cropController = new GameObject("Custom Crop").AddComponent(); - - var cropState = new GameObject("Crop"); - cropState.AddComponent(); - - var finalCropState = new GameObject("Harvest"); - finalCropState.AddComponent(); - finalCropState.AddComponent(); - //var interactionBerries = finalCropState.AddComponent(); - var structure = finalCropState.AddComponent(); - finalCropState.AddComponent(); - - var playerPosLeft = new GameObject("PlayerPositionLeft"); - var playerPosRight = new GameObject("PlayerPositionRight"); - playerPosLeft.transform.SetParent(finalCropState.transform); - playerPosRight.transform.SetParent(finalCropState.transform); - - var bush = new GameObject("bush"); - bush.AddComponent(); - var toShake = new GameObject("ToShake"); - var gameObj = new GameObject("GamObject"); - var stump = new GameObject("Stump"); - bush.transform.SetParent(toShake.transform); - toShake.transform.SetParent(gameObj.transform); - stump.transform.SetParent(gameObj.transform); - gameObj.transform.SetParent(finalCropState.transform); - - - // interactionBerries.berryToShake = toShake; - // interactionBerries.berryBush_Normal = gameObj; - // interactionBerries.Structure = structure; - // interactionBerries.PlayerPositionLeft = playerPosLeft; - // interactionBerries.PlayerPositionRight = playerPosRight; - // interactionBerries.berryToShake = stump; - - cropController.CropStates.Add(cropState); - cropController.CropStates.Add(finalCropState); - - return cropController; - } + LogInfo("GETTING CROP ASSET"); + var op = Addressables.Instance.LoadAssetAsync("Prefabs/Structures/Crops/Berry Crop"); - #endregion + op.Completed += (handle) => + { + LogInfo("OPERATION COMPLETED"); + if (op.Status == AsyncOperationStatus.Succeeded) + { + LogInfo("ASYNC OPERATION WE HAVE THE CROP PREFAB RESULT"); + LogInfo("ASYNC OPERATION WE HAVE THE CROP PREFAB RESULT"); + LogInfo("ASYNC OPERATION WE HAVE THE CROP PREFAB RESULT"); + LogInfo("ASYNC OPERATION WE HAVE THE CROP PREFAB RESULT"); + CropPrefab = handle.Result; + CropPrefab.hideFlags = HideFlags.HideAndDontSave; + DontDestroyOnLoad(CropPrefab); + } + else + { + LogInfo("ASYNC OPERATION FAILED WE DONT HAVE IT WE SUCK"); + LogInfo("ASYNC OPERATION FAILED WE DONT HAVE IT WE SUCK"); + LogInfo("ASYNC OPERATION FAILED WE DONT HAVE IT WE SUCK"); + LogInfo("ASYNC OPERATION FAILED WE DONT HAVE IT WE SUCK"); + //throw new NullReferenceException("Couldn't Find Berry Crop Object, Send a bug report!"); + } + }; + LogInfo("FINSIHED GETTING CROP ASSET"); + } } \ No newline at end of file diff --git a/COTL_API/CustomInventory/CustomCrops/Patches/CropControllerPatches.cs b/COTL_API/CustomInventory/CustomCrops/CustomCropPatches.cs similarity index 80% rename from COTL_API/CustomInventory/CustomCrops/Patches/CropControllerPatches.cs rename to COTL_API/CustomInventory/CustomCrops/CustomCropPatches.cs index 7e88a81..c1f6d95 100644 --- a/COTL_API/CustomInventory/CustomCrops/Patches/CropControllerPatches.cs +++ b/COTL_API/CustomInventory/CustomCrops/CustomCropPatches.cs @@ -1,5 +1,7 @@ using HarmonyLib; +using MonoMod.Utils; using UnityEngine; +using Object = UnityEngine.Object; namespace COTL_API.CustomInventory; @@ -11,50 +13,41 @@ public static partial class CustomItemManager private static void CropController_CropStatesForSeedType(InventoryItem.ITEM_TYPE seedType, ref int __result) { if (!CustomCropList.TryGetValue(seedType, out var item)) return; - + __result = item.CropStatesCount; } - + [HarmonyPatch(typeof(CropController), nameof(CropController.CropGrowthTimes))] [HarmonyPostfix] private static void CropController_CropGrowthTimes(InventoryItem.ITEM_TYPE seedType, ref float __result) { if (!CustomCropList.TryGetValue(seedType, out var item)) return; - + __result = item.CropGrowthTime; } - + [HarmonyPatch(typeof(CropController), nameof(CropController.GetHarvestsPerSeedRange))] [HarmonyPostfix] private static void CropController_GetHarvestsPerSeedRange(InventoryItem.ITEM_TYPE seedType, ref Vector2Int __result) { if (!CustomCropList.TryGetValue(seedType, out var item)) return; - + __result = item.HarvestsPerSeedRange; } - - [HarmonyPatch(typeof(FarmPlot), nameof(FarmPlot.Awake))] - [HarmonyPrefix] - private static void FarmPlot_Awake(FarmPlot __instance) - { - foreach (var key in CustomCropControllers.Values) - { - __instance.CropPrefabs.Add(key); - } - } - + + [HarmonyPatch(typeof(StructuresData), nameof(StructuresData.GetInfoByType))] [HarmonyPostfix] private static void StructureData_GetInfoByType(StructureBrain.TYPES Type, ref StructuresData __result) { if (CustomCropList.Values.All(x => x.StructureType != Type)) return; - + var crop = CustomCropList.Values.First(x => x.StructureType == Type); - + __result = new StructuresData { - PrefabPath = "Prefabs/Structures/Other/BerryBush", + PrefabPath = "Prefabs/Structures/Other/Berry Bush", DontLoadMe = true, ProgressTarget = crop.ProgressTarget, MultipleLootToDrop = crop.HarvestResult.Select(item => item.Type).ToList(), @@ -64,13 +57,26 @@ private static void StructureData_GetInfoByType(StructureBrain.TYPES Type, ref S }; __result.Type = crop.StructureType; } - + [HarmonyPatch(typeof(StructureBrain), nameof(StructureBrain.CreateBrain))] [HarmonyPostfix] private static void StructureBrain_CreateBrain(StructuresData data, ref StructureBrain __result) { if (CustomCropList.Values.All(x => x.StructureType != data.Type)) return; - + __result = new Structures_BerryBush(); } + + [HarmonyPatch(typeof(FarmPlot), nameof(FarmPlot.Awake))] + [HarmonyPrefix] + private static void FarmPlot_Awake_Prefix(FarmPlot __instance) + { + __instance._cropPrefabsBySeedType.AddRange(CropObjectList); + } + // [HarmonyPatch(typeof(FarmPlot), nameof(FarmPlot.Awake))] + // [HarmonyPostfix] + // private static void FarmPlot_Awake_Postfix(FarmPlot __instance) + // { + // __instance.CropPrefabs.AddRange(CropObjectList.Select(x => x.Value.GetComponent())); + // } } \ No newline at end of file From c95b4ce193cd9bb0eac8dd0a2c3efe732bf23063 Mon Sep 17 00:00:00 2001 From: zelzmiy <51797223+zelzmiy@users.noreply.github.com> Date: Thu, 9 Jan 2025 17:31:00 -0600 Subject: [PATCH 03/10] working custom crops --- .../CustomInventory/CustomCrops/CustomCrop.cs | 27 +++-- .../CustomCrops/CustomCropManager.cs | 98 +++++++------------ .../CustomCrops/CustomCropPatches.cs | 64 +++++++----- COTL_API/Plugin.cs | 5 +- 4 files changed, 90 insertions(+), 104 deletions(-) diff --git a/COTL_API/CustomInventory/CustomCrops/CustomCrop.cs b/COTL_API/CustomInventory/CustomCrops/CustomCrop.cs index 2c897fb..25ac35f 100644 --- a/COTL_API/CustomInventory/CustomCrops/CustomCrop.cs +++ b/COTL_API/CustomInventory/CustomCrops/CustomCrop.cs @@ -4,14 +4,13 @@ namespace COTL_API.CustomInventory; public abstract class CustomCrop : CustomInventoryItem { - internal InventoryItem.ITEM_TYPE ItemType; internal StructureBrain.TYPES StructureType { get; set; } internal int CropStatesCount => CropStates.Count; - public sealed override bool IsPlantable { get; } = true; - public sealed override bool IsSeed { get; } = true; + public sealed override bool IsPlantable => true; + public sealed override bool IsSeed => true; /// - /// The States of this crop, the last state should be the fully grown state. + /// The States of this crop, the last state should be the fully grown state. Requires at least two states. /// public virtual List CropStates { get; } = []; @@ -19,24 +18,24 @@ public abstract class CustomCrop : CustomInventoryItem /// The time it takes for this crop to grow, in game ticks. /// public virtual float CropGrowthTime => 9f; - + /// - /// How many resources this will drop upon collecting + /// The Crop and Seed that drops when this is harvested. Must be size 2 /// - public virtual Vector2Int HarvestsPerSeedRange => new(2, 5); + public abstract List HarvestResult { get; } /// - /// The Items, (and probabilities) dropped when harvesting this crop + /// How long (in seconds) it takes to pick this crop. /// - public virtual DropMultipleLootOnDeath.ItemAndProbability[] HarvestResult => []; - + public virtual float PickingTime => 2.5f; + /// - /// TODO: Find out what this does, it's probably how long it takes to break but that's an odd name for it + /// The range in how many resources will drop when collecting. /// - public virtual int ProgressTarget => 10; + public virtual Vector2Int CropCountToDropRange => new(3, 4); /// - /// TODO: Find out what this does, it's probably how many of the item drops, but then what's HarvestsPerSeedRange? + /// Shows when hovering the crop to harvest it. /// - public virtual Vector2Int CropCountToDropRange => new(3, 4); + public virtual string HarvestText => "Pick Berries"; } \ No newline at end of file diff --git a/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs b/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs index 2092215..da26bbb 100644 --- a/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs +++ b/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs @@ -1,4 +1,5 @@ using COTL_API.Guid; +using HarmonyLib; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; @@ -8,12 +9,12 @@ namespace COTL_API.CustomInventory; public static partial class CustomItemManager { - private static GameObject CropPrefab; + private static GameObject s_cropPrefab = null!; public static Dictionary CustomCropList { get; } = []; - internal static Dictionary CropObjectList { get; } = []; + private static Dictionary CropObjectList { get; } = []; - private static readonly List s_toRegister = []; + private const string AssetPath = "Prefabs/Structures/Crops/Berry Crop"; public static InventoryItem.ITEM_TYPE Add(CustomCrop crop) { @@ -23,100 +24,73 @@ public static InventoryItem.ITEM_TYPE Add(CustomCrop crop) GuidManager.GetEnumValue(CustomItemList[item].ModPrefix, crop.InternalName); CustomCropList.Add(item, crop); - CropObjectList.Add(item, CreateCropObject(crop)); return item; } - private static GameObject CreateCropObject(CustomCrop crop) + private static void CreateCropObject(CustomCrop crop) { - if (CropPrefab == null) - GetCropAsset(); + if (s_cropPrefab == null) + throw new NullReferenceException("This REALLY shouldn't happen, send a bug report!"); - if (CropPrefab == null) - throw new NullReferenceException(":/ Send a bug report"); - - var duplicate = Instantiate(CropPrefab); + var duplicate = Instantiate(s_cropPrefab); if (duplicate == null) throw new NullReferenceException("Somehow, the Crop Prefab could not be instantiated, send a bug report"); - duplicate.hideFlags = HideFlags.HideAndDontSave; - duplicate.name = $"{crop.Name()} Crop"; + duplicate.transform.name = $"{crop.Name()} Crop"; var cropController = duplicate.GetComponent(); cropController.CropStates = []; cropController.SeedType = crop.ItemType; - Destroy(duplicate.transform.GetChild(1)); // Stage 2 - Destroy(duplicate.transform.GetChild(1)); // Stage 3 - Destroy(duplicate.transform.GetChild(1)); // Stage 4 - - /* - * DEV NOTE: this is insane, why are you like this game? why the fuck are there two of them? why do they have - * identical scripts? Harvest is what happens if a crop grows out without fertilizer, and BumperHarvest is with - * fertilizer. the only difference seems to be a tiny sign... - * it also skips stage 2 of the crop states, it goes 1,3,4, (Bumper)Harvest. WHY? why is stage 2 there? - */ + // remove extra growth stages in case there are less than 4 + DestroyImmediate(duplicate.transform.GetChild(1).gameObject); // Stage 2 + DestroyImmediate(duplicate.transform.GetChild(1).gameObject); // Stage 3 + DestroyImmediate(duplicate.transform.GetChild(1).gameObject); // Stage 4 - // "Harvest" object var harvest = duplicate.transform.GetChild(1); - // "bush1" -> sprite of the final harvest crop bush - // "Harvest"/"GameObject (2)/"To Shake(2)"/"Bush1"/ - var bush1 = harvest.GetChild(2).GetChild(0).GetChild(0); + var bush = harvest.GetChild(2).GetChild(0).GetChild(0); - // "Bumper Harvest" object var bumperHarvest = duplicate.transform.GetChild(2); - // "bumperBush1" -> the final stage that gets activated with fertilizer - // "BumperHarvest"/"GameObject (2)/"To Shake(2)"/"Bush1"/ - var bumperBush1 = bumperHarvest.GetChild(3).GetChild(0).GetChild(0); - - bush1.GetComponent().sprite = crop.CropStates.Last(); - bumperBush1.GetComponent().sprite = crop.CropStates.Last(); + var bumperBush = bumperHarvest.GetChild(3).GetChild(0).GetChild(0); + + bush.GetComponent().sprite = crop.CropStates.Last(); + bumperBush.GetComponent().sprite = crop.CropStates.Last(); ; var cropState = duplicate.transform.GetChild(0); cropState.GetComponent().sprite = crop.CropStates[0]; cropController.CropStates.Add(cropState.gameObject); - foreach (var sprite in crop.CropStates) + + for (var i = 1; i < crop.CropStates.Count - 1; i++) { var newState = Instantiate(cropState, duplicate.transform); - newState.GetComponent().sprite = sprite; + newState.name = $"Crop {i + 1}"; + newState.SetSiblingIndex(i); + newState.GetComponent().sprite = crop.CropStates[i]; cropController.CropStates.Add(newState.gameObject); } cropController.CropStates.Add(harvest.gameObject); - - return duplicate; + + // Ensures that the object doesn't get deleted between scene loads + duplicate.hideFlags = HideFlags.HideAndDontSave; + + CropObjectList.Add(crop.ItemType, duplicate.GetComponent()); } - private static void GetCropAsset() + public static void InitiateCustomCrops() { - LogInfo("GETTING CROP ASSET"); - var op = Addressables.Instance.LoadAssetAsync("Prefabs/Structures/Crops/Berry Crop"); - + LogInfo("Getting Crop Asset"); + var op = Addressables.Instance.LoadAssetAsync(AssetPath); op.Completed += (handle) => { - LogInfo("OPERATION COMPLETED"); - if (op.Status == AsyncOperationStatus.Succeeded) - { - LogInfo("ASYNC OPERATION WE HAVE THE CROP PREFAB RESULT"); - LogInfo("ASYNC OPERATION WE HAVE THE CROP PREFAB RESULT"); - LogInfo("ASYNC OPERATION WE HAVE THE CROP PREFAB RESULT"); - LogInfo("ASYNC OPERATION WE HAVE THE CROP PREFAB RESULT"); - CropPrefab = handle.Result; - CropPrefab.hideFlags = HideFlags.HideAndDontSave; - DontDestroyOnLoad(CropPrefab); - } - else - { - LogInfo("ASYNC OPERATION FAILED WE DONT HAVE IT WE SUCK"); - LogInfo("ASYNC OPERATION FAILED WE DONT HAVE IT WE SUCK"); - LogInfo("ASYNC OPERATION FAILED WE DONT HAVE IT WE SUCK"); - LogInfo("ASYNC OPERATION FAILED WE DONT HAVE IT WE SUCK"); - //throw new NullReferenceException("Couldn't Find Berry Crop Object, Send a bug report!"); - } + if (op.Status != AsyncOperationStatus.Succeeded) + throw new NullReferenceException("Couldn't Find Berry Crop Object, Send a bug report!"); + + s_cropPrefab = handle.Result; + CustomCropList.Do(x => CreateCropObject(x.Value)); }; - LogInfo("FINSIHED GETTING CROP ASSET"); } } \ No newline at end of file diff --git a/COTL_API/CustomInventory/CustomCrops/CustomCropPatches.cs b/COTL_API/CustomInventory/CustomCrops/CustomCropPatches.cs index c1f6d95..9e4191a 100644 --- a/COTL_API/CustomInventory/CustomCrops/CustomCropPatches.cs +++ b/COTL_API/CustomInventory/CustomCrops/CustomCropPatches.cs @@ -26,16 +26,6 @@ private static void CropController_CropGrowthTimes(InventoryItem.ITEM_TYPE seedT __result = item.CropGrowthTime; } - [HarmonyPatch(typeof(CropController), nameof(CropController.GetHarvestsPerSeedRange))] - [HarmonyPostfix] - private static void CropController_GetHarvestsPerSeedRange(InventoryItem.ITEM_TYPE seedType, - ref Vector2Int __result) - { - if (!CustomCropList.TryGetValue(seedType, out var item)) return; - - __result = item.HarvestsPerSeedRange; - } - [HarmonyPatch(typeof(StructuresData), nameof(StructuresData.GetInfoByType))] [HarmonyPostfix] @@ -44,18 +34,16 @@ private static void StructureData_GetInfoByType(StructureBrain.TYPES Type, ref S if (CustomCropList.Values.All(x => x.StructureType != Type)) return; var crop = CustomCropList.Values.First(x => x.StructureType == Type); - + // Not sure that this is necessary but just in case? __result = new StructuresData { PrefabPath = "Prefabs/Structures/Other/Berry Bush", DontLoadMe = true, - ProgressTarget = crop.ProgressTarget, - MultipleLootToDrop = crop.HarvestResult.Select(item => item.Type).ToList(), - MultipleLootToDropChance = crop.HarvestResult.Select(item => item.Probability).ToList(), + ProgressTarget = crop.PickingTime, + MultipleLootToDrop = crop.HarvestResult, LootCountToDropRange = crop.CropCountToDropRange, - CropLootCountToDropRange = crop.CropCountToDropRange + Type = crop.StructureType }; - __result.Type = crop.StructureType; } [HarmonyPatch(typeof(StructureBrain), nameof(StructureBrain.CreateBrain))] @@ -66,17 +54,39 @@ private static void StructureBrain_CreateBrain(StructuresData data, ref Structur __result = new Structures_BerryBush(); } - + [HarmonyPatch(typeof(FarmPlot), nameof(FarmPlot.Awake))] - [HarmonyPrefix] - private static void FarmPlot_Awake_Prefix(FarmPlot __instance) + [HarmonyPostfix] + private static void FarmPlot_Postfix(FarmPlot __instance) + { + foreach(var kvp in CropObjectList) + { + __instance._cropPrefabsBySeedType.Add(kvp.Key, kvp.Value); + } + } + + [HarmonyPatch(typeof(Interaction_Berries), nameof(Interaction_Berries.OnBrainAssigned))] + [HarmonyPostfix] + private static void Interaction_Berries_OnBrainAssigned(Interaction_Berries __instance) + { + var cropController = __instance.GetComponentInParent(); + + if (cropController == null) return; + if (!CustomCropList.TryGetValue(cropController.SeedType, out var crop)) return; + + __instance.StructureBrain.Data.MultipleLootToDrop = crop.HarvestResult; + __instance.StructureBrain.Data.LootCountToDropRange = crop.CropCountToDropRange; + __instance.BerryPickingIncrements = 1.25f / crop.PickingTime; + } + + [HarmonyPatch(typeof(Interaction_Berries), nameof(Interaction_Berries.UpdateLocalisation))] + [HarmonyPostfix] + private static void Interaction_Berries_UpdateLocalisation(Interaction_Berries __instance) { - __instance._cropPrefabsBySeedType.AddRange(CropObjectList); + var cropController = __instance.GetComponentInParent(); + if (cropController == null) return; + if (!CustomCropList.TryGetValue(cropController.SeedType, out var crop)) return; + + __instance.sLabelName = crop.HarvestText; } - // [HarmonyPatch(typeof(FarmPlot), nameof(FarmPlot.Awake))] - // [HarmonyPostfix] - // private static void FarmPlot_Awake_Postfix(FarmPlot __instance) - // { - // __instance.CropPrefabs.AddRange(CropObjectList.Select(x => x.Value.GetComponent())); - // } -} \ No newline at end of file +} \ No newline at end of file diff --git a/COTL_API/Plugin.cs b/COTL_API/Plugin.cs index 005b2c2..631292e 100644 --- a/COTL_API/Plugin.cs +++ b/COTL_API/Plugin.cs @@ -251,7 +251,10 @@ private void OnDisable() LogInfo($"{MyPluginInfo.PLUGIN_NAME} unloaded!"); } - internal static event Action OnStart = delegate { }; + internal static event Action OnStart = delegate + { + CustomItemManager.InitiateCustomCrops(); + }; private void RunSavePatch() { From 254a9266e682a526819502d8fdadb35970e05b09 Mon Sep 17 00:00:00 2001 From: zelzmiy <51797223+zelzmiy@users.noreply.github.com> Date: Thu, 9 Jan 2025 17:43:54 -0600 Subject: [PATCH 04/10] remove old IsSeed toggle and change DebugItemClass2 to match making an item that's not a custom seed but has it toggled does nothing, and is therefore useless --- COTL_API/CustomInventory/CustomCrops/CustomCrop.cs | 3 +-- COTL_API/CustomInventory/CustomInventoryItem.cs | 1 - .../CustomInventory/Patches/CustomInventoryPatches.cs | 2 +- COTL_API/Debug/DebugItemClass2.cs | 9 +++++++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/COTL_API/CustomInventory/CustomCrops/CustomCrop.cs b/COTL_API/CustomInventory/CustomCrops/CustomCrop.cs index 25ac35f..bce6ba7 100644 --- a/COTL_API/CustomInventory/CustomCrops/CustomCrop.cs +++ b/COTL_API/CustomInventory/CustomCrops/CustomCrop.cs @@ -7,8 +7,7 @@ public abstract class CustomCrop : CustomInventoryItem internal StructureBrain.TYPES StructureType { get; set; } internal int CropStatesCount => CropStates.Count; public sealed override bool IsPlantable => true; - public sealed override bool IsSeed => true; - + /// /// The States of this crop, the last state should be the fully grown state. Requires at least two states. /// diff --git a/COTL_API/CustomInventory/CustomInventoryItem.cs b/COTL_API/CustomInventory/CustomInventoryItem.cs index 7fd274e..ce9a457 100644 --- a/COTL_API/CustomInventory/CustomInventoryItem.cs +++ b/COTL_API/CustomInventory/CustomInventoryItem.cs @@ -29,7 +29,6 @@ public abstract class CustomInventoryItem public virtual bool IsFood => false; public virtual bool IsBigFish => false; public virtual bool IsCurrency => false; - public virtual bool IsSeed => false; public virtual bool IsPlantable => false; public virtual bool IsBurnableFuel => false; diff --git a/COTL_API/CustomInventory/Patches/CustomInventoryPatches.cs b/COTL_API/CustomInventory/Patches/CustomInventoryPatches.cs index 10bacef..3dcbfc0 100644 --- a/COTL_API/CustomInventory/Patches/CustomInventoryPatches.cs +++ b/COTL_API/CustomInventory/Patches/CustomInventoryPatches.cs @@ -239,7 +239,7 @@ private static bool InventoryItem_GiveToFollowerCallbacks(InventoryItem.ITEM_TYP [HarmonyPostfix] private static void InventoryItem_AllSeeds(ref List __result) { - __result.AddRange(CustomItemList.Where(x => x.Value.IsSeed).Select(x => x.Key)); + __result.AddRange(CustomCropList.Select(x => x.Key)); } [HarmonyPatch(typeof(InventoryItem), nameof(InventoryItem.AllBurnableFuel), MethodType.Getter)] diff --git a/COTL_API/Debug/DebugItemClass2.cs b/COTL_API/Debug/DebugItemClass2.cs index e7d6ac8..0ecf4d7 100644 --- a/COTL_API/Debug/DebugItemClass2.cs +++ b/COTL_API/Debug/DebugItemClass2.cs @@ -2,12 +2,17 @@ namespace COTL_API.Debug; -public class DebugItemClass2 : CustomInventoryItem +public class DebugItemClass2 : CustomCrop { public override string InternalName => "DEBUG_ITEM_2"; public override CustomInventoryItemType InventoryItemType => CustomInventoryItemType.FOOD; public override bool IsFood => true; - public override bool IsSeed => true; + + public override List HarvestResult { get; } = + [ + Plugin.Instance.DebugItem, + Plugin.Instance.DebugItem2, + ]; } \ No newline at end of file From 1d20b6b7fac934be804e508287b044fa96aaf06d Mon Sep 17 00:00:00 2001 From: zelzmiy <51797223+zelzmiy@users.noreply.github.com> Date: Thu, 9 Jan 2025 17:44:09 -0600 Subject: [PATCH 05/10] bump ver --- COTL_API.Common.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/COTL_API.Common.props b/COTL_API.Common.props index 02b37a8..18274d7 100644 --- a/COTL_API.Common.props +++ b/COTL_API.Common.props @@ -1,7 +1,7 @@ net472 - 0.2.6 + 0.2.7 latest portable true From ff96928117bc9a4f815355a0125862b46f71bb75 Mon Sep 17 00:00:00 2001 From: zelzmiy <51797223+zelzmiy@users.noreply.github.com> Date: Thu, 9 Jan 2025 18:40:11 -0600 Subject: [PATCH 06/10] remove old IsPlantable Toggle (see 254a926) --- COTL_API/CustomInventory/CustomCrops/CustomCrop.cs | 2 +- COTL_API/CustomInventory/CustomInventoryItem.cs | 2 +- COTL_API/CustomInventory/Patches/CustomInventoryPatches.cs | 2 +- COTL_API/Debug/DebugItemClass3.cs | 1 - COTL_API/Debug/DebugItemClass4.cs | 3 +-- 5 files changed, 4 insertions(+), 6 deletions(-) diff --git a/COTL_API/CustomInventory/CustomCrops/CustomCrop.cs b/COTL_API/CustomInventory/CustomCrops/CustomCrop.cs index bce6ba7..a932c02 100644 --- a/COTL_API/CustomInventory/CustomCrops/CustomCrop.cs +++ b/COTL_API/CustomInventory/CustomCrops/CustomCrop.cs @@ -6,7 +6,7 @@ public abstract class CustomCrop : CustomInventoryItem { internal StructureBrain.TYPES StructureType { get; set; } internal int CropStatesCount => CropStates.Count; - public sealed override bool IsPlantable => true; + //public sealed override bool IsPlantable => true; /// /// The States of this crop, the last state should be the fully grown state. Requires at least two states. diff --git a/COTL_API/CustomInventory/CustomInventoryItem.cs b/COTL_API/CustomInventory/CustomInventoryItem.cs index ce9a457..5e79455 100644 --- a/COTL_API/CustomInventory/CustomInventoryItem.cs +++ b/COTL_API/CustomInventory/CustomInventoryItem.cs @@ -29,7 +29,7 @@ public abstract class CustomInventoryItem public virtual bool IsFood => false; public virtual bool IsBigFish => false; public virtual bool IsCurrency => false; - public virtual bool IsPlantable => false; + //public virtual bool IsPlantable => false; public virtual bool IsBurnableFuel => false; public virtual bool CanBeGivenToFollower => false; diff --git a/COTL_API/CustomInventory/Patches/CustomInventoryPatches.cs b/COTL_API/CustomInventory/Patches/CustomInventoryPatches.cs index 3dcbfc0..63cb612 100644 --- a/COTL_API/CustomInventory/Patches/CustomInventoryPatches.cs +++ b/COTL_API/CustomInventory/Patches/CustomInventoryPatches.cs @@ -217,7 +217,7 @@ private static bool InventoryItem_CapacityString(InventoryItem.ITEM_TYPE type, i [HarmonyPostfix] private static void InventoryItem_AllPlantables(ref List __result) { - __result.AddRange(CustomItemList.Where(x => x.Value.IsPlantable).Select(x => x.Key)); + __result.AddRange(CustomCropList.Select(x => x.Key)); } [HarmonyPatch(typeof(InventoryItem), nameof(InventoryItem.GiveToFollowerCallbacks))] diff --git a/COTL_API/Debug/DebugItemClass3.cs b/COTL_API/Debug/DebugItemClass3.cs index 30fd486..34ff69a 100644 --- a/COTL_API/Debug/DebugItemClass3.cs +++ b/COTL_API/Debug/DebugItemClass3.cs @@ -6,5 +6,4 @@ public class DebugItemClass3 : CustomInventoryItem { public override string InternalName => "DEBUG_ITEM_3"; - public override bool IsPlantable => true; } \ No newline at end of file diff --git a/COTL_API/Debug/DebugItemClass4.cs b/COTL_API/Debug/DebugItemClass4.cs index b3da21f..181d7f5 100644 --- a/COTL_API/Debug/DebugItemClass4.cs +++ b/COTL_API/Debug/DebugItemClass4.cs @@ -6,8 +6,7 @@ namespace COTL_API.Debug; public class DebugItemClass4 : CustomInventoryItem { public override string InternalName => "DEBUG_ITEM_4"; - - public override bool IsPlantable => true; + public override InventoryItem.ITEM_TYPE ItemPickUpToImitate => InventoryItem.ITEM_TYPE.BLACK_GOLD; public override CustomItemManager.ItemRarity Rarity => CustomItemManager.ItemRarity.COMMON; From dae7457bc372851d3584b43399fc28787de45683 Mon Sep 17 00:00:00 2001 From: zelzmiy <51797223+zelzmiy@users.noreply.github.com> Date: Thu, 9 Jan 2025 18:49:21 -0600 Subject: [PATCH 07/10] Fix Custom Crops with no CropStates from Erroring --- .../CustomCrops/CustomCropManager.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs b/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs index da26bbb..32bf23a 100644 --- a/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs +++ b/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs @@ -55,14 +55,17 @@ private static void CreateCropObject(CustomCrop crop) var bumperHarvest = duplicate.transform.GetChild(2); var bumperBush = bumperHarvest.GetChild(3).GetChild(0).GetChild(0); - - bush.GetComponent().sprite = crop.CropStates.Last(); - bumperBush.GetComponent().sprite = crop.CropStates.Last(); ; var cropState = duplicate.transform.GetChild(0); - cropState.GetComponent().sprite = crop.CropStates[0]; cropController.CropStates.Add(cropState.gameObject); - + + if (crop.CropStates.Count > 0) + { + bush.GetComponent().sprite = crop.CropStates.Last(); + bumperBush.GetComponent().sprite = crop.CropStates.Last(); + cropState.GetComponent().sprite = crop.CropStates[0]; + } + for (var i = 1; i < crop.CropStates.Count - 1; i++) { var newState = Instantiate(cropState, duplicate.transform); From 35a4cc11617a82d97ba600099782d5ed2e29a1bb Mon Sep 17 00:00:00 2001 From: zelzmiy <51797223+zelzmiy@users.noreply.github.com> Date: Sat, 11 Jan 2025 01:18:20 -0600 Subject: [PATCH 08/10] Actually remove old IsPlantable toggle ff96928 changed related patches but only uncommented the toggle. this one actually removes it --- COTL_API/CustomInventory/CustomCrops/CustomCrop.cs | 1 - COTL_API/CustomInventory/CustomInventoryItem.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/COTL_API/CustomInventory/CustomCrops/CustomCrop.cs b/COTL_API/CustomInventory/CustomCrops/CustomCrop.cs index a932c02..9b201e2 100644 --- a/COTL_API/CustomInventory/CustomCrops/CustomCrop.cs +++ b/COTL_API/CustomInventory/CustomCrops/CustomCrop.cs @@ -6,7 +6,6 @@ public abstract class CustomCrop : CustomInventoryItem { internal StructureBrain.TYPES StructureType { get; set; } internal int CropStatesCount => CropStates.Count; - //public sealed override bool IsPlantable => true; /// /// The States of this crop, the last state should be the fully grown state. Requires at least two states. diff --git a/COTL_API/CustomInventory/CustomInventoryItem.cs b/COTL_API/CustomInventory/CustomInventoryItem.cs index 5e79455..7e8f939 100644 --- a/COTL_API/CustomInventory/CustomInventoryItem.cs +++ b/COTL_API/CustomInventory/CustomInventoryItem.cs @@ -29,7 +29,6 @@ public abstract class CustomInventoryItem public virtual bool IsFood => false; public virtual bool IsBigFish => false; public virtual bool IsCurrency => false; - //public virtual bool IsPlantable => false; public virtual bool IsBurnableFuel => false; public virtual bool CanBeGivenToFollower => false; From cb74cd043b4643364b37a36dc0df6652363016ea Mon Sep 17 00:00:00 2001 From: zelzmiy <51797223+zelzmiy@users.noreply.github.com> Date: Tue, 14 Jan 2025 02:28:43 -0600 Subject: [PATCH 09/10] seal these. --- COTL_API/CustomInventory/CustomFood/CustomDrinks/CustomDrink.cs | 2 +- COTL_API/CustomInventory/CustomFood/CustomMeals/CustomMeal.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/COTL_API/CustomInventory/CustomFood/CustomDrinks/CustomDrink.cs b/COTL_API/CustomInventory/CustomFood/CustomDrinks/CustomDrink.cs index 54c37dd..07c6f9c 100644 --- a/COTL_API/CustomInventory/CustomFood/CustomDrinks/CustomDrink.cs +++ b/COTL_API/CustomInventory/CustomFood/CustomDrinks/CustomDrink.cs @@ -3,7 +3,7 @@ namespace COTL_API.CustomInventory; public abstract class CustomDrink : CustomFood { internal FollowerBrain.PleasureActions PleasureAction { get; set; } - public override InventoryItem.ITEM_TYPE ItemPickUpToImitate { get; } = InventoryItem.ITEM_TYPE.DRINK_GIN; + public sealed override InventoryItem.ITEM_TYPE ItemPickUpToImitate { get; } = InventoryItem.ITEM_TYPE.DRINK_GIN; /// /// The amount of Sin gained by the follower. Range: 0-65 diff --git a/COTL_API/CustomInventory/CustomFood/CustomMeals/CustomMeal.cs b/COTL_API/CustomInventory/CustomFood/CustomMeals/CustomMeal.cs index 2aaf8e1..dac1b6c 100644 --- a/COTL_API/CustomInventory/CustomFood/CustomMeals/CustomMeal.cs +++ b/COTL_API/CustomInventory/CustomFood/CustomMeals/CustomMeal.cs @@ -8,7 +8,7 @@ public abstract class CustomMeal : CustomFood /// public abstract float TummyRating { get; } - public override InventoryItem.ITEM_TYPE ItemPickUpToImitate { get; } = InventoryItem.ITEM_TYPE.MEAL; + public sealed override InventoryItem.ITEM_TYPE ItemPickUpToImitate { get; } = InventoryItem.ITEM_TYPE.MEAL; public virtual MealQuality Quality { get; } = MealQuality.NORMAL; public virtual bool MealSafeToEat { get; } = true; } From 971dd73e9bb14e833409a735fc605e45e84def1a Mon Sep 17 00:00:00 2001 From: zelzmiy <51797223+zelzmiy@users.noreply.github.com> Date: Tue, 14 Jan 2025 20:03:18 -0600 Subject: [PATCH 10/10] cleanup: renaming thanks Inferno for looking over my PR --- COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs | 8 ++++---- COTL_API/CustomInventory/CustomCrops/CustomCropPatches.cs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs b/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs index 32bf23a..2642e84 100644 --- a/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs +++ b/COTL_API/CustomInventory/CustomCrops/CustomCropManager.cs @@ -9,7 +9,7 @@ namespace COTL_API.CustomInventory; public static partial class CustomItemManager { - private static GameObject s_cropPrefab = null!; + internal static GameObject CropPrefab = null!; public static Dictionary CustomCropList { get; } = []; private static Dictionary CropObjectList { get; } = []; @@ -30,10 +30,10 @@ public static InventoryItem.ITEM_TYPE Add(CustomCrop crop) private static void CreateCropObject(CustomCrop crop) { - if (s_cropPrefab == null) + if (CropPrefab == null) throw new NullReferenceException("This REALLY shouldn't happen, send a bug report!"); - var duplicate = Instantiate(s_cropPrefab); + var duplicate = Instantiate(CropPrefab); if (duplicate == null) throw new NullReferenceException("Somehow, the Crop Prefab could not be instantiated, send a bug report"); @@ -92,7 +92,7 @@ public static void InitiateCustomCrops() if (op.Status != AsyncOperationStatus.Succeeded) throw new NullReferenceException("Couldn't Find Berry Crop Object, Send a bug report!"); - s_cropPrefab = handle.Result; + CropPrefab = handle.Result; CustomCropList.Do(x => CreateCropObject(x.Value)); }; } diff --git a/COTL_API/CustomInventory/CustomCrops/CustomCropPatches.cs b/COTL_API/CustomInventory/CustomCrops/CustomCropPatches.cs index 9e4191a..2738085 100644 --- a/COTL_API/CustomInventory/CustomCrops/CustomCropPatches.cs +++ b/COTL_API/CustomInventory/CustomCrops/CustomCropPatches.cs @@ -57,7 +57,7 @@ private static void StructureBrain_CreateBrain(StructuresData data, ref Structur [HarmonyPatch(typeof(FarmPlot), nameof(FarmPlot.Awake))] [HarmonyPostfix] - private static void FarmPlot_Postfix(FarmPlot __instance) + private static void FarmPlot_Awake(FarmPlot __instance) { foreach(var kvp in CropObjectList) {