#archived-dots
1 messages ยท Page 49 of 1
{
var healthStateMask = chunk.GetEnabledMask(ref HealthState_ReadHandle);
for (int i = 0; i < chunk.Count; i++)
{
if (!healthStateMask[i])
continue;
Method(in chunk, unfilteredChunkIndex);
}
}```
found the code which trashes my project. from 2.5ms to 20-27ms!! now if i just call Method (the previous Execute method, everything's fine) wtf is up with this? i expect some overhead but not utter destruction
whelp i'm a dummy ๐ created a double for loop. good lord what a mistake... well i'm leaving it there for everyone to laugh ๐
for so many calls performance is quite good lol
where is double though?
@rustic rain @viral sonnet It really makes much more sense to just open the folder as a unity project browsing from unity hub, idk why i didn't thought that before. Ooh and making the changes to URP really made it, just coming back to thank you both, it really helped. And maybe if someone in the future has the same questions they can rely to my confirmations here it worked. Thank you very much again.
that's what I was suggesting ๐ค
Yeah it worked! Hehe
in Method ๐ i just chained it. don't ask me why. there's no excuse for such a mistake lol
how is the transition to transforms v2 atm? will it break everything?
no it went pretty smooth
and would the new physics still work with transforms 1.0?
yes, if you set ENABLE_TRANSFORM_V1 manually
didn't new physics transisitoned to v2?
yeah, as new default
what would be the TLDR of what Transforms 2 changes?
it's all-in-one component now
Translation/Rotation are gone and replaced with LocalTransform
similiar to GO basically
if you don't do anything with scale, that's pretty much it
nu scale is still unsupported?
and it is still updating changes to the "LocalToWorld" only at the end of the frame in one system or does that work differently now
it's similiar system group
with a lot of systems
no idea what's inside
neither it should be concern anyway
i think what i am asking is when the WorldTransform is updated.
is it updated automatically when i write to localtransform right away or do i have to wait till the end of the frame?
just skimming through the docs and trying to figure out how much will break for me ^^
it's updated in the transform system at some point
so not updated automatically when LT changes
i'm still confused how to optimize this beast. like, on a root entity there's no need for WorldTransform
my previous method was to just use LocalToWorld but that wasn't working out with the physics package
anyway, LOTS of data now. LocalTransform, WorldTransform, LocalToWorld.
i wouldnt worry about that too much right now. that package is just too young. they will get to optimize it eventually.
im pretty sure they are aware of the problem of useless Unity IComponentData atm
a regression is if you relied on change filtering just for rotation as it's all packed now into one comp
^ I'm relying on transformaspect so that any future giant change I don't have to redo this all again
as i understood it its the whole selling point of aspects right?
But this has stopped any sliver of hope if updating work project
oh reminds me you wrote something about changing your perspective on aspects. you didnt explain further. what happend
1651 uses of translation
I try to only have 2 cases, 1 write many read but also 1 read but many writes
I just try to avoid many to many
The many write 1 read is very useful for this
essentially what the transform aspect is?
I'm pretty sure most people would use transform aspect as many read many write
Too much of a universal concept to avoid
many writes, many reads is such a problematic concept in every regard
pretty much everything that relies on order
ah then i understood you the wrong way. i thought you are talking about access to the components inside the aspect.
I havent worked with Transform aspect but as i understood it i write to Pos,Rot,Scale and i should only read from WorldTransform
the most time i spent on fixing / finding bugs is because of that
yeah and even if it gets stable. working within such architecture is like entering a minefield
what i found helping me a lot is trying to get everything of a bigger module inside its own update group. its not always possible though when interacting with transform etc
has anyone programmed in python? they declare variable names like source_transform instead of sourceTransform - i'm on the verge of changing my style ๐
typing underscore or what do you hate about it? ๐
well, best replacement for a space character
but yeah, underscore isn't really on a key that's easily reachable
i started to use this style for handles a long time ago
I guess the information is useful for unsafe containers...
yeah, i made mistakes with read/write states when binding the job and got annoyed. so i put the info in the variable itself. the first part is always the struct itself which i copy/paste
needed the underscore to seperate the information
i've only started with c++ and that was always camelCase wherever I looked
so i'm using the CamelSnake_Case for my handles. lol
It seems like default interface methods break burst compilation
I have done some searching but haven't been able to find anything. Is there a way to set IEnableableComponent to disabled by default on creation or when added, or do we need to manually set them for each component?
I also hate it. It's especially annoying when writing python web servers since serialized variable names then need to be aliased to proper JSON camelCase names if you don't want your request data to look ugly
Do you mean during baking or at runtime?
Runtime
I assume if you instantiate an entity that has the component set to disabled, it will also be disabled on the newly instantiated entity
That's a good point, I think that should work. Thanks
you can disable it with a baking system. only works for a closed subscene (unless that was fixed)
then the state is already baked into the prefab
I am not a baker, just a weak developer lol, everything comes from a database and gets generated at runtime, but when I create the prefabs from that I data can disable there so it works as intended, thanks again!
runtime generation? you still on 0.51?
No, 1
is your generation so complicated? some kind of prefab template can work quite well. pure runtime generation trashes archetype variations
I think its pretty solid, I have 4 items in my scene. Camera, Event, UI, then my single GO that starts everything once it finishes html request. I use a few archetypes that are pretty concrete and don't add/remove much so I think its ok. I still need to break apart some things and nest anything that will get add/remove, but I haven't noticed any issues so far. I moved away from game objects when I first started ECS so I don't want to go backwards with the baking system.
Gameobjects never hurt anyone
Yeah, I just don't see a point. I moved all data when .5 came out so I could make balance changes or add new units/ manipulate game on the fly. Data oriented just makes more sense to me being generated at runtime. Maybe a mistake but once I committed it was too much to backtrack
The reason unity uses subscenes is because it's insanely fast. Loading a scene is just a memcpy, that's why they are authored ahead of time
(vs creating everything at runtime which is most likely slower)
there's the content management system now which should be dots addressables. hooked up this will be much nicer for web updates
i think your system will work well enough though.
Yep, I think it also depends on the project to a degree
I have like 5 prefabs, and that's only because netcode requires it
I get what you mean, but so far I have not experienced an issue. Since I really only touch the initial data at launch of the game it takes less than .25s to load. After that there is zero load times, as everything in my game is entity driven its been instant. I still need to do some mobile testing but I am happy so far
My point was for a traditional AAA game, that loading time at runtime will be very long. A big draw of ECS is that it enables very large scale simulations and worlds
Subscenes make that loading as fast as possible
But for indie projects it most likely doesn't matter, unless you have requirements similar to those
Just go with whatever works
Aspect.Lookup doesn't seem to have a Has method? hmm
For optional components?
no just for the whole thing
if i have an entity, how do i know if it has a transform
Use a component lookup for a transform?
Is this an aspect that is different from an IAspect? ๐
damn, 13ms more in my stress test with TransformV2 -.-
no
just think TransformAspect.Lookup as example
I don't think I've ever used the .Lookup type, what's it for?
I just read the data from the aspect when querying
getting an aspect from another entity
Ah, I see
it has
Lookup(ref global::Unity.Entities.SystemState state, bool isReadOnly)
void Update(ref global::Unity.Entities.SystemState state)
TransformAspect this[global::Unity.Entities.Entity entity]
why not use the lookups generated?
i can do that, and i'm about to write an extension method for it
It was requested a video of nothing but warp drive cuts, and its very fun to watch, people have said I'm funnier than Saturday Night Live and movies: https://www.youtube.com/watch?v=96cIYun83FE Enjoy.
Yes, these are actual 1:1 size stars of 1400000000m big or 80x as big!
Star Trek TNG, And all games since just use like particle effects... Impressive, but this warp effect I invented and many said could not be done has been done. ENJOY!
We run a guild. Opportunity: I can teach you how to make games for free better...
but i have to write this for every aspect
That makes a lot of sense, since I was always confused on how that was supposed to be done (outside of querying it directly in an IJE or IJC)
(and they're internal so other users can't do it)
How do you create the lookup?
this.transforms = new TransformAspect.Lookup(ref CheckedStateRef, false);
Lookups are meant to have a Has method angry face
its just like doing
ComponentLookup<Transform> t;
t[entity] // crash if it doesn't exist
seems you lookup the whole aspect and then check for null pointers which can be returned from GetRefRWOptional
but yeah, that's not really the point of a lookup for a single comp
That can't be the intended user friendly way ๐
agreed, certainly needs a Has method
Weird that it's missing
i don't understand how no one has run into this before
I assumed you could check the RefRW / RefRO for the IsValid field, but that won't work if it won't even let you get the aspect
updating library to v2 and took me 15min to have an issue
i'm hoping i'm missing something
I've only used a single aspect and only read and write to it in an IJE
trying to convert all libraries to transforms v2
and it's tedious
hoping this is the last major refactor
Never
refactors 4 lyfe
Any netcode experts here? I'm running into an issue I don't understand
Pretty sure this isn't something new
ok try me
So I have a dynamic buffer that I am sending over the network, and the updates for it are run in a prediction system
ah the classic schnoozlereference
(side note, reference seems like bad naming, should be like schnoozleid or something since reference is kind of means something anyway continue)
Anyone knows how to manually initialise world in 0.51 with convertion systems and stuff? Because it seems that just adding ConvertToEntitySystem to world in 0.17 works, but in 0.51.1 it doesn't. I don't want to switch instantly to 1.0
It references a scriptable object
it holds a guid which matches a scriptable object
i can't access that scriptable object without an extra method/lookup right?
anyway side tracked its not important, your project
The scriptable objects are converted to blobs, and a struct container matches the SchnozzleReference to that blob for that scriptable object
ok, back to the topic
From my understanding of how the tick updates work, if the client sends a command at tick 100, and then updates that dynamic buffer, it should only be overwritten if new data is received by the server that was originally created on the server at tick 100, right?
And would then re-predict to the current time
you can try ICustomBootstrap and then adding those systems that you want (my custom world hasn't been updated since 0.51)
are you overriding a buffer on client that's being sent from server?
Yes, both the client and server write to this buffer as part of the prediction loop
Since the client is trying to predict the contents of the buffer in this case
So yes, if the client receives new information for the tick it previously wrote data to that buffer, that data would be overwritten, and then the prediction loop would run (from my understanding of how prediction works)
Is this correct, or am I misunderstanding something?
sounds about right
Ok, so then here is the issue:
This is the client sending a command on tick 793. That data is then processed by the client and server in the prediction loop
This is the buffer on the frame where the command was executed on the client:
However, due to latency the command has not reached the server, but that should be fine since the client hasn't received buffer information for the tick he is currently at. But for some reason on the next client frame, the buffer is empty:
ICustomBootstrap is something that was added a long time already in Entities (it present in 0.17 AFAIK), and I can't tell cause don't remember, but there was a reason why I don't use it and instead use manual world initialization from monobehaviour
Then, once the server receives the command, it is populated back to the client:
(blue is the server)
because the buffer is empty on the server so it's sent you that
But it's not empty on tick 793
it's not being populated on server until it receives your command sends you back its own data
The client is ahead of the server
how's the client issuing the ability?
yes but data from server is 3 frames behind (it looks like)
so for those 3 frames your data is being overridden no?
As an IInputCommandComponent (basically a command data)
But the point of prediction is for that not to happen
The data the server sends is always old
So the client re-predicts the state on the server from the old snapshot data
if it's in the command queue the buffer will be readded over and over again
https://docs.unity3d.com/Packages/com.unity.entities@0.51/manual/world.html#custom-initialization I think this is what you want if you don't care about Unity creating creating the default worlds and you just want to do it yourself.
That would have been my thought, but for some reason that's not happening
I would assume on prediction, the client gets the "old" data, and then re-adds it
and the command queue is correct?
you're predicting off the commands
But the prediction loop would reach the command that has the executed ability in it
and should re-add it
correct
it always predicts back to the "present"
This is the only explanation imo
But it uses the IInputCommandComponent from netcode 1.0, which should make this automatically correct
I can check the auto-generated buffer though and see if I find anything
there are some pitfalls with command queueing
it can happen that the prediction overwrites it
i'm unsure why abilitystate is even a ghost component - why is it not driven from the command
pretty common mistake from what i've read and had myself
You need to roll back to the old data so you can predict, so the server has to send it
i don't think this is true at all
if i send a start ability command at tick X all clients/server should be able to predict forward from this themselves
How do you roll back without the old state though?
Anyone knows how to manually initialise
i think tertles point is that they should always be calculated from the commands. which means the buffer would be empty everytime a new prediction starts
But the ability can run over hundreds of frames, prediction doesn't go back that far
if the data isn't too much i'd just keep it as it is though
if it's a been a while but i think prediction rolls back from ghost snapshots, not from data you arbitrarily set on client
you could split the data then. it seems the are getting in the way kinda. persistent data and input data that is
Yes, that's why the data needs to be sent
So it is in that snapshot
how are you sending this buffer though?
as a ghost component
you haven't posted your command
wait - dont ghost components only get sent 1 way from server to client
They do
The command sent from the client so server is the IInputCommandComponent I mentioned earlier
This is read back in the prediction loop, which starts the ability
yep ok
I think I may have found the issue though, let me check real quick
but anyway i still dont see why/how this buffer needs to be synchronized
So that the client gets sent the old snapshot data to then forward predict
but you can predict this just from the command
No necessarily
Say the ability runs over 2 seconds, and the client position is slightly out of sync. The client entity is hit by a stun on the server, but not on the client, interrupting the ability. It then needs to send the ability state snapshot so the client can re-predict the correct state
Sure, if you send everything else that can influence this buffer, you don't need to send it
I don't know if that's what I'll do. For now this is much easier since it assures they can't go out of sync
The issue was a really silly thing btw. Thanks for the talk though, it helped me find it.
Rubber ducky method always works
anyway this is mostly just from our game syncs way too much data
and we have network issues
and i'm always basically trying to find savings >_>
what was the issue just out if interest
It was a side effect of the command buffer, related to my issue with the InputEvent struct detailed here: https://forum.unity.com/threads/inputevent-payload.1366722/
I have this component on the thing triggering the ability:
And it was missing the ghost component fields, meaning the client wasn't re-executing the ability on prediction
The counter is what you mentioned yesterday @rotund token , as a workaround for events in a command buffer
I hope to get rid of it again though and just use InputEvent if I can figure out what the issue is there
Definitely, and I agree with you that it probably shouldn't be synchronized if possible, since each buffer element is pretty big
I've not done any sort of network optimization yet though
is this related to the problem that you press a button like jump and sometimes it doesn't do anything?
Yes
ah yes that would be an issue ๐
{
public static bool Has(ref this TransformAspect.Lookup transformAspectLookup, Entity entity)
{
Check.Assume(UnsafeUtility.SizeOf<TransformAspect.Lookup>() == UnsafeUtility.SizeOf<TransformAspectLookup>());
ref var ta = ref UnsafeUtility.As<TransformAspect.Lookup, TransformAspectLookup>(ref transformAspectLookup);
return ta.LocalTransformComponentLookup.HasComponent(entity);
}
public static bool TryGetAspect(ref this TransformAspect.Lookup transformAspectLookup, Entity entity, out TransformAspect transformAspect)
{
if (!Has(ref transformAspectLookup, entity))
{
transformAspect = default;
return false;
}
transformAspect = transformAspectLookup[entity];
return true;
}
private struct TransformAspectLookup
{
public byte IsReadOnly;
public ComponentLookup<LocalTransform> LocalTransformComponentLookup;
public ComponentLookup<WorldTransform> WorldTransformComponentLookup;
public ComponentLookup<ParentTransform> ParentTransformComponentLookup;
}
}```
i really dislike that i need this
and i dislike it more than i'd have to implement it for every aspect
this was my fix back then. (counters are also fine) ```if (inputBuffer.GetDataAtTick(serverTick, out var input) && input.Tick != serverTick)
{
// new frame, new input
input = default(PlayerCommandData);
}
input.Tick = serverTick;
input.jump |= jump;
input.angle = angle;
input.autoAttack |= autoAttack;
input.moveDirection = moveDirection;
input.placeablePosition = inputPlaceablePosition;
inputBuffer.AddCommandData(input);```
Ideally I'd like to use the InputEvent struct, since that automatically addresses the issue
ah that must be new ^^
It basically just auto generates a counter for you
ah cool, was wondering how they would handle this. as i said, pretty common problem back then
i'd rather change the codegen tertle
there's no point in writing this ๐
Missing the Has method seems really weird. I initially thought they hadn't even put in a lookup for aspects yet since I didn't see it in the aspects documentation
no package changes!
you know how annoying that would be for my 15 separate projects i have to maintain
give dani a friendly ping ๐
systemapi QueryBuilder also really needs an aspect option
are aspects uaed internally? seems odd they never needed a has to an optional comp
If the component is optional on the aspect itself, and you already have the aspect, you can just check there directly. Maybe they just rarely used the aspect lookup functionality? ๐คทโโ๏ธ
the thing is, i very specifically don't want to just 'know' the underlying types the aspect uses
because one of the nice things about aspects is they can completely change the required types without me caring
they could redo the transform system again completely and as long as all i'm using is the transform aspect it no longer matters
Yep, I was just trying to rationalize why this could have not been an issue for unity internally
i'm not going to speculate, i believe it's probably in some task tracker as a todo
Hopefully
unity uses like 2 aspects in physics. none has optional comps
i'm not sure how this should work. WorldTransform is optional. when you access via get, you get a RefRO value. i see no safety then
oh nvm, public unsafe bool IsValid => _Data != null;
a has lookup only needs to check the non-optional components
yeah, back to the same conclusion
but yes the safety is built into the generation of the ref components
so all it really needs is the generated ComponentLookups to be public
i don't think so
i think those should be hidden from users
i just think it needs to generate a has method and check component lookups for us that aren't optional
wouldn't work when the optional tag changes and the Has method is gone then
what do you mean?
if the signature changes the code gen would update the Has method
i don't see the point of hiding the lookups. they are core to entities
because that's the beauty of aspects
you don't care about the underlying data
you can change and refactor it completely
as long as the aspect methods itself don't change then it doesn't matter
but you do know with wanting to know if a certain comp is available
i dont care what component exists
i just want to know if the aspect is valid on a certain entity
It's like designing and interface, exposed functionality doesn't care about the internal state
(from the outside)
huh? lookup does exactly that
?
He wants to know if an entity fulfills the requirements to be called a specific aspect
So that certain functionality can be executed on them
If that makes sense
hm, i dunno. there's nothing specific when optional is involved
i just want a handy method
what do you mean
The functionality is specific. The methods can decide what to do with optional components
optional is completely irrelevant to this discussion
The caller only cares that the method can be executed on the entity
(regardless of what components the aspect actually has)
That's why exposing the lookups is probably a bad idea, because it makes refactoring it much harder (if you were to use the exposed lookups a lot)
var entity = state.EntityManager.CreateEntity();
// ArgumentException: A component with type:Unity.Transforms.LocalTransform has not been added to the entity.
// as far as i can tell I have no way in checking this would be an error
var aspect = transforms[entity];
// I just want these (which I have now implemented but only for TransformAspect) - please code gen them for me!
if (transforms.Has(entity))
{
}
if (transforms.TryGetAspect(entity, out var aspect2))
{
}```
How would you implement "actions" in an ECS ? Whats your typical approach ?
Like player and mobs are entities... all nice and makes totally sense.
But how do we deal with actions ? Like "Build that building over there, move there, place it and increase its health till its full"... or "Damage that entity in an interval, cancel when out of range or when its dead or some other condition was met".
I find this pretty hard to implement as components since they are getting pretty complex, however it does also not make sense to have that as its own entity.
it does also not make sense to have that as its own entity
unity dots shooter implemented abilities/actions as their own entity
So we would handle it as its own entity ? Basically an entity to controll other entities ?
In the case of building actions that entity would make sure that the player actually moves to the place and at some point it would "kill" itself to release the player and finish the building action ?
i'm not saying it's the best approach or how I'd do it (i would consider it though considering my success with effects as a standalone entity)
i'm just pointing out unity thought it made sense when they were doing something similar so it must be worth investigating
we do abilities states as entities at work though
an ability/action system is pretty complex if you want it to be extremely flexible
but it definitely pays off in the long run if you can make something very generic
I'm trying with a graph system that uses blobs, we'll see if I have to change it to entities at the end...
The major pain is node state
Alright thanks, im gonna look at that ^^
Since a flexible "action system" with components only is real pain... for example i currently have like 8 components to handle the building process...
Like some components doing range checking, placing it once the space was reached, some increasing the health of the building to "build it", some doing other stuff... only to make it flexible. Its a real pain actually xD
I have made something similar to Unreal GAS, entity as actions and effects. Condition to action such as range check would be done in "Request to activate step" for actions of specific type, if you want to share that request you can make it more tied to a component. Building to increase health would be from a gameplay effect that would give flag of being built and increasing hp.
private NativeArray<PhysicsCollider> physicsColliders;
private int entityIndex;
public bool OnChunkBegin(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
{
this.hits = new UniqueHitsCollector<DistanceHit>(0);
this.physicsColliders = chunk.GetNativeArray(ref this.PhysicsColliderHandle);
this.entityIndex = -1;
return true;
}
private void Execute(Entity entity, ref Cluster cluster, in TransformAspect transform)
{
this.entityIndex++;
if (!cluster.IsNotInitialized)
{
return;
}
cluster = Cluster.Initialize;
if (this.physicsColliders.Length == 0)
{
return;
}
ref var collider = ref this.physicsColliders[this.entityIndex].Value.Value;```
OnChunkBegin is as good as I expected. I can do chunk based any checks now in IJobEntity without a lookup
Do you store per-node state?
we are more like, ability start -> create entity
server/client simulate this independently
with their animations etc
server just has timings that it waits for which should match client
you should not use this project as a good practice though
our networking is jank as
Yeah but say you have a sequencer node that needs to remember what index it is currently "running"
we just have stages
windup, execution(s) etc
windup is just a delay on server, on client it would play say a swinging motion of a pickaxe
execution would actually mine the node on server, on client it tries to predict this
I see
I'm using a graph based system, and am still not sure if I should design it so each node is truly an instance when an ability is running, or if the state of the ability is just a single thing stored on the entity. The latter would mean I can only remember the state of the currently running node (without trickery)
again do not copy anything from work ๐
That's the scratchpad bit I posted yesterday
if i was writing this myself
and i intend to sometime next year
i would use a graph (re-using tech i did for my AI)
i would try to make nodes stateless though
(again what my ai does)
Don't you think that's a limitation on design? I'm still unsure
i don't think so
i can store state on the entity
it just won't be stored in the graph
How would you store per-node state though?
again i haven't really thought about this much yet
but first thought is most nodes need similar data
for example, when it entered node (to determine how long it needs to stay in node etc)
so this can be mostly stored in a single component
and just relate to current node
That's what I currently do
This is the context that is passed to the node
Where this is the state
But the scratchpad can only "remember" the state of the currently running node. I'm unsure if that's going to be an issue in the future
The other concern with this I have is that I would like to make it possible to design abilities in game at some point. This approach with blobs makes that more difficult I think
An entity based approach where each node is an entity would make it trivial to sync to clients and modify by clients
I guess alternatively you could use entities to store "custom" abilities and when changes are detected you could rebuild the blob asset for that single ability at runtime
is ability state a buffer because you can be in more than 1 ability at once or something?
Yeah
makes sense
This is my parallel node code
It basically just starts each connected port as its own ability
Sequencer nodes are actually pretty difficult to implement with this system, since they need to remember their own state. Alternatively you would need to write the sequencer stack somewhere, but I'm trying to avoid using pointers to make future serialization easier
(then again sequencer nodes don't actually do anything besides make graphs more easy to organize)
Some things you can cheat, such as repeat nodes by just creating more nodes during blob creation
I think the approach that would give the most flexibility, is have each node be it's own entity, and when an ability starts, the nodes are copied and all hold their own state. This would probably be much slower, but would make it much easier to implement custom abilities and node state
Alternatively create a single entity per ability with a dynamicbuffer on it that stores all nodes with their respective state, and use a type punned union to store the different data layouts
Maybe I'll try that and see how it goes
Does the profiler no longer show (Burst) on bursted jobs in the timeline ?
it shows as green doesn't it
I see, thanks ^^
not it's blue :
Would events in total also be their own entities ? I also struggled with that part... For example collision events, each entity has a collider... when entity A collides with entity B i wanna execute some logic.
My current solution is that each entity gets a Collisions component with a list in it basically to track collisions, theres also a "CollisionsEntered" and "CollisionsLeft" component which are getting attached once a collision lefts or enters.
This way im currently reacting on collisions... however this is not really "clean" in my opinion, since events are not really "data" which should be stored in an entity.
but yes it does still show (Burst) on jobs
but not for ISystem it doesn't seem
but they do appear in green
My bad, forgot I had disabled burst compile to debug last time :/
Is there a way to serialize a blob to bytes? Since the fields like blob ptrs etc are just int offsets inside the struct...
well since subscenes do this, yes
Since if that is possible, I can just serialize the blob onto a ghost component dynamic buffer to share it to clients if it's a custom ability
oh yeah you're doing runtime creation hmm
i would look at just using a blobassetstore per custom ability
or serializing / deserializing that
its only 3 hashmaps + a list
Like building components to synchronize the contents of it?
actually i guess each ability just starts as 1 blobassetreference?
what you want to serialize then is probably the BlobBuilder
It's a NativeHashMap<SchnozzleReference<AbilitySettings>, BlobAssetReference<AbilitySettingsBlob>>
if you just serialize the
blob builders
NativeList<BlobAllocation> m_allocations;
NativeList<OffsetPtrPatch> m_patches;
you could /easily/ regenerate a new blobbuilder on the client
and create the same blobasset references from it
Doesn't it use a bunch of pointers internally though?
yes you'd need to serialize out each one
:[
That's probably easiest though, since I could just serialize the scriptable object that contains the settings for the ability as JSON on the client, send it to the server, it creates the blob and syncs it on an entity
The scriptable object is probably easier to expand on during runtime than the blob format
I've never looked at blobbuilder and blobassetstore internally, so I'll take a look. Thanks for the pointers (hehe)
Ok the layout is actually a lot simpler than I thought
That seems doable
Can you not serialize a blob asset store at runtime?
I've barely used them
subscenes must serialize them
Kind of annoying that the blobbuilder values are private
yeah i think you should stick with blobassetstore
since thats how subscenes must handle it
you should just check what they do
It seems tricky to serialize the OffsetPtrPatches, since they store a pointer to the memory address of the offset field for a blob array or blob ptr
I'm not sure how to handle this, calculate the memory address offset in relation to the memory address of the constructed root?
In the final blob yes, but not in the builder
It stores the memory address in the struct
hmm honestly i dont know how subscenes save this
I wish I could just reuse their code
i've found digging through the source since their baking changes much harder to figure out
it just seems to magically do a step
then dispose stuff ^_^'

Couldn't I just memcpy the entire memory block of the stored blob data? Since I know the total size of the blob, and the entire blob is linearly stored in memory, couldn't I just copy that entire region into a byte array?
Then put that on a dynamic buffer, synchronize it to clients, allocate the required amount of memory, and copy it there?
is the entire blob asset store stored like that though
having a quick look it doesn't seem like it
the blobbuilder is
Really? I thought the blob is just a single block of allocated memory and all "reference types" (blob array and blob ptr) just store an offset for that memory block
There could be some unused space but that wouldn't matter
Actually, now I'm confused
Wait no, that's fine, right? It's taking the memory address of the offset field, and adding the offset field (an integer)
So the offset is relative locally to the memory block, not relative to the memory of the host machine
It's the same for blobptr
So I don't see why I couldn't just memcpy the entire thing...
Time to try it out!
as far as i can tell, a blobassetreference is a giant blob
which is setup from the builder
blobassetstore just seems to be like a collection of pointers. there doesn't seem to be any remapping to ensure they're all together.
which makes sense, i can just create a blobassetreference with any old pointer and add it to the store
Yeah, each one pointing to a memory block for a specific blob
I'll check the offsets, but it wouldn't make sense for them not to be together for a single blob
yes but that's created for a blobbuilder
so that will be packed together with other things from that blobbuilder
But It lives in the struct
This is the actual data that the blob asset reference points to
yes
BlobPtr only holds an int field as an offset for the memory location of the allocated data the reference points to
im not sure what this has to do with what i'm saying though
Maybe we are talking about different things?
๐
I'll try out my idea and see what happens
when you call blobbuilder.CreateBlobAssetReference
it creates a giant chunk of memory the size of everything you added to that blob
and stores it under the blobassetreference
Yes, so can't I just copy that entire memory block?
yes you can totally do that
That's what I meant ๐
Really?
If the blobptr just points to "5 memory jumps below me" that would still be valid in the copied block
once you call CreateBlobAssetReference
there is no offsets anymore
oh wait
thats not true
no i think you're right
The offset is stored in the blobptr
How else would it know where the memory is
Same for blobarray
yeah i think that'd be fine
Thinking about this also made me finally understand why blobs need to always be passed by reference
I never understood why it didn't copy the entire struct, but with this "pointer" layout it makes sense
just watch out for this gotcha
{
get { return ((BlobAssetHeader*) m_Ptr) - 1; }
}```
the header is stored at -1
so you need to serialize
from: ptr - sizeof(BlobAssetHeader)
length: header.length + sizeof(BlobAssetHeader)
actually you might not need the header
at all
just serialize
header.length
ptr -> ptr + header.Length
much easier to reconstruct
Create(void* ptr, int length)
and it'll setup the header for you
are there any issues with setting the internal values of a native array?
Or is there some fancy method to create a native array from a pointer
NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray seems to do the trick
Anyways, time to sleep now ๐ด thanks for the help ๐
unity rigidbody can not be used in burst jobs, right? i need the dots ecs for that?
nothing managed is allowed in bursted jobs
with tiny utility exceptions
hmmmmmmmmmmmm finally dived into my actual test game
and baking feels like it falls apart from large scenes
it takes me over a minute to open my test subscene
it's not even that large
(there's a bit more than you can see due to lods hiding small ground details)
closing subscene just as bad, this is feeling shocking atm
I hate baking ๐ฅฒ
Unity.Collections.NativeArray`1[T].FailOutOfRangeError (System.Int32 index) (at <44569b2d1c974b5eb5e85c3450cfe46d>:0)
Unity.Collections.NativeArray`1[T].CheckElementWriteAccess (System.Int32 index) (at <44569b2d1c974b5eb5e85c3450cfe46d>:0)
Unity.Collections.NativeArray`1[T].set_Item (System.Int32 index, T value) (at <44569b2d1c974b5eb5e85c3450cfe46d>:0)
Unity.Entities.Editor.HierarchyNodes+FilterSubSceneNodes.Execute () (at Library/PackageCache/com.unity.entities@1.0.0-pre.15/Unity.Entities.Editor/Hierarchy/Model/HierarchyNodes.cs:626)
Unity.Jobs.IJobExtensions+JobStruct`1[T].Execute (T& data, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, Unity.Jobs.LowLevel.Unsafe.JobRanges& ranges, System.Int32 jobIndex) (at <44569b2d1c974b5eb5e85c3450cfe46d>:0)
Unity.Jobs.LowLevel.Unsafe.JobsUtility:Schedule_Injected(JobScheduleParameters&, JobHandle&)
Unity.Jobs.LowLevel.Unsafe.JobsUtility:Schedule(JobScheduleParameters&)
Unity.Jobs.IJobExtensions:Run(FilterSubSceneNodes)```
Unity.Entities.Editor.HierarchyNodes:Refresh(Immutable, World, SubSceneNodeMapping) (at Library/PackageCache/com.unity.entities@1.0.0-pre.15/Unity.Entities.Editor/Hierarchy/Model/HierarchyNodes.cs:353)
Unity.Entities.Editor.Hierarchy:Update(Boolean) (at Library/PackageCache/com.unity.entities@1.0.0-pre.15/Unity.Entities.Editor/Hierarchy/Model/Hierarchy.cs:550)
Unity.Entities.Editor.HierarchyWindow:OnUpdate() (at Library/PackageCache/com.unity.entities@1.0.0-pre.15/Unity.Entities.Editor/Hierarchy/HierarchyWindow.cs:350)
Unity.Entities.Editor.DOTSEditorWindow:Update() (at Library/PackageCache/com.unity.entities@1.0.0-pre.15/Unity.Entities.Editor/Common/DOTSEditorWindow.cs:196)```
also i seem to have completely broken the entities hierarchy window
i do not think it likes cinemachine's hidden children gameobjects ๐
if i recall baker doesn't like HideFlags
i personally like baking, i'm just not liking this cost
either physics or renderer seems to take forever
though i've just realized burst has been off so let's give it 1 more shot
kind of forgot that could make a big difference these days
oh yeah that makes a huge difference, like 10seconds now
well except now i'm just being spammed by exception from the logging platform in burst
sigh this has not been my night
Those trees look familiar ๐
Just went to bed but it's basically this assets sample https://assetstore.unity.com/packages/3d/environments/fantasy/azure-nature-167725
thrown in a subscene
I can share project when I wake if I remember
Gotcha, good thing I just bought that asset then.. Those are the trees ๐ - Did you also like me have a fun time changing the shaders to be DOTS_INSTANCING? ๐
I replicated the shaders in Shader graph
So I can easily switch between hdrp and urp
And I wanted an excuse to learn it a bit
Well, that would do it too ๐ - I decided to just change #pragma target 3.0 to #pragma target 4.5 and then add #pragma multi_compile _ DOTS_INSTANCING_ON.. As that too is often all you need to fix up an Amplify shader ๐
I do like the visuals of the pack and it's detailed enough to test things like my nav mesh
Been a great test scene
https://media.discordapp.net/attachments/976098503921131520/1020309191988105277/unknown.png
Also looks spooky with a cylinder fog
Agreed - loving it for the same reason :3
Oh the one annoyance was converting the terrain - need some dots support!
I am still having problems with how to structure my project / package.
Simple example:
I have an AI package that needs to do some filtering based on UnitFaction. Sure i could give the user that component and tell him to write to it but then i force him to duplicate data from his own Faction component into the "UnitFaction" component of my package. Id need a way to alias those components so that my AI could be setup to directly read from the package users "Faction".
This is not a problem for static data like a UnitFaction but imagine my AI reading Health from Units to reason about them. I dont want to needlessly copy that every frame.
Atm i do this with codegen but i wonder if i am missing some simple solution here.
its what i do :S
Code gen would be less effort
we already talked about it about a year ago or so.
i am slowly migrating everything to codegen from generics right now
Whole thing is a lot less effort you aren't trying to distribute it
And handle every possible case, sigh!
Could you just not make unit faction flexible enough that it doesn't matter if they have to use that
If you're using someone's library there has to be some expectation of using the components from it
I don't just install unity physics and create my own standalone collider and sync them together!
And by flexible I mean using like an int over an enum nothing crazy
Hmm it is an interesting problem
True. and for UnitFaction that wouldnt be an issue really.
ATM i use Codegen to create scriptable objects in which the user links his own componentType in order to create Generic Systems from that.
Now just in one of my more specific systems i was doing some UnitFaction logic that is not generic. and it just seems like such a pain to not be able to "alias" componentTypes
You kind of can with dynamic handles
oh i dabbled with those at the very beginning but hit some roadblocks. dont know if they got expanded?
I'm not sure they're missing anything
Just randomly thinking about something I hadn't considered
when i used them there was no dynamic buffer allowed i think
But you could totally have a job and system that works on a component that doesn't exist
(There's a dynamic buffer accessor)
Imagine if you simply had an attribute to put in a field
On create you can reflect get the component type and the field offset
And pass that to your job that was written separately well before this component ever exists
You know it's not that different to how my save system works
This is a fascinating idea
Wonder what I could use it for
Anyway I really got to sleep like 2 hours past when I was meant to
But now I'm just going to be lying here thinking about this
This is an amazingly fascinating solution, I just don't have a problem for it to solve
im trying to understand your solution and then give you the problem :). sleep tight
I'll write up a proof of concept tomorrow if I find time
@rotund token oh and i just remembered another issue with all of this. what if i want to read from components defined in some other package. like i wanna read the Physics Velocity and want to let the AI do some fancy dodge. Now as a package user I dont have ownership over any component. So my way of creating the reference by discovering an Interface on a component and using codegen to reference it would not work.
Quick question: I have a ComponentLookup<LocalToWorldTransform> for a job and feed the entities in question through a job execute. Long story short, I can read them just fine but when I try to write to them absolutely nothing happens (not even errors). It's marked with [NativeDisableContainerSafetyRestriction] but notably not [ReadOnly], sooooo... judging by the documentation I should be able to do this, no? Where am I messing up here?
do you get the struct and then write back?
i don't know abou LocalToWorldTransform? you sure this is right? it's possible your value gets overwritten
[NativeDisableParallelForRestriction] is enough
Mhhh, I can't promise that, I tried a bunch of things. Probably tried that? I'll check it out again to make sure.
Same here, really, I'm basically not sure about anything I'm doing lol. Why, what would seem more right to you?
with the new TransformV2 system, LocalTransform is what you want probably
you can use GetRef from the ComponentLookup. it's what you should be using as there's no struct copy involved, so a bit faster
Hm. Visual Studio is not happy with LocalTransform, it doesn't appear to be informed about its existence?!
var test = Transforms.GetRefRW(entity, false); test.ValueRW.Value.RotateY(5);
Surely that can't be right? (because it doesn't appear to do anything either)
Hm.
test.ValueRW.Value = test.ValueRW.Value.RotateY(5);
That appears to work. Confusing. Wasn't it the entire point here to get a reference? And if so... shouldn't the rotate just work? My poor reference-trained brain can't handle this lol
Oh. Nevermind, I'm a dumbdumb.
Okay, so, still no idea how this other way is supposed to work, but figured out how the GetRef works now. And you're saying that's the better way anyway, so I should just be using that and call it a day, yes?
then you are probably still on TransformV1. In that case you either use Translation or LocalToWorld directly. (start with Translation)
Hmmm. Is there anything specific you gotta do for that? Wasn't that just a 1.0 thing? Or am I mixing something up here?
are you using physics and/or netcode? then v2 is only available in 1.0pre15
so either you are on v1 or the namespace is missing to get LocalTransform
the quickest way is to check is, if the Translation struct exists. if it does -> v1
GetRefRW is used like this ref var test = ref Transforms.GetRefRW(entity, false).ValueRW; test.Value.RotateY(5); get the ref to ValueRW and then it can be modified any way you want
I think I did import physics in this project at one point, which broke all my aspect usage, so upon finding out that that's not a thing, I threw it out again. Perhaps that messed something up? VS can't find Translation either, so... idk?!
Yup, after I stopped being a confused dumbdumb I figured that out, too...
are you using the Unity.Transforms namespace?
yeah, new for 1.0
Hm. So.. the way I understood this is that you get the new transform stuff if you are on ECS 1.0 but it breaks when using physics or netcode, no?
hm, inspect the TransformAspect. it should be obvious which path is used then
it's either LocalTransform/... or Translation/...
before entities 1.0pre15 physics and netcode fored ENABLE_TRANSFORM_V1
i don't think you have set this but you can take a look in the player settings if that scripting define is there
I'm not entirely clear on what you mean by "inspect the TransformAspect"?
in VS, right click -> go to definition
Wait, am I just on an older version or something? I'm on 1.0.0-exp.12 and the package manager doesn't give me anything new. Is there a new repo out there or something I'm not aware of?
newest
edit in manifest.json: "com.unity.entities": "1.0.0-pre.15", - sometimes it doesn't show up in package manager
same version for physics too
Wait, does that mean physics works just fine now?
wdym? it runs fine, yeah, but as i said it forces transformV1 system in your version. so Translation/Rotation is used
No, I mean if I use both of the new versions, pre.15, does it work with the new system then?
yes
Huh. Cool. That's rather good timing. Now I just gotta figure out how to actually get them because I'm a bit slow, you see...
I assume that's not right, is it? :<
find physics here
looks good to me
and make it 15
same version for entities.graphics
it's pre.15 too?
And then just restart Unity or how does that work? Still needs to import the stuff somehow, no?
save the json and switch back to unity
yes, graphics is on pre.15 too
i don't use it in my current project.
Burst Occlusion Culling occlusion browser tool
was added, seems cool
Is it supposed to show up in the package manager? Cause that's still saying exp12
Reloading does nothing, pretty sure I'm doing something wrong here ๐ค
you did edit projectFolder\Packages\manifest.json right?
hm, it should reload and do it's thing then
otherwise restart unity ๐
works 100% for me though. never had to actually restart
Just restarted, still nothing ๐ค
it's com.unity.physics
Crap, right. Still, presumably it should've found the rest, no? Hm. Let's see
could have ended up in a parsing error
Nope, no change :|
Just read this question, to those qurious here's the answer:
ref readonly var can produce a defensive copy, see: https://tooslowexception.com/readonly-ref-variables-in-parameters-and-readonly-structs/ (which is the same thing that can happen with the in keyword) That's the thing we want to protect you from as BlobAssets are not allowed to be copied.
i can only speak to transforms v1 but writing to localtoworld before the system that writes from transform/rotation/scale to localtoworld will just be overwritten. You either need to make sure you dont have any transform/rot/scale component on the entity or you need to apply your own localToWorld transform after the "TRSToLocalToWorldSystem"
or you can just do what you are supposed to do and write to transform ๐
Frankly, I'm just throwing stuff at the wall and see what sticks, that whole system is a mess of me testing things to learn, so I wasn't awfully concerned with the right way of doing things, but more a way of doing things lol. The mentioned GetRefRW appears to work just fine though. Having said that, what do you mean by "write to transform"? Could you be a bit more specific?
Ill just copy out of the documentation cause i cant be as precise as that:
LocalToWorld = Translation * Rotation * Scale
If any combination of Translation (float3), Rotation (quaternion), or Scale (float) components are present along with a LocalToWorld component, a transform system will combine those components and write to LocalToWorld. ```
you are supposed to write to Translation / Rotation /Scale and unity figures out what the LocalToWorld matrix will be from there
that happens in "TRSToLocalToWorldSystem"
but as i said i can only talk about transform v1.
same basic principals should apply though
Well, apparently that's where I'm at right now anyway (or am I? I'm getting increasingly confused lol), if you followed the rest of the conversation. But how do I even do that? I'm not entirely sure I follow here :o
Figured it out now, thanks for the help (please nobody ask what happened, thanks >.<)
Oh yeah that makes sense, defensive copies are so obscured.
There's no actual implementation in my library just an abstract class. The nodes are written outside of it by the implementation.
is 2022.2.0f1 good to use? find it a bit odd that forum and hub still show b16 as the last release for 2022.2
Yeah I'm guessing they found a last minute issue or just waiting for a blog post
But I've had no new issues in it
i recently had my urp renderfeatures break, seems like a switch was flipped and some old api just doesnt work any more and the new api doesnt render transparency ๐ฅฒ so was wondering if anything else was coming up buggy or just my code
My urp fog Shader broke at some point from 2021 to 2022. No idea why. So I reimplemented in the new Shader graph full screen effects yesterday because I cbf dealing with these breaking updates
heh, just reported a build issue where a shadergraph shader that worked for 2019-2021 now complains of exceeding the cbuffer slots in the latest editor
Bugger, don't tell me that
i really wish i had some automation going cos I dont remember if I even tested a build prior to this version, been dealing with so many upgraded apis
I spent a lot of time last night thinking about the EntityHierarchy and despite how buggy it is on domain reload, it's actually pretty decent.
Decent enough that I think a user (i.e. me) would have it open and used on a regular basis. So recreating and maintaining it is not worth the effort.
And I think there's some charm to the flat list that entity debugger presented for their entity list.
I would have the Entity Hierarchy window completely replace the regular hierarchy window if it didnt throw a billion (23) errors every reload:
project is in a bit of a state atm as i'm still updating to 1.0 but i can throw you the profile data
profile snapshot
just the big spikes at the end, most costly being meshrenderer
also 7 seconds on hierarchy window though ๐
from that profile 7 seconds is entities hierarchy rebuilding and 12 seconds seem to be baking
Does anyone know why world time triggers structural changes when updating?
triggering structural change on what?
Unless universal queries can not have order change filter applied
noChange is returning false and the only entity that passes through is World Time.
world time used to write back to a component
i'm not sure if that's the case anymore though
{
public TimeData Time;
}
internal struct WorldTimeQueue : IBufferElementData
{
public TimeData Time;
}```
still seems to exist
{
EntityManager.SetComponentData(TimeSingleton, new WorldTime() {Time = newTimeData});
this.Time = newTimeData;
}```
Order filter should only be structural changes. A write to the component shouldnt trigger it right?
unless order is both value and structural change filter...
hrm
you should be able to look at journalling
to see what is triggering an ordering change
hrm, actually it's my queries are constantly resetting. Give me a min...
going to be honest, i don't really understand the need for this? couldn't you have just reimplemented the chunk part in its own window
just seems combined the 2 existing windows into 1
Yea... It's also a educational exercise for me to learn how to use UI toolkit.
in that case i'm all for it!
ui toolkit is great
i'm most interested in your chunk port
I learned a lot doing this. And I agree, UI toolkit is amazing.
thats actually new content
I actually spent a few hours last night staring at that on my window and wondering, what am I doing?
you have done a great job on it
Because the Entity Hierarchy, minus the bugs, is actually really good.
it just seems like a pain to maintain
And I really didnt want to spend the time to recreate the EH.
I'm using a lot of the backend of the systems tab to create my systems list.
So if something back there breaks, the list viewer dies. But the entity list is ultra simple. Just iterate through the worlds and create universal queries.
The search functions I might just cut out. Too much work maybe. And I personally havent used them yet. But now it's the chunk viewer. Component viewer might get cut though. I dont like how it looks.
Yea, it's looking like I'm basically recreating DOTS windows but I would argue that I'm recreating classic Entities with DOTS characteristics.
Just need that chunk utilization widget
Yep. Working on that right now.
Alright, for selection to work, there can only be 64 worlds and 16.5M entities in total. Tertle, if you're using more than 16M entities across all worlds, Im sorry but this debugger will not work.
Yea, which is why I'm thinking of a way around the issue
while i am no longer hitting my previous highs due to capacity limits, i still like testing on 20M as an equiv
i dont think its that big a deal
it's a dumb test
anything above like 5m is dumb
Main problem is that element list indices are limited to ints. And I'm packing the first 6 bits with world index and the next 24 with entity index.
Okay, I got some assertions in there to cause a million errors if entity count gets too high.
filter bottom?
button*
i much prefer the search all components instead of c=
if i have more than like 8? components starting with
StatX
and i can't remember the full name it's very limiting in the drop down
or if i don't know what it starts with
SuperStatHealth or something, i can search Health
I was thinking about incorporating that into a components subwindow. Next to chunk info.
Although hrm, search...
Alternatively if you're looking for only the components in that filter window, I can just improve the search function.
what a trip, checked my youtube channel and watched my first small game release from 2013. https://www.youtube.com/watch?v=bCFqB_KgLRo I should make this available again
i've nearly forgotten i ever made this ๐
yeah, shouldn't take me that long
hmm yes i get that but in my case i dont want the user to write an implementation at all. It is all handled in Editor with a graph UI.
If i dont have ownership over the PhyiscsVelocity Component i cannot add an Attribute/ Interface for it to be discovered. So i cannot codegen the necessary reference to expose it to the user in the UI as a Scriptable Object. I can make him write that reference on his own (or just let him specify the the type he wants to codegen the ref for) but thats bad User Experience :S . I just dont see a way around that atm.
for my save system i have 3 approaches, attribute [save], manually adding types, but also i add some default types from unity libraries (localtransform, physicsvelocity)
i don't think the experience is that bad
from what i heard, some people don't like populating their components with attributes
so would rather be able to just pass a list of types in
that they can generate their own way
i think flexibility is key anyway
that said, im not certain what you're doing so i can't say that this is appropriate at all
hmm passing a list of types is a good idea.
my solutions atm are:
codegen a single ref for a single type (i should probably just make the userexperience here better...)
codegen all refs for components implementing a certain interface
manually write the script
the problem with attributes is always if they are using your library, they could be using someone elses third party library as well
as convenient as they are, often just can't add attributes to things you want
unless you do like assembly level attributes with a type
just having a scriptable object where the user can add types from any assembly to codegen references from sounds good enough as an alternative
at some point im slipping you a copy ๐ its just not untangled enough yet to export T_T
i will be fascinated to have a look
you are definitely doing some unique stuff that i haven't seen anyone else do
and it's stuff that is focused on what i care about (usability)
i guess early DOTS just attracts a different more hardcore code crowd atm. especially since usability of DOTS itself was not the best for a while ๐ glad to hear im not boring you with all my problems
i hang out here for the interesting problems and inspiration
i barely slept last night after our convo
and the ideas i had with what i was discussing
its been a rough day ^_^'
oh no. i try to not look into discord / any code 1-2 hrs before bed exactly because of that reason
emphasis on try...
I was already in bed trying to get to sleep and restless
Checked my phone 2 unity devs responding to my rant
And then a fascinating discussion with you
Yeah that was a mistake
lets not make the unity devs feel bad for answering here! ๐ its so great they check this channel from time to time
btw i am having the same kind of issues with other "packages" as well.
Abilitites can stun. Movement needs to react to stun. now both "packages" would need the same Stun component to work together or have unnecessary duplicate data.
I need a general pattern to solve this interop between packages / assemblies
just combine them into one?
or create 3rd one
with common buffs
but if its packages i have no ownership over the components. i cannot combine them. id want to have a way to so to say write adapters between them
sure you have ownership and could potentially edit the source but it then breaks with every update...
wouldn't it be vice versa?
like, if you hardcode reference to specific component type
it would be persistent between updates
meanwhile some soft link using reflection or smth
will more likely to break between updates
what i mean is if you update the package you need to redo your changes to the source
I don't get it. Are those your packages or not?
for the sake of argument no
๐ฅด
I don't understand why, but one way I see it
your packages use static init method
at some point
which obtain through reflection assembly attribute
which contains type
which then you use to get ComponentType
you do it with both packages and now they are dependent on this attribute, which gets assigned in assembly which references them
Wait till you realise you can be stunned from multiple places
you need to ref count it ^_^'
(this is why i'm so in favour of one write, many read)
i know im drifting into hypotheticals here but if id use someone elses ability package id assume he had that handled internally. id just have a way to trigger a stun from anywhere and also read from anywhere that i am stunned.
my issues arise when id have another package like AI that would need to reason about Stun. now it needs a way to know that the AI.StunComponent is the same as the Ability.StunComponent.
And both components can actually be totally different.... there would just be a way to interpret one into the other
I figured for myself that implemented mechanic cannot be modified, so if it wants to use specific component - it will only use that. And if someone wants to change that - he has to disable mechanic (system) all together and create his own
as i said i as a user of both packages would need an "AdapterComponent"
or just add new that will work together
otherwise we go into spaghetti zone where one depends on the other...
i see it the other way around. if i am not able to make packages work together easily then ill create chains of dependencies between packages cause they will only work together with specific other packages
why not have one hierarchy?
main package with most of core stuff and then packages that only rely on it, but not on other
or vice versa
unity themselves dont have that problem because they only ever have one package of a kind and just declare their components as the standard to use ones. when other users create packages they dont have that luxury
as long as its all your packages it works out ok like that.
how? youd need a core package that every dev would agree to?
they have a luxury to reference everything main game has
ahem. Are you talking about game modding or smth else?
i am talking about packages in unity
๐ค
I think Unity uses compiler constraints for that
#if PACKAGE_X
use <T> comp
#elseif
use <Y> comp
#endif
yes and they can do that because they know all of their packages and only care for theirs
what if the package doesnt have a component for stun
but stun is just an index in a buffer
that represents an arbitrary stat 'stun'
true. makes it even more complicated :S
thats effectively how my stat library works
there are no components, just 1 fixed buffer that represents everything
yes i remember. there are so many different ways that a 1:1 translation of components cant work
so maybe duplicating the data into the specific Package Components is the only real way to interop ...
Atleast for packages I create I could imagine some kind of AdapterAspect that needs to be adjusted outside of the package itself where the user can implement his own logic on how to read for example tertles stat Buffer.
why even bother with packages though?
"Everyone wants to write a framework, but no one wants to use one"
cause i cant write everything from scratch every single time
but smth like movement and ability which depends on specific Stunned component doesn't sound very generic to begin with
Could probably limit it to smth not directly related to game mechanics
if i work out my chunk like this: cs int2 Chunk = new int2((int)transform.position.x / ChunkSize, (int)transform.position.z / ChunkSize); Then logically i should workout my chunks centre world space position like this right? cs int3 ChunkCentre = new int3(Chunk.x * ChunkSize / 2, 0, Chunk.y * ChunkSize / 2); From here though im less certain, like how would i work out the chunks max corner position, like this?```cs
int3 ChunkMaxCorner = ChunkCentre * 2;
movement is not a thing id want to have generic. i do have a rather generic abilitysystem though.
I mean systems like that usually don't rely on anything but entities packages, so
and you are likely to change it to suit needs of game anyway
well you need to go from the center of a chunk half a size into x and half a chunksize into z direction to hit the corner no?
i dont know, im not good at math, i dont even know if my ChunkCentre is correct, although i hope it is lol
i also dont even know if my ChunkSize is a halfsize or one full length lol
max corner is just chunksize * chunksize
no? Cause chunks could be anywhere, the max corner isnt fixed?
why is your ChunkCentre not based on translation but on chunkposition?
id say you should probably look at how tilemaps work as an example to do this
nvm makes sense
ok ill have a look at how tilemaps work, thanks
any good examples to look at first? (google aint pulling anything up so far...)
โ
Get the Project files and Utilities at https://cmonkey.co/gridsystem
๐ Get my Complete Courses! โ
https://unitycodemonkey.com/courses
Let's make a Grid System that we can use to split our World into various Grid Cells.
Then we can use that to make a Heatmap or a Pathfinding Map with avoid/desire areas or a Building Grid System.
Complete Grid ...
thank you!
I just upgraded to pre.15, replaced all the transform related stuff in my code and now I'm running into the strangest issue. I'm not entirely sure what's happening, but something's not right with my transforms now and it basically broke everything. I made a little test object to figure out what's happening:
Test has a little move component (as simple as it gets, really), body is just a box, wings is another box and the two guns are also just boxes
Oddly, the body moves fine, the rest stay at origin
And it confuses me to no end oO
are wings attached as game objects or in runtime?
It's a gameobject
how does it look in hierarchy then?
try without live conversion
Same thing
I mean hierarchy
I'm not sure I follow?
show hierarchy
with closed subscene
live conversion is borked
it won't work correctly
and it shows game objects
not entities
You mean this?
Well, that's the entire scene, there's only one object in there which I would assume is the cube, since that's actually moving. So I guess the question is why did the rest get loose?!
Don't mind the changed IDs, was just playing around
But yea, that's the cube
Hm. With that only the one single gun gets left behind
Uh... okay, now children randomly teleport around when I change scale (building a second test object to narrow this down). Something seems really messed up right now. Also upgraded to b16, anything known about that version being weird with transforms or something?
Looks like only 1 child exists
Meaning other gets unattached for some reason
Yup, it would appear so. I can't seem to figure out why though. Hmmm. Maybe I should run this test on an empty project, perhaps some system somewhere is doing shady stuff ๐ค
They are basic primitives, they have whatever new objects have
Check subscene outside of game mod
How does it look?
Is it already borked or still OK?
I'm not sure what you mean "outside of game mode"?
I mean, they just appear in the normal gameobject form then, no?
(I'm frankly still struggling to figure out the entities hierachy...)
wondering what would be the Unity.Mathematics version of FloorToInt()?
Close subscrne
And look in hirtarchy
Uh... this is presumably my ignorance speaking, but everything just disappears and the scene says not loaded?!
Ah!
Okay, uhh
Well, yup, still looks borked
Hmmmm
That worked fine before?!
Wait, that can't even be it, can it? I'd imagine it breaks even without anything attached. Lemme test...
Yea, it someone only actually make the first object I add a child and everything else gets thrown out (or something like that, unclear)
Whether it has any baking on my end or not
Hmmmmmmmm. I just deleted the physics package on an out there hunch and now it randomly seems to be working ๐ค
Uhh... yup, everything is back to working as expected...
You sure your wings aren't physics objects?
Yup, as I said, I just made the thing to narrow things down, it's literally just a bunch of right click add cube type of deal. I mean, I supppose that means they have colliders, but that shouldn't explode everything, should it?
Nevermind... apparently it does explode everything. Huh...
Welp, guess I have some reading to do on the physics system, huh?
oh man going down this terrain rabbit hole right now
is it normal behaviour for managed bits to disappear in subscenes that are open? like particle effects, visual effects, terrain? I dont remember this happening prior to 1.0.x
Implemented a own quadtree for having AOI events when an entity left or entered or even stayed in the AOI of the player for example.
How would you implement those "events" ? As event entities like : Entity{ AOIEvent{ firstEntity, secondEntity }, AOIEntered } ? This way systems could react easily to those to network stuff e.g.
Any downside of this approach ?
downside is you have structural changes each frame which are quite expensive if done very frequently
you have other options like NativeStream to write events in parallel onto it. or if parallel is not necassary just a Dynamicbuffer on a singleton Evententity where you list all the events.
Oh, probably described it badly...
I basically mean that i realize AOI events as seperate entities... like when a new entity appears inside the players AOI, it will create a Entity{ AOIEvent{ firstEntity, secondEntity }, AOIEntered } entity which acts as an event. No structural changes here... and that one can be queried for systems to react to it.
Oh one problem i see is that this would still be kinda expensive since the AOIEvent references two entities and we need to acess their components manually then : manager.GetComponentData<..>(aoiEvent.firstEntity); ...
However thats probably cheaper than doing structural changes ?
spawning an entity is a structural change
what i do is just tagging all Entities with a component that are in the AOI of the player. works well enough for my usecase. and i think structural changes are ok if your objects stay in the area for long enough.
this way it lets me query all objects in the AOI directly
Oh i thought you mean adding/removing components ^^
Well tagging entities is actually also a structural change right ? And probably even more expensive since it copies the entity to a different archetype/chunk... So will it might be more performant to just spawn in event entities ? ^^
with tagging i refer to adding / removing empty components. its a structural change yep
the best thing is to not design events as entities
how was LOD handled by unity?
the only exception now is if the event entity is persistent and enable/disable can be used
that should be a good pointer on how to do this
In this case ( even if its empty ), it will still copy the entity to another archetype... which is actually more expensive than spawning in a small event entity, right ? ^^
Atleast it would make sense for me that creating a small event entity is faster compared to copying a rather large mob e.g. to another chunk.
And why ? ^^
because of the structural change overhead
I thought Unity still recommends the tagging style for event-based on less-then-per-frame events
im not the expert on micro optimization here but id say its basically the same
its also just too convenient not to use if it doesnt wreck your performance
filtering chunks incurs a structural change but down the line reduces your cache misses. its a tradeoff
Does unity really recommends this ? Kinda funny since i always here "avoid structural changes !!!!" and similar stuff
yeah because they don't want to open a can of worms how to do it better ๐
it's okay if the entity count is low but that solution doesn't scale well
@viral sonnet what would you say how is your usage of tagging vs enable/disable?
Archetype swapping with smaller component loads shouldnโt be a huge bottleneck, I think the idea is to lean more into ECSโs โdynamicโ ability to add arbitrary functionality to an entity
id say i do 90% tags 10% disables max
on a full archetype 16k are 16k. no difference in how many comps you have
For large amounts of entities i could actually think that event entities are pretty fast... since like a Entity{ StayedInAOI{ first, second }} entity has the size of a few bytes... the commandbuffer could bulk create them fairly easily and fast i assume. And the query speed would be considered "perfect".
youd have to have that event every frame then??
I thought if you have larger components datasets then 16kb it bumps to a larger chunk size
no it's not. i have tested this to death. command buffer is even worse
what you want is pre-allocated nativelist, nativestream or my parallel list which you can find in my discord profile (oh wait, i'll add the link ๐ )
Not really, the system capable of querying those entities could simply "remember" which were created to prevent spawning them in each frame.
So the fastest solution is just to put those events into a list instead of the ecs and systems processing events acess and read that list to do stuff ?
exactly
im not sure this is really faster if you just had some small amout of enter / leave events. tagging entities in AOI seems better because you can easily query them then. If we are talking very frequent events then definatly
and it's on a per-usage basis. in case you can utilize an enabled comp you should. that's also very fast but for everything else, specialized data containers will work best.
Also kinda depends on the usecase itself... if theres only one player, that works great... just get all entities with AOI and done.
If there multiple players with different aois... than this becomes a nightmare ( since you would basically need to map the entities to the players AOI )... in this case you can easily go with any other solution i assume
Wouldnโt it be simpler to use distance calculations over actually collision detection for persistent area triggers?
AOI is area of influence?
Thatโs what I assumed, that or Area of interest
so for my solution, similar to any mmo where you enter a certain radius of an enemy and the enemy aggros the player i used collisionWorld.OverlapSphere and write to my parallelList. i've tested triggers for this and that went really bad
manual overlapSphere checks scale really well
someone did a test a while ago where he checked wether its just faster to do the distance calculation in comparision to using Physics. if i recall correctly the outcome was that you need a really high number of entities before the physics package pulls ahead
there should be a forum thread around
Unless you have a lot of dynamic interactions that need to hot-load special effect components, I would imagine the constant expensive of some vector math might be more predictable then arbitrary physics collision checks
yep, straight up brute force works really well too
ooof i just checked my LOD system and i am using math.distance
instead of distancesq
that assumes a small count to check against but even what is considered "small" today, is quite big and easily in the 20k+ range
and it doesnt even matter. not visible in profiler for my entity counts
Yeah, my problem is the physics system is already doing all those exact same distance checks for itโs batching pass for collecting objects that might collide
So unless you actually need the physics simulation aspect of it, I would think it would be cheaper to just do the distance checks yourself on simpler volumes like rectangles or circles
for area of interest you dont need any shapes
That was my thought, if itโs just distance really, especially for static positions, might be worth it to create a system that saves those positions on a distance query component at the start, then just checks for distance < triggerDistance every frame in parallel, trigger some action via a book change when in distance
Bool* not book, damn it ac
Consistent cost is better then potential hitch in my book, especially with ECS where we get such tight control over memory/processing
How do you handle system dependencies on this ParallelList? Wouldn't a system reading your list need dependency on the system writing to it?
i handle each nativecontainer in a singleton struct with proper dependencies. before that i had to juggle jobhandles
it works really great. now i don't have to think about it anymore
Might as well throw it out here, anyone have a good idea how to handle a system where providing a essentially string ID returns a collection of methods for creating/updating particular archetypes of entities?
My initial thought was an interface with the methods, but Iโm having trouble loading the various implementation types into some sort of queryable system, my last resort is hand coding a large switch statement that just returns instanced structs, but I would prefer a more automatic solution
I thought of using a source generator and a registration attribute to create the switch statement on the fly during compile, but I cannot get scoping figured out for the generator and asmdefs,
Oh, forgot to say Iโm going for compile time constants as a constraint,
otherwise I would just use attributes to spin up a hash map of id/interface instances in a static class and use that, but I need it fast and accessible from job code, so static constants are best bet
hm, i don't have a good answer. have you considered generic systems?
source gen is the most powerful and flexible for this.
i use a mix for my stat system. that is, source gen and generic system/jobs
Hmm, I had not thought to containerize it with a generic, use constraints to enforce the interface, but thinking further on it, I would still need to hardcode the generics. I kinda wish attributes could run and do source modification at compile time without an external analyzer
yeah, no way around it when you want it at compile stage.
the generics would implement the interface at least. if not, code gen is your only option. then you are pretty much free to do anything
That seems to be where Iโm headed.
Iโve source generators before, so itโs not too bad, but Iโm having the most trouble with Unityโs weird scoping and inconsistent docs/behaviors vs normal c#, or maybe Iโm just misunderstanding something
Have you been able to properly scope your generators to asmdefs? I really donโt want to run the generator against every assembly under the sun each change,
I'm really struggling to understand how an open world workflow can work with dots and current baking.
As far as I can tell, any change that triggers a domain reload (or just opening unity) requires all subscenes to be re-baked even if it changes no dependencies (editor only assembly with post processing volumes)
A test area of 256x256 takes my 3900x 30s seconds to bake
Extrapolating to a 4096x4096 area which is 256 larger, would therefore take 128min or 2 hours to bake (now i don't believe it'd actually take that long but you get the idea.)
Seems like some type of caching is missing here
Even deleting an unused material that was previously used for a full screen pass on the renderer re-triggered all my bakers somehow
I thought that normal baking was more for less repetitive concepts like players or enemies, IIRC there is a way to batch gameobject conversion for larger sets of near-duplicates
i don't use an analyzer currently. don't need it. afaik analyzers pull the whole code, no idea about assembly constraining. it's fast so don't worry about it too much unless it slows you down.
tertle, that all sounds quite horrible ๐ฆ i wonder why it's that slow. that's absurd.
Just takes a while to get every material/renderer