#archived-dots

1 messages ยท Page 264 of 1

rotund token
#

always returns default at index 0

rustic rain
#

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>?

rotund token
rustic rain
#

for cleanup/setting up smth

rotund token
#

thats what unity designed ISystemState components for

rustic rain
#

hm

#

I should look into it

rotund token
#

if you care about created/destroyed

#

there's

EntityManager.GetCreatedAndDestroyedEntities

rustic rain
#

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

rotund token
#

in entity world of just tracking it'd be like
added = GetEntityQuery(readonly<Movement>, exclude<LineRenderer>()
removed = GetEntityQuery(exclude<Movement>, readonly<LineRenderer>()

rustic rain
#

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

rotund token
#

i mean otherwise you just need another component to represent line renderer enabled/disabled

rustic rain
#

that's what private UpdatedTag is for rn I guess

muted field
#

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 =/

rotund token
#

intptr is fine

muted field
#

but it wont allow this _node = (Node)Marshal.PtrToStructure(_nodePtr, typeof(Node));

#

in a job

rotund token
#

anyway don't use marshal, unity provides UnsafeUtility to do things like this

muted field
#

oh

rotund token
#

UnsafeUtility.AsRef<>()

#

is what you're looking for

muted field
#

not sure how i use that with intptr

rotund token
#

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

muted field
#

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

rotund token
#

oh yep sure

#

that's a legit use

muted field
#

fair enough ๐Ÿ˜›

#

thanks for the help there, you're a real life saver ๐Ÿ˜„

rotund token
#

need any distraction atm

#

trying to repo a painful burst cache issue for unity atm that is doing my head in

muted field
#

not sure what that even means tbh ๐Ÿ˜„

rustic rain
#

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

rotund token
#

its the wrap chained method calls right?

#

chop always

solemn hollow
#

ooh i didnt know this setting existed. so glad i came around to join the discord

rustic rain
#

this is the one

solemn hollow
#

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

rustic rain
#

kek

#

I just did this, and it's enough for me for now

#

forgot to add Components to it

rotund token
#

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

solemn hollow
rotund token
#

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

solemn hollow
#

whats the syntax for searching components?

#

ah found it:

rustic rain
#

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

solemn hollow
#

as i understand it you want 3 queries:

  1. Query : all: MoveTarget, CompanionlineRenderer ; None: UpdateTag
    2.Query : all: MoveTarget,CompLineRenderer, UpdateTag
    3.Query : all CompanionLineRenderer, UpdateTag ; none : MoveTarget

  2. Query triggers the job that adds the Update Tag

  3. Query does the actual Update

  4. Query is responsible for removing the UpdateTag

rustic rain
#

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?

solemn hollow
#

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

rustic rain
#

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

solemn hollow
#

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

rustic rain
#

well yeah, that's how it works rn

#

but now that I also got DisableRendering

#

I either need more queries or better pattern

solemn hollow
#

you just need to adjust the queries. not more

rustic rain
#

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

solemn hollow
#

there might be but im not using it with lambdas. would also like to know ๐Ÿ™‚

rustic rain
#

oh yeah, that's how

solemn hollow
#

ah thats what you meant. i meant i dont know how to use EntityQuery / EntityQueryDesc inside a Entities.ForEach as a parameter

rustic rain
#

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

solemn hollow
#

WithEntityQueryOptions()

rustic rain
#

if it was OOP it'd be if (!MoveTarget OR DisableRendering) {}

rustic rain
solemn hollow
#

which option do you need?

rustic rain
#

I want to add Disabled (prev: updatedTag) only under those conditions

solemn hollow
#

ok but that is not an available query option

rustic rain
#

so either when MoveTarget is absent or when DisableRendering is present

#

yeah

#

I figured

solemn hollow
#

you can combine queries for that to work

rustic rain
#

which forces me to add another query

#

kek

solemn hollow
#

EntityQuery query = GetEntityQuery(new EntityQueryDesc[] { desc1, desc2 });

rustic rain
#

but can I run EntityQuery in loop?

#

I didn't find a way for it

solemn hollow
#

well go with IJobEntity then

rustic rain
#

I can use it to create struct IJob, but that would be another pain

#

kinda wish I could stay within SystemBase

solemn hollow
#

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.

rustic rain
#

hm

#

I'm looking into it

solemn hollow
#

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

rustic rain
#

Can I use entity manager there tho?

#

since all those queries are with structural changes

solemn hollow
#

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)

rustic rain
#

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

solemn hollow
#

the job that disables the linerenderer can still run. afterwards you remove the component. Probably better to defer that removal to an ECB though

rustic rain
#

oh man, that's why I simply wish Unity would implement some kind of reaction queries

#

to structural changes

#

xD

solemn hollow
#

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

astral parrot
#

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?

solemn hollow
#

The package did not get updated with the last 0.50 release. Would be quite some work to get it running i guess.

astral parrot
#

So... does that mean I need to go back to previous version of entities?

#

Or is there anyway to work on animation?

solemn hollow
#

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.

astral parrot
#

hmmm... I'll find a way, tq for the info

rustic rain
#

Do I need to get EntityManager every update?

#

or can I store it in variable in OnCreate?

solemn hollow
#

You dont need to get it at all. SystemBase already has a reference to EntityManager

rustic rain
#

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?

rotund token
rustic rain
#

hm

rotund token
#

Get in a system adds the dependency to the system

rustic rain
#

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

rotund token
#

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

solemn hollow
#

but u still need to do the lookup though. isnt combining 2 queries better here?

rustic rain
#

How do I combine 2 queries?

#

Get one from 2 descriptions?

rotund token
#

oh yeah i slightly missread his requirement

#

you can make a multi query

solemn hollow
#

maybe there is a nicer way to combine now? i just got this from the Docs

rotund token
#

i think that's the way

#

under the hood it just uses EntityQueryDescBuilder

#

so you could use that i guess

rustic rain
#
            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?

rotund token
#

i hate the formatting but yeah sure

rustic rain
#

tips on formatting? xD

#

Actually have been tweaking with it a bit ago

rotund token
#
            {
                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

rustic rain
#

ok, so

#

this Query made from 2 descriptions

#

literally means that it will go through 2 queries

#

under the hood?

rotund token
#

yep

rustic rain
#

ok, that's great

rotund token
#

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

rustic rain
#

I am learning IJobEntity rn

#

watched vid from Turbo

#

and got hyped by it

rotund token
#

you don't need no video

#

but yes ijobentity is great

solemn hollow
#

aside from no HasComponent ๐Ÿ˜ฆ

rotund token
#

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

pulsar jay
#

Does WithChangeFilter automatically create a read dependency or would I have to do that manually?

rustic rain
#

oh well, seems like I can't use EntityManager in IJobEntity

#

or maybe I can

#

hmm

solemn hollow
#

with EntityManager you lose burst. use an ECB

rotund token
#

You shouldn't (use em in job)

rustic rain
#

I don't need burst

#

it's all working with class components anyway

solemn hollow
#

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

rustic rain
#

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());
                }
            }
        }
