#archived-dots

1 messages Β· Page 288 of 1

rustic rain
#

Kek

viral sonnet
rotund token
#

im aware of those methods

viral sonnet
#

not that I think this is a great implementation for the problem πŸ˜„

#

i still wonder why they save it in ecs

#

what a wasted chunk

rotund token
#

wish they actually read from the ecs

#

so i could manipulate the component directly ^_^'

#

they don't actually read current time from the component

viral sonnet
#

exactly 🀣

#

like someone falling between 2 chairs

viral sonnet
#

once a DB has been moved outside a chunk it never gets reintegrated into the chunk, right?

rotund token
#

you can reintegrate it

#

with TrimExcess()

#
        /// Removes any excess capacity in the buffer.
        /// </summary>
        /// <remarks>Sets the buffer capacity to the current length.
        /// If the buffer memory size changes, the current contents
        /// of the buffer are copied to a new block of memory and the
        /// old memory is freed. If the buffer now fits in the space in the
        /// chunk reserved with <see cref="InternalBufferCapacityAttribute"/>,
        /// then the buffer contents are moved to the chunk.</remarks>```
viral sonnet
#

thanks

#

hm, m_InternalCapacity is private. how would i get that? :/

#

i can't remember the other method

rotund token
#

TypeManager.GetTypeInfo(typeIndex).BufferCapacity;

viral sonnet
#

where would i get the typeIndex best? it's also private in the handle

#

oh it's only private in BufferFromEntity. they made it difficult -.-

#

cool, i have a method for BufferTypeHandle now but not for BufferFromEntity

rotund token
#

TypeManager.GetTypeIndex<T>()

viral sonnet
#

i just wanted to post that! haha, thanks anyway

#

now i'm doing the proper way and just use a constant

alpine parrot
#

Hold on. Let me get this straight. Is this basically how dots works?

Take an instance of an object.

Add it to a list with only a specific set of variables like position and rotation.

And create instances of that, which its only unique data to itself are the predescribed variables?
rustic rain
#

each works differently

#

and all together it's smth totally different from classic unity

alpine parrot
#

Yeah, figured that was a thing

rustic rain
#

hmmm, I am trying to figure out how I can simplify user input

#

I have many different screens which are responsible for different controls

#

Space controls, Map controls, UI controls (which can be different on same screens)

#

I wanted to try assigning mouse events to UIElement's VisualElement

#

but it lacks way too many features from New Input System

rustic rain
#

Is there a way to implement smth like RequireNoSingleton<T>()?

#

Basically I need system to run only if certain query doesn't exist

viral sonnet
#

Update would still be called but there you can check for HasSingleton

devout prairie
#

Or could just have a singleton that signals the opposite condition I guess

viral sonnet
#

yeah, the query could be used for that

rustic rain
#

I have normal game overview and Map game overview, in which Action maps should switch (normal gets disabled, map gets enabled)

#

And I also don't want to be attached to same entity

muted star
rustic rain
#

internal EntityQuery CreateEntityQuery(ComponentType* requiredComponents, int count)

#

internally Unity has this

#

hehe

#

meaning you could specify count for query

#

but it's internal

muted star
#

What is a good way to make update orders easier to see in code?
All these [UpdateBefore] and [UpdateAfter] attributes are really confusing πŸ˜•

#

Is it normal to have such bad physics world performance in editor mode? This is with 5000 physics bodies.

rustic rain
#

generally systems should not depend on other at all

#

instead just know their own position relative to other

rustic rain
#

hmm

#

I wonder if it's a good idea to have a special entity

#

for all singletons

#

in game kek

devout prairie
#

then in my systems i would use these groups and their ecb systems like this:

#

i just found it a bit more organized, so i could then go back to my custom groups file and change orders and ecb dependencies that way

#

rather than going into each individual system and doing edits

rustic rain
#

hmmm, sorting NativeList

#

ooh, there's actually SortJobs

#

welp nvm

#

seems like they aren't ready yet

#

kek

rotund token
#

Just use sort from within a job?

rustic rain
#

yeah, that's one way

rotund token
#

Also what do you mean by not ready yet

rustic rain
#

latest forum posts say that it's just not implemented yet

#

from devs

#

and collections manual has 0 mentions of it

rotund token
#

Have you tried it?

rustic rain
#

I couldn't even find info on how to use it

#

usually when I look it up, I just find your post on forum with examples

#

xD

rotund token
#

i haven't used the job in like 2 years

#

but i'm pretty sure it worked back then

#

pretty sure you just call .SortJob()

#
            where T : unmanaged
            where U : IComparer<T>```
rustic rain
#

btw, in order to convert array of smth to array of <smth4> you simple reinterpret to that type?

#

I am thinking about implementing smid a bit, kek

rotund token
#

yes

#

but your size must be right

#

you can't convert an array of ints of length 5

#

into a int4 array

rustic rain
#

why not?

rotund token
#

because your last 3 ints would be someone elses memory

#

and you would be writing / reading random memory

rustic rain
#

oooh, and we don't want to touch that

#

I guess that would require implementing 2 algorithms

#

1 for x4

#

other for whatever is left per 1

rotund token
#

which is what burst does btw

#
        {
            var maxValue4 = new int4(int.MinValue);
            var numSamples4 = length >> 2;
            for (var iValue = 0; iValue < numSamples4; iValue++)
            {
                var value4 = ((int4*)values)[iValue];
                maxValue4 = math.max(maxValue4, value4);
            }

            var maxValue = math.cmax(maxValue4);
            for (var iValue = numSamples4 << 2; iValue < length; iValue++)
            {
                maxValue = math.max(maxValue, values[iValue]);
            }

            return maxValue;
        }
rustic rain
#

actually, I kind of need to do that outside of burst

#

hehe

rotund token
#

an example of doing it by hand

rustic rain
#

not even sure if code will be compiled vectorized

#

without burst

rotund token
#

well it won't be

#

if it's just in mono

rustic rain
#

sadge

#

hmmm

#

I wonder what would be a better pattern

#
  1. if I want some global action I simply create entity with trigger event component.
    em.CreateEntity(ComponentType.ReadOnly<TriggerUpdate>());
    Once event is done, entity is destroyed.
  2. I keep global world reference to some entity with systemState component and instead just add/remove components to it
viral sonnet
rotund token
#

you can't reinterpret yourself to float4/int4

#

which is what he was asking

viral sonnet
#

mh, i see

#

wouldn't for (var iValue = 0; iValue < numSamples4; iValue++) be for (var iValue = 0; iValue < numSamples4; iValue+=4)?

rotund token
#

?

#

var numSamples4 = length >> 2;
numSamples4 has been divided by 4

viral sonnet
#

i mean, doesn't work with the divided by 4 numSamples but the index isn't offset by 4

#

ah nvm πŸ˜„

rotund token
#

if i have int4*
abcd|efgh|ijkl|mnop|q
index 0 is a
index 1 is e
index 4 is q
you'd be skipping a lot ^_^'

viral sonnet
#

the (int4*) cast makes sure of that

#

i never used [AssumeRange(0, int.MaxValue)], does that actually help burst is such a case?

rotund token
#

yes - it can

#

if you notice the collections package uses this extensively

#
        {
            get
            {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
#endif
                return CollectionHelper.AssumePositive(m_ListData->Length);
            }

            set
            {
                m_ListData->Resize(value, NativeArrayOptions.ClearMemory);
            }
        }```
#
        internal static int AssumePositive(int value)
        {
            return value;
        }```
viral sonnet
#

lol, never inspected this one. what will even happen when value is -1?

#

is this like an assert?

rotund token
#

assumes do no checks

#

you will get very unexpected behaviour

#

I like to use a lot of asserts in my code with Hint.Assume

#

because Hint.Assume can just magically make your code a lot faster under weird circumstances

#

but it's so unsafe

#

so i have a little wrapper for it

#
    public static class Check
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Assume(bool assumption)
        {
            IsTrue(assumption);
            Hint.Assume(assumption);
        }

        [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
        public static void IsTrue(bool condition)
        {
            Debug.Assert(condition);
        }
viral sonnet
#

i remember you meantioning this once

rotund token
#

this way i have actual asserts when collection checks are on

#

this way I get code safety and random free speedups

viral sonnet
#

what i find weird, wouldn't every static analyzer find that out anyway when i have a for loop starting with 0 and an integer?

rotund token
#

if there's nothing stopping you passing in a negative value it has to defensively code for it

viral sonnet
#

ah i get it, okay πŸ™‚

rotund token
#

swear the had a better example at one point

#

but yeah constrained ranges would be even better

viral sonnet
#

they only work on parameters for methods, right?

rotund token
#

you can mark the return type which is the nice way of reusing it

#

only works on scalar-integer values

#
static uint WithConstrainedRange([AssumeRange(0, 26)] int x)
{
    return (uint)x / 2u;
}```
#

