#archived-dots
1 messages ยท Page 264 of 1
yeah, I noticed
welp
just another 30 minutes down the drain xD
but at least, I got progress
Any idea btw regarding reaction on structural changes utilites from Unity?
As in, do some action on query during adding/removing component?
if that's smth to exist in 1.0
I'd be sooooo happy
Is there a way to create query with OR settings?
As in: query through all entities that have either X or Y component. As with WithAll<T>?
what do you mean by that sorry
for example if I want to do some loop only once and only when certain component is added/removed
for cleanup/setting up smth
thats what unity designed ISystemState components for
if you care about created/destroyed
there's
EntityManager.GetCreatedAndDestroyedEntities
nah, this is for adding/removing components
in this exact case it's for LineRenderer GO component
I need to disable/enable it everytime entity gets target component for movement
or loses it
in entity world of just tracking it'd be like
added = GetEntityQuery(readonly<Movement>, exclude<LineRenderer>()
removed = GetEntityQuery(exclude<Movement>, readonly<LineRenderer>()
LineRenderer never goes away
since it's class, Entity world doesn't really know it's state
that's why I do such clean up queires
[UpdateInGroup(typeof(TickSimulationSystemGroup))]
public partial class MovementLineSystem : SystemBase
{
private struct UpdatedTag : IComponentData
{
}
protected override void OnUpdate()
{
Entities.WithNone<DisableRendering>().ForEach((CompanionLineRenderer lineRenderer, in MoveTarget target) =>
{
Vector3[] positions = new Vector3[2] {target.value, lineRenderer.LineRenderer.transform.position};
positions[0].z = -5f;
positions[1].z = -5f;
lineRenderer.LineRenderer.SetPositions(positions);
}).WithoutBurst().Run();
var em = World.EntityManager;
Entities.WithNone<UpdatedTag>().WithNone<MoveTarget>()
.WithStructuralChanges().ForEach((Entity e, CompanionLineRenderer line) =>
{
line.LineRenderer.enabled = false;
em.AddComponentData(e, new UpdatedTag());
}).Run();
Entities.WithAll<UpdatedTag>().WithAll<MoveTarget>().WithStructuralChanges().ForEach(
(Entity e, CompanionLineRenderer line) =>
{
line.LineRenderer.enabled = true;
em.RemoveComponent<UpdatedTag>(e);
}).Run();
}
}
right now it looks disgusting
but it could ^_^
i mean otherwise you just need another component to represent line renderer enabled/disabled
that's what private UpdatedTag is for rn I guess
so unity won't allow IntPtr since i cannot use Marshal.PtrToStructure in jobs now i'm stuck
how do you get the values from pointers without that =/
intptr is fine
but it wont allow this _node = (Node)Marshal.PtrToStructure(_nodePtr, typeof(Node));
in a job
anyway don't use marshal, unity provides UnsafeUtility to do things like this
oh
not sure how i use that with intptr
i wouldn't really use intptr
but to answer your question intptr.topointer()
will return the actual pointer
which is what all unity methods require
yeh i tried that too
oh there we go
so why do you not recommend intptr ?
i couldn't find a way to store a collection of Struct* as my hash map's values so i had to use IntPtr
need any distraction atm
trying to repo a painful burst cache issue for unity atm that is doing my head in
not sure what that even means tbh ๐
is there a way to make Rider to format all additional options like WithAll<T>() or <WithNone<T>() on new line?
Can't find what setting is it
oh nvm, found it
ooh i didnt know this setting existed. so glad i came around to join the discord
this is the one
yes thank you i found it already!
Right now i am trying to get used to the new Debugging workflow for Entities and avoid the use of EntityDebugger. Overall i really like the flow of how i can debug things through the relations.
But what i always feel like is missing is filtering all Entities for a certain set of components. That was possible in the EntityDebugger but how can i achieve the same functionality in the new EditorWindows? Is there some way to Filter in the EntityHierarchy?
If there isnt this needs to be raised in the forums i think
kek
I just did this, and it's enough for me for now
forgot to add Components to it
But what i always feel like is missing is filtering all Entities for a certain set of components. That was possible in the EntityDebugger but how can i achieve the same functionality in the new EditorWindows? Is there some way to Filter in the EntityHierarchy?
yeah this is missing
and makes it too limited to use atm
multi component searches still needs to be done via entity debugger
if you saw the 1.0 talk though they had a filter button on the hierarchy window so i'm hoping that brings back this type of behaviour
they had this in earlier versions too. thats why i am so confused and searching for it everywhere
atm the search field while it can search for components
always does an Any query with them
and also always includes prefabs/disabled components
making filtering more than 1 component pretty impossible
hmmm
so I read through ISystemState, I get how it works, but I don't see how I can use to it so solve my problem
rn
I have LineRenderer which I need to enable during adding of MoveTarget component to entity
and which I also need to disable when MoveTarget is removed from entity
what I don't want to do
is to enable/disable it every update
so rn I have these little 2 queries which add tag to avoid doing it, but can I somehow avoid doing that and use ISystemSate features somehow?
var em = World.EntityManager;
Entities.WithNone<UpdatedTag>()
.WithNone<MoveTarget>()
.WithStructuralChanges()
.ForEach((Entity e, CompanionLineRenderer line) =>
{
line.LineRenderer.enabled = false;
em.AddComponentData(e, new UpdatedTag());
})
.Run();
Entities.WithAll<UpdatedTag>()
.WithAll<MoveTarget>()
.WithStructuralChanges()
.ForEach(
(Entity e, CompanionLineRenderer line) =>
{
line.LineRenderer.enabled = true;
em.RemoveComponent<UpdatedTag>(e);
})
.Run();
I don't remove entity during this whole process anyhow
and while it works fine rn, I need to expand it into another logic:
I need to also disable LineRenderer when entity gets DisableRendering component
as i understand it you want 3 queries:
-
Query : all: MoveTarget, CompanionlineRenderer ; None: UpdateTag
2.Query : all: MoveTarget,CompLineRenderer, UpdateTag
3.Query : all CompanionLineRenderer, UpdateTag ; none : MoveTarget -
Query triggers the job that adds the Update Tag
-
Query does the actual Update
-
Query is responsible for removing the UpdateTag
UpdatedTag is just tag that tells that LineRenderer is in disabled state and I don't need to disable it again.
for now it only triggers on absence/presence of MoveTarget
but now I also need it to trigger on DisableRendering
so when this DisableRendering exists, LineRenderer should be disabled
and my pattern of doing it
feels very bad
Do you know a better one maybe?
wait let me clarify. The job that is executed with the first query also enables the linerenderer and the job that is executed with the third query disables it
so if you have more conditions to be met on when to enable and disable the linerenderer you adjust the queries accoringly
hmmm, let me just explain it in depth
MoveTarget - component with float3 to which entity (spaceship) is moving to in world space (as in literally target to move to).
CompanionLineRenderer - is component with reference to LineRenderer component attached to companion game object of said entity.
While these 2 exist, I SetPositions on LineRenderer. like this:
Vector3[] positions = new Vector3[2] {target.value, lineRenderer.LineRenderer.transform.position};
positions[0].z = -5f;
positions[1].z = -5f;
lineRenderer.LineRenderer.SetPositions(positions);
and when MoveTarget doesn't exist, I need to disable LineRenderer, so it doesn't draw unupdated lines
Using UpdatedTag helped to avoid disabling/enabling LineRenderer every update
but now that I also got condition of DisableRendering
logic is getting very messy
Still what i wrote above should apply. maybe im bad at explaining it sry
that update logic you do to the linerenderer executes with 2.Query
well yeah, that's how it works rn
but now that I also got DisableRendering
I either need more queries or better pattern
you just need to adjust the queries. not more
yeah
I guess so
btw, is there some way to define all those WithNone, WithAll in separate variable?
I'm pretty sure there is
I don't remember how it's called tho
there might be but im not using it with lambdas. would also like to know ๐
oh yeah, that's how
ah thats what you meant. i meant i dont know how to use EntityQuery / EntityQueryDesc inside a Entities.ForEach as a parameter
hm
yep, I don't see an option to include query in loop
sadge
bruh, adjusting query options also doesn't seem possible atm
Entities.WithAny<>()
.WithNone<Disabled>()
.WithNone<MoveTarget>()
.WithStructuralChanges()
.ForEach((Entity e, CompanionLineRenderer line) =>
{
line.LineRenderer.enabled = false;
em.AddComponentData(e, new Disabled());
})
.Run();
for this Query I need to run with pretty weird conditionals
WithEntityQueryOptions()
if it was OOP it'd be if (!MoveTarget OR DisableRendering) {}
it's enum for smth else
which option do you need?
this one
I want to add Disabled (prev: updatedTag) only under those conditions
ok but that is not an available query option
so either when MoveTarget is absent or when DisableRendering is present
yeah
I figured
you can combine queries for that to work
EntityQuery query = GetEntityQuery(new EntityQueryDesc[] { desc1, desc2 });
well go with IJobEntity then
I can use it to create struct IJob, but that would be another pain
kinda wish I could stay within SystemBase
IJobEntity is not a pain anymore.
actually better than Entities.Foreach imo. I just had some problems with the codegen so im not using it too much yet.
You can declare the Execute method pretty much like you did with the entities.foreach and use the variables in the job. all the boilerplate is handled by codegen
Can I use entity manager there tho?
since all those queries are with structural changes
Good Question. I only ever use CommandBuffers and havent used IJobEntity enough yet to tell you. Pretty sure you can use ECBs inside. Not sure about EntityManager
Do you really need to use EntityManager inside though? wouldnt it be better to use EntityManager.RemoveComponent<MyComponent>(myQuery)
well, aside from removing component
I also need to actually disable LineRenderer
So, maybe I don't
maybe I can combine it with different things
the job that disables the linerenderer can still run. afterwards you remove the component. Probably better to defer that removal to an ECB though
oh man, that's why I simply wish Unity would implement some kind of reaction queries
to structural changes
xD
i dont think its too hard atm. Once you did it a few times its quite logical
for reference you could look into unitys ParentSystem
Hi, me wanna ask, I have installed the animation for dots, but it seems there's an error on the data flow graph dependency, how to fix this?
The package did not get updated with the last 0.50 release. Would be quite some work to get it running i guess.
So... does that mean I need to go back to previous version of entities?
Or is there anyway to work on animation?
Some people made their own ECS animations. There should be sth about that in the Forums. The other option is to use GameObjects for animations.
hmmm... I'll find a way, tq for the info
Do I need to get EntityManager every update?
or can I store it in variable in OnCreate?
You dont need to get it at all. SystemBase already has a reference to EntityManager
nah, I'm doing it with IJonEntity
just wondering whether I need to write to it's field it
or not
also kinda confused with queries
So from what I see
I can create EntityQuery from a lot of things
it can be ComponentType[] or EntityQueryDesc
meanwhile ComponentType itself can also be differen
any idea on their interaction with All, None and Any?
you'll get errors if you use things like exclude in a description query instead of using none field
hm
as for this, you shouldn't create them from EM unless you know what you're doing
Get in a system adds the dependency to the system
what I want rn is to create a Query with conditional
I need to go through entities that either have DisableRendering component or don't have MoveTarget component
so I either have cool query that specifies that, or I go through 2 different queries
use an EntityQueryMask
What's an EntityQueryMask you say?
Get your entity query and call something like CreateEntityQueryMask
this then provides a very fast lookup if an entity matches a specific query
but u still need to do the lookup though. isnt combining 2 queries better here?
already showed you : EntityQuery query = GetEntityQuery(new EntityQueryDesc[] { desc1, desc2 });
maybe there is a nicer way to combine now? i just got this from the Docs
i think that's the way
under the hood it just uses EntityQueryDescBuilder
so you could use that i guess
var disabledDesc = new EntityQueryDesc();
disabledDesc.All = new ComponentType[]
{
ComponentType.ReadWrite<CompanionLineRenderer>(), ComponentType.ReadOnly<DisableRendering>(),
};
disabledDesc.None = new ComponentType[] {ComponentType.ReadOnly<DisabledLR>(),};
var secondDisabledDesc = new EntityQueryDesc();
secondDisabledDesc.All = new ComponentType[] {ComponentType.ReadOnly<CompanionLineRenderer>(),};
secondDisabledDesc.None = new ComponentType[]
{
ComponentType.ReadOnly<DisabledLR>(), ComponentType.ReadOnly<MoveTarget>(),
};
disableQuery = GetEntityQuery(disabledDesc, secondDisabledDesc);
soooo, like this?
i hate the formatting but yeah sure
{
All = new[] { ComponentType.ReadWrite<CompanionLineRenderer>(), ComponentType.ReadOnly<DisableRendering>(), },
None = new[] { ComponentType.ReadOnly<DisabledLR>() },
};
var secondDisabledDesc = new EntityQueryDesc
{
All = new[] { ComponentType.ReadOnly<CompanionLineRenderer>() },
None = new[] { ComponentType.ReadOnly<DisabledLR>(), ComponentType.ReadOnly<MoveTarget>() },
};
disableQuery = GetEntityQuery(disabledDesc, secondDisabledDesc);```
is personally how i'd format it
{
All = new[]
{
ComponentType.ReadWrite<CompanionLineRenderer>(),
ComponentType.ReadOnly<DisableRendering>(),
},
None = new[] { ComponentType.ReadOnly<DisabledLR>() },
};
var secondDisabledDesc = new EntityQueryDesc
{
All = new[] { ComponentType.ReadOnly<CompanionLineRenderer>() },
None = new[]
{
ComponentType.ReadOnly<DisabledLR>(),
ComponentType.ReadOnly<MoveTarget>()
},
};
disableQuery = GetEntityQuery(disabledDesc, secondDisabledDesc);```
or if i need new lines
but entirely up to you - whatever you like
ok, so
this Query made from 2 descriptions
literally means that it will go through 2 queries
under the hood?
yep
ok, that's great
if an entity is in either query it will be returned by this
you won't know what query it's from so if you need to care about components conditionally
recommended to use IJobBatch and then use batch operations to check if a chunk as a compoent
so you can treat the whole chunk 1 way or another
aside from no HasComponent ๐ฆ
i actually write less than 10% of my jobs with entities.foreach
and this was before IJobEntity
i might legit never write an entities.foreach again that is longer than 4 lines
Does WithChangeFilter automatically create a read dependency or would I have to do that manually?
with EntityManager you lose burst. use an ECB
You shouldn't (use em in job)
But i also already told you that you don't even need to remove components inside the job. you can do it outside for the whole query as a batched command
ah yes
forgot about it
wait hold on
I also need to add components
so no, I'd rather have my ability of EM somehow
in short, job looks like this rn xD
private partial struct SetLineRendererJob : IJobEntity
{
public EntityManager em;
public bool mode;
private void Execute(Entity e, CompanionLineRenderer lineRenderer)
{
lineRenderer.LineRenderer.enabled = mode;
if (mode)
{
em.RemoveComponent<DisabledLR>(e);
}
else
{
em.AddComponentData(e, new DisabledLR());
}
}
}
you can also add components in a batched fashion
I do?
EntityManager.AddComponent<DisabledLR>(disableQuery)
yeah, I am looking into it
Batched commands are ways faster since no memory has to be copied around. the whole chunk just gets another component
private partial struct SetLineRendererJob : IJobEntity
{
// public EntityManager em;
public bool mode;
private void Execute(Entity e, CompanionLineRenderer lineRenderer)
{
lineRenderer.LineRenderer.enabled = mode;
// if (mode)
// {
// em.RemoveComponent<DisabledLR>(e);
// }
// else
// {
// em.AddComponentData(e, new DisabledLR());
// }
}
}
protected override void OnUpdate()
{
updateJob.Run(updateQuery);
setJob.mode = false;
setJob.Run(disableQuery);
EntityManager.AddComponent<DisabledLR>(disableQuery);
setJob.mode = true;
setJob.Run(enableQuery);
EntityManager.RemoveComponent<DisabledLR>(disableQuery);
}
looks a little bit silly, but let's try kek
well, no errors
That makes no sense though. you are adding and then removing the same component on the same query
looks like it works, but my logic is flawed somewhere
oh
should be different queries
yay
looks like it works
thank you, sir
ok, now that's something
hmm, this now bugs me with some dependency error
var translations = GetComponentDataFromEntity<LocalToWorld>(true);
Entities.WithReadOnly(translations)
.ForEach((Entity entity, ref MoveTarget moveTarget, in FollowShip ship) =>
{
moveTarget.value = translations[ship.Entity].Position;
}).Schedule();
How can I transform it into IJobEntity?
kind of get same behaviour of accessing random entity's component
this is the error
just assign the jobhandle to the Systems Dependency field:
Dependency = Entities.ForEach....Schedule(Dependency)
Dependency = new MyJob().Schedule(Dependency)
aaand, that didn't help btw
you need to pass ComponentDataFromEntity
same error
to a field?
Hello. Quick question. If I "instantiate" soemthing in DOTS, can I then save the instantiated objects into my project folder as a prefab?
{
public ComponentDataFromEntity<SpeedModifiers> modifiers;
public void Execute(ref DynamicBuffer<ActiveEffect> activeEffect,in SpeedEffect speedEffect)
{
}
}```
not out of the box. Youd need to code that yourself
ok then. I guess that helps. Thanks
My question would be why you need this. Can't you just make a normal GameObject Prefab and convert it when u need it as an entity?
wait a second
that dependency error
it's about reading Entity
ahem
Do I need to somehow specify dependency on Entities list?
I was thinking the same thing. It's more easier to work with GameObjects. But I guess if it is possible then it might be useful for letting for-instance a user to make a object and being able to save it at runtime.
id need to see more of the system to help you
oddly, error shifted to my other system
xD
I'm not even sure whether it's me who did smth wrong
or just unity doing it's dirty things
but error looks like this
it says it reads Entity
type
Yes same fix as before. Assign the Job to the System Dependency
@rotund token maybe knows under what circumstances unity handles those dependencies automagically and when not. i never got the pattern. i just always assign the dependencies when not sure
it says I read Entity
which makes me really curious
since I do indeed read Entity
as component
and in other system
I have Entity written inside component
which might potentially trigger some kind of race condition
Well yes that is what its saying. but the weird part is that Entity should be Readonly right?
I kind of assumed it is
i never had issues with the entities array and race conditions. So maybe Codegen of IJobEntity is flawed atm (forgot to make it readonly) or you make changes in the EntityManager which trigger this racecondition?
same error happened with ForEach loop
okay so its probably you making structural changes while those jobs are running?
is there a DOTS learning resource?
is moetsi a youtube channel?
nah, it's a website
thats great. seems like a lot of info
plz dont start with multiplayer though.
No , i wont. Luckily its got chapters on ECS and dots physics first.
Do ISystemStateComponents have overhead? I am thinking about having an EffectEntity that has an ISystemStateBuffer to keep track of all effected Entities. Once the EffectEntity is destroyed every effected Entity needs to get the effect removed. Until now i only used ISystemStateComponents as Tags. Not sure if it is a good idea to keep data in them that i need both for update and cleanup.
Well i guess since unity is using a SystemStateBuffer for their Child component i guess its fine to use it in my case.
I am thinking about creating a generic timer system. The system could add a generic component and remove it on the next frame. It could later easily change it to enable/disable component workflow. Foreach does not work in generic systems though. What would be the preferred Job to use in this case? IJobChunk, IJobEntity or anything else?
Why does the profiler not show the job running on the main thread?
Isn't that exactly what it's showing?
Usually I would be able to see the job name that's running
If you call Complete the job will force itself to finish on the thread you call it from
Hmm actually yeah nvm then
prefered should be IJobEntity. But im not sure how well it works with generics (if at all). following in order IJobEntityBatch, IJobChunk,IJobFor
Thx. Its the first time I use IJobEntity but the write once and reuse in multiple systems approach looks promising
interesting I've been wondering how to do something like that for a while ๐ค
Anybody has an example on using an ECB in a IJobForEntity?
Havent tried yet but you should be able to just pass it into the job like you would in for example an IJobChunk
Any example for that? Havent used that either ๐
{
public EntityCommandBuffer ecb;
public void Execute(Entity entity)
{
ecb.RemoveComponent<MyComp>(entity);
}
}```
Ok thats simpler than I thought
ofc if you use scheduleparallel u pass a parallelwriter
I see. But that would mean deciding beforehand weather the job should be schedule or scheduleParallel later on does it?
thats always the case
mhh I see. Always wondered what the overhead was of using a ParallelWriter in a Schedule job
if the overhead is minimal it would make sense to use ParallelWriters in all jobs because it could be Scheduled both ways ๐ค
id assume it is low overhead but i never really looked into it.
if you really look for this kind of performance you probably shouldnt use ecb and think about a way to avoid structual changes
yeah as mentioned earlier I am trying to build the system so I can replace adding/removing tag components with toggling component later on
I took it more as a general question not related to your generic timer. For a timer it should be no problem anyways since you wont add 100 timers per frame to entities. For such rare events adding and removing should be just fine. Don't overengineer, especially not with features that are comming in a year in mind
I see what you mean. The easy refactoring is really just a side effect though. The problem I actually try to solve is to have mutliple timers triggering different events on the same entity ๐ฌ
and I nearly got it working until I hit this again:
Assets\Scripts\Game\Trigger\Systems\TimerSystem.cs(37,1): error SGICE002: Seeing this error indicates a bug in the dots compiler. We'd appreciate a bug report (About->Report a Bug...). Thnx! <3 System.InvalidOperationException: Unknown typeSymbol type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.TypeParameterSymbol ๐ฌ
yes they can. but IJobEntity is a special case
Its a Job that reduces boilerplate through codegen. the codegen effectivly creates an IJobEntityBatch for u
Oh and the other IJobs dont use codegen?
yes
found this example and thought it would work with IJobEntity: https://nagachiang.github.io/unity-dots-creating-generic-systems-with-generic-jobs/#
well that sucks ๐
but I guess you are right that the codegen does not work with generics
generics are a huge PITA with ecs :S. The problem you will face is that every type of timer you create will need an extra system running to update the type. that costs a lot mainthread performance.
Thing is reusing code can get a pain with ECS too ๐ฌ
I got a trigger tag which triggers the targeting and the attacking systems. Now I want to separate these events. Cannot thnk of any better way then creating a second timer+tag ๐ค
So you want to wait between trigger and attack and attack to end of attack?
_followShipJob.translations = GetComponentDataFromEntity<LocalToWorld>(true);
_followShipJob.entities = _query.ToEntityArrayAsync(Allocator.TempJob, out var dep);
Dependency = _followShipJob.Schedule(JobHandle.CombineDependencies(Dependency, dep));
I swear this makes me crazy
what are you getting the translations for if you are not passing them into the job?
same with entities
show the whole code plz
public partial class FollowShipSystem : SystemBase
{
[BurstCompile]
private partial struct FollowShipJob : IJobEntity
{
[ReadOnly] public ComponentDataFromEntity<LocalToWorld> translations;
[ReadOnly] public NativeArray<Entity> entities;
private void Execute(ref MoveTarget moveTarget, in FollowShip ship)
{
moveTarget.value = translations[ship.Entity].Position;
}
}
private FollowShipJob _followShipJob;
private EntityQuery _query;
protected override void OnCreate()
{
_followShipJob = new FollowShipJob();
_query = GetEntityQuery(new ComponentType[]
{
ComponentType.ReadOnly<LocalToWorld>(), ComponentType.ReadOnly<Selectable>(),
});
}
protected override void OnUpdate()
{
_followShipJob.translations = GetComponentDataFromEntity<LocalToWorld>(true);
_followShipJob.entities = _query.ToEntityArrayAsync(Allocator.TempJob, out var dep);
Dependency = _followShipJob.Schedule(JobHandle.CombineDependencies(Dependency, dep));
}
}
when scheduling the _followShipJob.entities have to be there. but hey aren't
there is alot wrong here actually
they are async, then you schedule the job but the entities are still not calculated. so that trips up job scheduling
but I combine dependencies with out dependency of async operation
it doesn't matter if you use it as a dependency. the job scheduling fails
parameters are set in main thread and not later own
ahem
you can solve this with IJobDefered (sorry can't remember the exact interface name)
what is out dependency of nativearray is for then?
but you are not even using the entities you are getting with the async operation at all...
this takes a nativearray that is still unknown when scheduled
I am trying to add Entities to Dependency of system
to fix error
I have posted hours ago
Baiscally find a target -> track it -> shoot it. The track it step does not work if the other 2 happen at the exact same time
this error
ok, guess it should work. although I've personally always used IJobParallelForDefer for exactly that problem. Anyway, maybe something else is going on. the system is tied to the query you set in OnCreated so IJobEntity is scheduled with that query anyway. (notice you have no parameters in Schedule where usually the query variable would be used) There's no reason to set the entities a second time. Something else that could be going on is that burst culls entities because it's not used in the code. Also, the entities from ToEntityArrayAsync are not disposed.
thing is, it's either internal bug or idk what it is
idk
public partial class FollowShipSystem : SystemBase
{
[BurstCompile]
private partial struct FollowShipJob : IJobEntity
{
[ReadOnly] public ComponentDataFromEntity<LocalToWorld> translations;
private void Execute(Entity e, ref MoveTarget moveTarget, in FollowShip ship)
{
moveTarget.value = translations[ship.Entity].Position;
}
}
private FollowShipJob _followShipJob;
protected override void OnCreate() { _followShipJob = new FollowShipJob(); }
protected override void OnUpdate()
{
_followShipJob.translations = GetComponentDataFromEntity<LocalToWorld>(true);
_followShipJob.Schedule();
}
}
its a dependency issue between multiple systems
I removed all clutter, tried adding Entity as argument to execute
100% not an internal bug
then what are supposed to be the steps find out what is the issue?
well your error tells you it has sth to do with the dependencies in TestAI
try to set the dependency in the above code: Dependency = _followShipJob.Schedule(Dependency)
the next thing is to jobHandle.Complete and see if the error goes away. that will lead you to what's going on
at least it will pinpoint the exact problem where it happens because remember, scheduling works async so if something goes wrong, the next frame can schedule something and the dependency system starts to trip over.
I removed TestAI alltogether, error jumps to another system
I tried that
I'll try complete now
you can also try to disable all systems and work from there.
yeah, I'll try that too
and don't worry too much about this. the dependcy system gives us all headaches ๐
all right, Complete does fix it
just assign Dependency in every system the error pops uo
I guess, I need special place for such systems
up
As i said earlier thats what i do by default if im not sure about dependencies
There is some magic involved i havent grasped yet. So i am just explicit with Dependencies
you should avoid relying on order too much though. becomes a huge headache later on
I get it, but maybe I should just create some other group
that will be part of ECB sync point
and that will resolve all such issues
youd want to make your syncpoints as small as possible so id not advice that. You will run into this problem alot more anyways. better handle it correctly now
But rly i dont get why its not handled automagically. maybe IJobEntity doesnt do that yet
ForEach loop gives same results
AFAIK Entities.ForEach assigns the System Dependency by default when scheduling without params
literally same error
hmm ok
oh well
same error points to TestAI
I look at TestAI
Dependency = Entities
.WithAll<SimpleAI>()
.WithNone<MoveTarget>()
.ForEach((Entity entity, in Translation translation) =>
{
float3 pos = translation.Value;
int ind = Quadrant(pos.x, pos.y);
ind++;
ind = ind % 4;
MoveTarget target = new MoveTarget() {value = positions[ind]};
buffer.AddComponent(entity, target);
})
.Schedule(Dependency);
๐
I really think
it's because I use Entity in component
and I should just move all similiar systems to sync point
its perfectly fine to reference entities in components.
did u do a AddJobHandleForProducer for the Commandbuffer?
yeah
public abstract partial class SystemTemplateWithECB<T> : SystemBase where T : EntityCommandBufferSystem
{
protected T bufferSystem;
protected override void OnCreate()
{
base.OnCreate();
bufferSystem = World.GetOrCreateSystem<T>();
}
protected override void OnUpdate()
{
UpdateWithBuffer(bufferSystem.CreateCommandBuffer());
bufferSystem.AddJobHandleForProducer(Dependency);
}
protected abstract void UpdateWithBuffer(EntityCommandBuffer buffer);
}
I have this little utility template
kek
saves me some code
okay then im out of ideas. im doing the same stuff (probably everyone is doing something similiar) without problems...
I think it should be Dependency = UpdateWithBuffer(bufferSystem.CreateCommandBuffer());
it's not set otherwise, so the AddJobHandleForProducer doesn't know what to wait for
nah
it works fine
I basically decided to solve it this way
I just drop this subgroup
near ECB sync point
and if any system uses similiar pattern, I'll just put it there
how do I query for a certain entity within a mono behavior? Read only
And can I have entities link to other entities
Like have a component field be a pointer to another entity
So I do t have to waste time searching
yes you can.
i think its sth like this :
World.DefaultGameObjectInjectionWorld.EntityManager.CreateEntityQuery()
Okay am i crazy? Do ISystemStateComponents not get added when Instanciating an Entity from a Converted Prefab that has ISystemStateComponents ?????
Undocumented behaviour that makes no sense to me. Can someone explain the potential reasoning to have diffrent behaviour than IComponentData?
How? Is there an EntityReference like a blob asset reference
You can just have an Entity field inside your IComponentData. It is blittable
Oh. Okay
System state component are ment to be tied to a specific system (to make a reactive system). The reactive system could have data outside of DOTS like a dictionary or octree or trigger something that need to be cleaned up when the entity is destroyed. If the system state component were copied in prefab instantiating or serialized in subcene the reactive system would have not have to handle it and have no chance to initialize the out of DOTS data.
ugh
how do I use system state component for reactive system?
I thought you could only use it through destroying entity
I understand that it is not serialized in subscene but i dont see the reason why i shouldnt be able to setup a prefab with it to skip the initial setup when spawning it.
Well i would accept it anyways but then it should be documented somewhere
wasted like 2 hrs figuring it out...
it makes sense in that way that a system that's handling added would not get triggered
Make a system
Declare a private system state component in that system
Make a query that look for entities that don't have the system state component and run a job on it that does what you want and add the system state component
i agree, it should be documented
yes i understand that. but if i could setup my entity without requiring to change its chunk once that would be just better
Hi, i was wondering if it's worth using DOTS in production or not?
I just think that there would be no harm in allowing to Instanciate with SystemSate
just gives you options
Then how do you have the system data initialized and how do you know what entities were already handled?
If you really want to do it your way just use a regular component data
i wanna use SystemState for the cleanup logic
my usecase is a effect on an ability
the effect keeps track of effected entities in a SystemStateBuffer
the buffer is obviously empty when i spawn the effect. and it needs no further setup since it is filled at runtime when the ability hits sth
but when the effect is destroyed i need to undo the effect on all effected entities. this is where id prefer to use SystemState
Kind of like the Child buffer
well unity would say no
Jobs and burst -> yes
Ecs -> no
ok i see thanks
@solemn hollow I see, in that case you could add it through the ecb when you instantiate it from the prefab. But I agree that you use case is not ideally managed by system state component
@solemn hollow what's your workflow for the projectile prefab? if you still want to make this work you can add the SystemState in the beginning
i have a modular ability system. I spawn a whole hierarchy of abilities that activate each other to create chain reactions
Adding the SystemState after instantiation via command buffer is not a good solution IMO
so effects can be anywhere in that hierarchy
yes the prefab is authored as a gameobject
thats the point. i cant preprocess it with systemstate
you should be able to add it in the Convert stage of IConvertGameObjectToEntity
no i do add it. but on instantiation it is not copied over to the Instance
ah I see
so im stuck between 2 not optimal solutions. if systemstate was copied to Instances i would have no problems at all
yeah, I see the problem. I'm afraid there's no good solution I'm aware of
i mean its fine to be restricted like that. its just so strange to not find that behaviour in the docs
This is also new to me. I never had that use case
i necrod a thread about it. maybe there is a little attention from unity but i doubt it
i am using ECS from the very beginning and never stumbled upon it xD
someone on the forum has the exact different problem ๐
took me 2 hrs to figure it out... was totally blindsided
Poking through the ECS source code, in some of the low level stuff, I found this line:
var skip = type.IsSystemStateComponent || type.TypeIndex == m_PrefabType;
where it skips both Prefab and ISystemStateComponentData when Instantiating.
honestly i would need that too lol
even for the same ability system:
i actually first spawn a prototype Instance for every character with abilities for all abilities he holds from the Prefab. Then at runtime if the Unit gets a buff i adjust those Prototypes accordingly. On ability use i Instanciate a Prototype
So when spawning the Instance from the Prototype it would be nice to not have to remove the Prototype Tag
Why not use Prefab instead?
cause the buffs affecting the ability damage for example are not added to the prefab
since that can change per unit
about the systemState. you can utilize a batched add with a query, that way adding the systemState is really fast. as fast as it can be
yes doing that already
Its not really a performance issue for now. its just really annoying to deal with ๐
I am just mad i wasted hours on this
especially with the slow compile times i have right now...
about that though. do u think it is better to do it with ECB or directly in EM
ECB can't batch, so EM
ECB used to batch right? now with the new AddForQuery thing it doesnt anymore
Again nothing you cant work with but now you gotta take care of where to put that syncpoint
Okay i really want to end my rant now but i gotta say it even got more complicated...
I cant batch the add command for all components i need to setup. For example i need a flag for cleanup that is defined in the prefab. So i need to manually copy over that flag from a normal ICompData to a SystemStateComponent...
Do you know why when i installed DOTS all of these errors appeared i installed com.unity.entities , com.unity.rendering.hybrid and com.unity.dots.editor
just install latest version of hybrid renderer
You can remove com.unity.dots.editor package too, since it's part of the main entities package
ok
@hearty zinc don't forget you have to use unity 2020.3
i do use 2020.3
I want to store an object's position and rotation, but nothing else. Unity Entities has a built-in transform component, right?
that's a weird question. transform is a monoBehaviour term. entities uses Translation, Rotation, Scale and LocalToWorld
oh, they are separate? And what does LocalToWorld do?
LocalToWorld is the matrix that combines Translation,Rotation and Scale
okay
also, I got this error from using a NativeArray?
[Serializable]
public struct InventoryComponent : IComponentData
{
public NativeArray<Entity> inventory; //Pointers to entities
}
NativeContainer inside IComponentData won't work
either use a DynamicBuffer on the entity (the easiest solution) or make an unsafe struct with the pointer to the array
How do I use a DynamicBuffer here? Also I know beforehand that I want 32 pointers to entities.
The docs explain it best: https://docs.unity3d.com/Packages/com.unity.entities@0.50/manual/dynamic_buffers.html
If you're comfortable with NativeContainers you can also use a NativeMultiHashMap<Entity, InventoryElement> as example. There are really a lot of ways to make this work
Ok, using DynamicBuffer got rid of the error. So then when I initialize the component, I just preset the size to 32 for allocation?
(Also can entitiy components have constructors?)
a struct can have methods.
DynamicBuffer has a dynamic capacity but you can set the [InternalBufferCapacity(32)]
why is there an unsafe list but no unsafe array
a good question
that said,
public void* ptr;
public int length;
}```
is pretty much it ๐
lol fair point
it'd still be nice for the sake of methods
shame theres no way to see them in the inspector too
would be nice to verify my float2s populated correctly
I am currently using Entities.ForEach but I have no problem between the two
How do I query from a Monobehaviour for an entity that has a certain value in a component field?
Did you read the docs? queries and ForEach have filters to Include or Exclude components.
Really no way around iterating over the entities and component and finding what you are looking for. Or if it's crucial and used often, build a hashmap for it
So I've got this:
EntityQuery q = eManager.CreateEntityQuery(
typeof(RefIDComponent)
);
NativeArray<Entity> matchedEntities = q.ToEntityArray(Unity.Collections.Allocator.Temp);
foreach(Entity e in matchedEntities){
}
How do I get the component from the entity?
also I am disposing it dont worry
EntityManager.GetComponentData
@rotund tokengiven you're quite knowledged on this are you able to explain this in more detail:
In general, shorter jobs which can complete in a frame are much better. They are more predictable, and less likely to get in the way of each other. You should have a fixed time when you schedule a job, and a fixed time later when you call Complete on the JobHandle and access the data.
this was on the forums, but its not obvious to me why one frame jobs are "better" and more "predictable" what does that actually mean
well for starters imagine a user has 4 workers
and you have 4 jobs each taking more than 1 frame
you would saturate your workers stopping anything else running
is there a way to force a max frame count on a job then ?
How do I turn a regular transform into one of these?
you can use float4x4.TRS()
ah, thank you. very nice.
What's the proper way to do an array in a component?
I ask because I'm trying to do this but it's giving me a nullreferenceexception
DynamicBuffer<Entity> outInventory = new DynamicBuffer<Entity>();
outInventory.Capacity = 32;
that's not how you create a dynamic buffer
DynamicBuffer<X> buffer = EntityManager.AddBuffer<X>(entity)
you can't create a buffer yourself
I see, okay. Well my component needs a 32-slot array of references to other Entities. how do I do that
[InternalBufferCapacity(32)]
public struct MyGiantOldEntityReferenceComponent : IBufferElement{
public Entity Value;
}
Okay, so if I do this:
[InternalBufferCapacity(32)]
public struct EntityBuffer : IBufferElementData
{
public Entity Value;
public EntityBuffer(Entity e)
{
this.Value = e;
}
}
[Serializable]
public struct InventoryComponent : IComponentData
{
public DynamicBuffer<EntityBuffer> inventory; //Pointers to entities
}
you dont need to put it on a component
the component is on an entity
the dynamic buffer is on an entity
"they're the same thing"
Hi, me wanna ask, is there a way to "raycast all" using job system? Does the CollisionWorld.Raycastall make GC Alloc?
I tried using that with IJobEntityBatch and output the NativeList<ColliderCastHit> inside the job and it works, but I cannot compare the ID because due to two containers may not be the same (aliasing) error after I use ComponentDataFromEntity<MyComponent> and ComponentTypeHandle<MyComponent> at the same time. I was thinking using "Job inside Job" solution to compare tags for each detected collisions by RaycastAll but idk how.
you do raycast and you work with result data from raycast
if for some reason you don't want to work with result data in same job
you can cache it within some buffer
and then work with it through another job
raycast is struct
and can be dropped into dynamic buffer easily
During conversion, inside authoring mono. Do all gameobjects remain to exist?
I kind of want to setup templates of rooms through transform parenting of Unity, but avoid those empty game objects to be converted AND avoid their children getting parent components
Can I just remove all those gameobjects during authoring conversion and be done with it?
oooor do I need smth more complex?
You can add the stop convert entity authoring component to the first child of the parent game object that is converted to entity. That will prevent child to be converted and still allow you to query their monobehavior during the parent conversion.
If the aim is to not have the update transform on the whole hierarchy you can check the static box in the editor. It should add a tag component to the entity on conversion that will make the transform system ignore them.
AFAIK stop convert Entity doesnt work with subscenes.
@rustic rain I am currently in the process to convert everything to subscenes in my game. I also thought marking everything as static has effects on the hierarchy but it didn't. you need to use the StaticOptimizeEntity component
It flattens the hierarchy as much as possible unparenting everything that is below the Entity with that StaticComponent
This gave me a huge performance boost because the LocalToParentTransformSystem wouldnt need to run anymore on 10k entities
my goal is to prevent conversion at all
I don't need those parent entities
The only use for them - have them as prefabs
So I can quickly switch between my "rooms"
since they all exist in same space
and most internal objects are literally in same places
You probably shouldnt care about instantiating a few more empty static parents than necassary. AFAIK unity does not want you to delete Entities in the Destination world while converting. I had the same Issues but decided it is not a Problem for now to have some useless static entities.
hm
so did marking static did any changes to conversion process?
I'd want those entities to have as little components as possible then
The hierarchy was optimized. Nothing got deleted i think. maybe someone else knows how to leverage the ConversionPipeline better. You could write a ConversionSystem that tags all "useless" Entities and then at runtime have a system Destroy all useless Entities in batch.
here's what I mean
rn I have them in separate subscenes
but I want to move them all to one
and since all those "systems" will have same things in same places, I need to be able to differentiate easily during development in editor
without an actual effect after conversion
isnt that the perfect usecase for subscenes?
not really
I'll have other use for subscenes
for actual things that will need to be unloaded/uploaded quickly
but for those rooms
I need to be able to dynamically create them in any way I want
meanwhile subscenes are editor tool basically
So you just want a "Room" parent instead of a subscene
System1 and System2 GO are empty, and during conversion I'd like them to be removed completely
yeah
like this
Well then thats easy when it is defined for which objects you want the cleanup. Just add a TagComponent at conversion and destroy it in first frame. No reason to work against unities conversion guidelines then
First i thought u have a really deep dynamic hierarchy
combine it with the OptimizeStaticEntity component then it wont create children
hmm
I'm not sure, what it does
I do need children to be converted, I just want to avoid children components being created and set on all children
yes the childentities will be there but wont be parented anymore.
oh
just try it out
OptimizeStaticEntity so that's vanilla component?
yes
yyyep
pog
yeah, looks like no parents component
Thanks
We really need some kind of FAQ for such little tips ngl
rn, the only way to find out about them - other users of dots
kek
I assume the only hierarchy in this tool are subscenes?
hmm
During conversion, can I somehow affect all child entities?
In particular I want to add shared component
meanwhile also avoiding adding parent/child components
Read up on the conversion workflow. You have full access to the ConversionWorld and Destination world. In the ConversionWorld all GameObjects still exist. you can traverse the hierarchy if you want to
yeah, but for example, if I do it through authoring component:
I don't really control the order of those entities
So adding components dynamically to children GO doesn't seem viable
I should look into conversion systems
and what access they have
yes. have a conversionsystem loop over all transforms
public class InSystemConversionSystem : GameObjectConversionSystem
{
protected override void OnUpdate()
{
int index = 0;
Entities.ForEach((InSystemTag tag) =>
{
var systemTag = new InSystemComponent() {SystemID = index};
index++;
foreach (Transform transform in tag.gameObject.transform)
{
var entity = GetPrimaryEntity(transform.gameObject);
EntityManager.AddSharedComponentData(entity, systemTag);
}
});
}
}
hmm
this doesn't seem to work
debug doesn't even trigger on breakpoints
weird
open your scene turn on live conversion
from memory if you want to break point
i havent checked in a while but normal conversion used to run in a separate process for performance
huh, true
welp, in break points
it doesn't find entities
var entity = GetPrimaryEntity(transform.gameObject);
this always gives Null
yeah thats what i thought
but all right
mapping maps to components
transform + every component that are passed for conversion
Is there a way to make a Query with shared component filter?
you create a query then set your filters
thats what i mean
i dont really get you otherwise ^_^'
entityQuery.SetSharedComponentFilter(new SharedCompennt {Value = ValueToFilterBy });
is this not what you mean?
you wont be able to find sharedcomponents in the conversionworld though. they do not exist yet.
nah, it's for runtime
Entities.WithSharedComponentFilter(systemsList[add])
.WithStructuralChanges()
.WithNone<DisableRendering>()
.ForEach((Entity e) => { em.AddComponentData(e, new DisableRendering()); })
.Run();
Entities.WithSharedComponentFilter(systemsList[remove])
.WithStructuralChanges()
.WithAll<DisableRendering>()
.ForEach((Entity e) => { em.RemoveComponent<DisableRendering>(e); })
.Run();
I'm basically redoing this mess kek
hmm i get them in my conversion
if (!records.TryGetValue(sceneSection, out var list))
{
list = records[sceneSection] = new List<(SavableAuthoring, SavableScene)>();
}
list.Add((savable, savableScene));```
is a piece of code in my save conversion
yes you get it in the destinationworld but not in the conversionworld
sry was unclear
oh yep sure got you
hmm
is there any component list of all things that gets rendered?
I remember RenderMesh and CompanionLink
What kind of buffer can I use for this problem?
anything else?
Oh nvm
hmm i dont think that covers your question fully though sry
uh huh
Anyway, I have this entity that contains constraint body pair and physics joint, after the original entity has been destroyed, it become useless, so I'm trying to check whether that component has no entity inside PhysicsConstrainedBodyPair but one of the entityA or entityB is Invalid, how to check this invalid entity? or How to destroy this kind of unused entity? Is there a way I can manage this?
(with and without motion variants)
see for yourself in \Unity.Rendering.Hybrid\RenderMeshUtility.cs
@rustic rain
By the way that's v0.17, I don't DOTS nowadays
hmm
RenderBounds?
Basically, I'm looking for a component
that will be present on all rendered entities
so I can apply DisableRendering on it
and don't add it to other entities, that are unnaffected by rendering anyway
that's for culling, if the bounds aren't inside camera view, don't need to render
well yeah, I guess all rendered entities will have it
kek
expect maybe CompanionLink
which probably has it's own GO culling
ok so naive approach maybe would be to query WithAll first eight comps and WithNone DisableRendering
never really thought of it so maybe there's a better approach
I only need one component I think
or use some root wrapper
for each "rendering line"
but you said all rendered entities at first I'm confused ๐
sure if you're targetting only "rendering line" entities it might best to only work on them through tags
doesn't everything have RenderMesh for entity rendering
and I don't need any other component to know it
kinda same thing for other "lines"
with RenderMesh
I just need to know
whether there's any other similiar case
or is that it
just these 2
companion link can exist on gos that aren't rendering anything
though you may still want to disable them (e.g. lights)
can anyone do sanity check pls
private static IEnumerable<Transform> LoopTransforms(Transform parent)
{
foreach (Transform child in parent)
{
yield return child;
foreach (Transform anotherChild in LoopTransforms(child))
{
yield return anotherChild;
}
}
}
That would give me literally all transforms children of parent, right?
transform.GetComponentsInChildren<Transform>()
isn't that all you need?
(will return itself as well)
๐คก
yep
oh well
looks like StaticOptimizeEntity breaks all children
through hierarchy
not just it's own
hmm
Is there any way to assign names without edit mode of subscene?
public class EntityNameConversionSystem : GameObjectConversionSystem
{
protected override void OnUpdate()
{
Entities.ForEach((Transform tran) =>
{
var entity = GetPrimaryEntity(tran);
DstEntityManager.SetName(entity, tran.name);
});
}
}
I tried this, but no luck
yeah I've tried that before its never worked
Never tried it after my first attempts failed but here someone made it work in 2022:
https://forum.unity.com/threads/entity-setname-with-entitycommandbuffer.723947/
maybe you cant do it in conversion for some reason
ooof i lied.
found this is my code:
dstManager.SetName(pointEntityPrefab,"QueryPoint<" + GetComponentType +">");
#endif```
?
I don't really get it
I need to assign name during conversion
since that's the only place where I have my GO names
how do I access this component through EntityManager?
DynamicBuffer<Child> buffer = em.GetBuffer<Child>(parent);
This gives me buffer of Child, not of Entity
meanwhile I need to access, exactly Child component
The code Manarz posted is during conversion. DstManager is the EntityManager of the destination world of the conversion system
Also, your last two posts contradict each other a bit: do you want the Child element or not, cause that's what that buffer gives you
But the Value of Child is an Entity, I believe
well, I tried either EM and DST
so far, no names
I would take a look at how conversion in the editor works: https://docs.unity3d.com/Packages/com.unity.entities@0.50/manual/live_conversion.html
any idea about checking whether Entity has buffer thO/
if (!em.HasComponent<Child>(parent))?
is that it?
looks like it
That should work, but not until after TransformSystemGroup has run
I think that's where the buffer gets added?
Deleting entities doesnโt cause structural changes, right? Just a hole in memory that can be filled by another entity?
It is a structural change. It leaves a gap in terms of entity IDs that don't then reference any existing entity, but you're not gonna have gaps in your chunks after deleting entities
great, so deleting entities will shuffle around pointers? That's not good.
private partial struct GenerateColorsJob : IJobEntity
{
public CommandBuffer cmd;
public Dictionary<int, int> _entityIndexToVersion;
public MaterialPropertyBlock _idMaterialPropertyBlock;
public Material _idMaterial;
void Execute(Entity e, RenderMesh mesh, ref LocalToWorld localToWorld)
{
if (mesh.mesh == null)
{
return;
}
_entityIndexToVersion[e.Index] = e.Version;
_idMaterialPropertyBlock.SetColor(ColorPropertyID, IndexToColor(e.Index));
cmd.DrawMesh(mesh.mesh, localToWorld.Value, _idMaterial, mesh.subMesh, 0, _idMaterialPropertyBlock);
}
}
Any idea why this gives me this exception?
This function is apparently getting hit with a structural change? Why is this?
void generateInventory(IOD.GameplayElements.Inventory inv, Entity parent)
{
DynamicBuffer<EntityBuffer> outInventory = eManager.AddBuffer<EntityBuffer>(parent); //add buffer
outInventory.Capacity = 32;
print(inv);
foreach (IOD.GameplayElements.InventoryItemInstance item in inv.inventory)
{
Entity newEntity = eManager.CreateEntity(ItemsArchetype); //create data
eManager.AddComponentData(newEntity, new RefIDComponent { refID = item.refID }); //new refID
eManager.AddComponentData(newEntity, new ItemDataComponent //populate item data
{
inInventory = true,
whereStored = parent,
owner = item.owner == "" ? nullEntity : findEntityByRefID(item.owner)
});
eManager.AddComponentData(newEntity, new BaseIDComponent { baseID = item.item.baseID }); //baseID
eManager.AddComponentData(newEntity, new WorldComponent { world = SceneManager.GetActiveScene().name }); //determine current world
outInventory.Add(new EntityBuffer(newEntity)); //Add new entity to dynamic buffer. HERE
}
}
is it because I add new entities during this procedure?
and thus I cannot add more to the buffer
how can I forcefully allocate a block of data to allow it though
The EntityBuffer is this:
[InternalBufferCapacity(32)]
public struct EntityBuffer : IBufferElementData
{
public Entity Value;
public EntityBuffer(Entity e)
{
this.Value = e;
}
}
And I know that there will only be 32 of them
so how can I pre-allocate 32*32 bytes to this
eManager.AddComponentData will make a structural change. It's best to declare all the components you add in the archetype you are already using and just use setcomponent
same goes for the dynamicBuffer which you can also declare in the archetype (but that's on the parent)
no it won't and deleting also doesn't cause structural changes as the archetype in the chunk stays the same. structural changes only occur when the archetype is changed and entities and their data have to be copied to another archetype chunk. so this means only adding and removing components will create structural changes. creating and deleting don't
deleting will leave holes in the chunk which are filled when a new entity is created with the same archetype
the buffer is not the issue here. an internal capacity of 32 will be too big for the buffer to reside in chunk I guess. that means it will be allocated in heap, outside of chunk data, which is okay
how do i declare them in the archetype? also i didnt know setcomponent was a thing, whoops.
you should really read the docs: https://docs.unity3d.com/Packages/com.unity.entities@0.50/manual/index.html to learn all the concepts that are available
don't you already create an archetype for ItemsArchetype?
yeah
it's the same really. just use the type of the dynamicbuffer, in your case EntityBuffer
but put it on the parent. not on the ItemsArchetype ๐
guess it's a PlayerArchetype or smth
yeah ok to just typeof(DynamicBuffer<EntityBuffer>), //Inventory
having a prefab for it is more convenient though
it does, that's why you want to define it when you are instantiating. that way a totally new chunk with the correct data types is created
otherwise you instantiate and then move data around just because you're adding after instantiating
this can all be defined with this: https://docs.unity3d.com/Packages/com.unity.entities@0.50/manual/live_conversion.html
ok so putting typeof(DynamicBuffer<EntityBuffer>), //Inventory in the archetype will clear that space, and then AddBuffer will fill it?
GO in subscene with monobehaviour component that define how your entity will look
you'll have to use getbuffer
it will be already added when it's defined in the archetype
ok, got it
make yourself comfortable with the conversion workflow. you're in a world of hurt if you don't and things will be a lot more complicated.
I have spells in a subscene which are normal GOs. They have comps like this on them so due to the conversion I already get them as entitiy.
you can make complicated code with this conversion that would be too difficult or slow at runtime
Ok, so now I have this archetype, but the dynamicbuffer seems to be throwing an error:
NPCArchetype = eManager.CreateArchetype
(
typeof(RefIDComponent), //RefID
typeof(WorldComponent), //World
typeof(LocalToWorld), //Transform
typeof(DynamicBuffer<EntityBuffer>), //Inventory
typeof(NPCNavTrackerComponent), //NPC tracker
typeof(DeadOrAliveComponent), //Dead or Alive
typeof(NPCExtraDataComponent), //Extra NPC related data
typeof(BaseIDComponent) //baseID
);
And then this archetype doesn't get created which breaks everything later
so my suggestion is that you do the same for your player entity. define it in a subscene with these IConvert comps. it makes the whole thing dynamic and you can mix and match without code changes.
typeof(DynamicBuffer<EntityBuffer>) change to typeof(EntityBuffer)
Yes I will get more accustomed to the live conversion once I need to use it for something. The way my system works isnt compatible with subscenes at the moment, but I'm trying to use entities where I can (particularly with lots of objects/ static objects)
wait, what? then how will it know to allocate a buffer?
The way my system works isnt compatible with subscenes at the moment
I hardly believe that
because it's a IBufferElementData
entities understands that
if subsystems don't work you can also convert a normal GO prefab by hand with GameObjectConversionUtility.ConvertGameObjectHierarchy
my moniobehaviours would require a lot of setup for this and id rather focus on them actually working right first haha
dang it, again with the structural changes. the inspector to find structural changes is coming soon, right?
this has nothing to do with your MBs. think of it the same as the archetype you have just created. only that you create them in the editor and not by code
is this still your code you're having issue with?
yes, but now it looks like:
void generateInventory(IOD.GameplayElements.Inventory inv, Entity parent)
{
DynamicBuffer<EntityBuffer> outInventory = eManager.GetBuffer<EntityBuffer>(parent); //add buffer
outInventory.Capacity = 32;
print(inv);
foreach (IOD.GameplayElements.InventoryItemInstance item in inv.inventory)
{
Entity newEntity = eManager.CreateEntity(ItemsArchetype); //create data
eManager.SetComponentData(newEntity, new RefIDComponent { refID = item.refID }); //new refID
eManager.SetComponentData(newEntity, new ItemDataComponent //populate item data
{
inInventory = true,
whereStored = parent,
owner = item.owner == "" ? nullEntity : findEntityByRefID(item.owner)
});
eManager.SetComponentData(newEntity, new BaseIDComponent { baseID = item.item.baseID }); //baseID
eManager.SetComponentData(newEntity, new WorldComponent { world = SceneManager.GetActiveScene().name }); //determine current world
outInventory.Add(new EntityBuffer(newEntity)); //Add new entity to dynamic buffer. HERE
}
}
the parent's component data is now using SetComponentData
does subsequent calls to generateInventory also create structural changes? Because if the archetype doesn't exist yet, it'll count as a structural change (I think)
you can't iterate a buffer and make structural changes
all the archetypes are created on Start() so all of them should exist before this is done. Unless you mean if new entities are created
foreach (IOD.GameplayElements.InventoryItemInstance item in inv.inventory)
either you need to use inv.inventory.ToNativeArray to make a copy of your buffer
or switch entitymangaer to commandbuffer
I think this is main thread code, not a job, right?
i assume so since they're using entitymanager
right. And yes this is main thread
the reason is a structural change could move the buffer you're iterating to a new chunk therefore unity invalidates them all on any change
I'm not actually sure about this how this is counted in the structural change profiler. Just creating an archetype, more like defining doesn't create a chunk I believe. Creating an entity with that archetype does though
yes I get that part
I have loops elsewhere creating new entities (although this is the only one that populates data using new entities). Should everything be using command buffers?
command buffers are more for jobs. on main thread I wouldn't care too much about it at this point
personally i'd do this with a command buffer (not a command buffer system, just one you create and playback after the loop)
dang it, how do I get the current command buffer? is it in World.DefaultInjectionWhatever
sorry about all this, im hungry and frustrated haha
it says I need it from a system
but which system
er, entitycommandbuffersystem
thats what im saying, ignore entitycommandbuffersystem
var ecb = new EntityCommandBuffer(Allocator.Temp);
Loop()
ecb.Playback(EntityManager);
oh I make a new one, okay
oh and about the capacity. the problem is that the capacity doesn't really limit the buffer. if you have 32 elements in the buffer and add one the length will be 33 and the capacity likely 64. the 32 has to be limited somewhere else in code. on that note, I don't think you would want the data in the chunk so it's best to use [InternalBufferCapacity(0)] which forces the buffer data to be allocated in heap memory.
oh yeah I understand that part so it is limited implicitly elsewhere in the code
ok so now it looks like this:
void generateInventory(IOD.GameplayElements.Inventory inv, Entity parent)
{
DynamicBuffer<EntityBuffer> outInventory = eManager.GetBuffer<EntityBuffer>(parent); //add buffer
outInventory.Capacity = 32;
print(inv);
EntityCommandBuffer ecb = new EntityCommandBuffer(Allocator.Temp);
foreach (IOD.GameplayElements.InventoryItemInstance item in inv.inventory)
{
Entity newEntity = ecb.CreateEntity(ItemsArchetype); //create data
ecb.SetComponent(newEntity, new RefIDComponent { refID = item.refID }); //new refID
ecb.SetComponent(newEntity, new ItemDataComponent //populate item data
{
inInventory = true,
whereStored = parent,
owner = item.owner == "" ? nullEntity : findEntityByRefID(item.owner)
});
ecb.SetComponent(newEntity, new BaseIDComponent { baseID = item.item.baseID }); //baseID
ecb.SetComponent(newEntity, new WorldComponent { world = SceneManager.GetActiveScene().name }); //determine current world
outInventory.Add(new EntityBuffer(newEntity)); //Add new entity to dynamic buffer. HERE
}
ecb.Playback(eManager);
ecb.Dispose();
}
outInventory.Add(new EntityBuffer(newEntity)); this gets patched with the entityCommandBuffer then, right tertle?
good spot, it wont
use ecb.AppendToBuffer(parent, new EntityBuffer(newEntity));
instead
yeah
since that's outside of the loop
ok
HA! the errors are gone!
in the entity heirarchy is there some way to see what components are attasched to the entity
Also, thank you very much. I've neveer worked with the buffers or the command buffer before
great! uhm, don't you see them in the inspector when clicking on the entity in the hierarchy? window->dots->hierarchy
oh yeah. whoops. I have them occupying the same pane so I didn't see the inspector change
been a while since i worked with entities.
hehe
So, the docs specifically include creating and deleting entities in their list of structural changes (https://docs.unity3d.com/Packages/com.unity.entities@0.50/manual/sync_points.html) and those functions definitely force a sync point, so why don't you consider them structural changes?
Not saying you're necessarily wrong, just trying to better understand what's going on under the hood
I'll quickly test something so I don't say something wrong ๐
ok, technically the unity docs are correct. creating and deleting is counted as structural change (in the profiler). although the important thing why we generally don't recommend structural changes is because of the performance issues. creating and deleting entities doesn't have performance issues. only adding and removing comps does. Honestly, it's a really bad idea that Unity puts creating and deleting into the broad term of structural changes. I can go into detail why structural changes on adding and removing comps is so problematic.
public Entity CreateEntity(EntityArchetype archetype)
{
var changes = access->BeginStructuralChanges();```
Adding a new entity can create new chunks
And creating a lot of entities is currently my biggest bottle neck on loading a save
takes ~20ms for 100k
and there's no real way around it ๐ฆ
i think it's quite a problem when everyone is saying don't make structural changes and we actually mean, don't add/remove comps all the time
i made a pooling system for entities once XD
that's fair
the only cost was the big memcpy. figured nothing can be faster than that but it was honestly quite the pain to work with
doesn't help you for the save system of course. I hope you are keen to go down this rabbit hole and optimise it ๐
did you calculate how much data you are allocating and how fast a memcpy would be?
also, 20ms for 100k is still really fast. even today a player has the patience to wait for that long. in case that's for some rollback system, yeah, I see the problem
oh it's totally fast
and if you're saving subscene entities you don't need to pay this cost at all
How do Netcode peoples deal with authoring nested ghosts?
Do you just avoid it by using spawn points?
You canโt get GameObjects with traditional physics and entities with DOTS physics to interact at all, right.
no they dont talk to each other
i handle by no not having any nested ghosts ๐คฃ
Yeah, that is becoming a more desirable solution day after day...
I've got a ship that is a ghost and a bunch of things on the ship that are also ghosts, e.g. controllable guns or computers.
They are set up as ghosts so that I can swap command target and more easily select which things I want to be replicated.
But during authoring its a massive pain cos I have to place the object manually so I can see how it looks, then replace it with a spawn point so it can spawn at runtime.
For most things this isn't too bad, but even the walls need to be done in a similar way since I don't want their colliders to bake into the ship physics body.
It's all just a mess.
I wrote a gizmo to render meshes for spawn points
{
Draw(sceneView.camera);
}``` ```private void Draw(Camera camera)
{
if (mesh != null && mat != null)
{
var matrix = Matrix4x4.TRS(transform.position, transform.rotation, transform.localScale);
Graphics.DrawMesh(mesh, matrix, mat, gameObject.layer, camera);
}
}``` is the gist
Ah thanks! I'll give this a go.
how would i store this in a native collection:
void* r = UnsafeUtility.AddressOf(ref item);
do i have to convert to int64?
Can I apply SharedComponentFilter to ForEach loop?
hmmm
and it appears I can't use non-value fields for IJobEntity
nvm anything above
Can anyone remind what is called query option to only go through components that were written on?
So it doesn't touch components that were only read only
yeah, I think this one
I like DOTS
Is there a way to get component array of certain Query?
I'm learning how to do target finding
if there's any ready material - I'll appreciate sharing it
I found out you can:
hmmm
How am I supposed to do logic separation for different rooms
Do own query for each room?
yeah, just wondered
whether it makes any sense
hmm
So far I got this
protected override void OnUpdate()
{
foreach (var starSystem in _starSystems)
{
_targetQuery.SetSharedComponentFilter(starSystem);
var ltws = _targetQuery.ToComponentDataArray<LocalToWorld>(Allocator.TempJob);
so let's say I do some job where I determine LTW I want
how do I know, what Entity is that?
Why not just go this in a job?
Anyway you can do get entity array as well to get the matching entity
The array lengths will match
how?
I am doing target finding
so for each entity that wants to find target I do search
And to do that I need to pass array of entities to choose between
so, that's it
if there's a better option - I'd be glad to know
oh are you passing those values into a job?
yeah just pass the entity array in as well
usually you'd want to broadphase this though
rather than just brute force it all
what does it mean?
ah, you mean
split it into several jobs?
not necessarily but usually
like roughly, physics/spatial lookups are broken into 2 phases
a broad phase (say a BVH) and then the narrow phase to find the actual collisions
the idea of the broadphase is just to narrow candidates down as efficiently as possible
avoiding having to just brute force every possibility
a fast approach that doesn't use physics is to use a quantized hash map
in fact you could set it up in a way that you could do all your rooms in a single (2 phase) job
instead of having to iterate every room
hmm
thing is, pretty much every logic will be required to be separated between rooms
logic like: target finding mostly
and considering there's going to be a lot of rooms
and a lot of entities total
separating it all into job for each rooms will kind of narrow it down
severely
on average there would be I think 10 possible targets to find
per room
but say you have 100 rooms
thats 100 job schedules per query
that's not feasible performance wise
so what is better way?
#archived-dots message
so im going to base this off a similar technique i used for my orca
as i mentioned 1 approach is to quantize your data into a hash map - there are plenty of other spatial queries (bvh, quatrees, etc) but for my specific use case i'm going to use this and in particular to show off something in particular
my quantize job simply looks like this
{
this.Keys[entityInQueryIndex] = Hash(Quantized(this.Agents[entityInQueryIndex].Position, this.QuantizeStep, this.HalfSize), this.QuantizeWidth);
this.Values[entityInQueryIndex] = entityInQueryIndex;
}```
these keys/values turned into a hashmap afterwards efficiently
but what you really care about is this bit
Hash(Quantized(this.Agents[entityInQueryIndex].Position, this.QuantizeStep, this.HalfSize), this.QuantizeWidth);
private static int2 Quantized(float3 position, float step, int2 halfSize)
{
return new int2(math.floor((position.xz + halfSize) / step));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int Hash(int2 quantized, int width)
{
return quantized.x + (quantized.y * width);
}```
what this is doing is effectively grouping all entities into a simple grid so multiple entities can share the same cell
say if step is 10 (each cell is 10x10) and width is 100 (so 10*100 = 1000x1000) area they will exist in cells between 0 and 1,000,000
now this leaves plenty of digits to add some info about the room they're in
say you have 100 rooms
simply add roomID * 10,00,000 to the value
oof, smth pretty mind blowing kek
I'll need some time to figure out what you are talking about here
xD
this way you can store all your entities in a single map but can query specifically for the ones in the same room
anyway this means you can basically take
room + position.xz and find all other entities in the same cell
- neighbouring cells if you want etc
this gives you a small section of entities that are nearby to query if you want to target
anyway this was basically just the first idea that came to my head right now
and i also just had a few bottles of soju so it could be complete garbage