solemn hollow
#

you can also add components in a batched fashion

rustic rain
#

I do?

solemn hollow
#

EntityManager.AddComponent<DisabledLR>(disableQuery)

rustic rain
#

yeah, I am looking into it

solemn hollow
#

Batched commands are ways faster since no memory has to be copied around. the whole chunk just gets another component

rustic rain
#
        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

solemn hollow
#

That makes no sense though. you are adding and then removing the same component on the same query

rustic rain
#

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

solemn hollow
#

just assign the jobhandle to the Systems Dependency field:
Dependency = Entities.ForEach....Schedule(Dependency)

rustic rain
#

but is there a way to achieve similiar thing with IJobEntity?

#

just curious

solemn hollow
#

Dependency = new MyJob().Schedule(Dependency)

rustic rain
#

no I mean

#

regarding reading translation of random entity?

solemn hollow
#

you need to pass ComponentDataFromEntity

rustic rain
#

same error

rustic rain
ionic sierra
#

Hello. Quick question. If I "instantiate" soemthing in DOTS, can I then save the instantiated objects into my project folder as a prefab?

solemn hollow
# rustic rain to a field?
    {
        public ComponentDataFromEntity<SpeedModifiers> modifiers;

        public void Execute(ref DynamicBuffer<ActiveEffect> activeEffect,in SpeedEffect speedEffect)
        {
            
        }
    }```
solemn hollow
ionic sierra
solemn hollow
rustic rain
#

wait a second

#

that dependency error

#

it's about reading Entity

#

ahem

#

Do I need to somehow specify dependency on Entities list?

ionic sierra
solemn hollow
rustic rain
#

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

solemn hollow
#

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

rustic rain
#

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

solemn hollow
#

Well yes that is what its saying. but the weird part is that Entity should be Readonly right?

rustic rain
#

I kind of assumed it is

solemn hollow
#

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?

rustic rain
#

same error happened with ForEach loop

solemn hollow
#

okay so its probably you making structural changes while those jobs are running?

rustic rain
#

no

#

oh

#

maybe

ionic sierra
#

is there a DOTS learning resource?

rustic rain
#

moetsi has a very nice guide

#

Turbo Makes Games on YT

ionic sierra
#

is moetsi a youtube channel?

rustic rain
#

nah, it's a website

ionic sierra
solemn hollow
ionic sierra
solemn hollow
#

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.

pulsar jay
#

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?

void girder
#

Why does the profiler not show the job running on the main thread?

solar spire
#

Isn't that exactly what it's showing?

void girder
#

Usually I would be able to see the job name that's running

solar spire
#

If you call Complete the job will force itself to finish on the thread you call it from

void girder
#

Hmm actually yeah nvm then

solemn hollow
pulsar jay
pliant pike
#

interesting I've been wondering how to do something like that for a while ๐Ÿค”

pulsar jay
#

Anybody has an example on using an ECB in a IJobForEntity?

solemn hollow
#

Havent tried yet but you should be able to just pass it into the job like you would in for example an IJobChunk

pulsar jay
solemn hollow
#
    {
        public EntityCommandBuffer ecb;

        public void Execute(Entity entity)
        {
            
            ecb.RemoveComponent<MyComp>(entity);
            
        }
    }```