btw this is really a next level over optimization thing

#

i rarely use it

#

the effort (high) vs benefit (extremely low) not really worth it

viral sonnet
#

i mainly want to see if burst makes a different assembly and what's different about it

rotund token
#

there is a simple example of what it can do

{
    // The compiler will always replace this with the constant false!
    return na.Length < 0;
}```
viral sonnet
#

yeah, that's also the part of micro-optimisation i've never dealt with yet.

rotund token
#

something like hint assume also doesn't do anything like 99% of the time

#

but i had 1 really complex algorithm that it sped up 10%+ (voxel generation)

#

and if I'm using asserts anyway I may as well throw it in

viral sonnet
#

oh cool

#

say, have you ever used stackalloc in parallel jobs?

rotund token
#

sure

viral sonnet
#

is it any different to allocating temp memory?

rotund token
#

it is

viral sonnet
#

hm, i need to start utilising it then πŸ˜„

rotund token
#

this is why FixedList etc

#

exist

#

because they effectively stackalloc

#

but give you list/etc functionality

viral sonnet
#

what the ... i need that!

#

man, there's always something new i uncover from you πŸ˜„

rotund token
#

just remember you only get 4MB (i think it's 4MB x64, 1MB x86) on the stack per thread

viral sonnet
#

yeah, funky. it's not that FixedList is new to me. i just never made the connection that it's stack based

#

which makes sense when looking at the implementation

#

more than enough! πŸ˜„

#

i can replace some temp allocated native arrays

rotund token
#

but yeah, definitely used FixedList over Temp allocations if you can

viral sonnet
#

which get allocated, god knows where

#

damn, i asked that a few weeks ago but was probably phrasing it confusingly

#

anyway, thanks! πŸ™‚

rotund token
#

also if you're using stack

#

[SkipLocalsInit]

#

don't forget you can use this

#

to stop stack allocations being initialized to 0

#

but be careful otherwise you will have some really unexpected and hard to track down bugs

#

everyone assumes that new stack allocations are zeroed

#

And note the call to memset is gone - because the developer has promised the compiler that it is fine. Note that this is a power user feature for experienced developers - developers that are certain they won't run into undefined behaviour bugs as a result of this change.

viral sonnet
#

i have just read that. yeah, i know what to do. that one can be REALLY nasty though. this only affects stackallocs then and not other structs, right?

rotund token
#

but you're a power user

rotund token
#

everything (pretty sure)

viral sonnet
#

uhh boy

#

then better use a method for that then. that shit is dangerous! haha

#

also funny, i required that at some point. i think my ParallelListHashMap

#

yeah, new array and vales are set to -1 with memset

#

then i can skip the init to 0 hehe

#

oh wait nvm. that'a for uninitialised nativearray

rotund token
viral sonnet
#
        this ref SpellBlobRoot spellData, 
        //ref ArchetypeChunk chunk,
        //int indexInChunk,
        in SpellOwner spellOwner, 
        byte teamId, 
        in TargetInfo targetInfo,
        in SpellStats spellStats,
        bool fromMainEffect,
        AttackResult forceSpellResultHit = AttackResult.None)
    {
        var createData = new CreateBasicSpellDataComplex
        {
            spellOwner = spellOwner,           
            sourceTeamId = teamId,
            forceSpellResultHit = forceSpellResultHit,
            
            targetInfo = targetInfo,

            //spellBlob = spellBlob,
            //chunk = UnsafeUtility.AddressOf(ref chunk),
            //indexInChunk = indexInChunk,
            spellBlob = UnsafeUtility.AddressOf(ref spellData),
            spellStats = spellStats,
            fromMainEffect = fromMainEffect
        };

        return createData;
    }``` good candidate for [SkipLocalsInit] right?
#

would this even make a difference? hm

#

well, i can't find any memset in the burst assembly for it.

rotund token
#

i would not really worry about this except for stackalloc

viral sonnet
#

oh FixedList has no AsNativeArray, only To with a memcpy

#

that doesn't play nice with AddRange to a buffer

#

huh, i wonder why it doesn't. seems possible to me

rotund token
#

i am shocked you don't have a ptr extension for AddRange already πŸ˜„

#
            where T : unmanaged
        {
            CheckWriteAccess(buffer);

            int elemSize = UnsafeUtility.SizeOf<T>();
            int oldLength = buffer.Length;
            buffer.ResizeUninitialized(oldLength + length);

            var basePtr = (byte*)buffer.GetUnsafePtr();
            UnsafeUtility.MemCpy(basePtr + ((long)oldLength * elemSize), ptr, (long)elemSize * length);
        }```
viral sonnet
#

me too! thanks πŸ˜„

#

huh, rider warns me

rotund token
#

yes

#

classic stackalloc pitfall

#

gets worse if you do recursion!

viral sonnet
#

i wondered where's the catch

#

just a minor question but why do you have access to CheckWriteAccess(buffer)? have you copied the method too?

rotund token
#
        private static void CheckWriteAccess<T>(DynamicBuffer<T> buffer)
            where T : unmanaged
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckWriteAndThrow(buffer.m_Safety0);
            AtomicSafetyHandle.CheckWriteAndThrow(buffer.m_Safety1);
#endif
        }```
#

oh thats just a standalone method in my DynamicBufferExtensions class

viral sonnet
#

cool thanks. i just uncommented them. haha πŸ˜„

#

why not, better safe than sorry

viral sonnet
#

just tested FixedListX vs NativeList. seems on par in my case

#

what made the most difference in my job is moving out the NativeArray temp alloc and only allocate 1 list per thread. halfed the time πŸ˜„

#

temp allocs are really not that great in loops.

#

writing such patterns is a little weird. it's okay but eh

#

feels like it could be better

dreamy glade
#

I've generated an entity's mesh from scratch. The mesh seems to be complete- but is not rendering in the scene. Anyone thoughts on why this would be? Thank you!

rotund token
dreamy glade
viral sonnet
#

i wanted to say check translation but that also seems okay. hybrid renderer is installed?

dreamy glade
#

Not much documentation on the matter

rotund token
dreamy glade
rotund token
#

no idea, you shouldn't build mesh entitites from hand

dreamy glade
#

It's a voxel game. I have to generate them from scratch

rotund token
#

i have a voxel engine, my meshes are all authored

#

i just author a prefab then instantiate + set mesh/bounds

#

you can use RenderMeshUtility

#

to add the required components if you insist on doing it at runtime

#

excluding the scene components this is the type of stuff you need

viral sonnet
#

using stackalloc to replace these makes 0 difference

#

must be bottlenecked somewhere else

dreamy glade
rotund token
#

i converted it via authoring

#

which is what i suggest

dreamy glade
rotund token
#

I just create an entity prefab with my voxel material/etc and just instantiate that and set the mesh when generated

dreamy glade
#

but thanks for the help.

gusty comet
#

Hi, I was stopping by and wanted to know if this would be the place to ask about the progress of DOTS?

viral sonnet
#

sure, but we also get our info from the forum πŸ™‚

gusty comet
#

do you have the link?

#

please

viral sonnet
#

read the stickies in this subforum

gusty comet
#

thank you

viral sonnet
#

@rotund token any idea how I can get the BufferHeader* from a DB. my idea was to cast it but that's not going well

