#archived-dots
1 messages ยท Page 37 of 1
shouldn't you instantiate in server world and register the ghosts?
But I believe they should be able to remap correctly once connection setup properly
Do I have to have a prefab spawner wrapper for every single networked object?
Generally best way but it's not required I don't believe
Once the server sends a sub scene ghost it should be able to make to the disabled ghost
ugh. That will make per instance property override literal pain.
It sounds like you haven't setup a target on server yet
So aren't getting nearby ghost data
What about command target
And server (local host) receives it properly. I dont know where to go from there.
Or you relying on auto
Uh no. I disabled autoconnection
Setup a default cube spawned from server
Auto connection not same as command target
You need an Entity designated that receives commands
Gee, this would be great in documention...
Is this player input? I dont have any player input yet
I just want them to exist.
It's in here
commandBuffer.SetComponent(commandTargetEntity, new CommandTargetComponent {targetEntity = ent});
According to the updated 1.0 sample repo:
Yet this was not done for the getting started cube example. Where is CommandTargetComponent being created?
i remember witout a commandTarget nothing runs
Hazzah, I got a prefab spawned on the server world.....
I was missing one line on the server connection side. Dont forget to add NetworkStreamInGame component to the server's connection entity as well or else nothing will work
They use auto targeting
Which is what I was asking about before
But not through their frontend interface. I'm trying to mirror what they're doing with the neat looking frontend launcher.
Either way, it was my borked code copy paste anyways
๐ฅฒ How to fix this entity scene error? Until now I still can't get a working android build for my production project yet.
2022/10/21 11:27:28.300 4369 4409 Error Unity Loading Entity Scene failed because the entity header file couldn't be resolved: guid=ddbf76e59b749ef4699da3e5d016dc5a.
2022/10/21 11:27:28.300 4369 4409 Error Unity Unity.Scenes.SceneHeaderUtility:LogHeaderLoadError(HeaderLoadStatus, Hash128)
2022/10/21 11:27:28.300 4369 4409 Error Unity Unity.Scenes.SceneHeaderUtility:FinishHeaderLoad(RequestSceneHeader, Hash128, String)
2022/10/21 11:27:28.300 4369 4409 Error Unity Unity.Scenes.ResolveSceneReferenceSystem:ResolveSceneReferenceSystem_3ED87375_LambdaJob_1_LambdaBody(Entity, RequestSceneHeader&, SceneReference&, ResolvedSceneHash&, RequestSceneLoaded&)
2022/10/21 11:27:28.300 4369 4409 Error Unity Unity.Scenes.ResolveSceneReferenceSystem_3ED87375_LambdaJob_1_Job:RunWithStructuralChange(EntityQuery)
2022/10/21 11:27:28.300 4369 4409 Error Unity Unity.Scenes.ResolveSceneReferenceSystem:ResolveSceneReferenceSystem_3ED87375_LambdaJob_1_Execute()
2022/10/21 11:27:28.300 4369 4409 Error Unity Unity.Entities.SystemBase:Update()
2022/10/21 11:27:28.300 4369 4409 Error Unity Unity.Entities.ComponentSystemGroup:UpdateAllSystems()
2022/10/21 11:27:28.300 4369 4409 Error Unity Unity.Entities.SystemBase:Update()
2022/10/21 11:27:28.300 4369 4409 Error Unity Unity.Entities.ComponentSystemGroup:UpdateAllSystems()
2022/10/21 11:27:28.300 4369 4409 Error Unity Unity.Entities.SystemBase:Update()
usually just go to preferences dots clear cache
if that doesn't work, also restart unity and do another clear
then open/close your subscenes
should fix it unless you're actually doing something to break it
it's just an annoying bug atm
Btw do we still need to call ECB.AddJobHandleForProducer()? I guess ISystem no need anymore but SystemBase still need it?
not if you're getting it via singleton
i.e. SystemAPI.GetSingleton<EndSimulationEntityCommandBuffer.Singleton>()
Do u mean as long as are using SystemAPI.GetSingleton<EndSimulationEntityCommandBuffer.Singleton>(), technically it's doing ECB.AddJobHandleForProducer() under the hood?
no
it doesn't need to do AddJobHandleForProducer
as the dependency is managed by the component dependency instead
Anyone has a sample singleton entity for me to learn from?
Learn what?
anyone? ๐ข
Its use case, best practice on how to get/set them correctly, in jobs, etc.
Trying to setup a simple tile map walkable/unwalkable data for a lot of systems to share and use its data.
a discovery, incase anyone is curious: norton anti virus hates jobs (same with entities and burst)
Have you tried to turn safety on? ๐คฃ
Not sure how much of a dots question this is
How would the approach differ from dots vs gameobjects?
haha, nevermind, I can see now that the "jump" is part of the NavMeshQuery result, nothing magical here -- just my brain needed a break, I guess ๐
thanks tertle, somehow your answer helped! โค๏ธ
how do you use entitycommandbuffer to clear a dynamic buffer?
trying to replace all the values of a path on an buffer
so something like
var buffer = EntityManager.GetBuffer<FooElement>(entity);
buffer.Clear();
ecb.AppendToBuffer(buffer, new FooElement());
assuming it has something to do with SetBuffer
but can't figure out what it actually does
var buffer = ecb.SetBuffer(entity);
buffer.Add(new FooElement())
oh its temporary
it returns that buffer it will replace with
okay
you can use it there
yeah makes sense
other jobs won't see this local buffer until ecb plays back of course
yeah thats fine
but any changes you make to the returned buffer from SetBuffer will be applied during the playback of SetBuffer
thanks
including virtual entity remaps etc
it works fine
okay finally got all the pieces in place
god it took like 12 systems
just to get path finding in place
with repathing
deal with optimisation later
so far fine with 50 * 50 permutations x 1000 entities of path finding per frame
never gonna hit that limit so should be fine....
new RebuildColliderJob
{
Tree = _tree
}.ScheduleParallel();
// Wait for RebuildColliderJob to complete?
new CollisionJob
{
Tree = _tree
}.ScheduleParallel(/*RebuildColliderJobHandle?*/);
How to do dependencies on ISystem?
Need to rebuild collider before doing collision
Don't tell me I can just do this?
new RebuildColliderJob
{
Tree = _tree
}.ScheduleParallel();
state.Dependency.Complete();
new CollisionJob
{
Tree = _tree
}.ScheduleParallel();
Lol
how would you detect new chunks? How job would look like?
state.Dependency = new RebuildColliderJob
{
Tree = _tree
}.ScheduleParallel(state.Dependency);
new CollisionJob
{
Tree = _tree
}.ScheduleParallel(state.Dependency);
This way then?
When do I need to call state.Dependency.Complete();
I was just looking at this yesterday. Checkout the docs: https://docs.unity3d.com/Packages/com.unity.entities@1.0/api/Unity.Entities.SystemBase.Dependency.html Looks like if you schedule multiple jobs with ScheduleParallel, they'll be implicitly dependent on the previous one.
yeah
if it's IJobEntity
then you don't need it
codegen automatically creates such dependency chains for you
unless you want to manage them yourself
ofc
Ok that's really cool, thanks!
https://www.duskborn.com/posts/leaving-unity/ impressive optimizations in burst compiler itself
After three years of work at Unity Iโm leaving the company, today being my last day. Iโm immensely proud of the work I did to make Burst and HPC# so powerful for our users both within and outwith Unity, and to have worked with some really great people along the way.
I fulfilled a lifelong ambition to work closely with some heroes of mine like An...
Awesome stuff. That guy is a hero for contributing to Burst
Possible a real stupid question but.. we cant have a regular MonoBehaviour in a SubScene right?
Like have it do some stuff in its Start method
per assembly [BurstCompile] attributes that lets you specify the default options for an entire assembly
Does this mean I can change the default for all my code somewhere so I don't need to type [BurstCompile] everywhere?
https://docs.unity3d.com/Packages/com.unity.burst@1.8/manual/compilation-burstcompile-assembly.html yea it allows you to define the default options for the assembly
@rotund token How did you load the VisualTreeAsset in the system when using UI Toolkit?
My old UI solution used a bunch of convertToEntity so I'm trying to convert it now to UI toolkit.
I use addressables
make a call in OnCreate
and then once UI loaded, either create singleton tag <UILoaded>
or just do it OOP style
I'll try that, thanks
Here's how I do it
private class UIAssetManager : IDisposable
{
private List<AsyncOperationHandle> _handles;
public static async UniTask<UIAssetManager> Init(IReadOnlyList<UIBase> screens)
{
var manager = new UIAssetManager();
var tasks = new List<UniTask>();
manager._handles = new List<AsyncOperationHandle>(screens.Count);
foreach (var screen in screens)
{
var handle = Addressables.LoadAssetAsync<VisualTreeAsset>(screen.AssetAddressInternal);
handle.Completed += screen.OnAssetLoaded;
manager._handles.Add(handle);
tasks.Add(handle.ToUniTask());
}
await UniTask.WhenAll(tasks);
return manager;
}
public void Dispose()
{
foreach (var asyncOperationHandle in _handles)
{
Addressables.Release(asyncOperationHandle);
}
}
}
and then just like this
private async UniTaskVoid LoadUIAsync()
{
_assetManager = await UIAssetManager.Init(Screens);
where Screens is just as simple as that
public IReadOnlyList<UIBase> Screens => _screens ??= TypeUtility.InstantiateAllOfType<UIBase>().ToList();
So... what is the 1.0 way of linking a gameObjects transform to a entity? Lets say I want to have a CameraFollow component on a entity what is the way in 1.0 to sync the entity pos and rot to a gameObject?
Personally to get my camera to follow I'm just using GetSingleton in a monobehaviour to get the inputs that then move the cameras transform
I'm realising that's probably not the best way as I need to figure out how to delay the script so that it doesn't have an object not set error
neh mind I solved it with the calculateentitycount(), I kind of wish there is a HasSingleton in the EntityManager though
CompanionLink
it's internal
hmm
damn I forgot to set it up customly
Im not finding this in the 1.0 docs. Are you sure its still relevant ?
it's internal
meaning it's not meant for usage by us
but
asm ref trick is aimed to solve it
If I have to do reflection to get cinemachine to follow a entity
Im dropping this whole garbo
oh dw
it's not that hard
lemme show you how I did it without companion link
[UpdateInGroup(typeof(LateSimulationSystemGroup))]
public partial class PlayerCameraSystem : SystemBase
{
private EntityQuery _playerQuery;
private CinemachineVirtualCamera _cinemachineVc;
private Vector3 _cachedPos;
protected override void OnCreate()
{
_playerQuery = GetEntityQuery(typeof(PlayerTag), typeof(CompanionLink));
RequireForUpdate(_playerQuery);
_cinemachineVc = Object.FindObjectOfType<CinemachineVirtualCamera>();
}
protected override void OnStartRunning()
{
_cachedPos = _cinemachineVc.transform.position;
var link = _playerQuery.GetSingleton<CompanionLink>().Companion.transform;
_cinemachineVc.Follow = link;
}
protected override void OnStopRunning()
{
if (_cinemachineVc != null)
{
_cinemachineVc.Follow = null;
_cinemachineVc.transform.position = _cachedPos;
}
}
protected override void OnUpdate() { }
}
oh nvm
looks like I switched to CompanionLink after all
๐
๐
Syncing transform and entities is a really basic job, so just add the transform of the GO with AddComponentObject then you don't even need to bother with CompanionLink
If I call query.ToEntityArray() and query.ToComponentDataArray() will their items at the same index match?
Yes
Did they make CL public? Last I checked, it was internal. I had to asref hack it to public.
how could we create a true bit field component instead of wasting a whole byte for a bool? i could think of an allocated byte array that's accessed by index but that would not be in the chunk. for it to be in the chunk we would require the chunk capacity and that seems unlikely as valid solution
chunk component?
hm, yeah probably the best place
So.. I have been working completely unaware that 1.0 was released. Just now updated and read the forums and documentation. I guess I made a very big mistake because at .5 I changed entirely from Ijobs to 100% Systembase Entities.ForEach approach. It was a pain and I didn't love it but was fine with it if that was the direction moving forward. Now I am seeing ISystem and the new foreach approach. Which I think personally is less readable, since the local var name and definition are in different places. Can a more experienced member tell me if I should be moving forward with the new foreach or rewrite as Ijobs again?
The query api is not the same thing as efe
It only runs on main thread
Either that or a enabled tag component and then make your EQ ignore enabled status
IJobEntity is probably the best bet. IJobChunk would require a lot of rewriting from Entities.ForEach
IJobEntity is nearly identical to the old Entities.ForEach.
^
Alright, thanks guys
Is using ChunkIndexInQuery fine as a sortkey for a parallel entity command buffer?
Yep.
You can now use chunkIndex or unfilteredChunkIndex as an EntityCommandBuffer sort key. For more information, see the IJobChunk.Execute() API documentation.
[BurstCompile] Should be default
I have a pretty complete wrapper for cinemachine if you want
Can bake most of the components
Didn't see this in the docs, thanks!
Sure if you are willing to share Im willing to learn, but all I wanted was a simple and standart way to link the transform of a gameObject to a entity. This used to be possible in the past I think....
This 1.0 release is just hella confusing me
Are you trying to do hybrid or is this GameObject driven?
Im trying to have cinemachine. This is the end goal
I'll see if I can grab it when I get out of bed (5am atm)
It's basically a pure approach
You just assign entity to a component with follow / look fields
So you re-wrote cinemachine in pure ecs land ?
Can change at runtime
are you sleep discording ๐คฃ
No rewrite just wrapped it. From a user perspective it's pure though. You put your cameras in a subscene and then just use the components baked on entities
There is a reference to com.unity.cinemachine.entities in the entity asmdef though
So an official solution probably coming soon~
Ill have to look at your code to understand. Im still vey very confused on howe we would synch a lookat target
Tldr it creates an empty game object which is assigned to the field and then copies the entity transform to this gameobject
Does anyone know if there's a way to opt out of burst compilation for a specific job when using an assembly level BurstCompile? https://docs.unity3d.com/Packages/com.unity.burst@1.8/manual/compilation-burstcompile-assembly.html
Copying the entities transform to a go is all I wanted to know haha
Anyways ping me with the code when you can Im going to bed soon
Doesn't assembly level attribute still require per job attributes
It's just a quick way of applying a default config to all jobs in the assembly
In which case the answer would be, simply leave off the attribute on your job
Ah I see, thank you!
Holy shit. They did it. Hover over a command gives a shortish blurb about what it's doing
Baking and entity caching is so unstable rn. Any change done to any baking process and it's a tossup if the import at startup even works or an entire editor restart is required.
yep, it seems a bit worse than in 0.51
sometimes i don't even get changes or the changes are only visible with subscene closed
Man I'm still stuck on this ship-cannon thing. I can't figure out how to rotate a ship's cannons with user input. The input is on the root entity and the cannons are its children. I did figure out how to attach a SharedComponent to the children to mark them as being owned by the player. But how do I take the input from the root and use apply it to the children? As far as I can see, I would need to query for the input, then schedule a job using the input information from the query, which doesn't seem possible since you can't schedule jobs from inside jobs, nor can you get output from jobs to use in other jobs? Is there a way I could query for the input, save it, then use it in another job to rotate the cannons?
is this with netcode or custom?
Netcode
https://github.com/Unity-Technologies/multiplayer Up to date Unity sample repo for netcode. In particular: https://github.com/Unity-Technologies/multiplayer/tree/master/sampleproject/Assets/Samples/NetCube
They have a very basic input system that i've copy pasted nearly completely and it relies on GhostOwnerIsLocal to determine if this input component should be written to. Seems pretty straightforward
GhostOwnerIsLocal is only on the root entity though, and that example only applies input to the cube, so that doesn't help unfortunately ๐ค
I think I'm looking for a more general solution for how to take data from one entity and apply it to others. The ship-cannon example is just for context.
it depends on my core library https://gitlab.com/tertle/com.bovinelabs.core
but also requires a copy of the the copytransformtogameobject stuff from 0.51 that was removed, so it won't compile out of the box but if you just want to have a look at code there it is. if you wanted to actually use it I can probably package up the other stuff
{
public bool Enabled;
public Entity Follow;
public Entity LookAt;
public CinemachineVirtualCameraBase.StandbyUpdateMode StandbyUpdate;
// Lens
public float FieldOfView; // 1 to 179
public float NearClipPlane;
public float FarClipPlane;
public float Dutch;
public LensSettings.OverrideModes ModeOverride;
public float OrthographicSize;
}```
this is the basic virtual camera component, you can see the follow/lookat
there are similar components for composers, transposers etc
{
public float3 TrackedObjectOffset;
public float LookaheadTime;
public float LookaheadSmoothing;
public bool LookaheadIgnoreY;
public float HorizontalDamping;
public float VerticalDamping;
public float ScreenX;
public float ScreenY;
public float DeadZoneWidth;
public float DeadZoneHeight;
public float SoftZoneWidth;
public float SoftZoneHeight;
public float BiasX;
public float BiasY;
public bool CenterOnActivate;
}```
Wait.... This is actually pretty big is it not? Now there's 0 reason to use ICleanup?
? What is it?
If a *managed* IComponentData implements IDisposable, Dispose() will be called on the component when the managed ICD gets removed.
This is how unity handles the companion GO component, it implements IDisposable and the Dispose() deletes the GO when the ICD gets removed.
I guess if you're using a regular ICD with unmanaged NA<> or whatnot you'll still need cleanup.
Alternatively, the struct ICD can hold a pointer reference while an automatically managed class ICD holds the actual NativeArrays. No need for cleanup components. Doubles the chunk utilization though but no need for annoying cleanup systems.
hold up, where is this written?
Can't find it in API in web
EntityManager.RemoveComponent<>()
huh, true
Docs are fucky. Gotta source-dive for this stuff.
nah, it's good
it's there
well, this is poggie woggie stuff
I wish that would be a thing for unmanaged comps too
Yea, but disposal usually requires managed actions so it wouldnt pair nicely.
maybe
so what?
i dont know why, because all the NA variant disposal methods can be bursted.
if you worry about ECB
I'm pretty sure it's already split up in phases
I want this thing
because FMOD uses unmanaged pointers
but instantiated sound events require disposal
so if I could have it bursted normally, and managed during structural - that would be awesome
Im doing a dive into the source and I cant find where Dispose is actually being called
it's such a maze
maybe it's some kind of scheduled pattern?
Unity plz, add the ability to remove multiple components from a single query. I can see the internal functions that make it possible. Make them public plz.
for example component index from entity is removed
but stored in some unmanaged array
and then once bursted structural part is over
it calls Dispose
{
if (obj is IDisposable disposable)
disposable.Dispose();
}```
Yea, I think it's something to do with a pattern originating from the type index.
Ugh, all in managed component store. Expanding this to struct ICDs probably impossible from our side.
Still, great that it exists for class ICDs. Hrm, opens up a whole new world of possibilities... kinda. Not really.
as you say it's useful for removing cleanup components
but doesn't get rid of all use cases
Got an example? I'm trying to figure one out. Maybe as a persistent tag component for OnDestroy() system event patterns?
as long as it eases hybrid
which is essential for animation
Anyone know a way to detect that chunk was destroyed?
quick question, why?
second question to myself, are chunks actually destroyed?
i haven't checked in 1.0, but they tended to just exist previously even when empty
i want sync data between data in chunks and data in compute buffer, to oprimize writing in compute buffer i want to store range in which chunk corresponds to buffer. I also want to grab destroyed chunks and reuse space in compute buffer
i believe yes, because you can create 1kk entities and then destroy them, and if all chunks remains then they all will fetched by queries which leads to unnecessary work
yeah it kind of does though
in 0.17 when we did really deep performance testing we had long term performance issues
from queries having to iterate over a lot of empty chunks
Here's a great use of a cleanup component then. Have all entities in a chunk have a cleanup component tag and a regular component tag. The existance of a Cleanup without the regular component indicates the chunk has been destroyed.
Can you have a cleanup component as a chunk component?
yea, me neither. Havent really had much use for systemstates before this all.
yeah, i know about this comp, but it happens with entities and under the hood somewhere in process of entities destruction
archetype inspector does seem to imply 0 entities = 0 chunks now on empty archetypes
so maybe they are cleaned up
cant you just query the chunk count and compare to last frame
no, because i need to know capacity of created/destroyed chunk
chunks can go from different archetypes, so i need to know how much space i actually can reuse
Is it really that important to pack all the data into one compute buffer? I just have multiple compute buffer per data type.
I have one for vertices, one for light data, one for fov data, and multiple intermediate textures for post processing. I just continuously create and destroy them every frame if they change length. It's not that expensive compared to the actual rendering portion.
yes, because then it goes to GPU as one compute buffer
But why? One, two, or 12 separate compute buffers have little cost difference compared to what you're doing shaderside.
because i use instanced render method, so i need solid compute buffer
What matters is the GPU occupancy rate per threadgroup. GPU compute buffer count doesnt matter.
So? Just recreate the compute buffer.
every frame?
Yea.
CPU side it's just a register change. The GPU upload speed is constant. What you have to manage is the upload quantity.
yeah, for now i do it like so, and it is not worst part of calculations. But while we speaking in context of dots and PERFORMANCE why we should stop when we actually can lower calculations? ๐
Okay man. You do you.
Writing the same unchanged data to compute buffer every frame is still noticeable in profiler, because you need grab every chunk, read it's data and copy to buffer. So in my case it happens with all component which represents shader's instanced property
In place compute buffer modification is probably best done by assigning each source entity a unique sequential index integer then populating a NA that is then fed into a ComputeBuffer.SetData() method.
If you want to monitor for changes in source entity existence (new creation, deletion), make the index component a cleanup component and have an additional empty ICD tag. When the CC detects deletion, add that specific index to a stack / queue and replace the now deleted index with a magic number indicating "invalid" data for the GPU side.
Creation of new entities will first query the stack / queue of empty values to fill first before incrementing the compute buffer size.
Now the issue with this is that compute data will be increasingly fragmented and there wont be any easy set data range, instead specific indices of changed component data will need to be individually set and uploaded to the GPU. So you'll need to weigh (i.e. performance profile) the pros and cons of doing this.
I want EXACTLY what you've written. So i just try to figure out how it possible with chunks, because it is a batch for entities level
and yes, with chunks it is possible to just copy range of data
Chunks are limited now to 128 so you can either pre-allocate 128 slots of data per chunk and then do all of that on a chunk basis or somehow compute chunk size and then do it.
IIRC unity's chunk capacity calculators are editor only but you can copy paste whatever they're doing to make it work. Just a bunch of reflection IIRC.
i think about that every time and
- it can be unlimited from 128 in future if unity could detect no switch state comps in archetype
- it can still be less then 128 if per entity data is too big
I've tried doing per entity data myself but I have a max limit of 8192 and individual replacement wasnt really that cost effective for me.
So just compute the chunk capacity then. It's minimum of (16KB / Per Entity Usage, 128).
Well, find unity's implementation. it's somewhere in there.
Easiest way is probably just look at archetype window code. See how they grab it
16kb is max size of entity for 128?
16kb per chunk, 128 is the hardcap for num entities per chunk now
Oh 16kb per chunk
It's a constant somewhere inside the src. Wish they could make it variable, at least an editor setting for builds.
128 number of entities. Entities can use as much as they want.
Well, up to 16KB per entity.
huh, weird how that math works
1024"
Since an Entity takes 8 bytes only leaves 120 for components
Huh
So if you're using less than 120 bytes per entity, you're wasting memory.
Yeah...
Although seeing how liberal Unity is with their component sizes.... that wont be a problem.
Physics takes up around 300 bytes just for body+shape+transform. Netcode takes up another 300-400 bytes. Graphics around 200. Jesus.
Looks like I might get rid of solution to store graphics in separate entities
we're reaching single digit entities per chunk without any custom components at this rate. Unity, discover halfs and ushorts plz.
Lul
Jesus christ, prefab authoring is so fragile. Change a line of code completely unrelated and it breaks the baking cache.
Deleting the entity cache doesnt help, I need to go to the prefab authoring GO, delete it, close the subscene, run the scene, stop the scene, open the subscene, and then readd the GO
Are you not allowed to pass the same ECB as a parallel writer to two different jobs even if they depend on each other?
if there is an empty space for entity in chunk then new entity gonna get here, not in fresh chunk, yep?
They'll be put in a chunk if there is space, otherwise a new one will be created, unless you are doing something to force the entity into a new chunk even if there would be space
what can i do to force entity to go to new chunk?
Shared components for example
can someone confirm this: entity chunks are NOT linear in memory
same archetype
oh pretty sure they would not
would be a nightmare
add a new entity, new chunk, you'd have to relocate a huge amount of existing chunks to slip it in
right, i say this because single digit archetypes start to have the same problem that DOD wants to avoid
tertle have you ever tested increasing the hardcoded chunk size?
not that i recall
i want to give this a try
it's bugging me for the longest time ๐
i just feel like if it's just a matter of changing the const size unity wouldn't make a big fuzz about it
just try it
having a quick look at your original question
it seems like unity allocates up to 64 chunks in a row
if you are creating a lot of new chunks at once
yeah, that's what i gathered. that's pretty cool but requires mass instantiation, otherwise it seems to just allocate single chunks
i have not found any intelligence of further increasing by more than 1 chunk
my main project works with 64k chunk size. nice!
but my test project throws errors lol. might be something different then
it's as I thought. the jobs that i was testing here: https://forum.unity.com/threads/hierarchy-data-as-core-feature.1350353/#post-8526671 now run both(!) with 2.7ms
so if you want free performance, increase your chunk sizes everyone ๐
now the 128 cap is REALLY a problem
tertle, i'd be really interested how your stat system performs in 0.51 with chunk 16k vs 64k
how would it help i have the opposite problem
im entity capped
i can fit 225-400 entities in a 16k chunk
what i need is an 8k chunk
How are you changing the size?
๐
The unity components being so large (especially the buffers) really feels like an oversight
Chunk.cs public const int kChunkSize = 64 * 1024;
So you made a local copy of the Unity.Entities package?
yeah
btw what even is this? PhysicsColliderKeyEntityPair
oh right ๐
I only saw that it's freaking huge
for compound colliders
But I have none 
I really need to start stripping random stuff I don't need
I've not messed around with BakingSystem, can I just write a baker that removes these components?
Alright, I guess I'll try that
My entire hierarchy is flat, so I'll get rid of that too
just use this
damn, that's even worse. i just saw it's 0 length for all my tests
dump it in your project, and it'll clean up when they're not needed (length <= 1)
-edit- will need internal access or just add my library to your project and be happy
But what if it wasn't??? better reserve 208 bytes
Btw is this normal? I ended up creating two command buffers and that worked. I don't see why they couldn't be used across two jobs? Is it because the sortkey ordering wouldn't make any sense anymore?
hmm i though it worked fine across jobs
though i tend to create 1 per job
but i'm pretty sure we have plenty of places that someones written to reuse them
It gave me an error that I needed to set the dependency (which was set) or call Complete on the job
Using a non-parallel ECB worked ๐คท
had the same problem once. yeah you need 1 per job then in a system
Huh, alright. Thanks!
also as expected, my main project isn't profiting that much from 64k chunks. most job iterations are just too complex to profit from it. it is faster though in the overall frame time by 1ms which is still quite a lot
haven't come to a conclusion on this. increasing chunks to at least have 128 cap size for the big boy entities seems to be reasonable though.
and with how things are going, transform, physics, (netcode) 32k is a much better value than 16k
but this is ignoring memory constraints and having singleton entities in 32 or 64k chunks is really bad
i don't think there's any way to avoid it really, having modular chunk sizes
a singleton in 16k is just as bad
It's not a huge amount of memory
Does anyone have any idea what netcode variants are?
kind of
allows serializing components you can't add ghost attributes to right
but i also think it allows you to serialize the same component different ways on different ghosts
maybe you need less precision on one ghost vs another
They provide a sample of a 2d variant for transform and rotation and I have no clue what is going on. Is it code generated? Is it handwritten? What is NetCodeSourceGenerator.additionalFile?
all serialization is code generated in netcode by default (you can manually write one though)
[GhostComponent] [GhostField] etc all generate individual serializers
Yea, I think these samples are written manually because they only want to serialize XY of transform and the Z rotation. And there's no other way to specify that using attributes.
Unless I can stick a [GhostField] on a property.... which doesnt make sense?
Nearly all of my jobs use 1 or 2 ComponentLookup. Even though none of those jobs execute every frame, there will be thousands of entities and thus dozens of not hundreds of entities that feed into those jobs every frame. Will that be a severe performance issue worth optimizing for?
What do you mean by feed into the jobs?
Also, most of those jobs add and remove a single tag component within 2 frames as a sort of event system. Per-entity, each one of these โeventโ types occur once every 5-10 seconds, but with thousands of entities and potentially dozens of event types, will the resulting ECB usage cause issues?
As in only a few entities will be returned by an IJobEnrity query at a frame
Sure, I was just worried about the nonstop cache misses, unless that isnโt a huge issue either
If your code is slow fix what's slow
Otherwise don't waste your time preoptimizing something that isn't a problem
(Unless you're doing it for fun or a learning experience )
Okay, Iโll try. But avoiding performance considerations can result in โdeath by a thousand cutsโ where poor design all over the place add up to huge performance losses
I love preoptimizing
That happened in my previous project where I heavily relied on Component and Buffer Lookups
So Iโm not trying to squeeze every last drop of performance, but rather to understand general performance trade offs to make quick decisions about design
Lookups are unavoidable unless you never want your entities to interact
If you're doing the same lookups over and over again you might want to consider caching it once per frame
I see. What about adding and removing components in one frame once in a while to act as an event? You do have an event system, but if I were to simulate an event by sending an Entity wrapped in a struct, then processing that even will rely entirely on component and buffer lookups
Again, I just want to know if ECB memory copying or component lookups and writes are slower
Just in general
It's just a hashmap, whether or not that's "too slow" depends on the context
The easiest way to find out is to profile
componentLookups are okay but fast add/remove is absolutely not. consider just enabling/disabling them. this feature was built exactly for that
ECB is slow, keep that in mind and use wisely
hm, is there any explanation for something like this? after the first 3 jobs i have to call complete, then 12 others are fired. they are all very fast calculated with just 1k entities but quite far apart.
and the second question (maybe related to the new singleton commandbuffers) lots of disposes :/
ok, any idea for the gaps in the jobs? seems like the job scheduling overhead is in between
with more entites there are no gaps
It's 0.09ms. Probably job overhead
now that RegisterPhysicsRuntimeSystemReadWrite is obsolete, do I need to replace it with something or does getting the PhysicsWorldSingleton establish the dependency for me now?
using GetSingleton with PhysicsWorldSingleton is enough for dependency management
I think CreateSingleton<T> is aimed to solve at future
But it's really a question how it should be managed
NativeList<RectVolume> results = new(1, Allocator.TempJob);
new GatherResultsJob
{
Results = results
}.ScheduleParallel();
new UseResultsJob
{
Results = results,
}.ScheduleParallel();
results.Dispose();
Is this how I get outputs to NativeList? Do I need to do anything else in IJobEntity?
results.Dispose();
is not right
you are disposing the list before the job has completed
best approach is to use the world allocator instead of TempJob so you don't need to dispose
alternatively use Dispose(Dependency)
also GatherResultsJob wouldn't be able to write to the job as it's not a parallel container
Okay thanks, I'll try rewrite. Just found out how to write into parallel containers.
Sure, and thanks for the suggestion. The only thing is that component enabling/disabling doesnโt allow you to initially set it as disabled. Itโs always enabled by default. Whatโs the ETA on the Unity devs adding that feature?
I know that WithNone and Disabled is equivalent to WithAll and Enabled, but I donโt want to cause myself confusion
Also any chance we can have managed components in queries soon? 
you already have
managed component is index to managedcomponent array
SystemAPI.Query
I mean, managed components already work (SystemAPI.Query<MyMangedComponent>()), unity engine objects comming soon tm
any plans on making CompanionLink interatction public?
Haven't personally heard any plans ๐
Ah oops, I had one too many < ๐
Also any chance structural changes will be easier in the future using the query API? currently I just create an ECB and play it back right after, not sure if there's a better way ๐คท
That's indeed the current approach!
However, fun fact, you're allowed to call EntityManager.CreateEntity, EntityManager.Instantiate, and EntityManager.CreateArchetype inside a Query foreach as long as the Archetype doesn't match with the query you're currently iterating over :3
It's a minor thing, but I feel it would be cool if the query had a method to "request" an ECB that is passed to the iteration list and then automatically played back at the end
SystemAPI.ECB.RemoveComponent<T>(iteratedEntity);
Also will there eventually be a better way to early out with the query API? or e.g. pass an entityquery to the query api? Since for example here I'm creating and playing back an empty ECB even if the system api "query" is empty
Since it's kind of annoying to have to re-define your components using the querybuilder to early out above the query method
It works if you close the sub scene
It'll be fixed at some point to support this
//TODO: We might not need the RetainBlobAssetsSettings component anymore after removing livelink
o_O
i kind of forgot live link wasn't really a thing anymore
but that's kind of sad
that was definitely a cool feature when it was shown off
LiveLink is to be removed ? I missed that info. Sad.
well there's no button/stuff for it in 2022 anymore
and that was a random comment in the entities package
Oh F livelink. I guess play mode reloading with domain reload toggles is fast enough.
it's more for builds
oh wait, the builds inspector
right, confusing it for the in editor thing
Huh, you cant filter collider distance queries. Thats annoying.
because the collider has the filter
i do agree it'd be kind of nice to have an override though
Yea. This collider normally collides with everything but in this specific distance query, I want to find the distance to the closest collider that is part of group 2.
I think I can do it by creating a new temporary collider that uses the same shape blob and overwrite the collider mask
@viral sonnet this might interest you as I thought you tried to do this before
but you can totally create entities in BakingSystems
[WorldSystemFilter(WorldSystemFilterFlags.BakingSystem)]
public partial struct TestBakingSystem : ISystem
{
private Hash128 sceneGUID;
/// <inheritdoc/>
public void OnCreate(ref SystemState state)
{
this.sceneGUID = state.World.GetExistingSystemManaged<BakingSystem>().SceneGUID();
}
/// <inheritdoc/>
public void OnDestroy(ref SystemState state)
{
}
/// <inheritdoc/>
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
var entity = state.EntityManager.CreateEntity();
state.EntityManager.AddComponentData(entity, new TestComponent { Value = 1 });
state.EntityManager.AddSharedComponent(entity, new SceneSection { SceneGUID = this.sceneGUID, Section = 0 });
}
}
public struct TestComponent : IComponentData
{
public int Value;
}```
the annoying thing is i couldn't see a public way to get the SceneGUID as the baking settings are internal
without querying a random entity that's already converted
Anyone know how to suppress this error: Cannot create Settings Provider for: CreateDotsGlobalSettingsProvider?
It appears every time I open preferences. Doesnt seem to do anything
there's a file generated in your root assets
DotsClientSettings
basically means this isn't generating properly for some reason
let me try deleting it and recreating it
Seems to have gotten rid of the error. Wasnt using that file anyways
it's a crime to generate files in our Asset folder
they need to move these entity caches to library - they do not need to be in source control
Also incredibly annoying, every time I create a new system, I need to delete the baking cache and restart my editor or else unfixable error from deep inside unity breaks.
Physics layer names as well are just a list of strings in the root assets folder. Magic numbers everywhere. So annoying.
pretty sure you have to manually generate that file
via
dont think it generates by itself
Yea. I got it here:
you can put it anywhere though, it's just not auto generated into your root without you realizing
Random list of strings. Code it's just 1u << N. I wish I could replace it with an enum or something.
๐คข
Is there no order change filter for the codegen'ed variants?
I see with component change filter but not specific order change.
Because I need a job that runs only after a structural change.
Can only do it via IJobChunk
I don't think I've ever actually seen anyone but myself use DidOrderChange
So probably not high on Unity's todo list
but yeah it's very useful
Ugh, pain
huh, that's weird. i tested this and is wasn't working. same for another guy here
even closed the subscene ๐
state.EntityManager.AddSharedComponent(entity, new SceneSection { SceneGUID = this.sceneGUID, Section = 0 });
did you add your scenesection
that's the requirement
so all you need is scene section
huh
otherwise what scene does it belong to!
but yeah it's working great
can get rid of my gross hack for saving
they basically have this PublicEntityRef component they add to a new entity in each subscene
i simply looked at how that entity was created
entityManager.AddBuffer<PublicEntityRef>(refInfoEntity);
entityManager.AddSharedComponentManaged(refInfoEntity, section);```
low and behold, just a scenesection is the magic
so that's also a way to create singleton per subscene entity
PublicEntityRef what is that?
just a component with a reference to every entity in the subscene
i believe it's used to remap entities
when the subscene loads
so they keep their references
at what point?
and yeah that's exactly what it's used for
// Proper mapping from external reference in section to entity in main world
for (int k = 0; k < extRefs.Length; ++k)
{
var srcIdx = extRefInfo.EntityIndexStart + k;
var target = pubRefs[extRefs[k].entityIndex].targetEntity;
// External references always have a version number of 1
args.OutEntityRemapping[srcIdx] = new EntityRemapUtility.EntityRemapInfo
{
SourceVersion = 1,
Target = target
};
}```
end of conversion
ah
all right
well, that just solves most of my baking problems
Although it's probably going to break live conversion
ah nice! of course not! ๐ how did you find out?
the warning literally says it
i read the other stuff now. great find but which warning do you mean?
when you create an entity in baking system without adding a scene section
it tells you it's not going to serialize
i have warnings turned off. now i feel really dumb lol ๐คฃ
make this an error msg! haha
// * Detect closest distance to any player controlled object.
var filter = new CollisionFilter
{
BelongsTo = (uint)PhysicsLayers.Default,
CollidesWith = (uint)PhysicsLayers.Player
};
// * Get a local copy to modify collider such that it can only collide with player controlled bodies.
Collider col = *collider.ColliderPtr;
col.SetCollisionFilter(filter);
// * Construct input using modified collider.
var input = new ColliderDistanceInput
{
Collider = &col,
Transform = new(rot.Value, pos.Value),
Scale = 1,
MaxDistance = Radius
};;``` This works right? Getting a local copy of a collider and then setting that collision filter for a collider distance query
Nope, doesnt work. sad
sadge
Point distance query works but not this local reference collider copy method sadly.
Collider col = *collider.ColliderPtr;
oh well you're stripping the actual collider here
you're only using the header
you'd need to cast this to your type
SphereCollider col = *(SphereCollider*)collider.ColliderPtr;
at the very least
otherwise you're losing all your actual collider data
(this is why blob assets must always be referenced)
Thats done in SetCollisionFilter though
ugh, Do I need to copy paste that switch statement into the job to get a local copy?
the left is how it's stored
the right is how its stored when you just read Collider onto the stack
Colliders wont be isolated to spherical colliders only though. Pain.
yeah you'd need a nice switch like this
{
case ColliderType.Box:
this.DrawBox((BoxCollider*)collider, transform, color);
break;
case ColliderType.Triangle:
this.DrawTris((PolygonCollider*)collider, transform, color);
break;
case ColliderType.Quad:
this.DrawQuad((PolygonCollider*)collider, transform, color);
break;
case ColliderType.Cylinder:
this.DrawCylinder((CylinderCollider*)collider, transform, color);
break;
case ColliderType.Convex:
this.DrawConvex((ConvexCollider*)collider, transform, color);
break;
case ColliderType.Sphere:
this.DrawSphere((SphereCollider*)collider, transform, color);
break;
case ColliderType.Capsule:
this.DrawCapsule((CapsuleCollider*)collider, transform, color);
break;
case ColliderType.Mesh:
this.DrawMesh((MeshCollider*)collider, transform, color);
break;
case ColliderType.Compound:
this.DrawCompound((CompoundCollider*)collider, transform, color);
break;
case ColliderType.Terrain:
this.DrawTerrain((TerrainCollider*)collider, transform, color);
break;
}```
remember how unity has all these checks to always return BlobAssetReference by reference?
this is why
ugh
There are comments in the code saying how Colliders are gonna get overhauled soon-ish
Not modifiable?
Filter's baked into collider
I need to change to collision filter so it only hits against Player layer.
var clone = collider.Value.Clone();
clone.Value.SetCollisionFilter(default);
// do query
clone.Dispose();```
Since I'm trying to query closest distance to player for prediction - interpolation switching.
huh, right. that works
lets see..
// * Detect closest distance to any player controlled object.
var filter = new CollisionFilter
{
BelongsTo = (uint)PhysicsLayers.Default,
CollidesWith = (uint)PhysicsLayers.Player
};
// * Get a local copy to modify collider such that it can only collide with player controlled bodies.
using BlobAssetReference<Collider> col = collider.ColliderPtr->Clone();
col.Value.SetCollisionFilter(filter);
// * Construct input using modified collider.
var input = new ColliderDistanceInput
{
Collider = (Collider*)col.GetUnsafePtr(),
Transform = new(rot.Value, pos.Value),
Scale = 1,
MaxDistance = Radius
};
// * Check to see if closest distance enters predicted range.
if (!CollisionWorld.CalculateDistance(input))
return;```
Works, nice.
Thats what I get for trying to do something fancy myself instead of looking at available options
huh, sudden lagspike from what I think is a spiral of death every time prediction mode is changed...
Ah, it's from setting these objects to static. Re-introduction to predicted physics mode causes spike in fixed step to catch back up. Setting them to dynamic removes lag spike.
Seems like static optimization and predicted physics mode do not like each other, which makes sense.
i recommend in netcode to limit the number of network ticks/frame
in the editor
Recently I switch to use laptop and found that I only get roughly 8-12 fps which extremely slow with the same of my dots netcode project. It's powerful...
basically this advice
not sure what the 1.0 equiv is though
public class ClientServerTickRateAuthoring : MonoBehaviour
{
[Range(1, 144)] public int simulationTickRate = 60;
[Range(1, 144)] public int networkTickRate = 60;
[Range(1, 32)] public int maxStepsPerFrame = 1; // ? Default 4.
[Range(1, 32)] public int maxStepBatchSize = 4; // ? Default 1.
public bool sendCatchUpTicks = true;
private class Oven : Baker<ClientServerTickRateAuthoring>
{
public override void Bake(ClientServerTickRateAuthoring authoring)
{
AddComponent(new ClientServerTickRate
{
SimulationTickRate = authoring.simulationTickRate,
NetworkTickRate = authoring.networkTickRate,
MaxSimulationStepsPerFrame = authoring.maxStepsPerFrame,
MaxSimulationStepBatchSize = authoring.maxStepBatchSize,
SendSnapshotsForCatchUpTicks = authoring.sendCatchUpTicks
});
}
}
}``` Just threw this together. The comments on the actual component are very descriptive thankfully.
hrm, it seems that Netcode creates a client server tick rate singleton before this baked version loads in, causing error.
it's because the world ticks
before subscenes are loaded as they load async
it's created in NetworkStreamReceiveSystem if it doesn't exist
Yea. Is there a way to detect if all subscenes have loaded before beginning world tick?
I remembered reading about a way to do it in the docs somewhere... Something about a tag component in each subscene and then count them with a hardcoded value to check if they all loaded in
DOTS spawns a loading world per subscene right? Can I not just check for 0 loading worlds?
i have a system to handle this you can just drop into your project
Sure
magic is in SubSceneLoadingSystem
rest is just nice stuff
loading certain subscenes into certain worlds
loading/unloading subscenes only within radius of an entity
etc
what it does is just disable SimulationSystemGroup + PresentationSystemGroup
until the required subscenes are loaded
if you don't use the component it'll require all subscenes, but you can specify which ones are required
Huh neat. I currently load the scene using a launcher scene (not subscene, an entirely different scene). Will this work with that?
SceneManager.LoadScene("Scenes/SampleScene"); is how I load in to the main scene.
depends how it's setup
i just use Object.FindObjectsOfType<SubScene>()
in OnStartRunning
Wait, you can designate which world a subscene spawns in?
Oh, it's custom then? I'll hold off on that for now. Netcode probably will come with their own solution for that... eventually. One of the forum posts said they wanted to.
from what i'm seeing from reading the source
they won't be doing that
instead they'll have 2 different bake options on the same subscene
like a server only version
so you can strip components in server/client
(but again, this is just from reading the current source in 1.0 not an official statement)
/// Specify for which type of world the entity should be converted to. Based on the conversion setting, some components
/// may be removed (stripped) from the prefab at conversion or runtime.
/// </summary>
public enum NetcodeConversionTarget
{
/// <summary>
/// convert for both client and server worlds.
/// </summary>
ClientAndServer = 0,
/// <summary>
/// convert only for client worlds.
/// </summary>
Server = 1,
/// <summary>
/// convert only for server worlds.
/// </summary>
Client = 2
}```
and there are baker extensions for this already
/// The current conversion target to use for the baking.
/// </summary>
/// <param name="self">an instance of the baker</param>
/// <param name="isPrefab">state is we are converting a prefab or not</param>
/// <typeparam name="T"></typeparam>
/// <remarks>In the editor, if a <see cref="NetCodeConversionSettings"/> is present in the build configuration used for conversion,
/// the target specified by the build component is used.
/// <para>
/// Otherwise, the conversion target will be determined by the destination world for runtime conversion, and fallback to always be
/// <see cref="NetcodeConversionTarget.ClientAndServer"/> is nothing apply or for prefabs.
/// </para>
/// </remarks>
/// <returns></returns>
public static NetcodeConversionTarget GetNetcodeTarget<T>(this Baker<T> self, bool isPrefab) where T : Component```
Wait, this might be better than what I'm doing now.
Oh, you have to access these extension functions using this. Thats why I never found them
Hrm, doesnt seem to do anything
oh yeah it doesnt work atm
it's always defaults to clientserver
it would require 2+ bake passes
this is just what i'm seeing atm as what seems to be the plan
I can just add if (!IsServer()) return; for server only components?
Let me see if that works
Why is everything so slow? Checks profiler, sees everything is blue. Oh, burst is off.
Alright, I just threw together an alternative version here. Checks worlds for RequestSceneLoaded and IsSectionLoaded components instead of a per-subscene implementation. Not as flexible as your version but it's as minimal as possible.
It seems that despite it saying "async" loading and unloading, it still blocks mainthread render update for a solid second or two before it switches scenes.
you're doing scenemanager.loadscene
instead of scenemanager.LoadSceneAsync
so that could take a little while
Loadscene doesnt block, there's only camera and a bunch of subscenes. LoadScene unlocks the moment that camera loads in and the subscenes start loading. So not having async there doesnt matter.
It's SceneManager.UnloadSceneAsync() that's the problem.
hmm odd
well i haven't used scene loading in like 6 years or something
so really don't know much about whats going on under hood
How are you handling pre-connection work? Im using full scenes for Launcher / frontend actions.
i decided to just always have a client world (except in server only builds)
I guess theoredically I can just, yea.
And when you also need a server world, just spin one up?
yeah
How do you store the subscenes required for startup? Is that what your subscene systems and stuff are doing?
yes
oh, makes sense. hrm
basically lets me specify this per subscene
and when autoload selected
has option to be required (which means world won't start ticking until it's loaded)
Huh, and you place this on the subscene GO?
yeah
target world is conditionally compiled out when netcode doesn't exist so i can just use it in my standalone libraries as well for quick development
And there's no conflicts with what netcode is doing with GhostComponent prefab type?
not that i'm aware
i haven't thoroughly tested this in 1.0 yet due to other priorities (though I did make some big improvements to add support for live baking) but i've used this approach for like 18-24 months in 0.17/0.5X without issue
Alright, I'll check it out... tomorrow. Sleep for me.
does physics support the new transform system yet, or still not? (also is there a website i can check, so i dont have to keep asking you people this lol)
no
ah unfortunate, thanks!
EntityCommandBuffer ecb = new EntityCommandBuffer(Allocator.Temp);
// Unit : MonoBehaviour
Entities.ForEach((Entity e, Unit unit) =>
{
DynamicBuffer<CollisionInstanceDataBuffer> collisionBuffers = ecb.AddBuffer<CollisionInstanceDataBuffer>(e);
if (collisionBuffers.IsEmpty) return;
// Inform Unit : MonoBehaviour about all the collision hit this frame.
for (int i = collisionBuffers.Length - 1; i >= 0; i--)
{
unit.OnCollisionHit(collisionBuffers[i]);
collisionBuffers.RemoveAt(i);
}
}).WithoutBurst().Run();
ecb.Playback(World.EntityManager);
ecb.Dispose();
Am I using Dynamic Buffers correctly?
you are not reading from the buffer on the entity. you are always reading from an empty buffer.
the dynamicbuffer needs to be in your entityquery
I see, thanks!
Is there an API to get a singleton that is a singleton because it has a unique set of components?
e.g. i want to get the Entity that has Prefab and Unit IComponentData.
query.GetSIngleton()
EntityCommandBuffer ecb = new EntityCommandBuffer(Allocator.Temp);
Entities.ForEach((Entity e, DynamicBuffer<CollisionInstanceDataBuffer> collisionBuffers, Unit unit) =>
{
foreach (var collision in collisionBuffers)
{
unit.OnCollisionHit(collision);
}
ecb.RemoveComponent<CollisionInstanceDataBuffer>(e);
}).WithoutBurst().Run();
thanks! i knew i read about it somewhere but couldnt remember
Ok thanks!
but i guess you dont want to remove the component afterwards. you probably just want to clear the buffer
Ah, ok cool :)
so you dont even need an ecb at all
When should I use SharedComponent over Singleton?
They are both for sharing component data
sharedcomponent is more a grouping mechanism. each different value in a shared component is grouped in its own chunk. use it in order to reduce cache misses.
Singletons are useful for settings like entities that do change every once in a while.
Static settings could be stored in a blobasset.
there also are chunk components to have data associated with a chunk itself. i dont use them atm. not sure what their specific usecases are
Thanks again, understood!
The entire ISystem is unmanaged, so if I get a pointer to anything inside it shouldn't be moved, right?
Yes? Not recommended though. I think you can get any data from within a system using the system entity
Well, only if you write it to the system entity
For my use-case I want to have an interface that forces the ISystem to implement a method that draws its gizmo code, which I can then call from somewhere else
(Similar to the mono OnDrawGizmos method)
can't you just get the system struct and cast to the interface?
The struct is unmanaged and the interface is managed, so that wouldn't work
Alright, 4 hours of debugging and it seems like companion links are broken in build.
Something with baking probably.
And that's just for a sprite renderer
wait what? how does that work? how can the interface be managed? like managed, unbursted method?
You can't get a pointer of an interface type
the interface would be implemented and from that you can get a pointer.
You can't cast the pointer returned from the systemhandle to the interface
you can get the isystem struct
How?
state.WorldUnmanaged.GetUnsafeSystemRef<>()
I don't know the type at compile time
I'm iterating over all systems in the world to call the method on all isystem that implement the interface
oh, hm. i'm sure there's still a way.
{
ref var systemState = ref ResolveSystemStateRef(id);
return ref UnsafeUtility.AsRef<T>(systemState.m_SystemPtr);
}```
Also, if I know the compile time type, I can just call the method on the system, without using the interface at all
ptr is internal :/ but possible, the resolve is public
That's not the problem, like I mentioned, the issue is not knowing the compile time type
I already use the system pointers for other stuff, it's just annoying since the only way I know how to call the method on the unmanaged struct is with reflection
you could trick the system and just have a base ISystem.
What do you mean?
some empty isystem type. could be anything
Huh?
they just resolve and return a ref to a ptr. like you can cast anything with UnsafeUtility.As<U, T> this would also apply here. get some bogus struct back, cast it to your interface then
the important part is the starting address and that will be correct
That will at least copy it afaik
the interface cast? certainly not
yeah, and casts don't copy anything
If you cast a struct to an interface, it will 100% copy the struct
hm, in that case, the empty Isystem as base i mentioned previously. if this already implements the interface you'd be good
I still need to cast the returned ref to the interface. I have no idea if that copies it
I've never tried it with a ref value ๐คท
when the base already implements the interface you don't need to cast. the methods will be already available from the isystem struct
yes
Ill try it out later and see if it gets copied, thanks
hope it works out. this would give me some ideas for the generic systembase i still want to convert to an isystem
that sounds tricky
why?
Because otherwise will call the method on the incorrect type?
oh
Unity calls methods very low level
veeeeery low level
What do you mean?
I have no idea what you are talking about specifically
to invoke methods implemented by ISystem
Oh yeah, I know about that
so, that's not what you want?
That's only for ISystem though, not for "unity"
^
ah
so I don't get why you need to cast to Interface?
because in short - it's not possible
allthough
you could also box value
and then write it back
to System's ptr
That would still create a copy
well yeah, no other way around it
You can work around it with reflection
well, that's what Unity does
with those low level delegates
might just copy approach if that's your goal
I don't think they use reflection
but they do, that's how they get correct method for delegate
which is later stored in array
Where is that?
won't be able to remember, but just start with SystemGroup's UpdateAllSystems method
I didn't see any reflection there
it's the part where they decide
which method to invoke
which is gotten from array
by index
meanwhile this array is filled during creation
and since it uses Type to create system
it also obtains all method data
otherwise how else would they invoke compiler generated OnCreate, OnUpdate and OnDestroy
which are not part of interface
AddUnmanagedSystemType creates the delegates, but I can't see any calling code for it, and no reflection being used
So no idea how it's done
it's hidden somehow
took me a while
to find it
MethodInfo obtained from type contains Method smth like
CreateDelegate
which can be used for managed invocation
and Burst has it's own way to obtain function pointers
Does anyone know how enableable components interact with IJobChunks?
but since it's all done on fixed data struct, they use something reaaaally low level
You can just call Invoke on a MethodInfo
to convert it into delegate which works on exact struct ptr
You can use their enumerator to filter them
sorry, can't remember where it's hidden, but it's in there
take a look at manual, it has example of enumeration
Does a query containing a .WithNone<IEC>() and the chunk had partially enabled and partially disabled still get added to the chunk?
Yes, otherwise you wouldn't be able to iterate the enabled components
ECS treats a disabled component as though the entity doesn't have that component when determining if an entity matches an entity query. This means that an entity with a disabled component doesn't match a query that requires the component, and matches a query that excludes the component, assuming it meets all other query criteria.
I'm not exactly sure what you mean with the WithNone? Then you just aren't iterating over it
Since the query won't match
IJobChunk gets all chunks matching the query, including disabled components
Hrm...
What's the issue?
This copies the struct btw, as expected
the output has 2 different values or how do you know?
var str is no ref btw. ref var str = ref UnsafeUtility.AsRef<MyStruct>(ptr); is correct
To iterate over entities with a component disabled is pretty interesting.
Yep, that's the enumerator I meant
I missed that, my bad, but it doesn't change anything
Any interface functions are invoked on the copied struct
Why even cast to a reference? Just use the pointer?
๐
I don't know the compile time type
var inf = *(MyInterface*)str;?
You can't create a pointer to an interface
You can use what unity is doing and just have a header struct.
What do you mean?
That doesn't solve my problem afaik
I want to call a function on any ISystem that implements a specific interface
A small struct that contains an implementation of an interface that also contains memory size of the actual struct's implementation.
That way you can generically cast any implementation of an interface with this general header struct and call interface methods off it without reflection.
Yep, it's a cool trick. I use it for my chunk object spawning
I don't see how that would help with calling a function on an ISystem though?
Make an interface that extends ISystem and that interface contains the generic method you want implemented on all systems.
Also in that interface, it'll have the exact type property as a hardcoded enum.
Then in the header struct, it'll have a giant switch dispatch statement that casts itself to the appropriate system type and then calls the method you want.
That sounds horrible ๐
But no reflection
I'd rather just use reflection at that point
Thats what unity does here.
It's not generic unless you want to also have codegen implementation. Because ya gotta keep the enum list and switch dispatch up to date.
I don't want to have to do any upkeep for it
It doesn't really need to be fast, it's just for debugging
Use a SystemBase then.
That's what I currently do
Okay, what's the problem then?
Basically I create a system base that does the managed debugging stuff inside the ISystem, the question was if I can avoid that
I haven't been able to solve this schnozzlecat
I currently use reflection, but I'm wondering if there's another way
I changed my approach and used a singleton system component
I queried all systems for the component
So I basically used the system entity + component as a pseudo interface implementation
But if they all use the same component, you can't define different debugging behavior for each system?
Yeah I wasn't using logic in this interface
I was defining unique data per system
It was my state system
And each system instance needs to register a seperate component to the field in the bit mask for which state it owns
Previously I did this with a abstract system base
But I've managed to get it to work with Isystem this way
hmmm. Does Unity reuse empty chunks for other arcthetypes?
Could you just not set a key and the system can then just lookup the debug behaviour from the key
I believe so but I can't be certain as I haven't studied 1.0 behaviour
if no, that would be an interesting approach to solve memory leaking
Ideally I'd just like it in the system. I also planned to do to this for something similar to mono's OnDrawGizmos but inside ISystem
It's not a big deal, I just wanted to know if there was an easy way to do it
For now I'll probably just put it in a separate SystemBase
is there any good explanation why an interface cast creates a copy from a ref struct?
boxing
this doesn't happen for classes though, or does it?
No, those are reference types after all
An interface is a reference type, that's why the struct is boxed
(since a struct is not a reference type)
ref structs didn't exist back then
Well an interface can be used on both a struct and a class
So when cast it effectively needs to become the same thing
So structs just get boxed
I think enzi meant that it should somehow not copy the struct when you cast a ref struct
yeah ๐ it would enable us to do some pretty cool stuff
Isnt that just operating on a pointer?
well, actually you do
if it's normal boxed interface
yeah and you can use GetType() to figure it
Well obviously, that's the runtime type
KornFlaks was saying it's like using a pointer, but you need to know what type the pointer is
yeah, that's why interface invocation can only be done managed
Yes
I mean they didn't really reimplement it, more like they are trying to work around it
They are just interop-ing a lot with native code from C#, but trying to do it in a not-complicated way for the end user
Which isn't easy
internal part about ISystem invocation is hardcore
Yeah it's nuts
Imagine the madness going on with burst
I think I'll stick to reflection for now, I'm not a huge fan of the "System in System" approach
The only thing I actually have no idea on how to do, is calling a specific function that is marked with an attribute inside an ISystem
I'm not sure if that's possible
looks like runtime IL generation
I used to work with transpilers ๐
literally construct method out of IL instructions
one by one
oh good
If Burst is disabled, and an assembly is changed, Burst won't recompile that assembly once Burst is re-enabled.
they fixed my latest bug in 1.8.1
I guess the easiest way is to just invert the dependency and pass a delegate to the instanced function to the calling code, still kind of annoying though
personally i really dislike OnDrawGizmo
and was very happy when they added a DrawGizmoAttribute
What does it do? Never heard of it
that allows you to have the same behaviour without polluting your runtime logic with debug code
{
[DrawGizmo(GizmoType.Selected | GizmoType.Active)]
static void DrawGizmoForMyScript(MyScript scr, GizmoType gizmoType)
{
Vector3 position = scr.transform.position;
if (Vector3.Distance(position, Camera.current.transform.position) > 10f)
Gizmos.DrawIcon(position, "MyScript Gizmo.tiff");
}
}```
lets you write gizmo drawers and store them inside editor only assemblies
separating your debug/runtime logic
Interesting, but I'm guessing that only works for monobehaviours
Maybe I'll try writing something like that for systems and see how it goes
gizmos are so slow
I'd do this, but I'm still not sure how valuable game view gizmos at runtime are since I'm using ALINE
all my drawers are in editor | developmentbuild assemblies
dont use aline but i use my own library that is pretty similar to aline
How do you call the drawers from ISystem though?
my draw system works in isystem
But the code is outside of the system right?
the actual drawing code is
it used to use my eventsystem to fire draw events
but in 1.0 i got rid of that layer
when i rewrote it to use the singleton approach
Yeah since state is now shared with system state components and singletons more, I feel like it's easier to move it out
var drawer = SystemAPI.GetSingleton<DrawSystem.Singleton>().CreateDrawer();
Is the drawer populated with commands inside the isystem or somewhere else?
it just writes to my nativeeventstream
(same stream i used for my event system)
which is thread save
Yeah but you'd have to tell the thing what to draw
Where are these invoked?
/// <param name="center"> The center of the cuboid. </param>
/// <param name="orientation"> The orientation of the cuboid. </param>
/// <param name="size"> The size of the cuboid. </param>
/// <param name="color"> The color to draw with. </param>
/// <param name="duration"> How long to draw this. </param>
[Conditional("UNITY_EDITOR")]
[Conditional("DEVELOPMENT_BUILD")]
public void Cuboid(float3 center, quaternion orientation, float3 size, Color color, float duration = 0f)
{
#if UNITY_EDITOR || DEVELOPMENT_BUILD
if (!this.isEnabled)
{
return;
}
this.writer.Write(new DrawHeader(DrawType.Cuboid, duration));
this.writer.Write(new CuboidDrawer { Size = size, Center = center, Orientation = orientation, Color = color });
#endif
}
And that job is stored in a separate assembly?
nearly always yes
i write most of my drawers in a debug assembly
unless im debugging something and want like internal state
of a job to visualize
but my actual gameplay drawers dont usually need that
they are just doing stuff like, drawing navmesh
or i have a custom physics collider drawer that actually draws shit properly
Yeah I have no idea why the normal physics debug drawer is so weird ๐
So hard to see anything
i make assemblies that look like this for my debug code
so it exists in both editor & debug builds
but are stripped in runtime builds
as you can see from my above code my drawer is completely stripped in runtime builds anyway
all conditionally removed
calling from runtime is a no-op but not a compile error
Why do you need the guard inside the function if you already have the attribute?
because it can still be used outside these editor/development assemblies
and from my experience, most people are quite happy to mix their runtime and debug code
What system schedules the debugging jobs? It cant be the system being debugged
Unless you also add guards there
what do you mean
Nevermind, that wouldn't work either, since it would be circular