pulsar jay
solemn hollow
#

ofc if you use scheduleparallel u pass a parallelwriter

pulsar jay
solemn hollow
#

thats always the case

pulsar jay
#

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 ๐Ÿค”

solemn hollow
#

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

pulsar jay
solemn hollow
#

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

pulsar jay
#

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 ๐Ÿ˜ฌ

solemn hollow
#

you are using IJobEntity right?

#

I think the codegen cant deal with generics yet

solemn hollow
#

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

pulsar jay
#

Oh and the other IJobs dont use codegen?

solemn hollow
#

yes

pulsar jay
#

well that sucks ๐Ÿ˜•

#

but I guess you are right that the codegen does not work with generics

solemn hollow
#

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.

pulsar jay
#

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 ๐Ÿค”

solemn hollow
#

So you want to wait between trigger and attack and attack to end of attack?

rustic rain
#
            _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

solemn hollow
#

what are you getting the translations for if you are not passing them into the job?

#

same with entities

rustic rain
#

I do pass them

#

into fields

solemn hollow
#

show the whole code plz

rustic rain
#
    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));
        }
    }
viral sonnet
#

when scheduling the _followShipJob.entities have to be there. but hey aren't

rustic rain
#

wdym

#

how are they supposed to be there

solemn hollow
#

there is alot wrong here actually

viral sonnet
#

they are async, then you schedule the job but the entities are still not calculated. so that trips up job scheduling

rustic rain
viral sonnet
#

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

rustic rain
#

ahem

viral sonnet
#

you can solve this with IJobDefered (sorry can't remember the exact interface name)

rustic rain
#

what is out dependency of nativearray is for then?

solemn hollow
#

but you are not even using the entities you are getting with the async operation at all...

viral sonnet
#

this takes a nativearray that is still unknown when scheduled

rustic rain
rustic rain
#

to fix error

#

I have posted hours ago

pulsar jay
rustic rain
#

this error

viral sonnet
#

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.

rustic rain
#

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();
        }
    }
solemn hollow
#

its a dependency issue between multiple systems

rustic rain
#

I removed all clutter, tried adding Entity as argument to execute