rotund token
#
                var b = (DynamicBufferExposed<T>*)UnsafeUtility.AddressOf(ref a);```
viral sonnet
#

ah! thanks

#
            where T : unmanaged
        {
            var tmp = (DynamicBufferExposed<T>*)UnsafeUtility.AddressOf(ref buffer);
            return (BufferHeaderExposed*) tmp->m_Buffer;
        }

        [StructLayout(LayoutKind.Explicit)]
        [NoAlias]
        public unsafe struct BufferHeaderExposed
        {
            [NoAlias] 
            [FieldOffset(0)] public byte* Pointer;
            [FieldOffset(8)] public int Length;
            [FieldOffset(12)] public int Capacity;
            
            public static byte* GetElementPointer(BufferHeaderExposed* header)
            {
                if (header->Pointer != null)
                    return header->Pointer;

                return (byte*)(header + 1);
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct DynamicBufferExposed<T>
        {
            [NativeDisableUnsafePtrRestriction] [NoAlias]
            internal BufferHeader* m_Buffer;

            // Stores original internal capacity of the buffer header, so heap excess can be removed entirely when trimming.
            private int m_InternalCapacity;

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            internal AtomicSafetyHandle m_Safety0;
            internal AtomicSafetyHandle m_Safety1;
            internal int m_SafetyReadOnlyCount;
            internal int m_SafetyReadWriteCount;

            [MarshalAs(UnmanagedType.U1)] internal bool m_IsReadOnly;

            [MarshalAs(UnmanagedType.U1)] internal bool m_useMemoryInitPattern;
            internal byte m_memoryInitPattern;
#endif
        }```
rotund token
#
var tmp = UnsafeUtility.As<DynamicBuffer<T>, DynamicBufferExposed<T>>(ref buffer)```
#

thats better imo

viral sonnet
#

yep, gonna use that

#

now I have a safe way to save the ptr without relinking. basePtr + index is enough

#

it was such a mess with buffers being moved

#

i see no other way

#

now I don't have direct ptr access to elements but it's good enough

viral sonnet
#

noice, this BufferHeaderExposed madness works flawless πŸ˜„

viral sonnet
#

as I am using the BufferHeader now I also had the same problem as you with bumping the version. had to save the chunk too

drowsy pagoda
#

Shit. My editor keeps bloating up memory until something on the pc crashes at random. Profiler didn’t tell me anything useful. Any tips on how to track down this leak? I need to know if it was me, or if it’s a bug. Please help.

solar spire
rotund token
#

do you have leak detection enabled?

muted star
muted star
rustic rain
#

I personally have groups like this

#

They are either before ecb or after

#

Usually I use them for systems that aren't supposed to be scheduled

#

But instead just do mainthread stuff

#

It's like my own personal ECB

#

Hehe

#

I actually just came up with an interesting option to make my reactice systems faster by merging them

#

Allthough not sure if it's worth it

pulsar jay
#

How would you handle sth like a toggle group with ecs? Hacing each toggle have its on/off state but having a group which handles that only one or n toggles can be active at once?

#

I could group them via SharedComponents I guess. But that would potentially create a lot of mostly empty chunks

viral sonnet
#

what's the actual use case?

#

it depends on how many groups you'd have for shared comps being viable

#

somethign that would also work is a hierarchy. have the parent group as entity and the other entities as child. disabling the group, disables the childs. it's just not very performant when this enabling/disabling occurs often and there are a lot of entities

rotund token
#

^

pulsar jay
#

The actual use case I have is leg IK. An entity can have multiple legs. But only one leg should lift of the ground at a time. But there are potentially many entities that could have legs.

#

So the legs need to be grouped somehow and there needs to either be a system that handles that only one leg of a group can move at one time

rustic rain
#

and then process hip

#

instead of leg parts

#

where all leg parts would be accessed through random access

devout prairie
#

similar to what Issue suggested, the ik system loops over all of the character 'root' entities, which have an IK component with various parameters and also a buffer holding a reference to the bone and joint entities for all the ik chains on the character

#

i pass in a few native containers with all of the bone ltw's and the ik system reads from that to do the solver code and writes the results using ecb back to the bones

pulsar jay
#

Thanks for your input @rustic rain and @devout prairie. I think I might be going with the dynamic leg buffer but maybe just lock/unlock the legs from the leg syncing system

full epoch
#

Have this strange problem with vs 2022 : whenever i start vs community 2022(unity 2021.3.6) in console i get this warnings : Internal: deleting an allocation that is older than its permitted lifetime of 4 frames (age = 5)
UnityEngine.StackTraceUtility:ExtractStackTrace ()
Unity.Collections.NativeArrayDispose:Dispose ()
Unity.Collections.NativeArrayDisposeJob:Execute ()
Unity.Jobs.IJobExtensions/JobStruct`1<Unity.Collections.NativeArrayDisposeJob>:Execute (Unity.Collections.NativeArrayDisposeJob&,intptr,intptr,Unity.Jobs.LowLevel.Unsafe.JobRanges&,int)

i do not start the game at all - just try to edit files on vs 2022 and then these warning are flooding my console and cpu core activity is almost all the time at 100%. Changing api compatibility level to .NET standard 2.1 or .NET framework doesn't help. Also whenever i install new Unity Editor VS 2022 does not recognize unity libraries and the when i change api compatibility level this problem is solved but still i get those warnings above. I use latest DOTS v0.51 - can this be fixed somehow?

rotund token
#

a) is that the full stack?
b) are you using netcode?
c) have you turned on full stack trace?

full epoch
#

a) I also have this warning and nothing else : Internal: JobTempAlloc has allocations that are more than 4 frames old - this is not allowed and likely a leak b) no i do not use netcode c) hmm i think i did i'll check that - I created forum thread with full stack trace here : https://forum.unity.com/threads/leak-when-using-vs-2022.1310399/

viral sonnet
#

do you have [ExecuteInEditMode] somwhere?

full epoch
#

you mean as an attribute of an system - no i think i do not have that

viral sonnet
#

you can profile the editor, see which jobs are running

#

that's an odd bug for sure

rustic rain
#

I think this is the one

full epoch
#

i dont have that attribute also nowhere in my code

devout prairie
full epoch
#

i didn't try that(have only vs 2022 installed and use latest packages for dots) - also must add that i have a bigger project which doesn't suffer from the problem explained above which is very strange( i use the same packages in both projects) - but also on that project when ever i install new Unity version VS 2022 doesn't recognize unity libraries but when i change api compatibility levels everything works fine - very strange

#

Since the project is not too big i will later this day try to create new and port code and assets and will report here if problem is fixed somehow - thx for your contribution in discussion to all

drowsy pagoda
drowsy pagoda
rustic rain
#

oh god, I am so confused in game managed

#

I tried to implement ECS way

#

but I soon realised I can't open UI that way

#

brrrrruh

haughty rampart
#

what?

rustic rain
#

I have world overview, when user can look around world.
And I have map overview, where user sees map.
Thing is, they have different keybinds

#

meaning if you are currently in world overview

#

you obviously shouldn't trigger anything that is related to map

#

and vice versa

#

I am trying to implement it with trigger entities

#

with reactive system that requires singleton OpenMap to update

#

and then I enable/disable action maps in OnStart and OnStop

#

but here comes a problem, where removing that singleton results in closing map aaaand...

#

you potentially don't know what UI is supposed to be open during that moment

#

which makes whatever system I tried to implement somewhat garbage

karmic basin
#

New input system has easy config of multiple map inputs you can sswitch

haughty rampart
#

+1

rustic rain
#

Wdym, how you suggest to use that?

#

I have it this way

karmic basin
#

Yeah like
In-game controls
Map controls

And such

#

Oh yeah you do :)

rustic rain
#

General should work always
Game general should only work when it's loaded
Space should only work when game is loaded and map is not opened
Map should only work when game is loaded and map is opened
Player Space/Map same as previous, but also both require Player entity

#

kind of like this

#

and I'm so confused how to implement it all

haughty rampart
#

yeah. just enable / disable on demand

rustic rain
#

I made a super huge method of if structures

#

and I quickly realised

#

it's not the way I want to implement it

#

I couldn't figure how I implemented it the moment I wrote it xD

rustic rain
#

but that's not an option

#

or at least, implementation is hidden by internal protection

#

and probably has unknown consequences

rustic rain
#

no I mean

#

RequireSingleton<T>()

#

but

#

RequireNoEntites<T>()

haughty rampart
#

why tho?

rustic rain
#

how else would you create a reaction on closing map?

haughty rampart
#

i'd just have an entity with bools for every control scheme and update this entity, then only run my query when ChunkHasChanged() and apply the state to the control schemes.

i can't say that's exactly how i would do it, but that was the first immediate though

rustic rain
#

I have a feeling that means my jobs are completed as soon as they are scheduled

rotund token
#

i'm not seeing that?

#

there's no complete on your main thread

rustic rain
#

hmmm

#

so that just means

#

that my jobs are executed faster than scheduling?

rotund token
#

it just means you have overhead in your systems

#

i very much doubt that main thread cost is (primarily) scheduling

rustic rain
#

but it literally is

rotund token
#

show me huggerAI

#

