-
Couldn't load subscription status.
- Fork 4.7k
Botany Rework Part 3: Plants as Entities #31941
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
Conversation
|
🙏 |
|
this would also fix every sentience mutation being either hydroponics tray or soil? and it would kill the sentience with the plant? |
Yes, This would let the plant itself be sentient.
As written right now, without merging any of the other pieces smartly, this kills the sentience when the plant is destroyed (on shovel use to uproot, or on harvest if its a single-harvest crop). Whether sentient plants should stop aging when possessed, or get an extended lifespan, or just be fully at the mercy of a botanist's skills and patience is an unasked question. I would like the refactors to avoid changing balance or features as much as possible, so I expect that this would go in with "dead plants can talk, talking plants die on harvest" as known side effects and a discussion on how/if to change sentient plants occurs then. |
|
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
41c86d1 to
40bf2e4
Compare
|
Please keep idealLight. I'm using it on my fork on some plants (they need to glow in dark places) |
|
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
|
Still in progress? |
Yes. I haven't made a big deal of trying to push my changes through. The maintainers have had a pretty big pile of nonsense to deal with since I started this, and I don't want to add any additional pressure on them for a refactor PR. |
|
Yeah, I'm sorry for the wait, things have been really busy recently. I still got the review for this on my ToDo list and hope I can do it soon. But for a review this size I need at least half a day of free time. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay some thoughts: I really don't like the GetEverything method and how we're overwritting the PlantComponent in a lot of cases, it seems really pointless. You could really play around with the Entity and Entity<T?> patterns for signatures, some of this seems like it could be replaced with queries, especially stuff called from inside of Update(), and then passed on to other methods (which I think would be a better way of getting that data)
| namespace Content.Client.Botany.Components; | ||
|
|
||
| [RegisterComponent] | ||
| public sealed partial class PlantVisualsComponent : Component |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need a body declared.
| SubscribeLocalEvent<PlantVisualsComponent, ComponentInit>(OnComponentInit); | ||
| } | ||
|
|
||
| private void OnComponentInit(EntityUid uid, PlantVisualsComponent component, ComponentInit args) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Entity<T> ent, ref event args pattern.
| [Access(typeof(BotanySystem), typeof(PlantSystem), typeof(PlantHolderSystem), typeof(EntityEffect))] | ||
| public sealed partial class PlantComponent : Component | ||
| { | ||
| [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add the AutoPausedField attribute.
| [DataField] | ||
| public int LastProduce; | ||
|
|
||
| [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add the AutoPausedField attribute.
| /// The time between growth ticks. | ||
| /// </summary> | ||
| [DataField] | ||
| public TimeSpan CycleDelay = TimeSpan.FromSeconds(15f); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just 15.
| /// <summary> | ||
| /// Cease the growth and harvesting of a plant through the conclusion of biological processes. | ||
| /// </summary> | ||
| public void Die(EntityUid uid, PlantComponent? plant = null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overwritten.
| /// </summary> | ||
| public void Die(EntityUid uid, PlantComponent? plant = null) | ||
| { | ||
| if (!GetEverything(uid, out plant, out var seed, out var holder) || plant == null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seed can be discarded.
| /// </summary> | ||
| public void UpdateSprite(EntityUid uid, PlantComponent? component = null) | ||
| { | ||
| GetEverything(uid, out var plant, out _, out _); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need two separate plant components?
| /// </summary> | ||
| [DataField("packetPrototype", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))] | ||
| [DataField(customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))] | ||
| public string PacketPrototype = "SeedBase"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EntProtoId
| /// </summary> | ||
| [DataField("productPrototypes", customTypeSerializer: typeof(PrototypeIdListSerializer<EntityPrototype>))] | ||
| [DataField(customTypeSerializer: typeof(PrototypeIdListSerializer<EntityPrototype>))] | ||
| public List<string> ProductPrototypes = new(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EntProtoId
|
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
|
Thank you for your contribution! Due to this PR being having no activity and unresolved review comments, we've decided to close it. If you ever come back to it, feel free to open a new PR. |
About the PR
This PR creates plants as their own Entities, instead of a bunch of properties on a PlantHolder. SeedData gets moved to the PlantComponent.
This is part 3 of my Botany refactor writeup. Part 2 covers growth components. This is in draft state while I work on this logic for early feedback. While I work on moving and testing code, I'm only going to test on wheat stalks. I'll move everything to the final setup in YAML when I get there.
Why / Balance
As mentioned in the core writeup and other PRs, botany can't really get any major changes because the backend system is mostly handled in one big function and adding anything to that only makes it more difficult to clean up. This strips the plant-specific part out so PlantHolder can just update its lights and resources and the Plant can handle its tasks. Between this, growth components, and the mutation rework, the Botany code will be in a much better state for future maintenance and additions.
This should have no bearings on game balance, because this is just a refactor. A few bugs might be fixed or created in the process of porting code rather than porting poor/broken behavior.
Technical details
Plants are now entities. They are connected to their PlantHolder, and they are spawned when seeds are planted and deleted when they're harvested (if single harvest) or when the shovel is used to pull them out. SeedData is moved to the PlantComponent now.
All the existing plant logic was moved into a single Update() on PlantSystem. Breaking that out to separate components and systems is done in Part 2. It may be too granular to break each stat into its own component/system pair. Merging these should mostly require operating on Plants instead of PlantHolders.
Plants still need a PlantHolder. PlantHolder still has the water/nutrients the plant needs so the plant still need to have a connection to that. I have helper functions that get the Plant, PlantHolder, and SeedData all at once because of how often all 3 get referenced. The 2 entities keep a reference to the other, and blank it out when the plant is removed from the tray.
Chemicals are still applied to and run by the PlantHolder. The code that increases the water/nutrient level in the PlantHolder is a PlantEffect, so those all need to be run on the PlantHolder and then determine if the plant needs to be involved on each. Splitting this up to make more logical sense is a future enhancement.
Plants should grow identically to before, almost entirely unnoticeable to players. As entities, you can see them instead of the tray and view them in the right-click menu. That's visibly different. You also need to apply different items to different entities (EX: clippers must be used on the plant, but spades and chemicals need to be used on the tray itself).
The Slippery mutation no longer applies to the plant itself. It continues to apply to the produce harvested. I could not work out a way to make the plant entity both correctly fixed to the PlantHolder and get it to register the stepOn collision correctly. Oddly, it could handle a StepOFF trigger correctly but that happens once you've completely walked off the entity and it didn't feel right when everything else slips you when you step on it. Making the plant itself not slippery is the simplest, lowest-impact change to be made for this.
Additional changes:
Media
Requirements
Breaking changes
PlantHolder is pretty dramatically different.
Changelog
🆑