viral sonnet
#

100% not an internal bug

rustic rain
#

then what are supposed to be the steps find out what is the issue?

solemn hollow
#

well your error tells you it has sth to do with the dependencies in TestAI

viral sonnet
#

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.

rustic rain
rustic rain
#

I'll try complete now

viral sonnet
#

you can also try to disable all systems and work from there.

rustic rain
#

yeah, I'll try that too

viral sonnet
#

and don't worry too much about this. the dependcy system gives us all headaches ๐Ÿ˜„

rustic rain
#

all right, Complete does fix it

solemn hollow
#

just assign Dependency in every system the error pops uo

rustic rain
#

I guess, I need special place for such systems

solemn hollow
#

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

rustic rain
#

kek, it also fixed by ordering last

#

hm

solemn hollow
#

you should avoid relying on order too much though. becomes a huge headache later on

rustic rain
#

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

solemn hollow
#

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

rustic rain
#

ForEach loop gives same results

solemn hollow
#

AFAIK Entities.ForEach assigns the System Dependency by default when scheduling without params

rustic rain
#

literally same error

solemn hollow
#

hmm ok

rustic rain
#

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

solemn hollow
#

its perfectly fine to reference entities in components.

#

did u do a AddJobHandleForProducer for the Commandbuffer?

rustic rain
#

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

solemn hollow
#

okay then im out of ideas. im doing the same stuff (probably everyone is doing something similiar) without problems...

viral sonnet
#

I think it should be Dependency = UpdateWithBuffer(bufferSystem.CreateCommandBuffer());

#

it's not set otherwise, so the AddJobHandleForProducer doesn't know what to wait for

rustic rain
#

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

white island
#

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

solemn hollow
solemn hollow
#

Okay am i crazy? Do ISystemStateComponents not get added when Instanciating an Entity from a Converted Prefab that has ISystemStateComponents ?????

solemn hollow
#

Undocumented behaviour that makes no sense to me. Can someone explain the potential reasoning to have diffrent behaviour than IComponentData?

white island
solemn hollow
#

You can just have an Entity field inside your IComponentData. It is blittable

white island
#

Oh. Okay

uncut rover
# solemn hollow Undocumented behaviour that makes no sense to me. Can someone explain the potent...

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.

rustic rain
#

ugh

#

how do I use system state component for reactive system?

#

I thought you could only use it through destroying entity

solemn hollow
#

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...

viral sonnet
uncut rover
#

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

viral sonnet
#

i agree, it should be documented

solemn hollow
hearty zinc
#

Hi, i was wondering if it's worth using DOTS in production or not?

solemn hollow
#

I just think that there would be no harm in allowing to Instanciate with SystemSate

#

just gives you options

uncut rover
#

If you really want to do it your way just use a regular component data

solemn hollow
#

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

solemn hollow
uncut rover
hearty zinc
#

ok i see thanks

uncut rover
#

@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

viral sonnet
#

@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

solemn hollow
#

i have a modular ability system. I spawn a whole hierarchy of abilities that activate each other to create chain reactions

viral sonnet
#

Adding the SystemState after instantiation via command buffer is not a good solution IMO

solemn hollow
#

so effects can be anywhere in that hierarchy

viral sonnet
#

but the prefab has to exist somewhere?

#

which could be preprocessed

solemn hollow
solemn hollow
viral sonnet
#

you should be able to add it in the Convert stage of IConvertGameObjectToEntity

solemn hollow
#

no i do add it. but on instantiation it is not copied over to the Instance

viral sonnet
#

ah I see

solemn hollow
#

so im stuck between 2 not optimal solutions. if systemstate was copied to Instances i would have no problems at all

viral sonnet
#

yeah, I see the problem. I'm afraid there's no good solution I'm aware of

solemn hollow
#

i mean its fine to be restricted like that. its just so strange to not find that behaviour in the docs

viral sonnet
#

This is also new to me. I never had that use case

solemn hollow
#

i necrod a thread about it. maybe there is a little attention from unity but i doubt it

solemn hollow
viral sonnet
#

someone on the forum has the exact different problem ๐Ÿ˜„

solemn hollow
#

took me 2 hrs to figure it out... was totally blindsided

