This section is a lot more in-depth than others. If you do not have at least a basic understanding of ECS I would recommend playing around with Unity samples and learning how that works before tacking this section.
Getting Started
Baking your player or characters will only change slightly as the way StatusVariables are setup in Entities is a little bit different.
For everything that contains a StatusVariable you will need to implement the IEntityStatus interface on the class. Then in OnBake() append all of the StatusVariables to the baked Entity.
usingStatusEffects.Entities;usingUnity.Entities;usingSystem;usingUnityEngine;// Note that there is a UnityEngine.Hash128 // which we do not want to use here.usingHash128=Unity.Entities.Hash128;publicclassExamplePlayerAuthoring:MonoBehaviour,IEntityStatus{publicHash128 ComponentId => m_ComponentId;privateHash128 m_ComponentId =newHash128(Guid.NewGuid().ToString("N"));publicvoidOnBake(Entity entity,StatusManagerBaker baker) {baker.DependsOn(this);baker.AppendToBuffer(entity,newStatusFloats(ComponentId, StatusMaxHealth));baker.AppendToBuffer(entity,newStatusFloats(ComponentId, StatusSpeed));baker.AppendToBuffer(entity,newStatusInts(ComponentId, StatusCoinMultiplier));baker.AppendToBuffer(entity,newStatusBools(ComponentId, StatusStunned)); } // Example variablespublicStatusFloat StatusMaxHealth =newStatusFloat(100,true);publicStatusFloat StatusSpeed =newStatusFloat(5,true);publicStatusInt StatusCoinMultiplier =newStatusInt(1,true);publicStatusBool StatusStunned =newStatusBool(false);}
When baking using a Baker, directly convert the StatusVariables. For example StatusEffects.StatusFloat will convert to StatusEffects.Entities.StatusFloat.
using Unity.Entities;
using StatusEffects.Entities;
public struct ExamplePlayer : IComponentData
{
// This is important to look up StatusVariable
// data from the dynamic buffer.
public Hash128 ComponentId;
public StatusFloat MaxHealth;
public StatusInt CoinMultiplier;
public StatusBool Stunned;
}
public class ExamplePlayerBaker : Baker<ExamplePlayerAuthoring>
{
public override void Bake(ExamplePlayerAuthoring authoring)
{
var entity = GetEntity(TransformUsageFlags.Dynamic);
AddComponent(entity, new ExamplePlayer
{
ComponentId = authoring.ComponentId,
MaxHealth = authoring.StatusMaxHealth,
CoinMultiplier = authoring.StatusCoinMultiplier,
Stunned = authoring.StatusStunned
});
}
}
That is all you need to do to setup functional StatusVariables for ECS. The reason there is a two part baking system is because of the way StatusVariables needed to be dynamically updated by ISystems.
Here is an example of how you can lookup those dynamic variables from within a job.
partial struct DebugPlayerMaxHealthJob : IJobEntity
{
[ReadOnly]
public BufferLookup<StatusFloats> StatusFloatsLookup; // from SystemAPI.GetBufferLookup<StatusFloats>()
public uint LastSystemVersion; // from state.LastSystemVersion
public void Execute(Entity entity, in ExamplePlayer player)
{
var statusFloatBuffer = StatusFloatsLookup[entity];
// This is a check to see if the StatusFloats buffer was changed
// post baking. Unless you are doing something that modifies this
// buffer you may not need to check this and can exclude it from
// the GetValue() call.
bool structuralChange = StatusFloatsLookup.DidChange(parentEntity, LastSystemVersion);
player.MaxHealth.GetValue(player.ComponentId, statusFloatBuffer, out var maxHealth, structuralChange);
UnityEngine.Debug.Log($"Max Health: {maxHealth}");
}
}