I was using pubsub event system from Zbase package (you can find this on github). Unfortunately, he used classes for that (managed type) so i can't use that for my ISystem with burst.
I tried to create a simpler version of his pubsub system but only use managed types, but i stuck at the step that interface is managed type, can't put it into NativeList or what ever NativeCollection so that i can trigger Invoke() method inside that interface.
Any idea that you suggest me?
Thanks for reading.
#Pub sub event system for ecs is possible or not??
1 messages · Page 1 of 1 (latest)
while taking an interface valued type like IMyInterface value is not allowed in burst, you are allowed to have a generic method that takes a T that is constrained to an interface, like void MyMethod<T>(T value) where T : IMyInterface, as long as the concrete T you use it with is unmanaged
ECS and classic C# events are incompatible in nature.
Events in ecs are implemented by having specific lists/dynamic buffers being filled and having systems that query those explicitly
yeah, I use NativeQueue to store EventMessage inside a listener system and use Pub sub system from Zbase to add messages into the said NativeQueue, but that only works in systemBase cause PubSub from Zbase use classes so can't use that to communicate between ISystem
Someone has told me that I must not try to communicate between systems using pub sub like that, systems talk to each others by using data
If you use it to make systems directly communicate with each other - then yeah, this will turn any ecs project into spaghetti
You can just let systems write events to some dynamic buffer (or create entities tagged with some event component) and have other systems read it
I think thats already relatively close to what pub-sub tries to achieve anyways: any system can create those events independentely, and any other system can "subscribe" by reading them
know that way but we still need a clean up system which clear dynamic buffer at the end of frame
well for my attacks I actually use interface components, and then generic systems to read the implemented versions of those components, if you want to use generics
then you'd have one system for each type T (also one clean-up system for each type)
however, I am not sure if that was my wisest decision, I am kind of regretting doing that part that way in retrospect
But if you do not do dynamic buffers, but use event entities instead, you'd have no problem with clearing
just have a system query all entities with EventX or something end of the frame and delete them
havent known anything about interface component 🥲 About generic systems, they still not lay in my need for now
only one systems for clearing all kind of events? This statement hard to understand to me
This is the interface component
public interface ISkillProperty<T> : IComponentData
where T: unmanaged, IComponentData
{
public T GetSkillPropertyCurrentLevel();
public string Describe();
}
With a generic system which adds a skill property at a given level to a skill
public partial struct SkillAdditionSystem<T, TComp> : ISystem
where T:unmanaged, IComponentData, ISkillProperty<TComp>
where TComp:unmanaged, IComponentData
{
private EntityQuery query;
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate<CommandReloadAttackPrefabs>();
query = new EntityQueryBuilder(Allocator.Temp)
.WithAll<CommandReloadAttackPrefabs>()
.WithAll<CurrentAttackPrefab>()
.WithAll<T>()
.Build(ref state);
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
var em = state.EntityManager;
var createAttackPrefabCommands = query.ToComponentDataArray<CurrentAttackPrefab>(state.WorldUpdateAllocator);
var attackFactories = query.ToComponentDataArray<T>(state.WorldUpdateAllocator);
for(int i = 0; i < createAttackPrefabCommands.Length; i++)
{
var targetPrefab = createAttackPrefabCommands[i].prefab;
var comp = attackFactories[i].GetSkillPropertyCurrentLevel();
em.AddComponentData(targetPrefab, comp);
}
}
}
for example
however I do honestly regret doing it like that, I'd rather have kept this part out of the ECS alltogether I think (basically what it does is create an attack which is assembled of many small "skill properties" like damagePerSecond, ExplodeOnImpact etc)
You'd need one cleanup system for each type T which is a component event type
you can have a generic
public partial struct CleanUpSystem<T>{
//queries for `T` and destroys all of them
}
oh, got it
however, instead of doing it this way, you could just create entities which are the events themselves. Depending on their components, different systems can consume those entities and do stuff
all of them are tagged with EventEntity
at the end of the frame, you have a system querying for EventEntity and destroying all of them
that would not need generics and I imagine could be a better way
yea but Creating entity with such high rate like that would cause structure change and force lots of job to finished
That shouldn't be a problem. Just have one
or more like - not at the end of frame, but at the start