viral sonnet
#

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.

solemn hollow
#

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

viral sonnet
#

Why not use Prefab instead?

solemn hollow
#

cause the buffs affecting the ability damage for example are not added to the prefab

#

since that can change per unit

viral sonnet
#

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

solemn hollow
#

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...

solemn hollow
viral sonnet
#

ECB can't batch, so EM

solemn hollow
#

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...

hearty zinc
#

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

rustic rain
#

just install latest version of hybrid renderer

coarse turtle
rustic rain
#

it'll upload all dependencies itself

#

which includes all essential of ECS

hearty zinc
#

ok

uncut rover
#

@hearty zinc don't forget you have to use unity 2020.3

hearty zinc
#

i do use 2020.3

white island
#

I want to store an object's position and rotation, but nothing else. Unity Entities has a built-in transform component, right?

viral sonnet
#

that's a weird question. transform is a monoBehaviour term. entities uses Translation, Rotation, Scale and LocalToWorld

white island
viral sonnet
#

LocalToWorld is the matrix that combines Translation,Rotation and Scale

white island
#

okay

#

also, I got this error from using a NativeArray?

[Serializable]
    public struct InventoryComponent : IComponentData
    {
        public NativeArray<Entity> inventory; //Pointers to entities
    }
viral sonnet
#

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

white island
viral sonnet
#

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

white island
#

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?)

viral sonnet
#

a struct can have methods.

#

DynamicBuffer has a dynamic capacity but you can set the [InternalBufferCapacity(32)]

muted field
#

why is there an unsafe list but no unsafe array

rotund token
#

a good question

#

