#archived-dots
1 messages ยท Page 281 of 1
i stay away from generalization if i can. but if i want complete freedom for my designer i often have to use generic stuff
but I wonder about performance of such solution
performance is the same
I think dots is associated with jobs so ill post this here :
So I am working on a script to cut objects, It worked fine but the program doesnt handle high poly meshes well. So i started to try parallel jobs with burst.
Now the problem is that each time I add a triangle or vertex I must check if they already exist in the upper or lower half array. This is so that i dont add it and I find its corresponding index for the index list.
Now each thread is independent of the other, and will be adding to their own lists.
How on earth do I now make a mesh whilst being unable to have each thread read and effect the same data?
I think dots is associated with jobs so ill post this here : it is, Jobs are considered a part of DOTS
Ty โค๏ธ
if you really want full parrellelism you could maybe generate multiple submeshes. one on each thread and stich them together?
and to answer your question, there is "new" MeshAPI that allows you to work in parallel on the mesh
nice
https://catlikecoding.com/unity/tutorials/procedural-meshes/ - here is tutorial on this
โค๏ธ catlikecoding
yeah, he has good tutorial, I was learning SRP from there way back when it was a new thing ๐
I was thinking the same thing. Let each thread create a submesh and then use merge meshes, Ill then have to re do my inner slice method somehow by tagging the generated lip verts to render the unnder slice
Many thanks ill check it out now โค๏ธ
anyone got some whacky physics behaviour when game is started with subscenes in edit mode? my raycasts dont hit anything then. if i dont have them in edit mode everything works fine.
I have a script that stops me entering play mode if any sub scene is open
Because netcode just explodes
but shouldnt it just run through conversion then? whats the thing that can go wrong here?
is the old not newly converted subscene used instead?
Do you have live conversion on?
yes
authoring state in scene view
and its inconsistent.. now i restarted unity and everything is fine again.
should I watch on something to get my generalised jobs be busted in a good way?
its rather embarrassing to admit but i wasted the complete day just figuring out some basic raycasting...
burst tells you when its not happy. if you dont call the jobs with concrete types directly you need to register them in the assembly
can I somehow get data lenght from within IJobParallelFor or should I make a field for that?
do you mean for looping or do you need it for sth else?
btw you should use IJobFor.ScheduleParallel()
IJobParallelFor is obsolete?
yes thats the old version
for something else
then i think you need to pass it
ok thanks
can i share a list/array between threads in unity jobs ?
or must they be completely independent
latter one
well technically you can share with [DisableNativeParallelForRestriction]. but then youd need to make sure to not produce raceconditions
you can always have [ReadOnly] that is shared, writing is problematic
So with my code, i only need to add to the end of a list, i dont need to insert anywhere else.
would this be problematic.
(need to add a vert array, but cant have any dupes)
Im so sorry for all these questions, not much time left and havent ever touched jobs
you can use NativeList.ParallelWriter for that afaik
I haven't deved anything unity in a couple years. That being said...
- Is it any easier to animate entities?
- Is there a DOTS-capable SkinnedMeshRenderer or something similar?
but it wouldn't be sorted
No need for it to be sorted, aslong as I can find indecies and add to the end of it
there is Latios framework which have animations now
Thank you so muuch for the suggestion, ill look into it now
thanks
I also remember a while back it mattered if you used the alpha/beta version of unity for anything related to DOTS - is that still the case?
https://forum.unity.com/threads/experimental-entities-0-51-is-available.1281233/ here is the current status of DOTS
well version matters yes but you dont need alpha/beta anymore
- Unity 2021.3.4+
- Unity 2020.3.30+```
So I see that nativelist.parallelwriter uses the unsafelist, but the unsafelist then also has a unsafelist.parallelwriter.
What is the difference between them ?
I also noted that these lists cant/dont seem to be able to be resized.
I have no idea how large these lists are as I could need to store a pinky upto a whole body of verts
Then use best thing ever I found: NativeStream
I use it everywhere I don't know lenght of the data
ty again
i started learning ECS so I could have about 300+ enemies in a horde sort of game, but after looking into it i'm getting comparable fps with just normal gameobjects, when it comes to around 300 units does it make a difference what you use or have I perhaps just done something wrong
id say 300 is enough to see benefits. especially if everything is bursted
it depends on many variables, your enemies could be just light overall
and moving your code to ECS doesn't change much
oh right okay, i haven't tried that burst compiler thing yet
and do you go wide with your jobs? like 300AIs in parallel should be quite a lot more performant than the GameObject implementation
i dont really know what that means to go wide or parallel, i have just tested 300 basic AI enemies
yeah, so it seems you just moved your code to ECS without rewriting it to be parallel
that's why you don't see any improvements in performance
ah right okay i will research this more tomorrow thanks
What's the bottleneck? Rendering or actually moving / pathfinding those enemies?
If it's rendering, hybrid isnt in a good state right now but in the future (2022 LTS probably), the new hybrid rendering system promises a lot, and delivers quite a bit even now in alpha.
is there any build-in sort for NativeArray?
Yep. NativeArray().Sort()
It's not the best due to it's flexability
but it works for all sorts of cases, heh
can I use it inside a job?
anyone know off the top of their heads if possible and how to invoke an unmanaged function pointer within burst?
i thought i could use Marshal.GetDelegateForFunctionPointer
but burst isn't liking it
ok it's because it's returning a struct
There's a job and non-job variant of the sort. Just use the one that doesnt require dependency in the parameters
what are you implementing with it?
u sure you need that right now?^^ is it that performance critical? 1.0 hopefully has support for it. until then i wont need that performance
how would it? ECBS is a managed class
you can't use managed code in ISystem
i mean, for 15min work sure?
hm k. why did unity not do it then :S
because the way i'm doing it is gross
that said, i'm not certain 1.0 will even support it
unless they rewrite it as an ISystem
it cant be that hard to rewrite as an Isystem can it?
but ECB can be used within ISystem?
yes
it would lose all it's debugging
ok, then I misread previously
but you make a good point manarz, maybe i just write an ISystem version where I skip debugging
probably better than this memory hack i'm doing
pinning the buffer system
and creating pointers to the methods
and while you are at it look at DreamingImLatios optimizations for them
is ISystem a huge improvement in performance?
well all code in ISystem can be bursted.
most of my SystemBase systems are just scheduling so I don't see much to be improved
never mind
EntityCommandBuffer isn't unmanaged while ENABLE_UNITY_COLLECTIONS_CHECKS
bursting scheduling is the main benefit of ISystem. If you have a lot of scheduling and not that intensive of a job, then you want ISystem. Otherwise Systembase is more flexible for all ya needs.
so probably will never use it XD
also you need to call all the gethandles which are then bursted too right?
You can cache the handles on creation anyways.
yes but the handle.Update function still might be bursted. havent digged deep into the code though
honestly i expect like a 30% speedup. if not im disappointed ^^. since they said they want to get the overhead of systems so low that even with 1 entity its as fast as with 1 gameobject
It is, it's intended for use in ISystems. If you notice you can squeeze out a bit more performance, you can do that. Using ForEach code gens the caching of the handles at creation anyways.
i do have massive amounts of small generic systems. will be fun to update them. ill get alot of performance but im not sure i can do it without managed types
yeah, I don't know why no ECBs exists as ISystem. I think I'll just write one. It doesn't like like there's any showstoppers
Does Unity have any sort of unmanaged graph types?
the ISystems that I've converted and tested where sadly not much faster. What's great about it is that everythings bursted so a NativeContainer.Clear for example doesn't need to be scheduled then
Like UI graphs?
pretty much any code that interacts with NativeContainers sees huge improvements. Just getting component type handles and scheduling doesn't gain much
something that is serialized
and where I can put number between 0 and 1
and get value according to graph
having just looked at it, it's somewhat a pain
i just wrote the whole thing in 7 min
except i had to remove buffer support
oh cool! can you share? why are buffers not working?
the problem is safety doesn't work
i can't store command buffers in an unmanaged ISystem implementation
because command buffers have safety
(dispose sentinel etc)
ohhh snap
and if i turn off safety on the command buffer
then i can't create buffers because the constructor needs to be able to pass in safety info
while ENABLE_UNITY_COLLECTIONS_CHECKS is active in the editor
so yeah, this basically needs the collections update without dispose sentinels
i'm pretty sure you can confuse it with another safety struct
im using animationcurves for it
i probably could but at the stage of taking more than 10min i no longer have the effort
post what you have and i can take a stab at it
but that's managed
I need it inside of bursted code
somehow...
already deleted it
haha
literally just copy ecb into your own copy
and find&replace ENABLE_UNITY_COLLECTIONS_CHECKS with anything
you dont need the representation in burst right? you just need the curve
with nothing*
so just copy the keyframearray to a struct
with nothing will be a compile error
hmm i think i have a better way of doing this
cant you create a fake safety handle? Like the NullObject pattern?
no write is only once per index
bummer
yeah, haven't realized EntityCommandBuffer is also a NativeContainer. eh, not worth the effort haha
if ISystem is bursted can I schedule jobs from it?
yes
so can I schedule jobs from other jobs? ๐
are there other problems with Isystem right now or is it just the ECBS thing?
that has nothing to do with ISystem and no you cant
that wasn't the question ๐ sadly not, although I admit that would be quite useful sometimes
oh I get it... is ISystem bursted but not in parallel?
I didn't have any other problems
ISystem is the same as Systembase just not a class and thus can be bursted
ISystem is not a job. it's the equivalent of SystemBase but as struct and unmanaged memory which can be bursted
๐
EntityCommandBuffer has been weirdly implemented. so much setup and code is in the NativeContainer space.
if it was implemented better we could just use EntityCommandBufferData
is there a collection that allows that?
wait i've just realized you can't even create an ECB inside burst
i thought that was supported
i actually had this working apart from that minor detail >_>
maybe you could do sth like that in a MultiNativeHashMap? not sure if thats what you want
void ISystem.OnUpdate(ref SystemState state)
{
var test = new EntityCommandBuffer(Allocator.TempJob);```
this alone fails burst compiling
and its the creation only? ecb itself is unmanaged?
it's this pesky field atm
private static int ms_CommandBufferIDAllocator = 0;
can't use static non-readonly fields in burst
enzi is right about this
if it was implemented better we could just use EntityCommandBufferData
{
EntityCommandBufferData* data = ecb.m_Data;```
literally just does that but i'd have to rewrite chunks of this to make it not use ECB and just use EntityCommandBufferData
that i cbf with
but if you want to have a crack @viral sonnet here you go
just change UnsafeListPtr to an UnsafeList and fix up write backs
alternatively just need a re-usable ECB
thanks but we'd have to write much much more than just the ISystem
how would I create an entityQuery in a performance test? can I even use entities inside a performance test? ๐
this above works
it compiles fine
i think easiest approach would just to make it so ECB can be re-used
then you create it in OnCreate
ok cool! thanks then
yeah, enough reason ๐
@rotund token did you profile it? how much faster was it
ISystem over SystemBase?
it can be significant if you have a lot of queries and dependencies
i meant specifically your ecbs
i can't use it in a burst ISystem
because i can't create an ECB
and it does the exact same playback so i'd expect no different
ah sry i thought you had an ugly hack somehow with your functionpointers ^^
got it working
void ISystem.OnCreate(ref SystemState state)
{
var ecbs = state.WorldUnmanaged.GetExistingUnmanagedSystem<UnmanagedEntityCommandBufferSystem>();
this.commandBufferPtr = ecbs.Struct.CreateCommandBuffer(ref state);
}
[BurstCompile]
void ISystem.OnUpdate(ref SystemState state)
{
var buffer = UnsafeUtility.AsRef<EntityCommandBuffer>(this.commandBufferPtr);
buffer.CreateEntity();
var ecbs = state.WorldUnmanaged.GetExistingUnmanagedSystem<UnmanagedEntityCommandBufferSystem>();
ecbs.Struct.AddJobHandleForProducer(state.Dependency);
}```
basically do it the same way i do my event system 2.0
noice!
UnmanagedEntityCommandBufferSystem itself isn't burst compiled
but anything that uses it can be
now id like to have just one of those UnmanagedEntityCommandBufferSystems where i could get pointers to a new ecb which i could then playback at any other ECBS. more like a ECBProviderSystem than an ECBS itself
not sure if thats possible but then youd not have to have multiples of this system for every syncpoint
i only intend to implement one
i only ever use 2 max ecbs in a project (either endsimulation or beginpresentation and end initialization)
but i can live without end init as it's so rarely used
hm i need two. cause i always make changes in one and destroy in the other.
so i dont have to care whether or not i give the destroycommand in order
oh that's fair
but i won't be destroying anything in here
but yeah
copy paste
๐
managed to add all the ECB safety and logging back as well
think i'll leave it there
happy
nice!
(well not hard since the UnmanagedEntityCommandBufferSystems isn't burst compiled so it's just the same)
you post it to your repo?
ooh no fuck that xD
im afraid of importing too many things i dont know how to fix myself if an update breaks it ^^
thought that is a uninvasive upgrade ^^
im curious but unsure i would be equipped to understand a single thing ^^
if you google for VS bugs this is the default: Sorry, i can _not_ reproduce it. Yesterday, i wasn't able to get around that problem. Today, it just works.
the point of my core library is just to be added to any project
without modifying it at all
and just adding a bunch of extensions etc that you can use
yes but i somehow expect those extensions to be super lowlevel ๐
not really, very few of the outward facing extensions require low level knowledge and nearly nothing requires unsafe
List.AddNative
NativeArray.Set
Aabb.Shrink
AABB.Encapsulate
x100
well ill use it if that means i can get full support for Isystem already ๐
yeah i'm kind of torn on this UECBS
because the rule of this library was no systems
I don't get why Unity hasn't provided yet
sometimes I get the feel they have like 3 people on dots ...
it's not that they didn't have the time to get an unmanaged ecbs up and running
who says it's not done?
the entities we use was branched over 9 months again from their master
i say that, because when it would be already done, it's even worse ๐
but eh, I'll be whining at least till december and then we have 1.0 ๐
makes sense to not pack it into core library. but i thought the things i needed for it to run are in there
oh the only thing you need is UnsafeListPtr
which is just a ptr wrapper for usnafelist
can replace it and just write back
(basically nativelist without safety)
i see. but since i have 0 experience with pointers id prefer to get it from your core lib. at some point i need to learn it but atm there is so much else to do
it's unbelievable. i profile in VS. works fine 2 times, now I get "an error occured getting source file information" and there's literally just 1 post on the internet with it
maybe u need to use bing to find it ๐
good one, bing is not even able to find this one thread ๐
that's weird
i get 1 result on google and pages of results on bing
maybe i should switch
(that said, the bing results seem mostly unrelated >_>)
exactly ^^
dayum
why dis so expensive?
pointer to an IComp with blobAssetReference
Either this completely destroys locality or I dunno
Hmmm, so turns out I can put Graph data into blob
But how can I evaluate value from raw keys? hmm
All right, found some ready solution xD
how i do it is to not even use the keys. i set the keys only to have a visual representation of my curve in the editor. then i only write the parameters that i use to draw the curve to the blob. at runtime i evaluate the mathematical formula and dont interpolate between keyframes.
by creating the graph with the formula itself in the first place
so just function pointer with extra steps xD
I assume you just predefined curves?
MKBC are the parameters like dave mark uses them in IAUAI
i predefine curve types yes
and then whenever i change a value i create a new kayframearray based on that curvefunction just to display the curve in editor
but i dont need to use those keyframes at runtime
public struct ResponseCurveParameters
{
public ResponseCurveType curveType;
public float m;
public float k;
public float b;
public float c;
}```
thats all data i need
when you are dealing with a blob asset store thingy in a mono behaviour, do you need to dispose of it in onDisable()?
im tryna debug a few errors, which appear to have something to do with a blob thingy
blob asset reference, that was what it called it i think
yup here are the 2 main errors that kept popping up
you dispose it when you want to unload that memory chunk
oh ok, thanks!
aha, i appear to be getting errors that i have not enabled my mesh to be readable, how do i do this manually, and for later, how can i make this automatic in import settings (also where are they as i cannot find them)
i found a bunch of import settings, yay! But none of them are useful so far, the plot thickens!
aha i figured it out, there is no way to do it automatically, you have to manually move it to your asset, change a bunch of stuff, move it back to where you need it,
very painful proccess but oh well
did you create that mesh in code?
there's just a setting on mesh imports to enable read/write
That's what was causing inconsistent results in your custom hit Collector ?
yes
especially in combination with filtering collisions based on layers it got really buggy
where??? I have been searching and searching lol!
during my search i discovered an oddity with friction
and that is that 0 friction means no grip, meaning it acts the same as infinite friction, only it can be pushed by other objects
oh god, this Tween thingy drives me mad. I literally want to make it managed component xD
It was all fine until I realised I need to edit source generation algorithm to allow BlobAssetReference in generated code
they just dont use the apis that rely on codegen? write the job yourself
I wrote job myself
it's actually polymorph components
that need generation
and potentially I can make them myself, but I will certainly lose my mind completely if I try xD
I'd rather learn codegen
and fix it
is it possible to have some grip, while also having no friction?
grip is literally friction though
exactly the issue, it is super annoying, cause it means that spheres wont roll down slopes if they have no grip,
and my spheres need no friction for when they fly over ledges
but on hills they dont roll, no matter the steepness
this sounds weird. physically id expect an object that has 0 grip/friction to slide down the surface even if its a ball. if it had grip it would roll down
same, but it appears you need grip to be able to slide for some reason, so 0 friction acts like infinite friction, the only difference being that 0 friction can be pushed easilly!
im literally gonna have to write a script to make my spheres gain momentum in the direction of the hill downwards if they come into contact with my ramps!
cause they just sit there if i dont!
can you show the settings of the physics components?
hm cant spot anything.
same, perhaps ive underflowed somehow?
ive got to go to bed now, so imma mess around more with this in the morning, but thanks!
gn8
omg
[UpdateInGroup(typeof(SimulationSystemGroup), OrderFirst = true)]
[UpdateAfter(typeof(BeginSimulationEntityCommandBufferSystem))]
public class FixedStepSimulationSystemGroup : ComponentSystemGroup```
this OrderFirst effectively blocks you from updating your own systems before FixedStepSimGroup
Ignoring invalid [UpdateBefore(Unity.Entities.FixedStepSimulationSystemGroup)] attribute on ConsiderationUpdateGroup because OrderFirst/OrderLast has higher precedence.
so id need to flag my group as orderfirst = true too. which messes up other ordering...
main reason why i want to update before physics is because physics has some big gaps on worker threads and i can fill them with heavier work if i schedule expensive stuff before physics
my job scheduling got a lot worse in 2021. not sure why, there are big gaps and some threads are dormant for the last bit
same. but at the same time my jobs are performing better. so i figured thats why i have more gaps
Damn. Good to know, thanks for feedback.
And [UpdateBefore(typeof(BeginSimulationEntityCommandBufferSystem))] doesn't do the trick ?
that alone would be ignored. what you can do to solve it is this: [UpdateInGroup(typeof(SimulationSystemGroup), OrderFirst = true)] [UpdateAfter(typeof(BeginSimulationEntityCommandBufferSystem))] [UpdateBefore(typeof(FixedStepSimulationSystemGroup))] public class EarlySimulationUpdateGroup : ComponentSystemGroup { }
every system that needs to sort itself before a system marked with orderfirst in the same group needs the orderfirst too
I see. (I don't dots these days so couldn't try quickly myself)
And running your considerations in the init group is a no-no ?
yes because the begininitbuffersystem produces a syncpoint. so all my heavy jobs would be completed before fixedupdate. which defeats the purpose
yeah, oddly enough the overall time is the same to 2020.3
๐ฆ
can someone explain why i have spikes like this
does that WaitForPresentOnGFX only happen in editor and i can ignore that spike for now? I cannot build and test it atm....
ok I'm done, I'll just make animations managed xD
Is there a handle for managed components?
component type handle I mean
for chunk iteration
ManagedComponentAccessor
looks like this is the one
ah, I see
so you wanna use the animator now?
it's accessor
nah, I'll just create managed ECS Tweener
kek
with minimum amount of tweens I personally need
hmm you should be able to use getcomponenttypehandle with managed Icomponentdata
yeah, looks so
I actually wonder
what if I make managed component
which contains...
function pointers
xD
and then these function pointers are passed into Execute method of chunk
and get called bursted
Gfx.WaitForPresent: When the main thread is ready to start rendering the next frame, but the render thread has not finished waiting on the GPU to Present the frame. This might indicate that your game is GPU bound. Look at the Timeline view to see if the render thread is simultaneously spending time in Gfx.PresentFrame. If the render thread is still spending time in Camera.Render, your game is CPU bound and e.g. spending to much time sending draw calls/textures to the GPU.
From https://github.com/UnityCommunity/UnityLibrary/wiki/Profiler:-Overhead---Gfx.WaitForPresent-explained
yes i found that thread too but looking at my render thread its empty...
ah
that's vsync
but its off.
huh but yours a litle high
vsync should be WaitForTargetFPS though ?
i am CPU bound thats for sure.
I think you are right. I currently can't get vsync to work ๐
You could also be right, from a unity dev on the forums :
Disclaimer: I can't recall whether waiting for VSync will look like the first or the third example I shared. (Or a totally different example)
the third example he's talking about is a Gfx.WaitForPresentOnGfxThread case
enabling VSync just makes the spikes more consistent but they look the same for me
its also WaitForPresent. cant find WaitForTargetFps (but i might also be just blind)
Damn. Profiling is a nightmare ๐
Yeah, I also remember a mix of these. Not sure if it has to do with applying an Application.targetFrameRate or not
the odd thing is that it should be a straight line and not some sawtooth pattern
but maybe that really changed with the new srps
doesn't look right though
thats a frame before the spike
here the renderthread waits for the MainTHread. next frame the mainthread waits for the renderthread (which does nothing??)
And sry for another Profiler related question but what is up with all those fallback allocations? the thread about it i found says it comes from memory leaks. but i have leak detection enabled and do no unsafe lowlevel allocations without safety i might forget to clear.
if i remember correctly i just had 1 or 2 of those in Entites 0.17
is that size in kb?
it was off though. then i enabled it to check if i have any leaks. no leaks but still those FallbackAllocs without leakdetection
safety was on though. maybe i need to disable that
I am about to reduce the number of allocations i do in jobs considerably based on tertles suggestion to only allocate once per thread
this
but cannot get it to work yet. curious if that changes sth with the fallback allocations. maybe i just alloc too much
hmmm there was a leak which was not catched by leakdetection actually. 0.o
i did sth like that : ```var chunks = considerationQuery.CreateArchetypeChunkArray(Allocator.TempJob);
Dependency = new GenConsiderationJob
{
chunks = chunks,
}.ScheduleParallel(chunks.Length, 1, Dependency);
if (systemSettings.Value.actionSettings.Length > 0)
{
Dependency = new OutputBufferToDecisionJob<C>()
{
chunks = chunks,
}.ScheduleParallel(chunks.Length, 1, Dependency);
}```
and in the second job i used DeallocateOnJobCompletion on the chunks.
now before i added that if i had no leak but i would schedule a useless job.
after i added that if leakdetection didnt catch that i dont dispose the chunk array if the second job is not scheduled
the tempjob allocation?
yes
did we discuss this? that temp allocations don't need to be disposed?
i was getting a runtime error telling me its leaking though
i'm not sure anymore about tempjob. that shit is so unintuitive
i think it needs to be disposed if allocated on mainthread
in job you dont have to
ok then it's clear. i also dispose tempjobs usually
haven't used one in my project though so i wasn't sure
so then you have no leaks but still fallback allocations?
might allocate too much then for a single frame
Even if temp falls back out it does not need dispose
how much of an impact would a thread make in DOTS application?
I mean I know it will take the CPU time and all
but how it will behave, like will it steal working threads?
oh you mean like a default c# thread?
yeah of course it will "steal" some performance
hmm but will it stall unity's workers or other conflicts will be present?
it makes no difference for nativecontainers whether i pass them as ref or not right?
Reminder to initialize your Rotations.
I just spent 3 hours debugging an issue with physics raycasts not working on my terrain.
Found out it was because I had done EntityManager.AddComponent(entity, new Rotation()) instead of EntityManager.AddComponent(entity, new Rotation{Value = quaternion.identity}).
Everything else works (including collision), it's only physics collider raycasts that don't, and they fail silently. 
dots physics is ugh
@rotund token i am very confused RN. i did implement the sharing of a NativeHashMap instead of allocating one per entity. i defensivly allocated the Hashmap with a size of 1000. It got ALOT slower. like 10x slower on workers. So it seems in my case its better to allocate alot of very small and some bigger hashmaps instead of allocating one defensive one per thread. feels wrong TBH
the overall performance diffrence is :
less but big allocs -> 1ms Mainthread ; 2 ms on workers ;
more but small allocs -> 1ms Mainthread ; 1ms workers
several threads write to a nhm vs several threads write to several nhms?
no. 1 big hashmap per thread shared between entities vs 1 small hashmap per entity
but thinking about it now its maybe because the entitycount is not high enough to matter atm. i update about 25 AI Entities per frame in around 60 systems. only 10% of those systems need bigger hashmap allocs
the 1ms on mainthread is pretty huge. the 2ms are no wonder because nhm as parallelwriter isn't fast
are you allocating per frame or persistent?
in both cases its 1ms mainthread since i only alloc in jobs
per frame
are you doing anything else than just scheduling?
no. but as i said mainthread is the same. just workers have a lot more to do with less but bigger alloc
ill try what happens if i reduce the loadbalancer
hm, 1000 isn't a lot but nhm also clears the bucket array with -1 so it's not just allocating. best would be to do it persistent or in a job
so it's bursted
it is in a job
then what takes 1ms on main thread? that doesn't make sense when it's just scheduling. that stuff should be in the <0.001ms range
aaah now i see why you are confused. sry. All my 60-70 AI systems together take 1 ms on mainthread. just scheduling
ah i see ๐
and all those jobs of all systems on all workers need 1ms vs 2ms for both approaches
ok, then. yeah as I said I'm pretty sure the Interlockeds of the NHM.ParallelWriter is what makes the shared NHM approach slower
but its per thread. there should be no interlock happening right?
do you cast it to a parallelwriter?
no only one entity writes to it at a time
hm, I'd need to see code to say more honestly. something is fishy ๐
it shouldn't be that much slower, that's for sure
{
[ReadOnly]public NativeArray<ArchetypeChunk> chunks;
[NativeDisableContainerSafetyRestriction]
private NativeParallelHashMap<EntityDouble, float> entityToAxisMap;
public void Execute(int chunkIndex)
{
if (!entityToAxisMap.IsCreated)
{
entityToAxisMap = new NativeParallelHashMap<EntityDouble, float>(1024, Allocator.Temp);
}
for (int iEntityInChunk = 0; iEntityInChunk < entityChunkArray.Length; iEntityInChunk++)
{
//Do Stuff
}
}
}```
{
[ReadOnly]public NativeArray<ArchetypeChunk> chunks;
public void Execute(int chunkIndex)
{
for (int iEntityInChunk = 0; iEntityInChunk < entityChunkArray.Length; iEntityInChunk++)
{
var entityToAxisMap = new NativeParallelHashMap<EntityDouble, float>(10, Allocator.Temp);
//Do Stuff
}
}
}```
the second approach is the faster one. i dont actually alloc a size of 10. i evaluate some logic to see how big it needs to be and then allocate this. it can range from 0 to 10000 actually
if (!entityToAxisMap.IsCreated) 95% sure this is a race condition
debug.Log how many are actually allocated
oh wait you have it per thread, i forgot ๐
i'd still check ๐
i just checked what happens if i update all my AIs every frame (easily tripple the load but hard to say exactly):
4,7 for slow approach on workers
2,2 for faster approach
and the threads are much emptier overall with the faster approach
im not sure how i best check this.
one way woukd be to schedule just once and count
if you debug log in the mainsystem you have a seperator
and you can output the threadId
and not per thread. found the culprit
I had a similar case, other datatype and I changed it to a pointer
I'm honestly not sure why that doesn't work but structs are always reset or smth
but its a nativecontainer though
the bool isn't
no you are right, it actually checks UnsafeParallelHashMapData* m_Buffer for null
seems like that job struct is not really reused for multiple iterations of execute then?
very possible
im a bit out of my depth here ^^
per thread values are kind of missing sadly
the only thing you could do is pre-allocate 128 NHMs but that's ... yeah
or allocate with interlocked and unsafe containers
thats probably alot slower
all in all, I don't think it's worth it much
yes performance is fine. main thing i wanted to get rid of were the fallback allocs
but this was a leak and not too much allocs
you have the fallback with the 2nd appraoch too? small allocs?
nope they are gone now
ah cool
I don't get why it's 1 big hash map per thread
it allocs every iteration but it does multiple iterations with a struct
Instead of 1 small hash map per thread like it was previously
Though I gave by followed up convo so maybe you solved it
no its either 1 defensivly big hashmap per thread or one perfectly sized small Hashmap per entity
Why
The whole point of sharing is to do the exact same thing as you were doing previously
Except remove initial allocation
Why are you changing logic when sharing?
i need a hashmap per entity to multiply multiple axis together. each entity has multiple buffers which are the axis of the utility AI. the hashmap is there to calculate the score for every TargetEntity. So based on the lenght of the axis of an entity i can size the Hashmap perfectly
if i implement sharing to reduce the number of allocations i need to size defensivly
as if one of those many entities has an axis with 1000 targets
The map will resize by itself though
Also I don't see a clear
i do the clear inside the //DoStuff
that really depends. i tried with above 1000 entities and with 25. the AIs are diffrently complex so some chunks only have 3 entities (yes i need to change that somehow) and some have 30
Of containers to reuse I do think hash map is the worst
If you have large changes in data size
Because a large empty hash map has detrimental performance on lookups
While say an empty list is no different
oh i didnt know that
And clearing
In particular
List clear is length =1
Hash map clear requires 2 mem clear, menset and a loop from memory
Which it does on creation as well, but if it's large its going the same thing for all instances now
that explains alot. even if i start with an initial size of 10 the worker threads are still slower. but its much closer now
buts its amazing that i can do some logic to actually evaluate the perfect size for the hashmap per entity and still be faster than sometimes resizing
oh wait. how much is it resized by ? is it always doubled?
still ill keep your sharing pattern close to heart. pretty sure i have some usecases for it already that do increase performance
lol, job scheduling is exactly the same in 2021. my computer just had way too much stuff running and ScriptedSandbox64.exe from VS2019 literally used 1 whole thread -.-
a min/max/avg of jobs over several frames in the profiler would be nice.
btw i checked on a different PC if i get those renderspikes too. Nope. might have sth to do with metall API. idk
haha
what have you done
a very slow write
huh, i know with big structs there's usually a memcpy
question is how can i fix that?
use memcpy instead of WriteArrayElement?
usually that's slower for small writes
i'll just test it. let's see how this goes
MAN vs MACHINE
I don't have much chance
huh, I won
by a pretty big margin
Enzi holding off the inevitable machine takeover 1 battle at a time!
how large is this struct out of interest?
looks like a big boy
72 bytes
yeah, gonna need to research where the breakpoint is for memcpy
i got pretty tired of optimizing from source, so hard to figure out so now I'm just reading assembly and going over big blocks that stick out
and hold off on the final verdict because some error cropped up :/
do you merge jobs as frequently as i do?
what do you mean by merge? write bigger jobs instead of small ones?
var effectTimeRemainings = batchInChunk.GetNativeArray(this.EffectTimeRemainingHandle).Reinterpret<float>();
var attributeDestroys = batchInChunk.GetNativeArray(this.AttributeDestroyHandle).Reinterpret<byte>();
for (var i = 0; i < effectTimeRemainings.Length; i++)
{
effectTimeRemainings[i] -= this.DeltaTime;
attributeDestroys[i] += (byte)math.select(0, 1, effectTimeRemainings[i] <= 0);
}
// Job 2
for (var i = 0; i < effectUseRemainings.Length; i++)
{
Check.Assume(effectUseRemainings[i] != 0);
effectUseRemainings[i] -= (byte)math.select(0, 1, effectActives[i]);
attributeDestroys[i] += (byte)math.select(0, 1, effectUseRemainings[i] == 0);
}
// New Combined Job
var attributeDestroys = batchInChunk.GetNativeArray(this.AttributeDestroyHandle).Reinterpret<byte>();
if (batchInChunk.Has(this.EffectTimeRemainingHandle))
{
var effectTimeRemainings = batchInChunk.GetNativeArray(this.EffectTimeRemainingHandle).Reinterpret<float>();
for (var i = 0; i < effectTimeRemainings.Length; i++)
{
effectTimeRemainings[i] -= this.DeltaTime;
attributeDestroys[i] += (byte)math.select(0, 1, effectTimeRemainings[i] <= 0);
}
}
if (batchInChunk.Has(this.EffectUsesRemainingHandle) && batchInChunk.Has(this.EffectActiveHandle))
{
var effectActives = batchInChunk.GetNativeArray(this.EffectActiveHandle).Reinterpret<bool>();
var effectUseRemainings = batchInChunk.GetNativeArray(this.EffectUsesRemainingHandle).Reinterpret<byte>();
for (var i = 0; i < effectUseRemainings.Length; i++)
{
Check.Assume(effectUseRemainings[i] != 0);
effectUseRemainings[i] -= (byte)math.select(0, 1, effectActives[i]);
attributeDestroys[i] += (byte)math.select(0, 1, effectUseRemainings[i] == 0);
}
}```
like this
i have 2 small jobs writing to same component
instead i merge it into 1 job
halve job scheduling, query lookups
Sidenote : i replaced all GetComponentTypeHandle with the cache + Update workflow. i saw a 6-8% performance increase on mainthread
improve thread performance (jobs don't have to wait on each other)
it's big on jobs with lots of dependencies
machine gave me a short burst of victory only to crush it with unemphatic coldness. the memcpy makes zero difference
yes i do this everywhere. much more performant for me
๐ฆ
does the burst look any different?
let me check and yeah I've merged a looot of jobs into one.
basically the reason why i have 10 rainbows in the burst assembly ๐
maybe its time to invent SubJobs
we actually have giant partial struct jobs at work
to get some AI stuff running on consoles
like 20+ files each basically just looks like a standalone job
with 1 file dispatching them all
yap i have "processors" now which are basically the same thing
i optimized main thread on xbox from 6ms down to 0.35ms
structs that are called by a job execute
original implementation, lots of little systems - 6ms
merging to single system, lots of little jobs - 2.5ms
1 single system, merging into 1 large job (reusing Gets) - 0.75ms
1 single system, 1 large job, burst compiling Gets - 0.35ms
this was before Update on type handles
instead I burst compiled all the Gets in a function pointer
(reusing Gets) is similar to Update()
this was xbox one performance, so like 10 year old hardware
this level of optimization much less required on modern cpus
so what kind of game was it?
well but u save the environment
i do like living in the environment
my jobs also use partial and several code files
i've been preaching this since the beginning. the architecture of several jobs and systems is cool but really bad for performance
you say as I'm writing a lot of individual systems atm
for this attribute library
(though they are all ISystem so we'll see how much this bites me)
atm it's updating 10 systems on main thread in 0.06
so burst is doing it's thing
well maintainability matters
it really depends if you are even able to merge. but if you can, you should.
but rly im impressed that you can optimize it down to 0.35ms. nice game
there's no reason a game /needs/ more than 1 system
๐
so i could totally merge
like my first iteration basically iterated over the same data/chunks over and over again with different jobs
but i care more about maintainability than saving 0.05ms atm
oh none of these jobs iterate over the same data (but do a lot of the same chunks)
most of my components are single fields atm, i've managed to simd every single job so far
that's what I expected from you actually ๐
still a bit concerned about scalability atm
and i think the most annoying thing is i won't really know until everything is put together
as long as data access stays unique it's not too bad to have them split up
yeah that's the annoying part :/
but i'm not actually sure what level of performance i'm targeting
usually i like to aim for 250k
but am i aiming for 250k targets or effects
because 250k targets would be 2.5mill effect goal
atm i'm just testing 10k targets, 100k effects
oh boy that would be a lot ๐
so yeah, the burst assembly I've posted above. the memcpy is just a mov. I mean it's not really measurable even over a lot of copies (250k) but a lot less commands. funny that it matters so little
if you have your effects reactive i think you can go for 250k
a lot of effects will exist permanently
stats on armour, abilities unlocked, buffs, etc
i'm estimating only 10/actor just because npcs will likely have a lot less than player
oh wait a minute, there's a jmp. looks very much the same. what?
and those permanent effects wont update each frame right? sure some might but alot can be"static"
yeah they won't
though an active affect might bump the change filter and require a re-calc
though good chance that will be a different chunk anyway
maybe you should tag static effects to split up into static chunks
thinking about it, i think that'll just come naturally
so a recalc of one stat only triggers recalcs of non static chunks
they won't have components like, EffectTimeRemaining, EffectUsesRemaining
and often won't even have Conditions
ah yes makes sense. works the same in my system
i have some ideas to group effects loosely on targets
but i can't do all effects of target in same chunk
too much wasted memory
outside of player most chunks would be empty
i have a hashmap for that. okay i have a hashmap for everything...
i do it the other way around. my effects have lists of entities they effect. and when an effect updates it randomly accesses the entities and updates their values
OH i had a question for you enzi
just something i was randomly thinking about yesterday when a developer was trying to implement something at work
do you have a good way to record recent damage to a target and in particular killing blows?
my effects only affect 1 entity
but yeah that's how i'm doing it
except i'm not doing an entity lookup, i just made target + effect have a shared pointer I write to =S time will tell if this bites me
im not sure you actually gain much from that. since CDFE will hit the cache alot
yeah, I gather all combat events in a huge array so I can reuse it for combat logs, achievements, etc.. the job that process these events also trigger killing blows because that's sometimes a flag for spell activations
i don't maintain a history though
nice! though adding history wouldn't be hard with that setup anyway
a lot of games don't need history but some like it for death screens
yeah, pretty much the reason why I optimized this path so much. at some point you need the data anyway
yep, the history could be client/player only
I'm feeling like asking some noob question, so i'm sorry, but why my system updates if there is no match? What can trigger its update? I have no [AlwaysUpdateSystem] attribute
are you using filters on your queries?
i think Getsingleton also causes updates. but not sure
that should still show in query list
ah true
that was my assumption, but comment of .SetChangedVersionFilter did nothing
Why not just use RequireForUpdate?
From what I noticed, it breaks automatic update detection and uses whatever you define instead
anyway i'm trying to use no GetSingleton, because AFAIK it causes dependency completion
can you share system code?
i'm using 3 queries in system
Quick question about EntityTypeHandle. can i just cache it in OnCreate and be done with it? i dont think it ever needs an update right?
can [UnityEngine.ExecuteAlways] public class TransformSystemGroup : ComponentSystemGroup { } cause subsystems to always execute?
i've tried to move it outside from transform system group, but it didn't help
let me try to remove filtering and system group
well and last resort might be to add RequireForUpdate to all queries just to test if it would work. wont work for your logic i guess
๐
is it so bad (my code)? ๐
is this assembly building a jump table for the switch?
ok, it is combination of TransformSystemGroup always execute and using filtering
so there is no RequireForUpdate with Any mode
what i find strange is that it takes 0.18ms for the filters then. should be faster no?
you mean on my screen?
yes
well get rid of that by managing dependencies correctly and just update it every frame.
The issue with CDFE is i can't write in parallel to the target
0.02ms budget should be ok for a transform system ๐
but yes, filtering takes time, because it is just IF per chunk, i guess
also i'm pretty sure this will be significantly faster anyway i can write 100,000 effects to 10,000 entities in 0.17ms
no threading issues
if you do write that many every frame then its alot faster i bet
yeah i won't do that many writes per frame obviously
but the big issue is more the inability to parallel the work
unless i do it over 2 jobs and group by entity target in hashmap or something first - which is much slower
true. i think i write singlethreaded per stat.
this was definitely very much an experiment on being able to have a many-to-one parallel writing without locks
a common issue in ecs
honestly, i'm not really developing a game or anything
i just like to find a problem and try to solve it
many to one writing, unmanaged entity command buffer system (i don't even use it)
etc
yes i also like those design problems more than actual gameplay code. my "game" is just a testingground for the AI framework atm...
yeah i wrote my ai system more than 18 months ago
never used it
i tried to build an interesting sample game and got bored
thats sad. i would love to see the architecture
it was glorious for its time! it alone found 5 burst bugs (though 2-3 may have been the same just manifested in different ways)
dont wait too long with updating it to new Entities Version ๐ will only get harder
oh that's already done
entities 0.50 threw me a spanner
my generic component could no longer work in il2cpp builds
thats the smaller faster build option workaround right?
oh no
thats 0.51
this was a 0.50 change to property package
and how il2cpp generates generics
ah ok. i didnt try to build with 0.50 would have run into the same problem
the issue isn't fixed
so if you aren't having issues in 0.51 you don't need to worry
it basically manifest like this in a build
okay so i answered my own question with EntityTypeHandle. you cant cache it...
MissingPropertyBagException: No PropertyBag was found for Type=[BovineLabs.AI.Data.AIGraphs`2[[Shattered.AI.Core.AIContext, Shattered.AI, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null],[Shattered.AI.Core.AIStorage, Shattered.AI, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]]. Please make sure all types are declared ahead of time using [GeneratePropertyBagAttribute], [GeneratePropertyBagsForTypeAttribute] or [GeneratePropertyBagsForTypesQualifiedWithAttribute]
and
[assembly: RegisterGenericComponentType(typeof(AIGraphs<AIContext, AIStorage>))]
does not fix it - it only fixes it for entities not for il2cpp
yeah but it's much faster to get
hmm i didnt see that particular error. my build still fails with il2cpp atm though
this error happens after starting the game not during build
the issue is mostly the generic and implementation are in different assemblies
ah. no my generics luckily work fine
(it's because AIGraphs is a class based ICompnentData)
it basically just holds the reference to my scriptable object that owns all the graph data
3.7 ms for 100k - floats?
thats not writing a float
it's writing a struct
{
/// <summary> The stat type this affects. It matches the index in the stat schemas. </summary>
public ushort Type;
public ShortHalfUnion Value;
public StatModifyType ModifyType;
}```
i wish i could remove a byte from this
but it'd limit me to 255 stats
maybe that's enough ๐ค
sry i dont know the specifics of those types but did you consider padding?
it is padding 3 bytes
that's the issue i'd like to remove
if i reduce a byte the struct is just 4 bytes instead of 8
are those properties sorted after size?
sorry i don't follow
you can sometimes reduce padding by ordering the properties in the struct after their bytesizes
this is ordered as well as possible
2 bytes, 2 bytes, 1 byte
shorthalfunion is what its name suggests
public struct ShortHalfUnion
{
[FieldOffset(0)]
public short Short;
[FieldOffset(0)]
public half Half;
}```
ah ok. wasnt sure how much shorthalfunion is
unrelated but i misread that as "short half onion"
do you actually need that statmodifytype? cant that be encoded in the type itself?
or can a type have different statmodifytypes?
ah that is whether its add, increase or more right?
damn you. thats way more efficient than having my 3 values for add,increased,more in 1 struct ๐
honestly at some point i will probably get frustrated and bit pack it in
while i want more than 255 stats
i dont need 65k
i can take 3 bits away and still have 8k stats
yup.
and just wrap it with a few properties to hide this
i actually just did a bunch of stuff like this at work
halved our dynamic grid size
its always amazing how much you could optimize. i know a few things about what is possible but i never get around to it ๐
and after you optimzed your gamedesigner comes around and tells you he wants an effect that at the same time adds but reduces. and both with diffrent values
oh thats expected
items can have multiple effects
they are just created as separate entities
just a design choice i decided on
this way i have no limit on what can be added to something
if i want a god tier 4000 effect item
go for it
yes i know you could handle it with the system. just an example where sometimes an optimized datastructure makes things complicated
plz make that game. im curious how changelogs would look like
i'll put the code for unlocking this item 70% down the page of the TOS
and this code can only be applied to your account within 5min of reading the TOS ๐
that is so clever and so mean lol, brillient idea
i would do that to my game, except my game is a fluid puzzle thing, so i dont see how items could really be used apart from cheating the puzzles lol
roguelike puzzler. items modify the puzzles. make it harder in one way easier in another.
gl designing the puzzles though lol
ooh i like that idea! I was already gonna have different puzzles depending on how good the player thought their computer was, so why not, it may be difficult to design then, but oh well!
that does raise in interesting logistical question i hadnt thought about: How am i gonna test the good computer puzzles when my computer is quite low spec and can only handle low spec puzzles
game should always be designed around min specs?
not during fluid simulation (ish) stuff
cause my computer can handle around 3000 particles at once, whereas one of my friend's computer can handle around 60 thousand particles at once
large difference in amount of fluid emitters that can be used, how much water is allowed to stay active during the level, and in general it affects the whole puzzle design, hence why it is more fun to design different puzzles for different specs, cause more specs means more fluids means more fun
id really need to see one of your puzzles now. but id say you probably dont need a fully maxed out fluid sim for the gamelogic. ofc you can render diffrent amounts of particles based on spec anyways.
ye, my fluid sim is completely nonsense, it follows none of the principles of fluid simulation, it just gives spheres a lot of bounce and no friction
and it looks like they merge when close, although not very well, i havent fully figured out meta balls yet
so you can do 1 gamelogic sim that drives the boundingvolume of the fluid and 1 render sim thats inside the volume.
ooh that sounds fancy, ill probably do some research on those, thanks!
the job of game designers is to find stuff your code can't handle. they relish in it
cant blame them. love it myself ๐
its so slow....
it seems like adding empty ECBs is really slow
all those little lines are empty command buffers that try to execute anyways
as far as i can tell
tertle from what i gathered you iterate on the effects (10k) which have stats(10?) and write them to your unmanaged block? the stats are dynamic buffers?
in editor i assume?
yep
i think that goes down a lot in builds
because you can't remove safety from main thread in editor
ah
still it would be nice to first create a buffer and only if it contains anything it gets added to update
each effect is its own entity. an effect can apply stat changes. the final stat values themselves are stored on the entity in a buffer (as well as a second buffer that stores the ptrs for stat effects. the size of this second buffer matches the number of effects that are modifying stats on this entity)
and empty buffer earlies out first line
in playback
well it first completes the dependency. which also wouldnt be necassary
well the dependency isn't stored separately
so it'd be hard to not do that (though you could change this i guess)
but yes, avoiding scheduling a job with a buffer is ideal
if possible
using things like IsEmptyIgnoreFilter etc
id like it for the ecb only gets added to the update list of the ecbs if you declare the dependency. instead of already when you create an empty ecb
does every effect has it's own final stat values or how do you go around the problem of a bunch of threads writing to the same stats? or is this the code you posted some days ago with the bunch of NativeArrays that are all sumed up?
effects modify stats
they aren't a stat
like add, reduce, more, less etc
effects just write to the stat modifier buffer using a ptr directly
so there is no safety issue
and this stat modifier buffer is your unmanaged memory block?
it points to the block yes
{
[NativeDisableUnsafePtrRestriction]
internal StatEffect* Effect;
}
[InternalBufferCapacity(0)]
public unsafe struct StatValueBuffer : IBufferElementData
{
[NativeDisableUnsafePtrRestriction]
internal StatEffect* Effect;
}```
StatValue is on the effect
StatValueBuffer is on the actor with the stat
each element in StatValueBuffer maps to a StatValue
if the buffer resizes etc it doesn't matter
i don't even need to worry if the target entity has been destroyed
(though I clean this up already)
anyone then a separate system just iterates all StatValueBuffer and calculates each final stat value
this is why i needed to get that manual change filter triggering working
so i could trigger a change filter on StatValueBuffer without actually writing to it
so i didn't have to update every StatValueBuffer every frame
really nice. wait, is that change filter only for the buffer? what if something else on the actor changes?
what do you use to get that info? i had the problem that if anything on a chunk changes it triggers a change filter
what the ... I stopped using change filtering because that wasn't happening. hm
adding/removing an entity into a chunk or adding/removing components might trigger it if the chunk changes
but simply changing another component shouldn't trigger it
what's the code to check a specific comp?
I only know chunk.DidChange and CDFE.DidChange
query? hm, did I actually miss this. I was complaining about that ๐
i don't do change filtering on query because it causes a sync point
yeah Manarz, that was triggering even when another comp changed. seems I need to test this again
that usually happens if you just access with write by accident
i can say that all my systems don't do anything atm if there's no change
also i actually used DidOrderChange for the first time! I use this for checking if target chunk has changed at all invalidating my cache.
I totally believe you. yeah, seems that got mixed up with write access version bumping
ah right and you had this funky way of determining if you need to write
yeah i store all archetypechunks that effects reference in a chunkcomponent
this whole implementation is not something i'm going to recommend to anyone anytime soon
it's a huge experiment to see what's possible and atm it's not feeling /that/ gross. all the jobs are quite independent and small making the hackiness quite manageable and hard to break.
i think you're on the right track with this. i'm pretty much doing the same thing on one level but what's nice about yours is that you have a well designed block that you can simd
my stats work very different, I'm still searching where I could apply this. sadly I'm not finding anything ๐
man this whole thing with empty CommandBuffers is annoying me... in systems where i schedule multiple jobs that could share an ecb its really hard to find a decent way to not create it in the first place.
stat calculation is just a really nice application for simd
doesnt every game have a kind of effect?^^
sure but I have stat snapshotting. stats are calculated on a per-spell basis
i can simd the final stat calculation nicely, but the actual writing stats to actor is far from simd - completely random memory access
and my stat system isn't generic nor does it have 500 stats so it's quite fast.
not sure if i know what you mean. do you mean whenever you cast a spell it is effected by buffs the character has?
yes
like you can't buff a damage over time just because you get a %dmg modifier later
or a projectile that's already flying
ah i do that by basically treating spells as secondary characters with stats.
so my effects work for characters and abilities
yeah that's good design
well i do it too BUT imagine a game where your buffs are super short and you do combos like fireball -> splitshotbuff -> explosion to actually make the player cast a spell with timing his buttonpresses ๐
i haven't really thought much about a spell/skill/combat system yet - how could i compete with enzi anyway
i'll just wait for him to release it and use that for inspiration
you're too nice ๐
how do you share a bunch of methods for jobs? them being static leaves me with too few options for datatypes in parameters
and I need to get around a very lazy workaround
"inspiration"๐ต๏ธ
how do i best post some bigger code block rn?
upload the file itself?
yeah
promise to not judge. thats still unfinshed but it works
do those burst compile tags even do anything?
it made it very confusing as a first read
i was like, are these function pointers, hang on they are not static
yes sry i didnt clean it yet.
you remember when i asked why my functions dont turn up in burstcompiler? i was just desperate there lol
i probably do some roundabout stuff i could get rid of. but atm its a nice way for me to define scriptable objects and assign them to those basefiltersystems to run any logic i like
@viral sonnet sry i forgot to ping you there. thats how i handle reusing code between multiple systems and get some polymorphism
its not the complete code you need for it to run though since how this is authored atm is deeply embedded into my AI
I think this is pretty much what i meant with SubJobs before. im just not sure if you could somehow get rid of that PrepareProcessor() and still be able to use any ComponentDataArray without it beeing specified inside the system.
not sure what I'm looking at. my lazy workaround just shares a struct that has the methods. the methods don't use any public fields. it works but the design is bad
yeah its a bit of a chaos sry. just too tired to clean it up now. you look at a way to get a "processor" struct thats completely defined outside of the System to run without the system even having to know what data to pass in.
that's essentially what i'm doing too. hm, maybe i'm too strict on my "workaround"
Im not super happy with this but for a quick first iteration to get any new logic i ever want per drag and drop into my AI graph its really amazingly easy
got the basic idea from here : https://coffeebraingames.wordpress.com/2021/09/26/agent-actions-as-entities/
that's why I've been doing it too ๐ I'd rather use statics but those don't work for most datatypes so sadly not an option
ill hopefully get to a cleaner implementation soonish. then we can compare how we use it
shit. 3:33 am. gotta go :S
o/
I never got this error/warning before: WARNING: Hybrid Renderer using error shader for batch with an erroneous material:
Anyone got a good way of skipping the conversion of a certain UnityComponent? In my case i dont want old Phyiscs components to be converted (but i also imagine stopping conversion of a spriterenderer might be quite useful). I use the old physics components to build a navmesh but dont want them at runtime. Should i just disable the system (e.g. LegacyRigidbodyConversionSystem) with a system running earlier or do i have better options?
anything about conversion is hacky
so just use whatever is going to make your conversion faster
there is no way to see the conversionsystems running in the systems window right?
do you want the gameobject to be converted at all?
all right, I'm done with pure ECS in that project xD
I'm trying to figure out now, how to combine best out of ECS and Classic Unity
I'll be happy to have Entity bookkeeping, but how would I combine it without conversion... hmm
I don't know if the Stop components are still a thing. You can exclude whole leafs of the hierarchy from conversion.
sry was stuck in a meeting. well its in a subscene so i dont have to much of a choice. but yes i want parts of it converted.
afaik not working for subscenes. and excluding a whole hierarchy branch is also a bit weird because then i need more branches in my prefabs :S
i had that without the subscene workflow and it ended up in a branch that gets converted and a branch that doesnt for alot of prefabs which was really annoying
easiest way is probably just remove the components in post
rather than hacking in something
hmm thinking about that i guess for physics it would be enough to remove the physicsworldindex component. then id still have the colliders available if id need to do sth else with it (runtime navmeshgeneration is planned anyways)
i just wonder how much that bloats the subscene data
(but since most of it will be randomly generated at runtime who cares)
i was suggesting doing it during conversion
so it was never saved
for example, i have like a NoTransform component for completely stripping transform stuff and optionally from children
(instead of just leaving static/localtoworld)
that just runs after transform conversion
yes. i can remove it from physics sim with removing physicsworldindex and still keep the collider and do it in late conversion too. its just memory overhead so ill do it for now. but at some point ill completely remove it.
what do you do with those children? just data containers for sth?
since you cant render them without localToWorld
they don't render
they're just settings files
didn't seem much point including ltw on settings entities
hmm interesting. havent thought about having a setting entity as a child yet. id probably do sth like that with CreateAdditionalEntity and keep the authoring on the main entity
oh i don't think i actually use it anymore
as in children
it's all just 1 entity atm
but yeah still strip the transform fully
ah i see its global settings. i thought you had some per entity settings in childentities
yeah just global
ngl, I quite enjoy managed ECS
get out of here with your filth!
I couldn't bear with being forced to create code gen framework just to make tweens work
Having a brain fart. If I want an entity to render right in front of the camera like it was on the UI plane, do I have to tightly couple it with my moving camera, or do I make like a 2nd camera to render it on? This may not be a DOTS question.
you can just make another camera and use it as overlay
and draw whatever you want in front of it
i've reported this comment to discord admin and also just the overlords of the universe themselves
it's not nearly as bad as it sounds xD
haha you'll have to explain
basically ECS keeps references of everything I mark with IComponentData
and then I iterate through them in SystemBase
code is almost same as pure ECS
Hands are way less tied without being stuck in unmanaged world
but everything is stuck on main thread
Ah that's interesting, i didn't realise that was possible
kind of like this
i take it you have no choice but to use dirty managed objects
Maybe it's not xD
But so far, it works just fine
to lower yourself to such depths
I just want to focus on making game, not frameworks
that's why I went on this path
this way I don't have to work in OOP
and I also get to work on game using classic Unity components/DoTween and etc
how do you handle conversion though? the gameobject is destroyed. or do you use convert and inject or sth?
I don't use built in conversion at all
entities in my case are just reference containers
Currently I am working on destroying of them
So far I decided to make it this way:
only objects with special component can be destroyed legitimately
so everything is handled in system that destroys entity/gameobject
which uses this component for query
haha you are basically doing what conversion is doing in the Conversionworld. spawn an entity for every gameobject and add references to the monobehaviours to the entities so that you can query them in conversionsystems
so you do it purely for the SystemArchitecture? 0 memory layout benefits, 0 built in parallelism (you still can do normal jobs though), 0 burst
why dont u use the hybrid workflow as intended?
I tried, but in the end you are stuck inside unmanaged world
and in order to get simple stuff