people always blame scheduling without ever having profiled it and it's never scheduling -_-

#

job handle combining and data setup is always slower

rustic rain
rotund token
#

there's so many things inn here

#
            if (targetCount == 0)
            {
                return;
            }

            _hashMap.Clear();
            if (_hashMap.Capacity < targetCount)
            {
                _hashMap.Capacity = targetCount;
            }```
#

you think CalculateEntityCount is free?

rustic rain
#

hhhm

#

any suggestions?

rotund token
#

is this 0.51?

rustic rain
#

yeah

rotund token
#
       _hashMap.Clear();

can also be expensive if you have a large hash map

rustic rain
#

it is large

#

I'd even say it's supposed to be extremely large

rotund token
#
        {
            UnsafeUtility.MemSet(data->buckets, 0xff, (data->bucketCapacityMask + 1) * 4);
            UnsafeUtility.MemSet(data->next, 0xff, (data->keyCapacity) * 4);

            for (int tls = 0; tls < JobsUtility.MaxJobThreadCount; ++tls)
            {
                data->firstFreeTLS[tls * UnsafeParallelHashMapData.IntsPerCacheLine] = -1;
            }

            data->allocatedIndexLength = 0;
        }```
#

i always run clear in a job

#

anyway your systems are only like 0.05ms each?
apart from this minor main thread overhead if you want to reduce this you either need to
combine systems or switch to ISystem

rustic rain
#

ISystem would mean that everything will be bursted?

rotund token
#

yes

rustic rain
#

and thus no managed code...

#

how would you add buffer in this case?

rotund token
#

well i wrote an unmanaged ecbs

rustic rain
#

soo

#

in ISystem, you just get reference to UnmanagedWorld

rotund token
#

i don't really use it because reasons - i'm trying to write my libraries archetype change free so i only use it for destroy and happy to have 1 systembase for that

rustic rain
#

and gets ISystem from it?

rotund token
#

there's my sample of using it

rustic rain
#

interesting

rotund token
#

but yeah, use at own risk i only tested it enough to ensure it worked - 1.0 has native support for this

rustic rain
#

Entities 1.0?

rotund token
#

yes

rustic rain
#

waaaait a moment

#

NativeParallelMultiHashMap

#

capacity

#

is for Key or Values?

rotund token
#

(key, value)

#

it's stored in key, value pairs

#

it's not 1 key 1234 values

#

its 1234 of the same key, 1234 values

devout prairie
#

seems kinda wasteful no?

rustic rain
#

huh, turns out you can do so many stuff in jobs

#
            var map = _hashMap;
            var targetQuery = _targetQuery;
            Job.WithCode(() =>
                {
                    int targetCount = targetQuery.CalculateEntityCount();
                    map.Clear();
                    if (map.Capacity < targetCount)
                    {
                        map.Capacity = targetCount;
                    }
                })
                .Run();

Turned starting part into this, to make it bursted

#

in fact I can even Schedule it

#

bruh

        [BurstCompile]
        private struct MapJob : IJob
        {
            [NativeDisableUnsafePtrRestriction] public NativeParallelMultiHashMap<int, TargetData> map;
            [NativeDisableUnsafePtrRestriction] public EntityQuery targetQuery;

            public void Execute()
            {
                int targetCount = targetQuery.CalculateEntityCount();
                map.Clear();
                if (map.Capacity < targetCount)
                {
                    map.Capacity = targetCount;
                }
            }
        }
#

I guess I can't

rotund token
#

yeah it's actually an annoyance

#

EntityQuery is burstable (most of it)

#

but not safety friendly

rustic rain
#

Sooo, any way I can make it pass?

rotund token
#

not without turning off safety for the whole job

rustic rain
#

How?

#

Since whole job is mostly about it

#

It's fine kek

rotund token
#

for the record i have not tested the safety of using a query in a thread like this

#

as far as I know though, it should be safe as long as you have your handles setup properly

#

any structural to the data you're querying should sync it so it finishes before that happens

rotund token
#

this is likely the jobs debugger not the safety system within burst triggering

#

best bet would be to just pass in chunk array and sum it yourself

#

or just not bother

viral sonnet
rustic rain
#

I guess I need to figure out a solution

#

I could potentially update hash capacity from other system

rotund token
#

just pass inthe size

rustic rain
#

wdym

rotund token
#

just do targetQuery.CalculateEntityCount(); on the main thread and pass it into the job

#

to set capacity

#

or simply do targetQuery.CreateArchetypeChunkArrayAsync

#

and pass that into the job

#

and calculate the entity count yourself

viral sonnet
#

but that has entity array overhead

rustic rain
#

hm

#

I guess I can combine 2 jobs into one with this approach

#

btw

#

I guess if I do IJobEntityBatch

#

That means that some Batches will be calculated in parallel?

viral sonnet
#

if you scheduleParallel, yes

rustic rain
#

ah, it's not gonna work anyway

#

since I need chunk array

#

ok, so
I guess that would do entity count

            var chunks = _targetQuery.CreateArchetypeChunkArrayAsync(Allocator.TempJob, out var handle);
            Dependency = new FillMapJob { chunks = chunks }.Schedule(JobHandle.CombineDependencies(handle, Dependency));
        private struct FillMapJob : IJob
        {
            public NativeArray<ArchetypeChunk> chunks;
            public NativeParallelMultiHashMap<int, TargetData> map;

            public void Execute()
            {
                int count = 0;
                for (int i = 0; i < chunks.Length; i++)
                {
                    count += chunks[i].Count;
                }
            }
        }
viral sonnet
#

i mean, yeah. but WHY? πŸ˜„

rustic rain
#

because I need to fill a large hashMap

#

multihashmap

#
        private struct FillMapJob : IJob
        {
            public NativeArray<ArchetypeChunk> chunks;
            public NativeParallelMultiHashMap<int, TargetData> map;


            [ReadOnly] public EntityTypeHandle entityHandle;
            [ReadOnly] public ComponentTypeHandle<LocalToWorld> ltwHandle;
            [ReadOnly] public ComponentTypeHandle<StarNormal> starHandle;

            public void Execute()
            {
                int count = 0;
                for (int i = 0; i < chunks.Length; i++)
                {
                    count += chunks[i].Count;
                }

                map.Clear();
                if (map.Capacity < count) map.Capacity = count;

                for (int i = 0; i < chunks.Length; i++)
                {
                    var chunk = chunks[i];
                    var entities = chunk.GetNativeArray(entityHandle);
                    var ltws = chunk.GetNativeArray(ltwHandle);
                    var stars = chunk.GetNativeArray(starHandle);

                    for (int j = 0; j < entities.Length; j++)
                    {
                        map.Add(stars[i].systemID,
                            new TargetData { entity = entities[i], position = ltws[i].Position });
                    }
                }
            }
        }
#

looks like this rn

#

and since that large hashMap is unknown size, I do it manually

#

In short: I create a map per starSystem/potential target for AI

#

since AI shouldn't be affected by targets from other star systems

viral sonnet
#

hm ok, at least you reuse the chunks for the later iteration. you don't need to pre allocate a hashmap when it's not a parallel writer btw

#

still cleaner though with less allocations

rustic rain
#

I don't?

#

from what I remember

#

the sole reason I did it

#

because errors forced me to

#

kek

viral sonnet
#

single threaded lists/hashmaps can resize themself

#

only parallel writer have to be set beforehand

rustic rain
#

oooh

#

welp, I guess it's fine

viral sonnet
#

because in multi threaded you can't resize, makes sense, right?

#

yeah it's fine. even better because you only have 1 big allocation

rustic rain
#

oh god, I need to write ToArray method for multihashmap

#

I can't bear doing iterator manually anymore

viral sonnet
#

lol what? πŸ˜„ iterators are easy?

rustic rain
#
  if (map.TryGetFirstValue(star.systemID,
                            out var targetData,
                            out NativeParallelMultiHashMapIterator<int> iterator))
                    {
                        do
                        {

                        } while (map.TryGetNextValue(out targetData, ref iterator));
                    }
#

so much code

viral sonnet
#

don't optimize and then screw it up with a ToArray πŸ™‚

rustic rain
#

so ugly

viral sonnet
#

that can be done much nicer

rustic rain
#

how?

#

that's what I'm looking for

#

really wish I could just do foreach loop with it