that said,

    public void* ptr;
    public int length;
}```
is pretty much it ๐Ÿ™ƒ
muted field
#

lol fair point

rotund token
#

it'd still be nice for the sake of methods

muted field
#

shame theres no way to see them in the inspector too

#

would be nice to verify my float2s populated correctly

worldly isle
#

I am currently using Entities.ForEach but I have no problem between the two

white island
#

How do I query from a Monobehaviour for an entity that has a certain value in a component field?

viral sonnet
viral sonnet
white island
#

also I am disposing it dont worry

viral sonnet
#

EntityManager.GetComponentData

muted field
#

@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

rotund token
#

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

muted field
#

is there a way to force a max frame count on a job then ?

white island
molten flame
white island
white island
#

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;

rotund token
#

that's not how you create a dynamic buffer

#

DynamicBuffer<X> buffer = EntityManager.AddBuffer<X>(entity)

#

you can't create a buffer yourself

white island
rotund token
#

[InternalBufferCapacity(32)]
public struct MyGiantOldEntityReferenceComponent : IBufferElement{
public Entity Value;
}

white island
rotund token
#

ah no

#

dynamic buffer does not exist on a componet

#

it exists on the entity

white island
#

...oh

#

so, what do I do instead?

white island
#

ugh, i can't use hasmaps either.

#

hashmap

rotund token
#

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"

astral parrot
#

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.

rustic rain
#

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?

uncut rover
#

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.

solemn hollow
#

@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

rustic rain
#

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

solemn hollow
#

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.

rustic rain
#

hm

#

so did marking static did any changes to conversion process?

#

I'd want those entities to have as little components as possible then

solemn hollow
#

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.

rustic rain
#

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

solemn hollow
#

isnt that the perfect usecase for subscenes?

rustic rain
#

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

solemn hollow
#

So you just want a "Room" parent instead of a subscene

rustic rain
#

System1 and System2 GO are empty, and during conversion I'd like them to be removed completely

#

yeah

#

like this

solemn hollow
#

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

rustic rain
#

but that still would create a lot of "child" components

#

on all children

solemn hollow
#

First i thought u have a really deep dynamic hierarchy

rustic rain
#

and shitload of archetypes

#

due to it

#

and there would be a lot of children

solemn hollow
#

combine it with the OptimizeStaticEntity component then it wont create children

rustic rain
#

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

solemn hollow
#

yes the childentities will be there but wont be parented anymore.

rustic rain
#

oh

solemn hollow
#

just try it out

rustic rain
#

OptimizeStaticEntity so that's vanilla component?

solemn hollow
#

yes

rustic rain
#

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

solemn hollow
#

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

rustic rain
#

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

solemn hollow
#

yes. have a conversionsystem loop over all transforms

rustic rain
#
    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

rotund token
#

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

rustic rain
#

huh, true

#

welp, in break points

#

it doesn't find entities

#

var entity = GetPrimaryEntity(transform.gameObject);

#

this always gives Null

rotund token
#

try just transform

#

let me load up rider and have a quick look

rustic rain
#

huh

#

transform did work

#

weird

rotund token
#

yeah thats what i thought

rustic rain
#

but all right

rotund token
#

mapping maps to components

#

transform + every component that are passed for conversion

rustic rain
#

Is there a way to make a Query with shared component filter?

rotund token
#

you create a query then set your filters

rustic rain
#

no, I mean

#

make a query of certain sharedComponent?

rotund token
#

thats what i mean

#

i dont really get you otherwise ^_^'

#

entityQuery.SetSharedComponentFilter(new SharedCompennt {Value = ValueToFilterBy });
is this not what you mean?

rustic rain
#

ooh,yeah

#

that one

solemn hollow
#

you wont be able to find sharedcomponents in the conversionworld though. they do not exist yet.

rustic rain
#

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

rotund token
#

                    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

solemn hollow
#

yes you get it in the destinationworld but not in the conversionworld

#

sry was unclear

rotund token
#

oh yep sure got you

rustic rain
#

hmm

#

is there any component list of all things that gets rendered?
I remember RenderMesh and CompanionLink

astral parrot
rustic rain
#

anything else?

astral parrot
solemn hollow
#

hmm i dont think that covers your question fully though sry

rustic rain
#

uh huh

astral parrot
#

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?

karmic basin
#

(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

rustic rain
#

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

karmic basin
rustic rain
#

well yeah, I guess all rendered entities will have it

#

kek

#

expect maybe CompanionLink

#

which probably has it's own GO culling

karmic basin
#

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

rustic rain
#

I only need one component I think

karmic basin
#

or use some root wrapper

rustic rain
#

for each "rendering line"

karmic basin
#

but you said all rendered entities at first I'm confused ๐Ÿ˜›

rustic rain
#

well yeah

#

Doesn't mean I need literally all components mentioned in query for it

karmic basin
#

sure if you're targetting only "rendering line" entities it might best to only work on them through tags

rustic rain
#

since all entities rendered for example through GO

#

will have CompanionLink

rotund token
#

doesn't everything have RenderMesh for entity rendering

rustic rain
#

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

rotund token
#

companion link can exist on gos that aren't rendering anything

#

though you may still want to disable them (e.g. lights)

rustic rain
#

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?

rotund token
#

transform.GetComponentsInChildren<Transform>()

#

isn't that all you need?

#

(will return itself as well)

rustic rain
#

๐Ÿคก

#

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

pliant pike
#

yeah I've tried that before its never worked

solemn hollow
#

maybe you cant do it in conversion for some reason

#

ooof i lied.
found this is my code:

        dstManager.SetName(pointEntityPrefab,"QueryPoint<" + GetComponentType +">");
#endif```
rustic rain
#

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

rustic rain
#

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

left oak
#

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

rustic rain
#

oh yeah

#

nvm

#

I didn't notice

#

that Child contains Entity through field

#

kek

rustic rain
#

so far, no names

left oak
rustic rain
#

if (!em.HasComponent<Child>(parent))?

#

is that it?

#

looks like it

left oak
#

That should work, but not until after TransformSystemGroup has run

#

I think that's where the buffer gets added?

rustic rain
#

it's runtime thingy, no worries about conversion

#

kek

white island
#

Deleting entities doesnโ€™t cause structural changes, right? Just a hole in memory that can be filled by another entity?

left oak
#

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

white island
#

great, so deleting entities will shuffle around pointers? That's not good.

rustic rain
#
        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?

white island
#

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

viral sonnet
#

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)

viral sonnet
#

deleting will leave holes in the chunk which are filled when a new entity is created with the same archetype

viral sonnet
white island
viral sonnet
#

don't you already create an archetype for ItemsArchetype?

