#archived-dots
1 messages Β· Page 11 of 1
error CS0104: 'TreeView' is an ambiguous reference between 'Unity.Editor.Bridge.TreeView' and 'UnityEngine.UIElements.TreeView'
whatntha heck?
I just installed entities and this error is here.
2022.1.0f1 and entities 0.51.1-preview.21
entities is not supported in 2022 until 1.0
you need to stick to 2021.3 for 0.51
did they give any ETA yet?
So I moved to 2021.3 and now there are several of these : error CS0117: 'JobsUtility' does not contain a definition for 'GetSystemIdMappings' π
21.3.4f is minimum
When 2022.2 reaches lts probaby
is l1 cache and stack speed somewhat comparable?
Doesn't stack exist on l1?
hmmmm
any idea why prefabs spawned during runtime and rendered through SpriteRenderer
don't render in scene view?
while the game is running?
yeah
Any way to manipulate a rendermesh while in a .scheduleparallel() for each loop? (In hopes to be burst compatible) If not, I would love to understand why something like that isnβt possible. Thanks. (:
nothing related to Unity components can be done in parallel
oh wait
RenderMesh
it's managed component (all shared are)
burst does not support managed data
Like the HR's render mesh? It contains a Material and Mesh property. Both classes. So no burst.
even unmanaged shared won't be allowed in parallel process afaik
since they are stored in managed list
You can copy that list to a NA if it's unmanaged. Then query the NA using the SC's index.
well yeah, kind of
Strange set of errors I've been getting lately. It's an editor error and I dont think it affects the actual play
oh
you have a process of UnityEditor
somewhere
which wasn't closed
just force close all processes of Unity
it'll get fixed
kill them all ^,...,^
10,000 simultaneous box collisions: 2.5ms total. Half of that is the single threaded BVH builder.
Circle colliders about 0.2ms faster per thread.
fingers crossed that this will work in 1.0. there were talks about it to make sharedcomps burstable
Yea, back in the 0.50 pre-release thread, they were talking about a unmanaged SCD that was accessable in a job. No sign of it in 0.51 nor the training samples though
shouldn't be hard
just gotta split managed shared and unmanaged
so if they won't implement it, that would really mean they lack workforce
fingers crossed that this will work in 1.0. there were talks about it to make sharedconls burstable
from my guestimations, they have at least a dozen people working on DOTS. 3 unique forum accounts for HR, 2 unique for Netcode, 4 unique in DOTS main, 3 unique in burst.
it's all meaningless if they won't be able to implement unmanaged share comps π
Does anyone have any experience with mem-move?
Is this logic right for inserting a value at index inside an array?
Where vertices is a large stackalloc array
seems fine
Missing a pointer. I think this is now right. Im worried about off by 1 errors though. Edge.Index starts at 0.
I think it works but wow, finding penetration depth is extremely expensive. For 10,000 entities overlapping with only 2 other identical box entities, it costs 3ms per thread. That's the same as the total amount of time to generate the BVH, find overlapping entities, and determine if they're colliding.
Im gonna see if Unity physics has any better idea. Or the interwebs, than this brute force method
arrowx has started another exquisite thread. been a long time
Ha, imagine if each component was structured SOA.
I mean, that is what I'm doing with these collision checks but getting usable per instance data out of it is extremely expensive.
Arowx has been haunting the forums for so long, his user ID is in the tens of thousands whereas the usual member is in the mid millions.
to double check. the loop is unrolled and vectorized, right?
The burst output? No. You can tell if something is unrolled if the same vectorized command is repeated 4 times in a row
For that, in order to get vectorization, you want to memcpy then conduct the multiplication on a float*, not a float3
Unrolling for burst is most recognized for single scalar operations.
mh i see. then why are there 2 fors?
and 2nd question, is unrolling important here?
i was under the impression burst + mathematics output the best assembly for such a simple use case
The first jump is testing if i == floatArray.Length and it skips to return instead of going through the setup of pointers for the float array.
the second jump is the actual for loop.
For this, you might get it unrolled if you use a float4 array. float3 results in unaligned vectorized operations (not aligned to 16 byte wide or float4 width)
This is unrolled operation. Notice how the original math is operating on a single scalar float to allow burst the best chance to recognize and unroll
Also how there's 4 identical operations just shifting pointers after another. That's the most obvious sign of unrolling
yeah, right! and unrolling is nice for scalar values but not so much for values that can already be packed, right?
with float4, less instructions
I havent seen any obvious example of an unrolled float4 operation but it should be possible.
try making multiplier a float4
only change is a vmovups instead of vbroadcastss
Huh, guess not then.
i don't think there's any point in unrolling here. it won't work faster when 4 instructions are behind each other. the loop essentially does this anyway - just trying to figure out when to focus on unrolling
It cuts down on the very very small cost of the iteration and comparison done when looping around in the for loop. And, possibly, improved speed on the operations because it's still "fresh". 4 packed single float operations mean 4 * 4 * 4 = 64 bytes being operated on at once. That's an entire bare minimum cache line.
true dat
Actually, it's 128 bytes at once. 4 bytes in 1 float, 4 floats in a packed single, modern chips have 2 packed singles in a single vectorized operation. And 4 operations means 128. Unrolling means entire cache line operations at once.
so why is this not unrolled then! i see no reason
Burst not that intelligent? No clue.
What if you made the loop condition a constant and a multiple of 4, like 64?
for (var i = 0; i < 64; i++)
wait no, something weird was happening with burst. this is the assembly
ah fuck. the assembly is lagging behind. above is for float, not float4
i think i queued 2 changes on accident haha
Yea, that's fully unrolled. There are no more for loops anymore
can't get float4 to unroll
Guess not, huh
and float unroll with length
Imagine not being 5 digits
He's got ya beat by about 20k.
float4s? Nice
i'm pissed that we haven't found unity earlier. we were still writing our own c++ engine around 2009 and failed hard
Still 5 digits π
no float4s
Just floats? Yea, that's my experience with unrolling.
instruction size exceeded with float4 or what's going on here that the unroll is not happening?
wait that can't be. i've seen 512 sets
around that time unity was really unknown. i mean i was in gamedev.net pretty much daily and haven't heard anything about it.
how did you find it tertle? yep, we also dabbled in ogre3d
I think probably because it had c#
I started in 2.0
A month or so before 3.0 came out
I think my forum account is a year or so younger than I actually started working with it
i still remember this 13 year old kid from the ogre3d forums who was a shader wizard and wrote some pretty good SSAO shaders
I guarantee you there are kids out there hammering out water shaders and raytrace algos in their free time.
Imagine the legions of free labor just going wasted out there. Playing video games and having fun when instead they could be leveraged to pump out hlsl.
Anyone know of a way to convert a dynamic buffer (containing 1 float3 in each element) to a native array of float3's?
Or to ask another question, is there a way to make a dynamic buffer hold float3's rather than a dynamicBufferElement? Hopefully that'll at least better explain what I'm try to accomplish. Thanks.
Do you need a copy? Or directly point to same memory
Reinterpret<float3>()
Then AsArray() to change it to a native array
Note it'll point to same memory so changes in native array with affect buffer
Clone the array if this is not desired
But yeah Reinterpret is what you're looking for
Exists on both buffer and native arrays
I need someone who knows C# to tell me if this works:
I am fixing a ref return property of a interface
Will this work?
It does work, that is wild.
I am generically obtaining the pointer to a float property.
This is cursed c#.
It works in burst as well. Generics is a pathway to many abilities some consider to be unnatural...
i think i need some context why you are amazed by this because i have seen you doing this a bunch of times. what i see is that you are juggling a pointer several times and I don't really get why you are not just using the pointer
the variable I don't see is X and what it is
I'm getting a float pointer to a generic float or float4 property
Two implementations of IPolyShape.
so in the get, why not UnsafeUtility.AsRef<float> ?
and you don't need to pin. it won't leave memory
Cant use an asref<float>() for this.
As for why generic method, I'm trying to make one method for both a box and a polygon. Box is just a polygon with 4 points and special math.
And I'm pinning it in order to cast to a float as that is what is returned
UnsafeUtility.AddressOf might also work. you can typecast the void* to float*
That simplifies the box ref at least
yep a bit cleaner. the UnsafeUtility methods are really cool
i'm interested if the assembly is actually any different with AddressOf vs pinning
No clue, I am nowhere near ready to check assembly right now. Slowly crunching through this tutorial
the AddressOf code is pretty much the same. they also just return &var. the interesting bit is that it won't compile if you write it like that instead of using the method
I think this also works to obtain the index of the maximum value in a float4:
i don't get it haha that shit is wild
Given a set of 4 points, find the point that is furthest away in a given direction without using a for loop
This returns the vertex that defines the support point in a specific direction.
And this is what bitmask does. Turns a bool4 into 4 bits.
funky thanks π
This is why I want the generic float pointers, so i can get everything into neat float4 operations.
I think this is right. The repo I'm scraping this physics engine from is in standard unoptimized scalar math.
Are your physics compatible with Local to world component?
if i run a custom conversion system on an object will components like SceneSectionComponent still get used?
do you mean just implementing a GameObjectConversionSystem?
because all that's doing is adding into the pipeline
every other conversion system still runs on it
Yeah that is exactly what I mean
ok cool I wasn't sure if it ignored any conversion systems attached as components after implementing a GameObjectConversionSystem
Thank you
conversion is just like other ECS systems
the only difference
they only update once when there are game objects to convert
they even follow same achitecture with update groups
smth super weird going on
_query = state.GetEntityQuery(new EntityQueryDesc
{
None = new[] { ComponentType.ReadOnly<InteractionSound>() },
All = new[] { ComponentType.ReadOnly<SoundInstance>() },
Options = EntityQueryOptions.IncludeDisabled
});
I have this
_query = state.GetEntityQuery(new EntityQueryDesc
{
None = new[] { ComponentType.ReadOnly<SoundInstance>() },
All = new[] { ComponentType.ReadOnly<SoundSource>() },
Options = EntityQueryOptions.IncludeDisabled
});
And I have this
oh, f
nvm
am i insane thinking about updating BuildPhysicsWorld on frames that don't tick fixed update
classic physics allowed using normal Update by default...
I don't want to tick the simulation
Just update the world to have new entities and remove destroyed entities
if the fps of my world is > the fixed rate fps
then when new entities are created and I do queries outside of FixedUpdate then there is a (good) chance they won't exist in the world
(same thing if you destroy, might still have destroyed entities in the world)
this is not something i've really had an issue before
until i moved to a complete change filter setup
so i'm only ever going to query once on the first frame of a change and if the entity doesn't exist in the world everything breaks π
i moved logic into the fixedupdate but it just causes more issues
since not all the logic can move in there
so instead i'm just thinking, what if fixed simulation system group doesn't update this frame, just manually update BuildPhysicsWorld
how so?
Shouldn't next fixed step pick it up?
yes
but if my fps is higher than the fixed update
my update loop will run multiple times before fixed update ticks
considered it
but you can't create entities from Update in fixed step ecb
without leaking
or if you really want to try normal update, why not just do it?
if your update loop is 4x fixed update then you leak 4 frame tempjob thing you've probably seen
all you gotta do is just change update groud
?
Foreach system that updates in FixedStep, remove from update list and add to update list of simulation group
no?
i don't want to update physics in Update
if you want physics to update in Update you can just access FixedStepSimulationGroup and set RateManager to null
and it'll just work like normal
ah,
tertle, wouldn't it be easier to move the systems in question to fixedstep?
I figured, that another solution: personal ECB
if it's only entity instantiation
then can be done in a very simple manner
so instead of creating command buffer
you simply access list/array or whatever
or stream
i figured the problem isn't just about ecb. the physics world is only built in fixed steps so in between, entities that are added/destroyed are either still able to be raycast or not
well yeah, and it's fixed by using special ecb
that has no non-persistent allocations
Thanks Tertle, I'll be sure to look into this! Much appreciated.
I made my own 2x3 local to world
Third solution, code your own physics engine. Now you can do whatever you want with the systems
@rotund token btw what were the hybrid renderer changes in 1.0 for unique meshes(saw you mention this in a forum thread)?
Might be the "Register Resources" blurb on the new HR BRG post: https://forum.unity.com/threads/new-batchrenderergroup-api-for-2022-1.1230669/
Honestly, after setting up now 2 custom render passes for sprites and lighting, the BRG seems extremely unwieldy when you can do the exact same thing with a ComputeShader and DrawProceduralIndirect. Far less unity keywords, strange custom formatted input buffers, and opaque defines.
The only major advantage of using the BRG is the ability to setup and dispatch draw commands in a job. Or at least schedule the commands in one and then unity does whatever they do in the engine black box.
For a practical example, in my sprite renderer system, I must call complete dependency on the system following execution of a setup job to release any safety handles on NativeArrays of GPU data I'm putting together in the CPU. Potentially, I might be able to delay this to just before the rendering system kicks off but that means two separate systems to do the work of one temporary solution. The lighting rendering system however I am looking into that completion system. Maybe one that forms a generic completion and upload to GPU.
hm is that test scene in the post of 24k implying that each mesh/material is unique, so 24k unique types or just there are a handful few different types?
I highly doubt each GO in that image highlight is individually unique. Per instance data possibly but actual Mesh/Vertices and Shader unique? Very unlikely.
Unless Unity has reinvented a new graphics driver along with this pipeline, there is no way that is possible with the current driver API.
I see 4 individual GO meshes and 2 separate materials. That's reasonable. Each GO may have unique per instance data but that's fairly standard for instanced drawing, or drawing in general.
yeah, being able to create commands directly from a job sounds nice, I was using drawmeshinstancedindirect with a 1 frame delay so I didnt need to use .Complete
1 frame delay causes stuttering in movement when combined with a physics engine (this was back when I was using Unity's default Box2D, maybe different when I implement my own). The cost of rendering is comparatively insignificant so i havent invested a lot of effort in making it run optimally.
ah thats true, my particles were just dumb transforms
i really dislike having systems in fixed update
your fps drops below 60 (or whatever your fixed update tick is)
and you are in a death spiral
there's no point for these systems to be in fixed update, they don't affect the physics simulation
they just want to use the spatial map for querying
so what would be the harm in updating the spatial map every frame?
then you could just use it in Update with always up to date data
i still haven't thought of a downside of doing this - except it didn't work as expected first time i tried ^_^'
Fixed step death spiral check is as simple as a maximum limit to number of fixed per update.
hmm can't find the post i'm thinking about so ah, not going to say anything just in case
i thought it was in the batch render group api stuff kornflaks posted
does it make any sense that buildphysicsworld can run twice?
yeah i thought about that - just removing it entirely from fixed update
but i realized it does because you could destroy an entity on collision
after the step stage
or create new entities
so if you don't use that it should be good
create/destroy at that stage ... hm I don't like that
The BVH needs to get regenerated if anything moves. So it needs to run every fixed step
this is basically what i'm testing
[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
public struct FixedStepUpdatedSystem : ISystem
{
private EntityQuery query;
/// <inheritdoc/>
void ISystem.OnCreate(ref SystemState state)
{
this.query = state.GetEntityQuery(ComponentType.ReadWrite<PhysicsUpdated>());
}
/// <inheritdoc/>
[BurstCompile]
void ISystem.OnUpdate(ref SystemState state)
{
this.query.SetSingleton(new PhysicsUpdated { Value = true });
}
/// <inheritdoc/>
void ISystem.OnDestroy(ref SystemState state)
{
}
}```
[UpdateInGroup(typeof(SimulationSystemGroup), OrderFirst = true)]
public partial class BuildPhysicsUpdateSystem : SystemBase
{
private BuildPhysicsWorld buildPhysicsWorld;
/// <inheritdoc/>
protected override void OnCreate()
{
// TODO remove just testing
var fix = this.World.GetExistingSystem<FixedStepSimulationSystemGroup>();
fix.Timestep = 1 / 30f;
// TODO end
this.buildPhysicsWorld = this.World.GetExistingSystem<BuildPhysicsWorld>();
this.EntityManager.CreateEntity(typeof(PhysicsUpdated));
}
/// <inheritdoc/>
protected override void OnStartRunning()
{
this.RegisterPhysicsRuntimeSystemReadWrite();
}
/// <inheritdoc/>
protected override void OnUpdate()
{
if (this.GetSingleton<PhysicsUpdated >().Value)
{
this.SetSingleton(new PhysicsUpdated { Value = false });
return;
}
this.buildPhysicsWorld.Update();
}
}```
if you have fps issues. don't make it worse. there's no reason to step more than once
So complicated. So nice having full control over physics. Kinda. My collision detection is fucked...
It attempts to maintain a fixed update time, without taking into account actual frame rate.
yep, which makes no sense
i mean, in which case does this profit? some kind of fast forward simulation? i can step manually for that
in realtime, i see no reason
For multiplayer rollback
manually stepped
And if there's a desync, a frame where fixed step updates more than once to catch up automatically is nice.
you really want it to tick the same rate on client/servers
Manual stepping can be done. Just turn off PhysicsWorld update then do it yourself.
catch up is indeed nice for multiplayer. yet those physics systems are not really built for multiplayer. their design of multiple steps in a frame goes way back before that
Is there a proper way to 'sleep' or more specifically, wait for the end of a frame to continue a function inside of a foreach loop within a system? Similar to how coroutines have WaitForEndOfFrame. Thanks.
No. You will need to create a separate system that is updated at the end of the frame (probably through a manual Update() from a monobehavior inside OnPostRender())
a component system group is probably the best fit for this. There's also EntityManager.CompleteAllJobs(); and some other methods to force a sync point
oh right misunderstood what you said before
that's for unmanaged sharedcomps, right?
i wonder what's taking them so long for this. seems like such a minor change on the surface
or does this just tie in the core of the render system and I'm overlooking something?
Unmanaged SCD should just be a readonly from job chunk component that also fragments a chunk by their value.
Simple enough, I would imagine.
yeah i dunno. must be reasons but i was honestly expecting this in 0.5
Might be tied up in somehow allowing for shared components to be added during conversion / bake.
minor change π
Instead of a list of shared component data, you have a NMHM with the unmanaged-SCD component type as the key.
if you know more about the why please eleborate π
Another code blurb. Calculate the normal vector formed by a linestrip point set:
Fully vectorized. The only section that dips into scalar math is the inverse length calculation.
Actually no it doesnt. rsqrt has a vectorized version:
why do you think it isn't already done? we haven't had an update from their main branch in 11 months
then the question just changes, why wasn't it in 0.50 π
is there any resource which elements already exist in ui toolkit? i need a list that can be reordered
Like click and drag reorder?
yeah
https://docs.unity3d.com/Manual/UIE-create-drag-and-drop-ui.html This is for the drag and drop portion. You'll need to extend this to then reorder a list by the interspace portion between the list elements.
But there is no by default drag and reorder list in UI elements. It's pretty bare as intended.
cool thanks! i googled and got to the 2019 doc. was a little sparse. should have figured lol
https://docs.unity3d.com/Manual/UIE-HowTo-CreateRuntimeUI.html
Here's an actual list implementation
i can go from there. thanks
I havent played around with UIE since 2019. But it has clearly evolved to become fully mature since then (unlike dots *cough*). Still no per element custom shader/material though. Wonder what's taking them so long.
I probably know why though. It's a single indirect draw call for all UI elements which is fantastic for performance but you can only have 1 shader per draw call. They'll need to develop their own UIShader that's compatible with their universal UI shader to allow it.
10,000 circles. Each colliding with 19 other circles. Performance acceptable.
I've gotta say, unity's BVH really is fantastic. 10,000 entities each matching AABBs with each other. In that screenshot, 19 times.
I've been seeing in some of the source there are comments mentioning jump tables for burst. Anyone know how to activate it?
use when i think
article from 2019 though
tldr: instead of
{
case 10: outVal = 20; break;
case 20: outVal = 40; break;
case 30: outVal = 50; break;
case 40: outVal = 60; break;
default: outVal = 100; break;
}```
``` switch (InVal)
{
case int _ when InVal == 10: outVal = 20; break;
case int _ when InVal == 20: outVal = 40; break;
case int _ when InVal == 30: outVal = 50; break;
case int _ when InVal == 40: outVal = 60; break;
default: outVal = 100; break;
}```
interesting, okay I'm gonna see if I can use this
wait what. i read, and i think it was even in the docs that you only need to implement every case. that is a pretty roundabout way. shit. i need to rewrite switches ...
maybe they have improved it? i have never checked the assembly
I'm not getting a definitive answer if jump tables are actually better for todays cpu.
Who knows, Unity wants to use them so I'll stick with their opinion
yeah, i just don't get why we have to use when
I'm gonna check the burst output when im done
Produces a jump table, I think
This produces the exact same result
huh, so they do have fixed it
any ideas for a better coding style with this? basically i want to define stats to enable/disable them
What do you mean?
is there anything better than a bunch of if/endif
You want to be able to toggle the existence of these chance modifiers per file? Where each file is its own spell?
i have programmed a bunch of stats. it's for the asset. the incremental game i'm making uses not even half the stats i've defined and i wanted to make a stats editor anyway. what this editor should be able to is to enable/disable stats via checkbox and set the data type
That's probably a problem you want to throw code-generation at.
i feared that. no i don't think so lol
I dont think you can actually modify compiler defines from the editor without code generation anyways.
that stats.cs is very simple. but yes, i'll use code gen for it. just not for everything
Unless you want to go file by file and change #define for each one.
setting directives is actually quite simple in unity. how would codegen even help me here? the solutions i've are all cumbersome af
that said, i have 0 experience with these new codegens
but i don't want to rely on some template or smth
Oh, are these universal for all spells? Then a universal directive probably works. If these are per spell like some have a hitchance and some dont, then you'll need code gen.
Codegen is eh, It works in Unity but you need to open an actual C# NET project and then compile that project and add it as a DLL plugin to work.
Yea. That's probably the best code you can get. Unless you want to fragment that into components, i think
hm, i'd like some bitmask directive. i don't want to have 30+ smth directives in unity. that would be annoying
I have a bitmask going. Burst compiles this into a jump table.
But this is fully dynamic, object against object collision call jump table.
not really a bitmask smth like #if STATS_STRING[...] contains CRIT. i have to google a bit what's possible here
c#'s preprocessor defines are fairly limited if I remember correctly. I dont know if that's possible. C++ sure.
yep, sadly it's the most basic thing ever. how this never evolved is beyond me
Code gen
Preprocessor directives are very inflexible. Code generation is the next frontier.
ah yeah, the overengineered output of thousand of devs that is able to write text files
i'm a bit snarky because i've never seen one straight forward codegen example where i thought, yep, that's intuitive and really nice.
everything i've seen is, wtf is this. WHY
it makes textfiles and copy/replaces strings
It's very flexible in copy pasting strings. You can use the entire library of C# logic to copy paste strings conditionally
Hrm, I dont know if this is just me but always label your method properties as either in or ref. If it isnt inlined, this will remove the burst move operations
Or just aggressively inline everything
would it not be a lot better to define your stats via configs rather than hard coding them?
it's an enterprise solution that can do a lot. i'm just looking for something in between. :/
From my observations right now, the method call doesnt need the in but the method property list does.
Burst does constant fold / delete branches if statements if the conditional is constant.
I dont know how that will work with an editor setting the value though. But if you just have a const int value mask and a if/switch statement, it works identically to preprocessor defines
how my stats are defined, completely data driven
so i'm better of codegening some const bool hitEnabled?
oh i recorded that in potato format
if you squint you can read it
just + the list, auto generates the asset, sets the id and off you go
how does your code for calculating crit is handling this then?
i dont have an example on hand since i'm in a different project
but the key is just an index to my stats buffer
i just assign it to the system via config
int critChanceIndex;
NativeArray<Stat> statBuffer;
var damage = statBuffer[baseDamageIndex].Value + math.select(0, 1, rand.Next() < statBuffer[critChanceIndex]```
something like that i guess if i was to write it in notepad right now
i guess it's a bit different depending on your objectives
my system is meant to be usable in any project with any number of stats
a designer should not have to change code to add stats is my objective
Not the best for vectorization though
it's never going to vectorize well
That indirect to the statbuffer will prevent any vectorization of calculation of damage
but it doesn't need to
you might have 100s of damage instance
but they'll only calculate damage usually once
and only 1 or 2 entities per chunk
Chunk capacity of 1 or 2?
chunk capacity of 640 atm~
Ah, okay.
but only 1-2 need to update their damage
is that just physics components?
It's everything
Yea, I'm dreading that situation
trying to avoid it in my own project
so painful though using multiple per entities
i should just go back to everything -_-
Im thinking about moving the poly to a unsafe list but polyreal is directly vectorized in collision code. It's only hardcode max 8 points as well.
The issue of course is that there's no way to convert a unsafe list. Maybe a dynamic buffer....
But dynamic buffer is 16B, I only need 8 as these lists are NaN terminated.
Ah I remember why I dont use dynamic buffers. I strongly dislike the API
The main problem with Dynamic Buffers is that BufferTypeHandle is so much shorter than ComponentTypeHandle so in my vertical spacing formatting, it just generates so much empty space.
sure, same goal here. i just want to remove the whole code path. i mean these stats are bound to a very specific set of calculations
Just look at this. Everything's nice and organized accessing pointers from handles. Then you get the BufferAccessor blurb.
well i guess, is your stat system generic?
oh and your index in the statBuffer has to exist. the question is, why do stats exist that are not used
because i did the maths
and it was fine memory wise up to a lot of stats
and much faster if i don't have to check
and solves so many calculations
i can write direct to index
without adding/removing/findingelement
the only thing it costs is the single job calculating the final value
which is annoying as it's slowest part
but i'm happy to live with that for convenience everywhere else in my project
i'm not concerned about the stat system itself but the systems that are using it. lots of bloat. like i said in the beginning. i would only use half of them in my project. a have thousands of monsters with stats that are not used then. not good.
That's what the NA<Stats> is for, it's a redirect to a section of memory that is dynamically sized.
so, this?
otherwise i'm not getting what you want to tell me π either way, i think my best options are now compiler directives or using constants and check if burst removes the code paths. (it probably will)
oh i think i was slightly off from what you're trying to do
you just want to remove some stats from your damage calc etc
because your game won't ever use those stats?
yep
precompiler grossness π
i really wish ides would process precompiler paths optionally
so easy to break things
yeah i wanted to avoid that π
or if there is, please let me know
Code gen is that way...
i hate directives in my code
IDEs have full support for code gen functions
it's still a huge pain to go through and test every config
to make sure you haven't broken something at some point in the past
because it requires recompiling not as simple as a basic unit test
i'd need to codegen the whole method and parts of my jobs
i don't quite see the gain of it
Do you really need to make this a conditional?
yes π
You're gonna need those directives everywhere then.
haha this is too ugly. i'll give constants a try
or better yet, i'll sleep over it and think about codegen. might be a nice learning experience
i've encapsulated this well enough that my brain shouldn't explode from it
So many dot products. So so many dot products. Dot products apparently are key to rendering and physics.
I've got to say, pokemon progress bars is an amazing plugin
What a man has to do to reinterpret a fixed buffer.
Another vectorized snippit. Counting the number of elements in an array that is NaN terminated:
Vectorized.
Originally this horrific comparison table:
It's so good, now the normal calculation has been unrolled:
Also, dont forget to plaster AssumeRange on int counters passed to functions if you know it's at least 1. Removes 1 early jump to return but when horizontal space in the burst inspector is rationed by the number of jumps, reducing one from the rainbow is valuable.
You can also stick it on functions that return ints.
tzcnt is so useful holy shit. I've placed it everywhere now.
is there an attribute for a system to run in fixedupdate?
You just add it to the fixed update system group
This isn't the same fixed update as physx though
is it just an attribute or something?
Ah yep I guess its just this
seems it's not important here to get an accurate count, right? a bitmask of 0100 would return 2, right?
because in that case, would a math select work too?
for an accurate count you'd need a left shift before hand. just thinking out loud
and what about 1011? the count would be 0
Bitmask flips the order. So there's no need to subtract
Yep. Its NaN terminated. Anything past the first NaN will not count but everything should be NaN past the first one anyways
hm, how does the order matter here?
Say the buffer is 0, 1, 2, 3, 4, NaN, NaN, NaN for an maximum of 8 values.
The first part, IsNaN returns: (F, F, F, F), (F, T, T, T) for 2 bool4s.
If Bitmask did not flip, this will return 0000 0111
Tzcnt will then return: 4 + 0. But the count should be 5.
you sure this works? i'm just testing the output for just float4. no nan return 32 for example
Since bitmask does flip, it returns: 0000 1110.
what do you mean?
Oh, bitmask returns an int. Not just a bit4. If there is no NaN in the float4, there needs to be a final math.min(tzcnt, 4)
There will be no situation in which there is a value past the first NaN. So something like (1, NaN, NaN, 1) will not be possible.
ah i see. ok this clears things up
0, 1, 2, 3, 4, NaN, NaN, 7, 8 will throw an error. Not from any of the math functions but a custom verification check at conversion
hopefully the min check doesnt break the vectorization
ugh, adds 2 extra commands
Doesnt break unrolling though which I'm happy with
pretty cool that tzcnt is hardware level
Yea, there's even a vectorized componentwise version. But in this case it's not used
Like... you could...
Here's an alternative that reduces the number of scalar operations to a minimum. Max number of elements in the list is 32 though.
Wow, this performance is amazing. 7ms for 200,000 collisions simultaneously (box - box). Each box (10k) is colliding with 19 other boxes.
For comparison, this is what happens when 200k circle collisions (4ms):
And this is the actual most complex interaction, 200,000 polygon - polygon collisions (12ms)
bruh, sir
can't you make it compatible with Unity Transforms? xD
you are teasing me so hard with those results
Well, the actual collision detection doesnt require my 2D transforms. It only needs world space shape position values.
So this can use 3D transforms. Just you'll be wasting a lot of the chunk capacity for empty float values
the reason behind 3D transforms
is because it's compatible
with everything
you don't have to reimplement lighting, renderer and etc
besides
it's also compatible with 3D
kek
which is also required is certain applications
unless you want to implement patches for that
I mean, you can replace all my 2D transforms with 3D and it'll work perfectly fine: This is the only interaction between my 2D O2W and the actual physics components.
Lighting: βοΈ Renderer: βοΈ Physics: In Progress. Etc: Soon.
I took a look at my games performance using superluminal, 80% of my execution time is spent on releasing semaphores? Am I reading this correctly?
Any callstack? This a networked game?
Mostly job system stuff
Yea it's using DOTS Netcode buut it seems like all the semaphores are just coming from scheduling and completing dependencies
This is only the main thread execution time by the way
Is your game vsynced?
I sampled without fps lock or vsync, running at 125fps and it's barely GPU bottle-necked
Hrm. No clue then. Unity's profiler might not be the most accurate source but it'll at least tell ya where sync points between job threads and main thread exist
Yea but those ReleaseSemaphore calls are not sync points, it's just notifying the job system about work (I think)
If I would have sync points I would expect the main thread to spend time idling on WaitForSingleObject...
its waiting for jobs. look at the inclusive time. it's nit actually doing anything
here's a profile of my project
Semaphore_Release is very small
the unity profiler timeline will give you much better clues what's going on
Wild, actual statistics. I just read the burst output and hope.
My screenshot above shows the inclusive time
Mine definitely seems to be spending all those 8k ms inside ReleaseSemaphore and not WaitForJobGroupId
sorry, meant exclusive time
i find the function list not that useful
call stack is much better. the time is spent somewhere. otherwise there's still some vsync or smth going on
Profiling threaded code without timeline is a waste if time imo
Some things are literally x16 times bigger than they actually are
I guess the callgraph or looking at the timeline would be useful if I would have some sync points to look at or other spikes, but the execution time is pretty well spread across my ~460 systems
Per frame it's spending 12.5ms on ReleaseSemaphore kernel calls
I'm only looking at the main thread time, I have very very little time in which the main thread is actually blocked by a worker
But apparently this got better in 2022.2 (?) https://twitter.com/s4schoener/status/1550477564266815493?s=20&t=AohVWX2IlOp5xY8BxdiiOg
Probably the most significant change from my POV is that 2022.2 ships with a new job system. The old one was stretched far beyond its intended use and I have frequently seen customer projects spend ~25% (!) of main thread time just on job overhead (kernel calls on main thread).
Wow, that's actually pretty big news. Anything more about the new job scheduler in 2022?
A close second favorite of mine is the removal of DisposeSentinel from NativeArray. That thing is finally fully unmanaged
No clue, I also haven't tried it out yet π€·
But apparently even the jobs debugger got faster
Holy shit, NativeArrays in IComponentData in 2022.
You can also now schedule IJob from burst without using that weird IJobBurstSchedulable thingy
Nice. That's the reason why one system in my physics loop is a SystemBase instead of the better ISystem
I'd guess they'll have to have special attribute for fixed capacity?
What do you mean?
Well, how else would it work?
NA is just a pointer and an int for length at bare minimum. There's a bunch of safety for read write and race conditions.
Hmm
Pretty sure it's unsafe list like that
Meanwhile native collections actually allocated in struct
No, NC are definitely not fixed buffers. That's the FixedListXBytes.
Allocated inside a struct is fixed. Pointers to the heap is what NCs are.
Then what is even a difference between unsafe and native list?
Unsafe is an expansion of NAs without the disposal sentinel that also can resize its capacity with add.
If you never resize an UnsafeList, it's an NA. If you do, it's a NL.
Lists just have that little bonus where it also has an int for count and a second int for capacity. NAs just have 1 int for length.
Then I am really confused why you can't have arrays of arrays
And forced to use unsafe lists
You can, UnsafeList<UnsafeList>
You can do NA<UnsafeList> as well
Just not nested NAs because NAs also have that race condition safety system and nesting NAs prevents the safety system from working.
Why not native of native?
Native has safety. Unsafe does not.
Last I heard they're going to include a static analyser to prevent it. Or was that to stop native arrays of arrays... Let me check
the dispose sentinel in NA is managed.
Not in 2022. Or they may have deleted it.
yeah, just adding to the NA in icomp discussion
I wonder, use a custom rewindable allocator, set a bunch of ICD with NAs out into the wild. At cleanup, all you need to do is just rewind the original allocator and boom, doesnt even need a ISSCD
F
Literally nothing changed with Unity 2D Physics (not DOTS) in 2022.2 beyond 1 fix. Wow, they fired everyone.
Wait no, it's foldered under regular physics
N/A (internal): Added: AtomicSafetyHandle.SetExclusiveWeak and AtomicSafetyHandle.GetExclusiveWeak.
Huh, anyone know exclusive weak safety means?
Without reading at all, could be related or replacing secondary handles
They have their whole netcode for gameobjects stuff now right
That seems pretty well received, not that I've used it
Core: Improved Job Debugger performance to avoid redundant work. Most users should feel comfortable to leave the Job Debugger enabled at all times.
Core: Improved the Job System to better scale as core counts increase and reduced the cost of scheduling jobs and combining dependencies.
Core: Changed so that IJob, IJobFor, and IJobParallelFor schedule sites can be burst compiled.
I leave the Job Debugger on at all times. Havent noticed any cost of it personally
Inferior unity physics (so much redirection. It's a fucking enterprise java program)
In our project at work (without physics) load times to from 15 to 45s
From our terrain gen
With it on
This entire section's equivalent in unity dots physics is about 4 separate methods
Located in 3 separate files
I dont get it, why build a literal maze of methods and function calls when a nice and linear execute pathway works?
Is code reuse really that valuable? At which point does reusing the same line of code for multiple other methods become a problem rather than a solution.
But I dont think that's the issue with the jobs debugger though. Just multiple jobs start building up overhead with the debugger
if you ever go into enterprise you're going to be extremely depressed π
I'm depressed just looking at unity's code.
unfortunately everything changes as soon as 1 other person has to work on the code as well
some dev gets a ticket for a bug, goes in and fixes it, doesn't realize you have duplicate code elsewhere in project that also need to updated. now you have 1 bug fixed, but multi new bugs
that is literal pain
This is why one coder is better. The source of the bugs is the same person who will be forced to fix it.
man, if some ide could analyze similar code
I look back at my lighting code and for a few minutes I have no clue how any of it works. And I'm the one who made it. Comments save time and lives.
And one thing I've gotta say is really nice working solo. Pushing straight to master. No need for PRs, no need for review, no need to compartmentalize changes. I can work on physics one moment, polish up some part of lighting, go make a new debug visualizer. And force push to master instantly at the end of the day.
disgusting
not frequently, maybe once a month
but just a good excuse to have a quick look over stuff
i would say there has never been a time i haven't spotted something broken
none of the libraries in my project are pointing to master, i just work on all of them at the same time in various branch/states
i have integration testing on my gitlab
automatically runs tests + makes builds
catches issues nice and early
i absolutely hate doing a bunch of development
only to make a build and everything is broken
and having to spend a day (often days) debugging it
the bane of my existance
I do need to build test though.... ehhhhhhhh
wait, the bot didnt delete my comment
ehhhhhhhhhhhhhhhhhhhhhhhhhhhh
Nice
so for my problem yesterday. i'll use a mix of const bools for definitions and code gen
the const bools are nicest for my actual runtime code. burst will just rip them out when false
the stat enum and config struct will be code gen'd
i figured i need some form of definition so the source generator can actually analyze something
it probably will get a bit more complex once i introduce different data types but i have to start somewhere and this is a good excuse to learn some source generator
var worldPos = world.EntityManager.GetComponentData<LocalToWorld>(e);
var newPos = new LocalToWorld() { Value = worldPos.Value };
newPos.Value = float4x4.Translate(new float3(position.x, 0, position.y));
newPos.Value = float4x4.RotateY(rotation);
world.EntityManager.SetComponentData(e, newPos);
is this really the correct way to write an entities position and rotation?
Ideally, you want to go through the Translation, Rotation, and Scale properties and not write directly to a L2W.
Those properties only have get and not set so you can't?
Unity's transform systems converts the 3 (or less) components into the unified L2W.
No no, the actual IComponentData
Translation ICD, Rotation ICD, and ScaleICD. Not the L2W ICD.
Oh ok i got you
Unity ships by default 4 component datas.
Will an entity being rendered with hybrid renderer get a translation component automatically or do I have to add it?
I replaced the first list with my custom 2D second list but otherwise they're analogous.
Translation and the other 3 are added automatically during conversion of a GO's Transform.
Well, Nonuniformscale isnt if your scale is 1, 1, 1. But the other 3 will always be added.
Check Unity.Transforms.Hybrid\TransformConversion for the conversion logic.
How do you handle scriptable objects with dots? You cant reference it in a component since they aren't blittable, am I best off just making a component that takes a pointer to the scriptable objects address?
you convert your scriptableobject data to unmanaged data in setup or just don't use them
or just write the values to variables in the job
The values of the scriptables aren't blittable either I am using things like animation curves. Its a shame unity didn't expose any of the low level methods cause looking at the sourece of animation curve its just a pointer already anyways.
someone wrote a much faster version of animation curves for dots like 2-3 years ago
oh really ima look on github now
@viral sonnet Also, just added systemstate extensions to the EntityExposed CDFE versions:
[BurstCompatible]
public static UnsafeCDFE<T> GetUnsafeCDFE<T>(this SystemState state, bool isReadOnly = false)
where T : struct, IComponentData
{
return state.EntityManager.GetUnsafeCDFE<T>(isReadOnly);
}```
Nice and colorful
is this what you're talking about?
https://gist.github.com/keenanwoodall/c37ce12e0b7c08bd59f7235ec9614562
different name than i remember
but more than 1 person could have done it
there's already one in. yours is nicer because i have just duplicated the code π
this is unsafe unless you register your dependency manually with the system
you haven't told the dependency management that the system depends on this component
if your system version is doing the same thing using EntityManager, again unsafe
wait does isystem register differently?
what's your normal system version doing?
the same as unity
return EntityManager.GetComponentDataFromEntity<T>(isReadOnly);```
is what unity does
it calls AddReaderWriter
before calling entity manager
the code above is not calling AddReaderWriter so it's never adding the dependency to the system
he calls an extension method. it's in there
Are blob arrays performant if they are preallocated upfront?
but i see i have commented this out. haha yeah might want to add that again
thanks for checking
can you show me the method because i dont see how calling entity manager extension could add a dependency
yeah it's probably the reason i have commented this out
since you're writing your own unsafe version, if you want to make this fast
i can add it to the systemstate extension though as i have the state there
just create it in OnCreate, cache it
and add an Update method like TypeHandles have
(this will exist in 1.0)
yeah good idea
i'm mostly stress testing under heavy load but on no load the systembase onUpdate could be a lot smaller with not setting these up every frame
man this is fun, getting the stat system to support 8/16/32/64 bit datatypes
[BurstCompatible]
public static UnsafeCDFE<T> GetUnsafeCDFE<T>(this SystemState state, bool isReadOnly = false)
where T : struct, IComponentData
{
state.AddReaderWriter(isReadOnly ? ComponentType.ReadOnly<T>() : ComponentType.ReadWrite<T>());
return state.EntityManager.GetUnsafeCDFE<T>(isReadOnly);
}```
I've so far not been caching any of the handles since my jobs far outstrip the system update times (per systems range in 0.1 ms, per jobs in the 2-3 ms).
so simple data types aren't working to use as a generic T. are there any good solutions for it to not write several jobs with just different data types? there's Single, Double structs. should I use these?
can't you just store it all in a 64bit type?
and reinterpret depending on what you need
Reinterpreting is magical.
Does dspgraph work with entities 0.51?
i don't believe so
so no options for sound atm?
i think that would actually be for the best. i just have to be able to mix them all and that is a lot easier when seperated
ReinterpretLoad will be helpful
Get the pointer and then you can do whatever you want with it
what i find complicated right now is how to access the values with its correct data type without too much overhead
overhead?
the values would be stored in a byte buffer
Will these values be constant across a chunk or unique per entity?
actually something cool for codegen. writing offset myself is tedious
they are stats, so unique per entity. every entity has the same amount of stats though
I cant quite visualize what the overhead would be. Memory size?
just concerned about performance π i think i'm getting somewhere though.
Performance comes from vectorization. Data packing often comes with the cost of having to unpack it before doing math on any of it. For example, bytes only have addition, subtraction, and comparison vectorized commands. Multiplication or division will require broadcasting to ints.
yep, that's my concern. right now it's just a nice vectorized job running on floats
Anything wrong with doing this? so I can have arrays inside of components?
public unsafe struct BlitableArray<T> : IDisposable where T : unmanaged
{
public void Dispose()
{
Marshal.FreeHGlobal((IntPtr)arrayPointer);
}
private readonly T* arrayPointer;
private readonly int length;
public int Length => length;
public BlitableArray(int length)
{
this.length = length;
arrayPointer = (T*)Marshal.AllocHGlobal(Marshal.SizeOf<T>() * length);
}
public T this[int key]
{
get => GetValue(key);
set => SetValue(key, ref value);
}
private void SetValue(int key, ref T value)
{
arrayPointer[key] = value;
}
private T GetValue(int key)
{
return arrayPointer[key];
}
}
Does unsafe list not work?
Oh it does. I figured since nativearray didn't work other collection types didn't either
None of the NativeXs do. UnsafeXs do not have the managed safety components of NativeX containers so they can be used inside a ICD. But you need to dispose of them manually somehow.
When I was looking at possible solutions all I seen mentioned was DynamicBuffer and I didn't want to use that in this scenario
So I basically just rewrote unsafeArray lmao
Sorta, basically yes.
I think ima keep using mine then cause as far as I am aware unsafe list doesn't include the leak detection already anyways, and I really only need an array anyways.
This is what a dynamic buffer is. A pointer to an array in heap, an int for count of elements, and an int for capacity.
I recommend not reinventing the wheel when not needed. A Dynamic buffer is just a native array component.
can I put a dynamic buffer inside of a component or do I have to attach it to an entity?
Dynamic Buffer is a component. IBufferElementData for the T.
you can put it a component as well apparently
public struct VehicleComponent : IComponentData
{
DynamicBuffer<float> gearRatios;
}
this compiles anyways
any problem doing that?
I know its not what it is
but will it work?
because I can't have two dynamic buffers of type float on an entity
No. Because the pointer is invalidated on structural change
Thats why you make wrapper structs.
but the arrays aren't the same lengths
What?
public struct VehicleComponent : IComponentData
{
DynamicBuffer<VehicleDataWrapper> gearRatios;
}
public struct VehicleDataWrapper : IComponentData
{
public float gearRatio;
public float gripRatio;
}
you're proposing this right?
Im trying to have two dynamic buffers of type float
then make 2 structs with a float and implement IBufferElementData
No, I am proposing this:
public struct GearRatio : IBufferElementData
{
public float Value;
}
public struct GripRatio : IBufferElementData
{
public float Value;
}```
And then reinterpret the DB.Reinterpret<float>() to get the base values.
sorry for the confusion xd
If you dont want the buffer from flooding the chunk, set the InternalBufferCapacity to 0 to force it onto the heap (basically a NativeList at that point)
Is there any negative side effects to this?
It takes far longer to obtain the data inside the DB since the CPU needs to access Allocator.Persistant (where DBs larger than IBC are located).
And writing also takes a while since it needs to travel all the way over to the heap.
But Entity is a Int2 and Manifold is an Int10 so storing it inside the chunk would basically cut chunk capacity from the current low 50s to 20.
Yeah I need to go read about chunks tbh
Ok so if I understand this right. Entities of the same type might be located in seperate chunks of memory. if the dynamic buffer is also inside this chunk of memory then it will cause my chunks to contain less entities and queries will take longer due to this?
Not entirely. The queries will take longer yes but that may be offset by the rapid access of DB data since it's located extremely close.
If you want to do fast iteration across multiple DB on multiple Entities, you want the DB to be located inside the chunk so you're not waiting on the read-write back and forth to the distant Persistent. But that comes at the cost of less entities inside the chunk since the DBs are now taking up space. And if you surpass the DB's ICB, then that inside chunk space is wasted and the DB will instead point to a persistent allocation.
Alright thank you so much for clarifying! Just out of curiosity what exactly is the point in unity designing it this way vs one chunk per world?
you mean like, all entities of an archetype in a single chunk?
yeah
You dont get an option to shove everything into a single chunk (that would be amazing personally)
Chunks are fixed size and you gotta work with what Unity hardcodes as the limit.
basically adding/removing works faster in chunks. that principle is used a lot in advanced data types that use several small blocks of memory and not one huge one. for example, NativeList uses one huge block and resizing when you have 10k elements in it gets exponentially expensive
To expand on this, the cost comes from any resizing requiring memcpy of the old data into a section where the free memory space is larger.
Since you have 1 pointer and 1 length, everything from the pointer head to the pointer at length must be valid and in that list.
What I really wish is the ability to shove everything into one chunk if I know the entities themselves will never structurally change but the values will.
They said they were looking into the possibility for user defined chunk sizes but that was... a long time ago
So since ISharedComponentData forces entities to the same chunk would that not be an ideal way to force entities into the same chunk?
ISCD forces entities apart. You can not use it to force entities together as that is the default condition for entities.
entities of the same archetype are in the same chunks. SCD is like a groupBy method
No I mean if you put a ISCD with the same value on all entities of a certain archetype wouldn't that force them all to a single chunk since they have the same ISCD?
No. Chunks have a fixed byte capacity. 16KB per chunk (i think). Your entities and all the components on that entity divides that 16KB among themselves and that's how you get chunk capacity. ISCD does nothing to change that.
ah alright
If you have a mega-entity with size 16KB, that means one chunk can only contain 1 entity. Even if multiple of these megaentities share the same ISCD, that will do nothing to change the number of entities per chunk.
What will change if you have an entity of 8KB (so 2 entities per chunk) and a different ISCD per entity, you will force every chunk to now contain one 8KB entity. But the chunk remains a total of 16KB.
I am going to have awful chunk utilization I feel like. Each vehicle has a dynamic buffer of floats that relates to gear ratios with a size of 5-8, torque for any given rpm with a size of 256, and a slip curve with a size of 256.
That is something you might want as a parameters for a line of best fit equation (you only need 4 for a quadratic) instead of a float array of 256 values.
The AnimationCurve?
An literal mathematic curve. Ax^2 + Bx + C
a buffer is only 16 bytes if stored outside the chunk
i think you're being way too influenced by this channel when you're reasonably new to entities π
we have like 6 entities per chunk at work. our server still runs really fast
performance issues are still all tied to main thread job scheduling etc
First google result. 7 floats.
Guess I will just keep moving forward and worry about it if its every a problem
Looks empirical but good enough. You wont get any simulation running off of that equation past the feds but if this is for a game, it's sufficient.
So this procedurally generates the torque curve basically interestting
Also note, I'm a guy coding my own physics engine because I dont like the existance of a z float in unity's DOTS so my advice is probably not the best.
i gave way too much shit on chunk capacity. it doesn't matter too much.
you say that
but the only difference between these 2 is increased chunk capacity
50% faster by tripling chunk capacity
(fuck linked entity group)
It's also 5M entities...
you should see the 100M version π
My poor comp dies at 10k...
i think it was 13GB of just linked entity list
It's slowly creeping higher
you should profile that. i would bet most is spent on GetNativeArray
now you have to see how putting it all in blob memory compares π
Box and centroid might be able to go into a blob memory as it's constant per shape. I need to figure out how conversion with blobs work
and can't be said enough. LinkedEntityGroup should be burned at the stake
btw. i found GetPtr more light than GetNativeArray. with such a testcase it might be worth exploring the difference
aaand, caching accessors for threads. can we make this a thing?
GetPtr?
GetComponentDataPtrRO and friends
the safety overhead also kicks in even with checks off, there's some left
Oh, for the CDFE. Yea, there's no memcopy struct
no, the handles
Oh, that would be nice. Got a copy?
it's built in
good thing we talk π
the nice thing about getting RO directly is that version doesn't get bumped on write handles
As in bypassing the version increment?
yes
You could just do that with the old unsafeReadOnlyPtr as well
wdym, it's built into GetNativeArray
wait, seriously? Oh my god
explains so much about why my version checks break so easily
ChunkDataUtility.GetComponentDataRW does it and that is used in GetNativeArray based on if the handle is read or write
https://github.com/enzi/Entities.Exposed/blob/main/EntitiesExposed/ChunkExtensions.cs has an extension for manual version bumps
I see there's also a way to get a random component data from a chunk inside a job without a handle. Interesting
why does this all look so familiar π
i dunno we must be doing the same things π
// This should (=S) be thread safe int writes are atomic in c#
even write the same comments π
i'll add a β€οΈ tertle
not being able to write extension methods for pointers makes me a sad panda
?
Method(this float* array, ...) doesn't work
you don't write them for pointers
you write them for the underlying type
and then just use pointers on them
Oh yea, that wouldnt work.
makes no sense to me tbh. i can write a normal method just fine with a float* parameter. so why no extension
afaik it's just a wrapper anyway
it works fine
you're just writing it wrong
public static void Method(this float array) {
}
}```
you probably want to do something like
var ptr = (float*)UnsafeUtility.AddressOf(ref array);
}```
the issue with that is now every float will have this extension method...
well yeah
but that's what he's asking for π
personally i'm a fan of container structs
and i have a default Ptr<T>
with implict conversion for this
that i can write extensions on
public readonly unsafe struct Ptr : IEquatable<Ptr>
{
public readonly void* Value;
public static readonly Ptr Zero;
public Ptr(void* value)
{
this.Value = value;
}
public static implicit operator void*(Ptr ptr)
{
return ptr.Value;
}
public static implicit operator Ptr(void* ptr)
{
return new Ptr(ptr);
}
public bool Equals(Ptr other)
{
return this.Value == other.Value;
}
public override int GetHashCode()
{
return unchecked((int)(long)this.Value);
}
}```
oh that's the non generic one
but yeah i find this one useful as well
for storing in containers
where T : unmanaged
{
public readonly T* Value;
public Ptr(T* value)
{
this.Value = value;
}
public bool IsCreated => this.Value != null;
public static implicit operator T*(Ptr<T> node)
{
return node.Value;
}
public static implicit operator Ptr<T>(T* ptr)
{
return new Ptr<T>(ptr);
}
/// <inheritdoc/>
public bool Equals(Ptr<T> other)
{
return this.Value == other.Value;
}
/// <inheritdoc/>
public override int GetHashCode()
{
return unchecked((int)(long)this.Value);
}
}```
then you can just write extension methods on Ptr<T>
anyway back to original point
what he wants to do is totally possible
extension methods on floats
{
var tmp = array.ReinterpretLoad<double>(Health_Index);
tmp = value;
}``` any better suggestions to write a double to a byte array?
Hrm, does anyone know how blob assets creation during conversion works? I know you have to do something with BlobAssetComputationContext in order to register between a converted entity and blob asset but how does incremental generation and update of a single blob asset work?
reinterpret the byte array as a double array
it's a huge pain and you don't need BlobAssetComputationContext there's a few different ways to do it
i might just get the ptr. reinterpret has some overhead
does it without safety?
it's what i'm doing tertle. just using load because it has an offset
i've seen burst basically strip it to nothing
there's a very basic example here
with just blob builder
I have 10 entities sharing the same shape properties. I want to ultimately make all these entities point to the same blob asset which contains the shared shape. Is that possible?
so using computation context can help with that
but the actual blob asset store can do it as well
Right, the docs are pretty sparse on that.
conversionSystem.BlobAssetStore.AddUniqueBlobAsset()
/// Adds a blob asset where the key that makes it unique is based on the BlobAsset contents itself. If the contents of the generated blob asset is the same as a previously inserted blob asset,
/// then the passed blobAsset will be disposed and the reference to the blob asset will be replaced with the previously added blob asset
/// </summary>
/// <param name="blobAsset">The blob asset that will be inserted or replaced</param>
/// <typeparam name="T"></typeparam>
/// <returns>Returns true if the blob asset was added, returns false if the blob asset was disposed and replaced with the previous blob.</returns>
unsafe public bool AddUniqueBlobAsset<T>(ref BlobAssetReference<T> blobAsset) where T : struct
{
Hash128 key = default;
ulong hash = blobAsset.m_data.Header->Hash;
UnsafeUtility.MemCpy(&key, &blobAsset.m_data.Header->Hash, sizeof(ulong));
key.Value.w = ComputeTypeHash(typeof(T));
if (m_BlobAssets.TryGetValue(key, out var previousBlob))
{
blobAsset.Dispose();
blobAsset = BlobAssetReference<T>.Create(previousBlob);
return false;
}
m_BlobAssets.Add(key, blobAsset.m_data);
return true;
}```
i must have been thinking about something different. it's just pointer arithmetic
if it already exists in the store, it will delete it and re-use the existing one
if you can hash it yourself you can speed up conversion
m_BlobAssets?
(uint)this.sockets.GetHashCode(),
(uint)this.type.GetHashCode(),
0,
0);
if (conversionSystem.BlobAssetStore.TryGet<Piece.Asset>(hash, out var piece))
{
return piece;
}
// ...
piece = blobBuilder.CreateBlobAssetReference<Piece.Asset>(Allocator.Persistent);
conversionSystem.BlobAssetStore.TryAdd(hash, piece);
that's the source from BlobAssetStore
yeah it is painful
Oh wait, that code blurb is unity's
yes
I see it, yea. Blob asset building is terrible. My god.
So in what situation would you use a computational context? This seems to handle unique filtering by itself
i think it's for performance
Oh, okay. hrm
i will admit i am not super familiar with blobs
i think you can use jobs to pre-compute all hashes with BlobAssetComputationContext and things like that
instead of running it all single thread
at least that's what i've seen physics doing
{
private NativeArray<byte> _array;
private readonly byte* _ptr;
private const int Health_Index = 1;
public StatsWrapper(ref NativeArray<byte> array)
{
_array = array;
_ptr = (byte*) array.GetUnsafeReadOnlyPtr();
}
public void SetStat_Health(double value)
{
ref var tmp = ref UnsafeUtility.ArrayElementAsRef<double>(_ptr, Health_Index);
tmp = value;
}
}``` this might be a bit better
i dunno, allocates a struct though :/
eh, don't like it either. static methods it is
tmpMultiplicativeStatsWithValues[ii] = 1;``` i have to convert this very simple loop to work for a byte array that has double at first, then all floats and then all shorts. ```var bytePtr = (byte*) tmpMultiplicativeStats.GetUnsafePtr();
var doublePtr = bytePtr;
var floatPtr = bytePtr + StatsConfig.STATS_64BIT_AMOUNT * UnsafeUtility.SizeOf<double>();
var shortPtr = floatPtr+ StatsConfig.STATS_32BIT_AMOUNT * UnsafeUtility.SizeOf<float>();
double* doubleValue = stackalloc double[1];
doubleValue[0] = 1.0;
float* floatValue = stackalloc float[1];
floatValue[0] = 1.0f;
short* shortValue = stackalloc short[1];
shortValue[0] = 1;
UnsafeUtility.MemCpyReplicate(doublePtr, doubleValue, UnsafeUtility.SizeOf<double>(), StatsConfig.STATS_64BIT_AMOUNT);
UnsafeUtility.MemCpyReplicate(floatPtr, floatValue, UnsafeUtility.SizeOf<float>(), StatsConfig.STATS_32BIT_AMOUNT);
UnsafeUtility.MemCpyReplicate(shortPtr, shortValue, UnsafeUtility.SizeOf<short>(), StatsConfig.STATS_16BIT_AMOUNT);``` any input?
i migh have overcomplicated this π
Just use sizeof() in unsafe...
use &floatValue instead of stackalloc to get a pointer to a local var.
at this point, would it just not be better to keep everything in double
for your sanity
but also, weirdly enough, peformance
wdym, to have everything in doubles with no other data types?
yeah
if you're going to have to do all this weird extra math to support different types
why not just only support the double
this only happens once per thread. everything that goes beyond that though. i think i can kiss my beautiful vectorization goodbye
personally after our last discussion i ended up adding the option for high precisions because you were right, i guess some weirdos want higher values
well, not really when i'm smart about but it's gonna be a pain
[StructLayout(LayoutKind.Explicit)]
public struct StatValueUnion
{
[FieldOffset(0)]
public int Whole;
[FieldOffset(0)]
public float Fraction;
}
#else
[StructLayout(LayoutKind.Explicit)]
public struct StatValueUnion
{
[FieldOffset(0)]
public short Whole;
[FieldOffset(0)]
public half Fraction;
}
#endif```
so they can optionally unlock it
only place in my code that actually needs this #if though
which is kind of nice
oh i don't really mind if it's a pain to code tbh. regarding perf, i can access them via const index so it should be really the same
and it's gonna be nice when it's done so i think it's worth the effort π
float floatOne = 1.0f;
short shortOne = 1;
var bytePtr = (byte*) tmpMultiplicativeStats.GetUnsafePtr();
var doublePtr = bytePtr;
var floatPtr = bytePtr + StatsConfig.STATS_64BIT_AMOUNT * sizeof(double);
var shortPtr = floatPtr + StatsConfig.STATS_32BIT_AMOUNT * sizeof(float);
UnsafeUtility.MemCpyReplicate(doublePtr, &doubleOne, sizeof(double), StatsConfig.STATS_64BIT_AMOUNT);
UnsafeUtility.MemCpyReplicate(floatPtr, &floatOne, sizeof(float), StatsConfig.STATS_32BIT_AMOUNT);
UnsafeUtility.MemCpyReplicate(shortPtr, &shortOne, sizeof(short), StatsConfig.STATS_16BIT_AMOUNT);``` a bit nicer, thanks @robust scaffold
@rotund token There's this superior option to build single value blob references. Without having to go through the pain of a blob builder
That is what I expect blob asset building should be like. Smooth, painless, and efficient.
I wonder, can you have generic components?
Hrm, yes you can. A bit cumbersome but it works.
is this actually saving memory
im trying to mess around with unity physics rigidbody if I want to do something similar to AddRelativeForce do I just do it on the linear velocity property of PhysicsVelocity component?
No?
The blob asset still uses the same amount of memory, the type doesnt change.
i mean in the chunk
No. The type of the blob asset reference is the same as the blob asset reference created from the BlobBuilder
i just mean, using blob in general in a component
over storing the box in a component
A box component is 8 floats on every single component. A blob asset is 1 int pointer.
blobs are a long
internal long m_Align8Union;```
internal unsafe struct BlobAssetReferenceData : IEquatable<BlobAssetReferenceData>```
but yes the box is still 16 so that's fine
i missdid the maths
Right, size 8, not size 4. Still, that means 2 ints. Still 6 less int sized fields.
oh are those ints?
int sized, 4 bytes
yea, half the tile size. I dont use half floats.
all good
The tile's position is at the center of the box. Then half size for the 4 points.
I think this works?
I havent used blobs but I am allergic to ref.
there isn't a way to enable/disable specific components is there? Just entire entities?
Soooooooon. That was promised years ago but nothing has come.
rip
Certain vanilla systems have their own disable tags
Like DisableRendering
Transform uses write group filters
Disabling the entire system isn't an option for me unfortunately
I need to just be able to exclude an entity from a system temporarily guess i will just remove/readd the component
uh whatever system handles gravity for the entities converted with the physicsbody attached
What I mentioned excludes entities
There's physics mass override component
Let's you turn bodies into kinematics or disable velocity
So in the editor when you attach the physics authoring component you can make it static or dynamic but there doesn't appear to be a way to do this at runtime.
most of the code is there in 0.51 but won't be usable till 1.0
PhysicsMassOverride
So just addcomponent it?
And set it's settings
PhysicsMassOverride is good for short term behaviour
but it does cause your statics to exist in dynamic world for updating
for long term changes just add/remove PhysicsVelocity
I have clawed back 64 bytes per entity. My physics systems are completely broken but I can fix that slowly.
AABB could be a half4... Hrm
huge
63 usages. Ughhhh. Maybe doesnt need to be converted to half4.
why would I be getting an error message stating that there is no translation component on an entity for using SetComponentData but I can see with my eyes in the entity hierarchy that it is there.
you dont need translation to render
just localtoworld
static entities don't have translation
Yeah hascomponent fails but i can see the translation component on it in entity heiarchy so idk whats going on x)
it means when the code runs
it doesn't have Translation
but when you look at it in hierarchy it does ^_^
or maybe it's different entity
I am using Instantiate to copy an existing entity that has a translation component attached so that isn't it.
Is it possible the conversion system isn't finished or does that happen at edit time?
No
ok i found the issue, the entity is a subscene section entity and is still being loaded when the request for translation is made
ahem
@rotund token does it work like this?
I highly doubt entities can be loaded with half of their components
yeah...
that's not how it works
but i feel like he's talking about the actual subscenesection entity
not the entities in the subscene?
but basically the subscene gets loaded from disk then when done the whole thing is just copied into your world all at once
I am talking about the actual subscene entity, I am using subscene sections to stream prefabs in and out of memory. each prefab gets its own section in a subscene, so when I need the prefab i just instantiate a copy of it, but if the subscene section isn't loaded the conversion process hasn't happened(im guessing this is how it works? not 100% sure on this part)