Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crops persistence #2137

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions NitroxClient/GameLogic/ItemContainers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ public void BroadcastItemAdd(Pickupable pickupable, Transform containerTransform
return;
}

// Plantable pickup should not be managed by EntityReparented, but by Items.PickedUp
if (pickupable.GetComponent<Plantable>())
// calls from Inventory.Pickup are managed by Items.PickedUp
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

V minor

Suggested change
// calls from Inventory.Pickup are managed by Items.PickedUp
// Calls from Inventory.Pickup are managed by Items.PickedUp

if (items.InventoryPickingUp)
{
return;
}
Expand Down
13 changes: 11 additions & 2 deletions NitroxClient/GameLogic/Items.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ public class Items
public static GameObject PickingUpObject { get; private set; }
private readonly EntityMetadataManager entityMetadataManager;

/// <summary>
/// Whether or not <see cref="Inventory.Pickup"/> is running. It's useful to discriminate between Inventory.Pickup from a regular
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really understand this comment. What is regular?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cut the comment again 💀 "a regular Pickupable.Pickup"

/// </summary>
public bool InventoryPickingUp;

public Items(IPacketSender packetSender, Entities entities, EntityMetadataManager entityMetadataManager)
{
this.packetSender = packetSender;
Expand All @@ -36,14 +41,18 @@ public void PickedUp(GameObject gameObject, TechType techType)
PickingUpObject = gameObject;

InventoryItemEntity inventoryItemEntity = ConvertToInventoryEntityUntracked(gameObject);
Log.Debug($"PickedUp item {inventoryItemEntity}");

if (inventoryItemEntity.TechType.ToUnity() != techType)
{
Log.Warn($"Provided TechType: {techType} is different than the one automatically attributed to the item {inventoryItemEntity.TechType}");
}

PickupItem pickupItem = new(inventoryItemEntity);
packetSender.Send(pickupItem);

if (packetSender.Send(pickupItem))
{
Log.Debug($"Picked up item {inventoryItemEntity}");
}
PickingUpObject = null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ private void SetupObject(InventoryItemEntity entity, GameObject gameObject, Game
inventoryItem.isEnabled = false;
planter.AddItem(plantable, metadata.SlotID);

// Reapply the plantable metadata after the GrowingPlant (or the GrownPlant) is spawned
// Apply the plantable metadata after the GrowingPlant (or the GrownPlant) is spawned
// this will allow the GrowingPlant to know about its progress
entityMetadataManager.ApplyMetadata(plantable.gameObject, metadata);

// Plant spawning occurs in multiple steps over frames:
Expand All @@ -140,6 +141,9 @@ private void SetupObject(InventoryItemEntity entity, GameObject gameObject, Game
{
MetadataHolder.AddMetadata(plantable.growingPlant.gameObject, metadata.FruitPlantMetadata);
}

// NB: Entities.SpawnBatchAsync (which is the function calling the current spawner)
// will still apply the metadata another time but we don't care as it's not destructive
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ public class PlantableMetadataExtractor(FruitPlantMetadataExtractor fruitPlantMe

public override PlantableMetadata Extract(Plantable plantable)
{
PlantableMetadata metadata = new(plantable.growingPlant ? plantable.growingPlant.timeStartGrowth : 0, plantable.GetSlotID());
// Default value for no progress is -1
PlantableMetadata metadata = new(plantable.growingPlant ? plantable.growingPlant.timeStartGrowth : -1, plantable.GetSlotID());

// TODO: Refer to the TODO in PlantableMetadata
if (plantable.linkedGrownPlant && plantable.linkedGrownPlant.TryGetComponent(out FruitPlant fruitPlant))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,26 @@ public override void ProcessMetadata(GameObject gameObject, FruitPlantMetadata m

// 2. The entity with an id has a Plantable (located in the plot's storage),
// we want to access the FruitPlant component which is on the spawned plant object
if (gameObject.TryGetComponent(out Plantable plantable))
if (!gameObject.TryGetComponent(out Plantable plantable))
{
if (plantable.linkedGrownPlant && plantable.linkedGrownPlant.TryGetComponent(out fruitPlant))
{
ProcessMetadata(fruitPlant, metadata);
}
Log.Error($"[{nameof(FruitPlantMetadataProcessor)}] Could not find {nameof(FruitPlant)} related to {gameObject.name}");
return;
}

if (!plantable.linkedGrownPlant)
{
// This is an error which will happen quite often since this metadata
// is applied from PlantableMetadataProcessor even when linkedGrownPlant isn't available yet
return;
}

if (!plantable.linkedGrownPlant.TryGetComponent(out fruitPlant))
{
Log.Error($"[{nameof(FruitPlantMetadataProcessor)}] Could not find {nameof(FruitPlant)} on {gameObject.name}'s linkedGrownPlant {plantable.linkedGrownPlant.name}");
return;
}

Log.Error($"[{nameof(FruitPlantMetadataProcessor)}] Could not find {nameof(FruitPlant)} related to {gameObject.name}");
ProcessMetadata(fruitPlant, metadata);
}

private static void ProcessMetadata(FruitPlant fruitPlant, FruitPlantMetadata metadata)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ public override void ProcessMetadata(GameObject gameObject, PlantableMetadata me
return;
}

// For Plantables which were replaced by the GrowingPlant object
if (plantable.growingPlant)
{
plantable.growingPlant.timeStartGrowth = metadata.TimeStartGrowth;
}
// For regular Plantables
else if (plantable.model.TryGetComponent(out GrowingPlant growingPlant))
{
// Calculation from GrowingPlant.GetProgress (reversed because we're looking for "progress" while we already know timeStartGrowth)
Expand Down
8 changes: 4 additions & 4 deletions NitroxClient/Helpers/NitroxEntityExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public static bool TryGetNitroxId(this GameObject gameObject, out NitroxId nitro
}

nitroxId = nitroxEntity.Id;
return true;
return nitroxId != null;
}

public static bool TryGetNitroxId(this Component component, out NitroxId nitroxId)
Expand All @@ -43,7 +43,7 @@ public static bool TryGetNitroxId(this Component component, out NitroxId nitroxI
}

nitroxId = nitroxEntity.Id;
return true;
return nitroxId != null;
}

public static bool TryGetIdOrWarn(
Expand All @@ -67,7 +67,7 @@ public static bool TryGetIdOrWarn(
}

nitroxId = nitroxEntity.Id;
return true;
return nitroxId != null;
}

public static bool TryGetIdOrWarn(
Expand All @@ -91,7 +91,7 @@ public static bool TryGetIdOrWarn(
}

nitroxId = nitroxEntity.Id;
return true;
return nitroxId != null;
}

public static Optional<NitroxId> GetId(this GameObject gameObject)
Expand Down
10 changes: 7 additions & 3 deletions NitroxClient/MonoBehaviours/Gui/Modals/Modal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,11 @@ private void UpdateModal()
yesButton.onClick = new Button.ButtonClickedEvent();
yesButton.onClick.AddListener(ClickYes);
buttonYesObject.GetComponentInChildren<TextMeshProUGUI>().text = YesButtonText;
buttonYesObject.GetComponent<RectTransform>().anchoredPosition = new Vector2(0, 50f - Height);
RectTransform yesButtonTransform = buttonYesObject.GetComponent<RectTransform>();
yesButtonTransform.anchoredPosition = new Vector2(yesButtonTransform.anchoredPosition.x, 50f - Height);


// TODO: fix yes and no button positions
if (HideNoButton)
{
UnityEngine.Object.Destroy(buttonNoObject);
Expand All @@ -171,9 +174,10 @@ private void UpdateModal()
{
Button noButton = buttonNoObject.GetComponent<Button>();
noButton.onClick = new Button.ButtonClickedEvent();
noButton.onClick.AddListener(() => { ClickNo(); });
noButton.onClick.AddListener(ClickNo);
buttonNoObject.GetComponentInChildren<TextMeshProUGUI>().text = NoButtonText;
buttonNoObject.GetComponent<RectTransform>().anchoredPosition = new Vector2(0, 50f - Height);
RectTransform noButtonTransform = buttonNoObject.GetComponent<RectTransform>();
noButtonTransform.anchoredPosition = new Vector2(noButtonTransform.anchoredPosition.x, 50f - Height);
}
}

Expand Down
20 changes: 20 additions & 0 deletions NitroxPatcher/Patches/Dynamic/Inventory_Pickup_Patch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Reflection;
using NitroxClient.GameLogic;
using NitroxModel.Helper;

namespace NitroxPatcher.Patches.Dynamic;

public sealed partial class Inventory_Pickup_Patch : NitroxPatch, IDynamicPatch
{
private static readonly MethodInfo TARGET_METHOD = Reflect.Method((Inventory t) => t.Pickup(default, default));

public static void Prefix()
{
Resolve<Items>().InventoryPickingUp = true;
}

public static void Finalizer()
{
Resolve<Items>().InventoryPickingUp = false;
}
}
2 changes: 1 addition & 1 deletion NitroxPatcher/Patches/Dynamic/LiveMixin_Kill_Patch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public static void Postfix(LiveMixin __instance)

// We don't broadcast if we don't have objectId or if the object is whitelisted,
// in which case kill broadcast is managed differently
if (!__instance.TryGetIdOrWarn(out NitroxId objectId) ||
if (!__instance.TryGetNitroxId(out NitroxId objectId) ||
Resolve<LiveMixinManager>().IsWhitelistedUpdateType(__instance))
{
return;
Expand Down