I’ve been attempting to make things as modular as possible, although I haven’t yet tested, I believe someone can make a mod to my game by creating a system that runs in between two existing systems, or one that straight up replaces a system, so long it’s DLL is loaded before the world initialization (which I took control of).
The unfortunate side effect is that I have a f-load of systems doing very small stuff each, not sure if it’s bad or not, but struct systems that will supposedly come out in the next update will help with whichever side effects it have, probably.
Imagine you have a huge OOP method that handles all the complexities of how a plant grows, matures, change stages, get fruits, etc. Instead, I use a whole lot of systems that are strictly ordered to do the same thing.
Some examples of what I ended up with:
Resets all values for the plant, equivalent of a whole bunch of variable initializations at the start of a huge method
Frame Start Reset Values
[UpdateInGroup(typeof(GroupPlantFrameStart))]
public class FrameStartUpkeepCopyCrop : JobComponentSystem {
public EntityQuery query1;
public EntityQuery query2;
protected override void OnCreate() {
base.OnCreate();
query1 = GetEntityQuery(ComponentType.ReadOnly<NuAdd>(), ComponentType.ReadOnly<KaAdd>(), ComponentType.ReadOnly<PiAdd>(),
ComponentType.ReadOnly<ResilienceAdditive>(), ComponentType.ReadOnly<ResilienceMultiplier>(), ComponentType.ReadOnly<PlantTemperatureBufferMax>(),
ComponentType.ReadOnly<PlantManaBufferMultiplier>(), ComponentType.ReadOnly<PlantWaterBufferMultiplier>(), ComponentType.ReadOnly<PlantNutrientBufferMultiplier>(),
ComponentType.ReadOnly<PlantTemperatureBufferMultiplier>(), ComponentType.ReadOnly<BasePlantData>(),
typeof(PlantNuUpkeep), typeof(PlantKaUpkeep), typeof(PlantPiUpkeep), typeof(PlantNutrientBufferMax),
typeof(PlantWaterMinNeed), typeof(PlantWaterMaxNeed), typeof(PlantWaterBufferMax),
typeof(PlantManaMinNeed), typeof(PlantManaBufferMax),
typeof(PlantDamageThisCycle), typeof(ShouldPlantTakeDamage));
query2 = GetEntityQuery(typeof(CurrentPlantStage), typeof(CurrentStageTempData),
typeof(PlantTemperatureMinNeed), typeof(PlantTemperatureMaxNeed), typeof(PlantGrowPerDay), typeof(PlantGrowThisCycle));
}
#region Systems
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyAutoAdd0 : AutoAddSystem<BasePlantData, CanHarvest> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyAutoAdd1 : AutoAddSystem<BasePlantData, PlantNuUpkeep, PlantKaUpkeep, PlantPiUpkeep> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyAutoAdd2 : AutoAddSystem<BasePlantData, PlantNutrientBufferMax> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyAutoAdd31 : AutoAddSystem<BasePlantData, PlantWaterMinNeed, PlantWaterMaxNeed, PlantWaterBufferMax> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyAutoAdd32 : AutoAddSystem<BasePlantData, PlantManaMinNeed, PlantManaBufferMax> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyAutoAdd33 : AutoAddSystem<BasePlantData, PlantTemperatureBufferMax> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyAutoAdd4 : AutoAddSystemShared<StageData, PlantTemperatureMinNeed, PlantTemperatureMaxNeed> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyAutoAdd5 : AutoAddSystemShared<StageData, PlantGrowPerDay, PlantGrowThisCycle> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyAutoAdd6 : AutoAddSystem<BasePlantData, PlantDamageThisCycle, ShouldPlantTakeDamage> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyAutoAdd7 : AutoAddSystem<BasePlantData, PlantShouldTakeNUDamage, PlantShouldTakeKADamage, PlantShouldTakePIDamage> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyAutoAdd8 : AutoAddSystem<BasePlantData, PlantShouldTakeWATERDamage, PlantShouldTakeMANADamage, PlantShouldTakeTEMPDamage> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyAutoAdd9 : AutoAddSystem<BasePlantData, PlantUsingNUBuffer, PlantUsingKABuffer, PlantUsingPIBuffer> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyAutoAdd10 : AutoAddSystem<BasePlantData, PlantUsingWATERBuffer, PlantUsingMANABuffer, PlantUsingTEMPBuffer> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyAutoAdd14 : AutoAddSystem<BasePlantData, PlantNutrientBufferMultiplier, PlantWaterBufferMultiplier> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyAutoAdd15 : AutoAddSystem<BasePlantData, PlantTemperatureBufferMultiplier, PlantManaBufferMultiplier> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyAutoAdd11 : AutoAddSystem<TileAdjacency, PlantNeedNutrients, PlantNeedTemperature, PlantNeedWater> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyAutoAdd12 : AutoAddSystem<TileAdjacency, PlantNeedMana, PlantAlertNutrients, PlantAlertTemperature> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyAutoAdd13 : AutoAddSystem<TileAdjacency, PlantAlertWater, PlantAlertMana, CanHarvest> { }
[UpdateInGroup(typeof(GroupPlantFrameInitialization))]
public class CopyAutoBuffer1 : AutoCopySystem<PlantNutrientBuffer, PlantNutrientBufferMax> { }
[UpdateInGroup(typeof(GroupPlantFrameInitialization))]
public class CopyAutoBuffer2 : AutoCopySystem<PlantWaterBuffer, PlantWaterBufferMax> { }
[UpdateInGroup(typeof(GroupPlantFrameInitialization))]
public class CopyAutoBuffer3 : AutoCopySystem<PlantManaBuffer, PlantManaBufferMax> { }
[UpdateInGroup(typeof(GroupPlantFrameInitialization))]
public class CopyAutoBuffer4 : AutoCopySystem<PlantTemperatureBuffer, PlantTemperatureBufferMax> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyNuTile : FrameStartUpkeepCopyTile<SoilNuBaseGain, SoilNuGainThisCycle> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyPiTile : FrameStartUpkeepCopyTile<SoilPiBaseGain, SoilPiGainThisCycle> { }
[UpdateInGroup(typeof(GroupPlantAutoAdd))]
public class FrameStartUpkeepCopyKaTile : FrameStartUpkeepCopyTile<SoilKaBaseGain, SoilKaGainThisCycle> { }
#endregion
[BurstCompile]
struct FrameStartUpkeepCopyBasePlantDataJob : IJobChunk {
[NativeDisableContainerSafetyRestriction, ReadOnly] public ComponentTypeHandle<BasePlantData> BasePlantData;
[NativeDisableContainerSafetyRestriction, ReadOnly] public ComponentTypeHandle<ResilienceAdditive> ResilienceAdd;
[NativeDisableContainerSafetyRestriction, ReadOnly] public ComponentTypeHandle<ResilienceMultiplier> ResilienceMultiplier;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<NuAdd> NuAdd;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<KaAdd> KaAdd;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PiAdd> PiAdd;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantNuUpkeep> PlantNuUpkeep;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantKaUpkeep> PlantKaUpkeep;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantPiUpkeep> PlantPiUpkeep;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantManaMinNeed> PlantManaMinNeed;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantWaterMinNeed> PlantWaterMinNeed;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantWaterMaxNeed> PlantWaterMaxNeed;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantManaBufferMax> PlantManaBufferMax;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantWaterBufferMax> PlantWaterBufferMax;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantDamageThisCycle> PlantDamageThisCycle;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<ShouldPlantTakeDamage> ShouldPlantTakeDamage;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantNutrientBufferMax> PlantNutrientBufferMax;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantTemperatureBufferMax> PlantTemperatureBufferMax;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantManaBufferMultiplier> PlantManaBufferMultiplier;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantWaterBufferMultiplier> PlantWaterBufferMultiplier;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantNutrientBufferMultiplier> PlantNutrientBufferMultiplier;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantTemperatureBufferMultiplier> PlantTemperatureBufferMultiplier;
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) {
var BasePlantDataValuesArray = chunk.GetNativeArray(this.BasePlantData);
var ResilienceAdd = chunk.GetNativeArray(this.ResilienceAdd).Reinterpret<float>();
var ResilienceMultiplier = chunk.GetNativeArray(this.ResilienceMultiplier).Reinterpret<float>();
var NuAdd = chunk.GetNativeArray(this.NuAdd).Reinterpret<float>();
var KaAdd = chunk.GetNativeArray(this.KaAdd).Reinterpret<float>();
var PiAdd = chunk.GetNativeArray(this.PiAdd).Reinterpret<float>();
var PlantNuUpkeep = chunk.GetNativeArray(this.PlantNuUpkeep).Reinterpret<float>();
var PlantKaUpkeep = chunk.GetNativeArray(this.PlantKaUpkeep).Reinterpret<float>();
var PlantPiUpkeep = chunk.GetNativeArray(this.PlantPiUpkeep).Reinterpret<float>();
var PlantManaMinNeed = chunk.GetNativeArray(this.PlantManaMinNeed).Reinterpret<float>();
var PlantWaterMinNeed = chunk.GetNativeArray(this.PlantWaterMinNeed).Reinterpret<float>();
var PlantWaterMaxNeed = chunk.GetNativeArray(this.PlantWaterMaxNeed).Reinterpret<float>();
var PlantManaBufferMax = chunk.GetNativeArray(this.PlantManaBufferMax).Reinterpret<float>();
var PlantWaterBufferMax = chunk.GetNativeArray(this.PlantWaterBufferMax).Reinterpret<float>();
var PlantDamageThisCycle = chunk.GetNativeArray(this.PlantDamageThisCycle).Reinterpret<float>();
var ShouldPlantTakeDamage = chunk.GetNativeArray(this.ShouldPlantTakeDamage).Reinterpret<byte>();
var PlantNutrientBufferMax = chunk.GetNativeArray(this.PlantNutrientBufferMax).Reinterpret<float>();
var PlantTemperatureBufferMax = chunk.GetNativeArray(this.PlantTemperatureBufferMax).Reinterpret<float>();
var PlantManaBufferMultiplier = chunk.GetNativeArray(this.PlantManaBufferMultiplier).Reinterpret<float>();
var PlantWaterBufferMultiplier = chunk.GetNativeArray(this.PlantWaterBufferMultiplier).Reinterpret<float>();
var PlantNutrientBufferMultiplier = chunk.GetNativeArray(this.PlantNutrientBufferMultiplier).Reinterpret<float>();
var PlantTemperatureBufferMultiplier = chunk.GetNativeArray(this.PlantTemperatureBufferMultiplier).Reinterpret<float>();
for (int i = 0; i < chunk.Count; i++) {
BasePlantData BasePlantData = BasePlantDataValuesArray[i];
PlantNuUpkeep[i] = BasePlantData.BaseNu + NuAdd[i];
PlantKaUpkeep[i] = BasePlantData.BaseKa + KaAdd[i];
PlantPiUpkeep[i] = BasePlantData.BasePi + PiAdd[i];
PlantManaMinNeed[i] = BasePlantData.BaseMana;
PlantWaterMinNeed[i] = BasePlantData.BaseWater - (BasePlantData.Resist + ResilienceAdd[i]) * ResilienceMultiplier[i];
PlantWaterMaxNeed[i] = BasePlantData.BaseWater + (BasePlantData.Resist + ResilienceAdd[i]) * ResilienceMultiplier[i];
PlantManaBufferMax[i] = BasePlantData.ManaBufferMax;
PlantWaterBufferMax[i] = BasePlantData.WaterBufferMax;
PlantDamageThisCycle[i] = 0;
ShouldPlantTakeDamage[i] = 0;
PlantNutrientBufferMax[i] = BasePlantData.NutrientBufferMax;
PlantTemperatureBufferMax[i] = BasePlantData.TemperatureBufferMax;
PlantManaBufferMultiplier[i] = 1;
PlantWaterBufferMultiplier[i] = 1;
PlantNutrientBufferMultiplier[i] = 1;
PlantTemperatureBufferMultiplier[i] = 1;
}
}
}
[BurstCompile]
struct FrameStartUpkeepCopyStageDataJob : IJobChunk {
#if UNITY_EDITOR
public float Multiplier;
#endif
[NativeDisableContainerSafetyRestriction, ReadOnly] public ComponentTypeHandle<CurrentPlantStage> CurrentPlantStage;
[NativeDisableContainerSafetyRestriction, ReadOnly] public ComponentTypeHandle<CurrentStageTempData> CurrentStageTempData;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantTemperatureMinNeed> PlantTemperatureMinNeed;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantTemperatureMaxNeed> PlantTemperatureMaxNeed;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantGrowPerDay> PlantGrowPerDay;
[NativeDisableContainerSafetyRestriction] public ComponentTypeHandle<PlantGrowThisCycle> PlantGrowThisCycle;
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) {
var CurrentPlantStage = chunk.GetNativeArray(this.CurrentPlantStage).Reinterpret<float>(24);
var CurrentStageTempData = chunk.GetNativeArray(this.CurrentStageTempData).Reinterpret<float>(8);
var PlantTemperatureMinNeed = chunk.GetNativeArray(this.PlantTemperatureMinNeed).Reinterpret<float>();
var PlantTemperatureMaxNeed = chunk.GetNativeArray(this.PlantTemperatureMaxNeed).Reinterpret<float>();
var PlantGrowPerDay = chunk.GetNativeArray(this.PlantGrowPerDay).Reinterpret<float>();
var PlantGrowThisCycle = chunk.GetNativeArray(this.PlantGrowThisCycle).Reinterpret<float>();
for (int i = 0; i < chunk.Count; i++) {
PlantTemperatureMinNeed[i] = CurrentStageTempData[i * 2 + 0];
PlantTemperatureMaxNeed[i] = CurrentStageTempData[i * 2 + 1];
#if UNITY_EDITOR
PlantGrowPerDay[i] = 1f / CurrentPlantStage[i * 6 + 5] * Multiplier;
#else
PlantGrowPerDay[i] = 1f / CurrentPlantStage[i * 6 + 5];
#endif
PlantGrowThisCycle[i] = 0;
}
}
}
protected override JobHandle OnUpdate(JobHandle inputDependencies) {
var job = new FrameStartUpkeepCopyBasePlantDataJob();
job.BasePlantData = GetComponentTypeHandle<BasePlantData>(true);
job.ResilienceAdd = GetComponentTypeHandle<ResilienceAdditive>(true);
job.ResilienceMultiplier = GetComponentTypeHandle<ResilienceMultiplier>(true);
job.NuAdd = GetComponentTypeHandle<NuAdd>(false);
job.KaAdd = GetComponentTypeHandle<KaAdd>(false);
job.PiAdd = GetComponentTypeHandle<PiAdd>(false);
job.PlantNuUpkeep = GetComponentTypeHandle<PlantNuUpkeep>(false);
job.PlantKaUpkeep = GetComponentTypeHandle<PlantKaUpkeep>(false);
job.PlantPiUpkeep = GetComponentTypeHandle<PlantPiUpkeep>(false);
job.PlantManaMinNeed = GetComponentTypeHandle<PlantManaMinNeed>(false);
job.PlantWaterMinNeed = GetComponentTypeHandle<PlantWaterMinNeed>(false);
job.PlantWaterMaxNeed = GetComponentTypeHandle<PlantWaterMaxNeed>(false);
job.PlantManaBufferMax = GetComponentTypeHandle<PlantManaBufferMax>(false);
job.PlantWaterBufferMax = GetComponentTypeHandle<PlantWaterBufferMax>(false);
job.PlantDamageThisCycle = GetComponentTypeHandle<PlantDamageThisCycle>(false);
job.ShouldPlantTakeDamage = GetComponentTypeHandle<ShouldPlantTakeDamage>(false);
job.PlantNutrientBufferMax = GetComponentTypeHandle<PlantNutrientBufferMax>(false);
job.PlantTemperatureBufferMax = GetComponentTypeHandle<PlantTemperatureBufferMax>(false);
job.PlantManaBufferMultiplier = GetComponentTypeHandle<PlantManaBufferMultiplier>(false);
job.PlantWaterBufferMultiplier = GetComponentTypeHandle<PlantWaterBufferMultiplier>(false);
job.PlantNutrientBufferMultiplier = GetComponentTypeHandle<PlantNutrientBufferMultiplier>(false);
job.PlantTemperatureBufferMultiplier = GetComponentTypeHandle<PlantTemperatureBufferMultiplier>(false);
var job2 = new FrameStartUpkeepCopyStageDataJob();
#if UNITY_EDITOR
job2.Multiplier = EverydayEngine.GameEngine.instance.DEBUG.PlantDebugGrowSpeed;
#endif
job2.CurrentPlantStage = GetComponentTypeHandle<CurrentPlantStage>(true);
job2.CurrentStageTempData = GetComponentTypeHandle<CurrentStageTempData>(true);
job2.PlantTemperatureMinNeed = GetComponentTypeHandle<PlantTemperatureMinNeed>(false);
job2.PlantTemperatureMaxNeed = GetComponentTypeHandle<PlantTemperatureMaxNeed>(false);
job2.PlantGrowPerDay = GetComponentTypeHandle<PlantGrowPerDay>(false);
job2.PlantGrowThisCycle = GetComponentTypeHandle<PlantGrowThisCycle>(false);
return job2.Schedule(query2, job.Schedule(query1, inputDependencies));
}
}
public abstract class FrameStartUpkeepCopyTile<T, T2> : JobComponentSystem where T : struct, IComponentData where T2 : struct, IComponentData {
public EntityQuery query;
protected override void OnCreate() {
base.OnCreate();
query = GetEntityQuery(ComponentType.ReadOnly<T>(), typeof(T2));
}
[BurstCompile]
struct FrameStartUpkeepCopyJob : IJobChunk {
[ReadOnly] public ComponentTypeHandle<T> T;
public ComponentTypeHandle<T2> T2;
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) {
var T = chunk.GetNativeArray(this.T).Reinterpret<float>();
var T2 = chunk.GetNativeArray(this.T2).Reinterpret<float>();
for (int i = 0; i < chunk.Count; i++) {
T2[i] = T[i];
}
}
}
protected override JobHandle OnUpdate(JobHandle inputDependencies) {
var job = new FrameStartUpkeepCopyJob();
job.T = GetComponentTypeHandle<T>(true);
job.T2 = GetComponentTypeHandle<T2>(false);
return job.Schedule(query, inputDependencies);
}
}
Bolting Plant Trait that checks if the plant is taking damage this frame, if so, the plant grows faster, taking even more damage than otherwise, overriding the natural plant growth value before the plant has a chance to grow. Equivalent to two IFS, one for checking if the plant has the bolting trait, and another to check if it is taking damage, then changing the temporary variables to match the effect
Bolting
[UpdateAfter(typeof(CalculatePlantDamageThisCycle))]
[UpdateBefore(typeof(PlantGrow))]
[UpdateInGroup(typeof(PlantGroupAfterUpkeep))]
public class BoltingGrowMod : JobComponentSystem {
public EntityQuery query;
protected override void OnCreate() {
base.OnCreate();
query = GetEntityQuery(ComponentType.ReadOnly<BasePlantData>(),
typeof(ShouldPlantTakeDamage), typeof(PlantGrowThisCycle), typeof(PlantDamageThisCycle), typeof(PlantGrowPerDay), typeof(BoltingTrait));
}
[BurstCompile]
struct BoltModJob : IJobChunk {
[ReadOnly] public ComponentTypeHandle<BoltingTrait> BoltingTrait;
public ComponentTypeHandle<PlantDamageThisCycle> PlantDamageThisCycle;
public ComponentTypeHandle<PlantGrowThisCycle> PlantGrowThisCycle;
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) {
var PlantDamageThisCycle = chunk.GetNativeArray(this.PlantDamageThisCycle).Reinterpret<float>();
var PlantGrowThisCycle = chunk.GetNativeArray(this.PlantGrowThisCycle).Reinterpret<float>();
var BoltingTrait = chunk.GetNativeArray(this.BoltingTrait).Reinterpret<float>();
for (int i = 0; i < chunk.Count; i++) {
if (PlantDamageThisCycle[i] != 0) {
PlantDamageThisCycle[i] *= BoltingTrait[i];
PlantGrowThisCycle[i] *= BoltingTrait[i];
}
}
}
}
protected override JobHandle OnUpdate(JobHandle inputDependencies) {
var job = new BoltModJob();
job.PlantDamageThisCycle = GetComponentTypeHandle<PlantDamageThisCycle>(false);
job.PlantGrowThisCycle = GetComponentTypeHandle<PlantGrowThisCycle>(false);
job.BoltingTrait = GetComponentTypeHandle<BoltingTrait>(true);
return job.Schedule(query, inputDependencies);
}
}
Applies the temporary variables to the plant state, equivalent of waiting all of the chances the plants has to modify their plant growth value, then at the end of the huge method, applying the plant plant growth to the plant actual growth state.
Plant Growth
[UpdateInGroup(typeof(PlantGroupAfterUpkeep))]
public class PlantGrow : JobComponentSystem {
public EntityQuery query;
EndSimulationEntityCommandBufferSystem entityCommandBufferSystem;
protected override void OnCreate() {
base.OnCreate();
entityCommandBufferSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
query = GetEntityQuery(ComponentType.ReadOnly<BasePlantData>(), ComponentType.ReadOnly<CurrentPlantStage>(), typeof(CurrentPlantGrowth),
typeof(PlantGrowThisCycle), typeof(PlantTotalGrowTime),
ComponentType.Exclude<RequiresChangingStage>());
}
[BurstCompile]
struct PlantGrowJob : IJobChunk {
[ReadOnly] public ComponentTypeHandle<PlantGrowThisCycle> PlantGrowThisCycle;
[ReadOnly] public ComponentTypeHandle<CurrentPlantStage> CurrentPlantStage;
[ReadOnly] public EntityTypeHandle Entities;
public ComponentTypeHandle<PlantTotalGrowTime> PlantTotalGrowTime;
public ComponentTypeHandle<CurrentPlantGrowth> CurrentPlantGrowth;
public EntityCommandBuffer.ParallelWriter EntityCommandBuffer;
public float DayFrameDiftime;
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) {
var PlantGrowThisCycle = chunk.GetNativeArray(this.PlantGrowThisCycle).Reinterpret<float>();
var CurrentPlantGrowth = chunk.GetNativeArray(this.CurrentPlantGrowth).Reinterpret<float>();
var PlantTotalGrowTime = chunk.GetNativeArray(this.PlantTotalGrowTime).Reinterpret<float>();
var CurrentPlantStage = chunk.GetNativeArray(this.CurrentPlantStage).Reinterpret<int>(24);
var CurrentPlantStageF = chunk.GetNativeArray(this.CurrentPlantStage).Reinterpret<float>(24);
var Entities = chunk.GetNativeArray(this.Entities);
for (int i = 0; i < chunk.Count; i++) {
PlantTotalGrowTime[i] = (CurrentPlantGrowth[i] * CurrentPlantStageF[i * 6 + 5] + CurrentPlantStage[i * 6 + 3]) / CurrentPlantStage[i * 6 + 4];
if ((CurrentPlantGrowth[i] = Mathf.Min(1, CurrentPlantGrowth[i] + PlantGrowThisCycle[i] * DayFrameDiftime)) == 1) {
EntityCommandBuffer.AddComponent(chunkIndex, Entities[i], new RequiresChangingStage());
}
}
}
}
protected override JobHandle OnUpdate(JobHandle inputDependencies) {
var job = new PlantGrowJob();
job.DayFrameDiftime = GameEngine.GameDeltaTime / StaticFlags.GameEngine_RealSecondsInDay;
job.PlantTotalGrowTime = GetComponentTypeHandle<PlantTotalGrowTime>(false);
job.CurrentPlantGrowth = GetComponentTypeHandle<CurrentPlantGrowth>(false);
job.PlantGrowThisCycle = GetComponentTypeHandle<PlantGrowThisCycle>(true);
job.CurrentPlantStage = GetComponentTypeHandle<CurrentPlantStage>(true);
job.Entities = GetEntityTypeHandle();
job.EntityCommandBuffer = entityCommandBufferSystem.CreateCommandBuffer().AsParallelWriter();
JobHandle jobHandle = job.Schedule(query, inputDependencies);
entityCommandBufferSystem.AddJobHandleForProducer(jobHandle);
return jobHandle;
}
}
With this I can easily create more and more traits that changes most aspects of the plant life cycle just by inserting more and more systems that run in between the FrameStartUpkeepCopyCrop and the many systems in the PlantGroupAfterUpkeep system group.
My plant related system groups, I might need to rename them to make more explicit what they do:
[UpdateBefore(typeof(InitializationSystemGroup))]
public class PlantGroupCleanUp : ComponentSystemGroup { }
[UpdateInGroup(typeof(InitializationSystemGroup))]
public class GroupPlantAutoAdd : ComponentSystemGroup { }
[UpdateAfter(typeof(GroupPlantAutoAdd))]
public class GroupPlantFrameStart : ComponentSystemGroup { }
[UpdateAfter(typeof(GroupPlantFrameStart))]
public class GroupPlantFrameInitialization : ComponentSystemGroup { }
[UpdateAfter(typeof(GroupPlantFrameInitialization))]
public class GroupPlantApplyUpkeeps : ComponentSystemGroup { }
[UpdateAfter(typeof(GroupPlantApplyUpkeeps))]
public class PlantGroupAfterUpkeep : ComponentSystemGroup { }
[UpdateAfter(typeof(PlantGroupAfterUpkeep))]
public class PlantGroupEndFrame : ComponentSystemGroup { }