viral sonnet
#
{
    while (enumerator.MoveNext())
    {
        var item = enumerator.Current;

        ...
    }
}```
rustic rain
#

what

#

oh god

#

I lived in a lie

viral sonnet
#

haha

rustic rain
#

hopefully

#

Unity will integrate it with foreach in future

viral sonnet
#

not sure about the reason they haven't. it's good enough for me. biggest upside, i have written a custom enumerator that supports ref values. so no copy process on getting .Current

rustic rain
#
            public NativeArray<ArchetypeChunk> chunks;
            public NativeParallelMultiHashMap<int, TargetData> map;
            
            [ReadOnly] public EntityTypeHandle entityHandle;
            [ReadOnly] public ComponentTypeHandle<LocalToWorld> ltwHandle;
            [ReadOnly] public ComponentTypeHandle<StarNormal> starHandle;

            public void Execute()
            {
                int count = 0;
                for (int i = 0; i < chunks.Length; i++)
                {
                    count += chunks[i].Count;
                }

                map.Clear();
                if (map.Capacity < count) map.Capacity = count;

                for (int i = 0; i < chunks.Length; i++)
                {
                    var chunk = chunks[i];
                    var entities = chunk.GetNativeArray(entityHandle);
                    var ltws = chunk.GetNativeArray(ltwHandle);
                    var stars = chunk.GetNativeArray(starHandle);

                    for (int j = 0; j < entities.Length; j++)
                    {
                        map.Add(stars[i].systemID,
                            new TargetData { entity = entities[i], position = ltws[i].Position });
                    }
                }
            }

hmmm, I get out of range exception somewhere here

rotund token
#

for (int j = 0; j < entities.Length; j++)
{
map.Add(stars[i].systemID,
new TargetData { entity = entities[i], position = ltws[i].Position });
}

#

j

#

i

rustic rain
#

oh

rotund token
#

this is such a common issue at work we basically self banned i/j in double iterations

rustic rain
#

what are you using?

viral sonnet
#

was gonna say. use i/k or i/ii πŸ˜„

rotund token
#

just have to name at least 1

#

i mean i'd jsut use foreach on the chunks here

#

foreach (var chunk in chunks)

rustic rain
#

huh

#

didn't know that's allowed

rotund token
#

foreach is fine on native arrays

rustic rain
#

Lists too?

viral sonnet
#

sure, lists can cast to nativearray very fast

rotund token
#

^

rustic rain
#

what about vice versa?

rotund token
#

[1.4.0-preview.1] - 2020-06-26

  • Add support for try/finally and using/foreach for IDisposable patterns.
#

basically you can do this you just can't catch

rustic rain
#

all right, let's do some stress tests, kek

#

oh well, 6k entities and I'm already in trouble

#

most of it is in ECB

rustic rain
#

most I do with buffer:
buffer.RemoveComponent<DoWorkTag>(entityInQueryIndex, e);

#
            buf.AddComponent(sortKey, e, a.actionType);
            var queue = buf.AddBuffer<QueuedAction>(sortKey, e);
#

and this

#

is it actually that expensive?

rotund token
#

any structural change is expensive

#

how many are you doing per frame?

rustic rain
#

idk, it's AI

#

I have 3k huggers

#

and 3k potential targets

#

tbh, I think I can optimize it

#

a lot

rotund token
#

i would say at max you can do a couple of hundred per frame before shit starts going down hill

rustic rain
#

Instead of doing it per entity

#

I can do it for query

#

but I'd need additional buffer for that

#

that knows how to do delayed entityQuery changes

#

luckily normal ECB knows that, heh

rustic rain
#

oh god, I'm stuck with dependency problems again

#
            var entityHandle = GetEntityTypeHandle();
            _ltwHandle.Update(this);
            _starHandle.Update(this);

When I literally do this in OnUpdate

#

it says I haven't resolved LocalToWorld dependency

#

kek

#

The system SpaceTycoon.Runtime.AI.HuggerAISystem reads Unity.Transforms.LocalToWorld via HuggerAISystem:FillMapJob but that type was not assigned to the Dependency property. To ensure correct behavior of other systems, the job or a dependency must be assigned to the Dependency property before returning from the OnUpdate method. UnityEngine.Debug:LogError (object)

#
            var entityHandle = GetEntityTypeHandle();
            _ltwHandle.Update(this);
            _starHandle.Update(this);

            // First we gather data of potential targets
            var map = _hashMap;
            var chunks = _targetQuery.CreateArchetypeChunkArrayAsync(Allocator.TempJob, out var handle);
            Dependency = new FillMapJob
            {
                chunks = chunks,
                map = map,
                entityHandle = entityHandle,
                ltwHandle = _ltwHandle,
                starHandle = _starHandle
            }.Schedule(JobHandle.CombineDependencies(handle, Dependency));

I don't get it

#

what's wrong

rustic rain
#

uugh, I couldn't figure what's wrong

#

but apparently

#

mixing ForEach codegen and EntityBatch

#

is causing dependency problems

#

welp, this is way better

#

from 30 fps to 120

#

meanwhile FixedStep is running 120 iterations

#

per second

rustic rain
#

ah crap, nvm all above. Turns out my job just didn't work correctly

rustic rain
#

bruh, I hate automatic Dependency handling through codegen

#

Can I assign dependencies myself?

rotund token
#

you are already assigning them yourself (in the above code)

#

the only dependency thing that code gen does is add the Dependency
Job.WithCode(() => {}).Schedule();
Dependency = Job.WithCode(() => {}).Schedule(Dependency);

rustic rain
#

yeah

#

but it screams at me for not setting up dependencies

rotund token
#

that's because you've broken something

rustic rain
#
  protected override void OnUpdate()
        {
            var buffer = _bufferSystem.CreateCommandBuffer();

            var entityHandle = GetEntityTypeHandle();
            _ltwHandle.Update(this);
            _starHandle.Update(this);
            _actionWeightHandleRw.Update(this);
            _actionWeightHandleRo.Update(this);

            // First we gather data of potential targets
            var map = _hashMap;
            var chunks = _targetQuery.CreateArchetypeChunkArrayAsync(Allocator.TempJob, out var handle);
            Dependency = new FillMapJob
            {
                chunks = chunks,
                map = map,
                entityHandle = entityHandle,
                ltwHandle = _ltwHandle,
                starHandle = _starHandle
            }.Schedule(JobHandle.CombineDependencies(handle, Dependency));


            //Then we set weights to those who look for job
            Dependency = new FindTargetJob
            {
                map = map,
                // entityHandle = entityHandle,
                starHandle = _starHandle,
                ltwHandle = _ltwHandle,
                actionWeightHandle = _actionWeightHandleRw
            }.ScheduleParallel(_setWeightsQuery, Dependency);

            // Now we assign target to those who want it

            if (!_assignTargetQuery.IsEmpty)
            {
                _cacheHandle.Update(this);

                Dependency = new AssignTargetJob
                {
                    entityHandle = entityHandle, cacheHandle = _cacheHandle, buffer = buffer.AsParallelWriter(),
                }.ScheduleParallel(_assignTargetQuery, Dependency);

                buffer.RemoveComponentForEntityQuery<DoWorkTag>(_assignTargetQuery);
            }

            _bufferSystem.AddJobHandleForProducer(Dependency);
        }
#

here full code of system

#

The system SpaceTycoon.Runtime.AI.HuggerAISystem reads Unity.Transforms.LocalToWorld via HuggerAISystem:FillMapJob but that type was not assigned to the Dependency property. To ensure correct behavior of other systems, the job or a dependency must be assigned to the Dependency property before returning from the OnUpdate method.
UnityEngine.Debug:LogError (object)

rotund token
#

buffer.RemoveComponentForEntityQuery<DoWorkTag>(_assignTargetQuery);

#

is not allowed

#

i dont think

rustic rain
#

why not?

rotund token
#

because _assignTargetQuery

#

does not have your dependencies from the previous systems

#

try do
_assignTargetQuery.AddDependency(Dependency)

#

before it

#

or do it before teh job

#

remember, automatic dependency management is only between systems

rustic rain
#
            if (!_assignTargetQuery.IsEmpty)
            {
                _cacheHandle.Update(this);

                Dependency = new AssignTargetJob
                {
                    entityHandle = entityHandle, cacheHandle = _cacheHandle, buffer = buffer.AsParallelWriter(),
                }.ScheduleParallel(_assignTargetQuery, Dependency);

                _assignTargetQuery.AddDependency(Dependency);
                buffer.RemoveComponentForEntityQuery<DoWorkTag>(_assignTargetQuery);
            }

Like this?

rotund token
#

dependency management within OnUpdate is ALWAYS managed by you

#

there is no dependency management done for you

rustic rain
#

anyways, it's not erroring about AssignTargetJob

#

it errors about previous jobs

rotund token
#

is there a second error in unity

rustic rain
#

The system SpaceTycoon.Runtime.AI.HuggerAISystem reads Unity.Transforms.LocalToWorld via HuggerAISystem:FindTargetJob but that type was not assigned to the Dependency property. To ensure correct behavior of other systems, the job or a dependency must be assigned to the Dependency property before returning from the OnUpdate method.
UnityEngine.Debug:LogError (object)

rotund token
#

that comes after this

rustic rain
#

no

#

only this

rotund token
#

oh

#
            {
                _cacheHandle.Update(this);

                Dependency = new AssignTargetJob
                {
                    entityHandle = entityHandle, cacheHandle = _cacheHandle, buffer = buffer.AsParallelWriter(),
                }.ScheduleParallel(_assignTargetQuery, Dependency);

                buffer.RemoveComponentForEntityQuery<DoWorkTag>(_assignTargetQuery);
            }```