white island
#

yeah

viral sonnet
#

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

white island
#

yeah ok to just typeof(DynamicBuffer<EntityBuffer>), //Inventory

viral sonnet
#

having a prefab for it is more convenient though

white island
#

But won't AddBuffer create a new buffer?

#

and thus cuase structural changes

viral sonnet
#

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

white island
#

ok so putting typeof(DynamicBuffer<EntityBuffer>), //Inventory in the archetype will clear that space, and then AddBuffer will fill it?

viral sonnet
#

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

white island
#

ok, got it

viral sonnet
#

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

white island
#

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

viral sonnet
#

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)

white island
#

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)

white island
viral sonnet
#

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

white island
#

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?

viral sonnet
#

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

rotund token
white island
# rotund token 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

viral sonnet
#

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)

rotund token
white island
#

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

rotund token
#

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

viral sonnet
#

I think this is main thread code, not a job, right?

rotund token
#

i assume so since they're using entitymanager

white island
#

right. And yes this is main thread

rotund token
#

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

viral sonnet
white island
#

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?

viral sonnet
#

command buffers are more for jobs. on main thread I wouldn't care too much about it at this point

rotund token
#

personally i'd do this with a command buffer (not a command buffer system, just one you create and playback after the loop)

white island
#

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

rotund token
#

thats what im saying, ignore entitycommandbuffersystem

#

var ecb = new EntityCommandBuffer(Allocator.Temp);
Loop()
ecb.Playback(EntityManager);

white island
#

oh I make a new one, okay

viral sonnet
#

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.

white island
#

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();
    }
viral sonnet
#

outInventory.Add(new EntityBuffer(newEntity)); this gets patched with the entityCommandBuffer then, right tertle?

rotund token
#

good spot, it wont

#

use ecb.AppendToBuffer(parent, new EntityBuffer(newEntity));

#

instead

white island
#

ok

#

I can still set the capacity the way I did though, right

viral sonnet
#

yeah

white island
#

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

viral sonnet
#

great! uhm, don't you see them in the inspector when clicking on the entity in the hierarchy? window->dots->hierarchy

white island
#

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.

viral sonnet
#

hehe

left oak
#

Not saying you're necessarily wrong, just trying to better understand what's going on under the hood

viral sonnet
#

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.

rotund token
#
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 ๐Ÿ˜ฆ

viral sonnet
#

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

rotund token
#

that's fair

viral sonnet
#

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

rotund token
#

oh it's totally fast

#

and if you're saving subscene entities you don't need to pay this cost at all

molten flame
#

How do Netcode peoples deal with authoring nested ghosts?
Do you just avoid it by using spawn points?

white island
#

You canโ€™t get GameObjects with traditional physics and entities with DOTS physics to interact at all, right.

safe lintel
#

no they dont talk to each other

rotund token
molten flame
# rotund token 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.

viral sonnet
#

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
molten flame
muted field
#

how would i store this in a native collection:
void* r = UnsafeUtility.AddressOf(ref item);

#

do i have to convert to int64?

rustic rain
#

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

rustic rain
#

yeah, I think this one

covert lagoon
#

I like DOTS

deft ridge
#

has anyone met some error by 0.50.1 p2

#

unity version 2020.3.34

rustic rain
#

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

rustic rain
#

hmmm

#

How am I supposed to do logic separation for different rooms

#

Do own query for each room?

rotund token
#

Create a seperate job for each room

#

You can reuse the same query

rustic rain
#

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?

rotund token
#

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

rustic rain
#

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

rotund token
#

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

rustic rain
#

ah, you mean

#

split it into several jobs?

rotund token
#

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

rustic rain
#

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

rotund token
#

but say you have 100 rooms

#

thats 100 job schedules per query

#

that's not feasible performance wise

rustic rain
#

so what is better way?

rotund token
#

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

rustic rain
#

oof, smth pretty mind blowing kek

#

I'll need some time to figure out what you are talking about here

#

xD

rotund token
#

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

rustic rain
#

oh man, seperate job strat

#

feels bad

#

0.56ms

#

with 1 entity

#

xD

#

allthought it happens 60 times per second

#

so maybe I can fix it