#

can you comment this entire thing out

#

just for my sake of testing something

rustic rain
#

I guess

#

let's see

#

yep

#

no errors

rotund token
#

if (!_assignTargetQuery.IsEmpty)

#

is your problem

#

remember how i said change filters cause sync points

rustic rain
#

oh

#

ok

#

that's fine I guess

rotund token
#

its triggering a sync point there but it doesn't have your Dependency of the new jobs that should be part of it

rustic rain
#

I removed query check

rotund token
#

hmm

#

i thought
_assignTargetQuery.AddDependency(Dependency);

#

would have saved you

rustic rain
#

I do have it, though

rotund token
#

buffer.RemoveComponentForEntityQuery<DoWorkTag>(_assignTargetQuery);
now makes a copy of all entities on the spot

rustic rain
#

huh

#

I guess I'll make my own Query ecb, for this kek

#

but still

#

that doesn't explain

#

what's wrong with dependencies

#

I'll try to remove it

#

to check

rotund token
#

all RemoveComponentForEntityQuery does

#

is ToEntityArray

#

and write them all to the buffer

rustic rain
#

ok

#

now I see

#

it is indeed

#

causing sync point

#

somehow

rotund token
#

well ToEntityArray is a sync point

remote crater
#

Where is the new Entity list tool? all I see is Entity Debugger, but I can't search it by name

#

Stuff is getting fun, patches out in my game 1-2 times a week gonna keep increasing. I'm adding asteroid shooting(actually breaks into many) and selling of the components.

remote crater
rustic rain
remote crater
#

wow

#

mine is up higher

#

Thank you. I didn't see it. Got moved around.

#

This is very helpful. Thank you Issue for solving my issue.

rustic rain
#

Hmmm

#

I wonder how I can implement such mechanic:

#

After searching entity has found it's target entity it applies special tag to it, making target invisible to all other searching entities

#

kind of busy indicator

#

by itself it's not hard, but here's the hard part:
What if searching entity gets destroyed during it's job

#

and now that tag left unhandled

viral sonnet
#

via a hashset

rustic rain
#

that's the way to store data

#

but what about handling it

#

in OOP that would OnJobFinish callback

viral sonnet
#

if you need any kind of unique tagging a hashset is best as datatype

rustic rain
#

which is obviously not an option

#

yeah, I get it

#

but I simply don't get

#

how to even handle that kind of thing

viral sonnet
#

hm, it could be broken down to 2 hashmaps. gives you more options to do whatever. first is hashmap of key: searching entity value: found entity then a hashset of found entities so they are blocked for other searching entities

#

in case a searching entity gets destroyed, lookup the value, remove from hashset

rustic rain
#

thing is

#

I am kind of looking forward having this kind of mechanic for a lot of searching queries

#

since it's AI simulation

#

so that would require blocking search through several systems, that potentially don't know about each other

#

so that's why I'd want to have it through component

#

but how to handle releasing of entities from it is a question

amber flicker
#

would recommend having a single place where you destroy entities - e.g. at the end of frame

#

if they need to be 'dead' or unprocessed by systems before end of frame then either a tag, associated entry in an array/nhm etc or a bool flipped on a tag that already exists on the entity that the systems check against. They all have trade-offs.

viral sonnet
rustic rain
viral sonnet
#

remember the native container is just a pointer

#

you can share it between systems in several ways

rustic rain
#

for example AI is looking for free slot in some station. It found it, it blocks it.
How for example would some totally other AI figure whether station is free or not, if it's not called by same AI system

#

yeah...

#

and this is where OOP comes in

#

and ruins fun

#

hmmm

viral sonnet
#

why is that oop?

rustic rain
#

maybe I can keep singleton entity with blob

rotund token
#

have you considered inverting your logic?

rustic rain
#

could you elaborate?

rotund token
#

you don't find targets, targets find things to target them

rustic rain
#

nah, that's not an option

rotund token
#

an empty station finds an entity to fill it

rustic rain
#

it's about entities in space, living life

viral sonnet
#

yep, that's also always good to think about

rustic rain
#

meaning one spaceship might have hundreds of different things to do

rotund token
#

so?

#

how does that change anything

viral sonnet
#

how do you find out what can be targeted? via range check? sphere cast?

rustic rain
#

I have a lot of star systems

#

between which entites can travel only through special warp jump or smth (haven't really thought of lore part kek)

#

meanwhile they all exist in same world space

#

so all entities that exist in it have special component

#

with ID of current system

#

and while doing any algorithm on AI

viral sonnet
#

that's all fine but doesn't answer my question πŸ™‚

rustic rain
#

I just make a hashmap of ID/potential targets with data

#

which later than used for all AI finders

rustic rain
rotund token
#

you don't need to share the hashmap between systems btw

#

you just need it to validate writing data is safe

viral sonnet
#

ok, you can possibly invert the logic. doesn't really matter from where the range check is started, right?

rustic rain
#

I don't want to invert logic though...

#

that doesn't work with the way AI is written

viral sonnet
#

just saying, to think about it. it's possible to dig quite a deep hole and then being stuck

rustic rain
#

but it's simply not smth that will work the way it's all organized

rotund token
#
            {
                if (alreadyTargetted.Add(entity))
                {
                    isTargetted[entity] = new IsTargeted { Value = true };
                    break;
                }
            }```

```            NativeParallelHashSet<Entity>.ParallelWriter alreadyTargetted;
            NativeArray<Entity> potentialTargets;
            ComponentDataFromEntity<IsTargeted> isTargetted;```

it's never going to be amazing but this does work if you need unique targeting in a parallel job
rustic rain
#

hmm

#

That seems to make sense btw, I just need to figure a good pattern of how to access it

#

between systems

rotund token
#

you dont need to access it between systems

#

in the next system Value = true will have already been set

#

the only problem is doing this in parallel because 2 things could target the same thing in the same frame

#

another easy solution is simply just creating a single queue of all operation requests

#

and just resolve it linearly after everything has written to it

#

if AI fails because something beat it, so what

#

it waits 1 frame to find something else

#

(this isnt going to scale to 6 figures of entities)

viral sonnet
#

i'd just share the alreadyTargetted hashset. why write the data back to ecs. it's essentially just overhead - temporary processing data

rustic rain
#

wait a second

#

I forgot the main problem with that

#

it's when whoever blocked target entity

#

might be gone, poof

#

and block is not released

viral sonnet
#

that's why i suggested the additional hashmap

rustic rain
#

Target,Blocked

viral sonnet
#

key: searching entity value: targeted entity

rotund token
#

personally i just make things clean up after themselves

rustic rain
#

that's a callback, basically

rotund token
#

well my effect system for example

    {
        // If true will run the destroy routine on this attribute next Initialization
        public bool Value;
    }```
#

i dont destroy entities, i just write to a component

#

and change filters trigger

rustic rain
#

hmm

rotund token
#

then the effect is responsible for cleaning up any references it's setup etc

#

before it destroys itself

#

also avoids having issues being destroyed from multiple places on the same frame

#

and crashing

#

that's always a fun one

#

i basically have a fix life cycle management of every entity in my project

#

can only be created and destroyed from 1 specific spot

#

(different entity types will be in different spots depending on their requirements)

viral sonnet
#

that's good design

rotund token
#

but i've spent 2.5 years at work fixing crashes in production code related to ECB errors

#

and i never want to do this in my own project

viral sonnet
#

unity recommends systemstate for removal and it's garbage because essentially significant data can be lost which you would need to save in the systemstate or in the worst case, even keep updating

#

so i've also went into destroy comps

rustic rain
#

it's not really about actually destroying entitiy though

#

it's about when AI for some reason instantly changes it's current task

#

for example, some ship was doing smth

#

and then suddenly it got attacked

#

and obviously that means it has to instantly react and change it's current task

#

while cleaning up whatever is related to it's previous task

viral sonnet
#

but that's more like a task queue?

#

you were talking about searching entities that get destroyed

#

and the target to be released

rustic rain
#

I do have task queue already though, kek

viral sonnet
#

anyway, on that note. be careful - what happens when a ship gets attacked, switch targets and then gets attacked by another. it switches targets again?

rustic rain
#

cause rn, AI looks for task only if it has no task

remote crater
rustic rain
#

which is QueuedAction buffer

#

I just need to figure out a way to have cleaning up callbacks I guess

errant hawk
#

oh crap lets gooo

rustic rain
errant hawk
rustic rain
#

link?

errant hawk
#

very bottom is the DOTS message

devout prairie
#

seems positive, nice

rustic rain
#

Is there a way to have EntityQuery with conditional exclusion?

#
GetEntityQuery(ComponentType.Exclude<QueuedAction>(),
                ComponentType.ReadOnly<ActionWeight>(),
                ComponentType.ReadWrite<AICache>());

Currently I have this query

haughty rampart
#

No. Optional components should be passed as componenttypehandles

rustic rain
#

Meanwhile QueuedAction might exist, only if there's also some TriggerComponent

rustic rain
haughty rampart
#

Possibly? Though not the recommended way

rustic rain
#

I guess, I better just schedule 2 jobs

#
            _findTaskQuery = GetEntityQuery(
                new EntityQueryDesc
                {
                    None = new[] { ComponentType.ReadOnly<QueuedAction>() },
                    All = new[] { ComponentType.ReadWrite<AICache>(), ComponentType.ReadOnly<ActionWeight>() }
                },
                new EntityQueryDesc
                {
                    All = new[]
                    {
                        ComponentType.ReadWrite<AICache>(),
                        ComponentType.ReadOnly<ActionWeight>(),
                        ComponentType.ReadOnly<FindTaskTag>()
                    }
                });

This approach game me weird and wrong result

rustic rain
#

Can I somehow check whether EntityQuery has changed since last update?
GetCombinedComponentOrderVersion

#

will that one do?

safe lintel
#

WithChangeFilter?

rustic rain
#

I can't do ForEach

haughty rampart
rustic rain
#

because I need chunk specific logic

#

basically

haughty rampart
#

you can do that in ForEach()

rustic rain
#

Because it's literally done through IJob

#

kek

safe lintel
rustic rain
#

oh

#

it does have change filter

#

hmm

#

how do I apply it

haughty rampart
#

.SetChangedFilterVersion()

rustic rain
#

ah, I didn't scroll low enough

#

hmmm

#

that's actually not what I want tbh

#

I need to know whether query changed

#

added/removed entities

#

I don't care for their components itself

#

tbh

safe lintel
#

CalculateEntityCount ?

rustic rain
#

it might be added 2, removed 2

safe lintel
#

well store the previous number in the system or go crazy and store it in another component on a different archetype

rustic rain
#

but count doesn't solve it

#

count might be same for different queries

#

hmm

haughty rampart
#

well then track it yourself. keep track of the Entity themselves

#

i doubt unity is doing any ultra fancy tracking on them like you want to

rustic rain
#

I figured

#

I can do it by checking all chunks

#

hmmm

#

but it only works with component type handles

#

oh

#

nvm

#

there's a check for structural changes

#

all right, that works

#

hmmm

#

I assume

#

chunk will only contain entities with same shared component?

#

In other words: can chunk contain entities with 2 different shared components?

haughty rampart
rustic rain
haughty rampart
rustic rain
#

but, you answered yes, kek

#

I meant 2 different versions of same T of shared component

solemn hollow
#

is there some easy to work with function like Transform.RotateAround for entities?

rustic rain
#

allthough...

haughty rampart
rustic rain
#

I solved rotate around by literally creating child and parent matrix4x4

#

and then just multiplying

haughty rampart
#

^^

rustic rain
#

in your case, you can get parent's (entity you want to rotate around) LTW matrix

#

and rotate it how you want

#

and then multiply with LocalToParent matrix of how you want your entity to be rotated around

eager pawn
#

could i make a system set component data by reading data from another object, like i was thinking of replacing my database with value objects if that makes sense?

haughty rampart
#

could probably. does it make sense? questionable.

eager pawn
#

public class person { public int id {get; private set; } = 1;

#

or something like that

#

well the data is static and doesn't change

#

it's game obj data

haughty rampart
#

why not simply have an array then?

eager pawn
#

hm wouldn't that be messy when i have arrays of objects with arrays of objects etc

solemn hollow
haughty rampart
rustic rain
#

you make them yourself

#

you need LTW of parent

#

and LTP of child

#

LTP would be offset position to parent

haughty rampart
solemn hollow
#

ah damn

rustic rain
#

you can get best idea of what I mean

#

by playing with GOs in editor

#

just drop 2 random cubes somewhere in space

#

and assign 1 to other as child

#

and watch how position/rotation/scale is changed

#

this is how you'll get your LTP matrix

#

and then you just need to rotate LTW of parent

#

and multiply with that LTP

#

and you'll get LTW of child with that rotation applied

solemn hollow
#

yes its easy to get relative coordinates to other entities. the second step im not so sure about

rustic rain
#

what's great is that since it's matrix multiplication: everything is figured for you

#

scale/rotation/position

solemn hollow
#

ill try!

haughty rampart
#

goddamnit. no fun memes allowed

rustic rain
#

no fun here

#

Dancing is forbidden

haughty rampart
#

nooooooooooooooooo

eager pawn
#

or would this be some kinda anti-pattern i hope not

rustic rain
#

can you elaborate, what kind of type of data you want

haughty rampart
#

you can read from them no problem

viral sonnet
rustic rain
viral sonnet
#

especially orderchange is nice because it keeps track of structural changes

rustic rain
#

this how I'll basically can see whether data is invalidated

#

and I need to recreate my hash lookup

viral sonnet
#

but seriously, start investing into proper change filters. it'll make sooo much easier

rustic rain
#

for potential targets

viral sonnet
#

and don't rely on add/remove comps

haughty rampart
#

+1

rustic rain
#

well, filters require components

#

and I only have entities, kek

#

that match query

#

that's all I care about

eager pawn
viral sonnet
#

add a small state comp and bump the version accordinly

viral sonnet
#

i don't know if versions exist on empty comps/tags. i don't think they do

rustic rain
#

I simply store int,Entity hash

eager pawn
rustic rain
#

and each time query changed, I'd need to recreate it

#

that's about it

haughty rampart
rustic rain
#

components don't affect it

#

only matching query

eager pawn
#

using a db would be faster than using code generation that creates dots compatible c# data?

viral sonnet
#

oh i see you're still on the hashmap πŸ™‚ so the hashmap is not frame based?

eager pawn
#

(im noob so i don't know how to do optimization and stuff besides caching ig)

haughty rampart
haughty rampart
#

:/

rustic rain
#

this exact one does, but future ones won't

#

for example when it would be related to static entities

viral sonnet
#

if you can keep track of the entities and keep a previous array you could do a fast memcmp to detect changes

rustic rain
#

I wouldn't want to keep previous array

#

but I can store chunk, version map

#

which would probably be way cheaper

#

in cost of memory

viral sonnet
#

you'd need a lot of entities to really matter

rustic rain
#

well, there are thousands

#

kek

viral sonnet
#

thousands is like nothing πŸ™‚

rustic rain
#

it's for AI simulation of whole galaxy, kek

viral sonnet
#

an entity struct has 8 bytes. so even with 10k you are just looking at 80k bytes

rustic rain
#

meaning you lose l1 cpu cache potential

#

hmmmm, I am currently looking into way to have cleanup for my AI system, which is based of action queues (go to point, do action X, idle for 300 ticks and etc)

#

so that some actions could potentially reserve certain entities

#

making them for other AIs

#

rn if some AI is assigned to some task, for example: go and hug X entity.
in OOP I'd just assign reserved tag to X entity and remove it through callback once hug action is finished

#

but since there's no callbacks in ECS

#

I need some other solution

eager pawn
# haughty rampart i don't know how much data you have, but if you put it all as entities it will e...

instead of making those systems read from something, i could use code generation to create a system and set the data immediately. what i dislike about this is that the hard-code approach wouldnt be modular. since i already did 35% of my db tables i think ill just keep it as my storage location, mostly due to bias and ease of use, and it appears from what you're saying that databases are probably more optimized for this anyway

gusty comet
#

Some of my code uses World.AllWorlds in a for loop, but that is now an internal variable - how do I retrieve all worlds?

haughty rampart
eager pawn
#

would it be faster?

haughty rampart
rustic rain
eager pawn
#

assuming im not gonna write the most optimized stuff

gusty comet
eager pawn
#

it's a one time thing btw. the data is created once and then you don't have to do anything but read from it

haughty rampart
# eager pawn would it be faster?

well, since it doesn't have to read from database at startup and has all the data available already....probably? slightly.
but if you ever want to change it you WILL have to recompile your game

gusty comet
#

like foreach(var world in World.AllWorlds) { var network = world.GetExistingSystem<NetworkStreamReceiveSystem>(); if(world.GetExistingSystem<ClientSimulationSystemGroup>() != null) etc

eager pawn
#

okay thank you @haughty rampart (: that helps me and i feel more confident in just using a db now

viral sonnet
#

i'll just say this on databases: database data are not a good fit for ecs mainly because you generate a lot of archetypes with chunks that potentially are mostly empty. then, database data is most likely not read in a linear fashion in game code. it's mostly, read this row, read that row. as entities is SoA, there is zero benefit from cache lines reading 64 bytes as you're reading the next value of other table rows essentially. what's really good for database data are blobs. they are linear in memory, easy to read single entries fast, and can build pretty much any data except pointer data. they are not that good for relational data but when built at runtime, even relational data i.e entity references work. building at runtime is really fast. they are easy to store on an entity because they are just a pointer and easily mappable via a hashmap and a key for fast lookups.

mystic mountain
#

When designing systems would you consider optimizing for chunk utilization over avoiding random accesses(GetComponentDataFromEntity)?

rustic rain
#

ofc

#

why would you access data randomly if you can access it through chunks

mystic mountain
#

I mean you either [create more different chunks] or [have less different chunks, but you access some additional data through GetComponentDataFromEntity]?

rustic rain
#

whenever you can you utilize chunks, whenever you can't you use random access

#

it's that simple

#

chunks iteration is the fastest out of all options

#

random access is for cases when chunks are just not an option

#

for example when you need to some data by Entity reference

solemn hollow
mystic mountain
#

Hmm, I don't think you get my question completely. I'm designing some system. I can either have a combination of Logical Triggering data on a single Entity of A,B,C,D,E (which could anything from [A,B] [D,E] [A,B,E] etc, thus utlizing chunks badly). Or I can move the Triggering data into their own entities, but doing so adds requirement of using GetComponentDataFromEntity when doing the logic.

mystic mountain
#

Components

rustic rain
#

if you have single Entity you are not utilizing chunks though

mystic mountain
#

There can be multiple entities of the combinations, which includes some that can be same combination.

viral sonnet
#

CDFE is never that great but it's also fast enough. unless you are simd'ing your code don't worry about that stuff too much. just make archetypes as small as they can be and stay away from structural changes or entities that only live for 1 frame. in scalar code, the amount of read/writes is what's crucial (throughput), not really in which memory location it is. without simd you'll have L1 cache misses left and right. the good thing about it is that there's a high chance the data you need is still in some cache (L2/3)

solemn hollow
#

honestly i wouldnt worry about bad chunk utilization here. either you have alot of entities which means your chunks are full anyway or you have a small amount of diffrent combinations of entities and dont hit cache but also you dont have much work to do anyways.

mystic mountain
#

Thank you : )

solemn hollow
#

if you have huge entities where for example only 2 can fit in a chunk that is where id worry about chunk utilization. cause that would mean alot of cache misses while iterating over chunks in any system.

viral sonnet
#

when scalar you will have a cache miss on every new comp you read from the chunk unless the cpu prefetches, which has a low chance of happening because scalar

#

i brought this problem up once in the forum but AoS has a near 0 chance if being implemented

solemn hollow
#

guess i need to check out some talks again to get it right

solemn hollow
viral sonnet
#

1 comp read turns into 1 cache line of 64 bytes that read compA of entity1/2/3/4/5 ... until 64 bytes are read. perfect for simd. not that great for scalar, especially when the archetype is quite big.

#

after you've read every comp chances are quite high that on the next iteration you'll have a cache hit though.

#

but the cache hits are still not linear

#

the rest is really up to cpu implementation and this is where it gets really hard to predict anything

#

on that note. i had ideas where i have a stage where i read a whole chunk linear and then the rest of the code πŸ˜„

#

most caches are 32k data and 16k chunk leaves me enough room with other data to do what i want and still have cache hits

#

but i've never tested this. still on my mind

#

with the job scheduler there's a good chance the l1 thread cache belongs only to you. the other caches are shared so once you're in L2 land, chances are quite high you never have a hit because you're not on a console and kther processes push out your data

#

there's a really good talk about concurrency. i'll post the link then here

rotund token
#

L2 on modern gen is still per core on amd

solemn hollow
#

i really need to check out the DOTS best practices guide now. havent gotten to it yet. maybe i have a few other misconceptions i can get rid of

viral sonnet
#

its theory. last time i merged comps into a 64 byte comp i got a huge performance loss.

#

pretty entertaining too

rotund token
#

Think you're over thinking this. If your concerned about it not being prefetched, Unity.Burst.Intrinsics.Common.Prefetch you can do it yourself but I'm pretty sure the compiler has you sorted for native containers

viral sonnet
#

probably. i just want my theory to be correct, otherwise it leads to wrong assumptions

#

I'll try the prefetch. do you know more about or have tried it?

lavish wharf
#

Hello, I'm rather new to unity and especially dots. I was wondering if dots and the ecs infrastructure is currently production ready or if I should be waiting for an official finished release.

rotund token
#

Burst and jobs is considered production ready but entities is not yet by unity

#

That being said there have been multiple games released using entities

lavish wharf
#

alright thanks, I'll check out the pinned messages, seems to cover a lot

rotund token
safe lintel
#

@lavish wharf dots currently doesnt include native animation, pathfinding or audio and 1.0(ie "production ready" in unity's terms) wont either. unknown when those things will have dots native equivalents

viral sonnet
#

on my blob that is reused over and over again it changed absolutely nothing. pretty sure the cpu figures it out

#

it mostly works as expected. the hardware knows best :) my concern above wasn't really the lack of prefetching but that prefetching can't be applied well when the data layout and code isn't suited for it. just putting data in chunks isn't good enough

rotund token
#

just putting data in chunks isn't good enough
I guess i just don't understand this bit

#

if i turned off auto vectorization and just let it run scalar i would expect no difference (except being ~4x slower)

viral sonnet
#

as i said, possibly i overthink l1 and cache misses. the thing about auto vec or turned off. the data is already near perfect to even run in scalar with no cache misses. so that use case guves the expected 4x difference.

#

I'm mostly refering to data that isnt laid out that nice or has very complex code compared to what usually runs in a simd loop. lots of branching, bad locality

rotund token
#

yep sure

#

funny enough though, that's what my AI system does and it runs magnitudes faster than our nicely laid out data implementation at work

viral sonnet
#

achieving better locality is key here otherwise the l1 cache looks like a fragmented mess

#

huh, any idea why that is?

rotund token
#

because my entire ai is 1 job instead of dozens and i can early out

#

it was designed around near perfect thread scaling

viral sonnet
#

yeah, the job scheduling overhead is significant

#

not just running the job but everything up to that point

#

anyway, your ai system could run even faster πŸ˜„ i'm not saying it's possible to achieve. i'm pretty stuck since months on one of my jobs. ^^

#

it would need a redesign but i also can't find any other way to do the same things but faster. i've reached some kind of equilibrium with it, yet, i'm still looking for improvements like a mad man πŸ˜„

rotund token
#

i'm not sure my ai could run faster with it's design tbh

#

i think it hit its limit for what this design could do

viral sonnet
#

that's also my humble conclusion. every improvement would mean a heavy cut in the game design and that's not something that can change

rotund token
#

biggest benefit of my AI is i can do partial updates