#archived-dots
1 messages Β· Page 267 of 1
I don't really see your point
you mean I should just do some Method
which will add something to List
and then do some logic of triggering code itself?
{
private event Action<bool> myEvent;
private bool initialized;
public event Action<bool> MyEvent
{
add
{
myEvent += value;
if (initialized)
{
value.Invoke(true);
}
}
remove { myEvent -= value; }
}
protected override void OnCreate()
{
initialized = true;
myEvent.Invoke(true);
}
is one way you can tackle it
(where bool is _playerInput etc)
apart from that
dont call code like this in OnStart
maybe call it on OnStartRunning instead
yeah
I thought so
hmmm
that's a very curious one
myEvent += value;
if (initialized)
{
value.Invoke(true);
}
didn't know it was even possible
and microsoft manual never even mentioned it
lol
you're not the first person i've talked to who hasn't realized you can have custom event implementations
some pretty experienced devs haven't known this
i feel like in regular c#/oop they are pretty popular
i just let rider teach me everything π
hmm, under what circumstances Entity can change?
Basically I want to save player entity in field OnStartRunning and then use it
Do I need certain checks or it'll remain same through all cycle of World?
hi guys, when i press play in my dots project the cubes disappear, i can get them to stay if i select 'convert and inject' but my understanding is that unity should render an entity.. i have the entity rendering package installed. Can i ask for help here?
what render pipeline
Are you using the built-in render pipeline? Hybrid Renderer now only supports scriptable render pipelines, or at least URP and HDRP
hmm maybe when i started the project im pretty sure i hit URP
how do i check in project?
I know that to start with you can check the "Package Manager" window for the presence of the "Universal RP" package in your project
ahh ok cool, universal RP is installed
Check the materials used for your cubes
The material's name, if it's the default material, or at least the material's shader's name, should contain "URP" iirc
seems right i think
none
Do you have the NetCode package installed?
yes i do
Then I think I know what the issue is
You need to create a subscene GameObject, give it a component called something like "Convert To Client Server Entity," and put your cubes inside that subscene
ahh shit ok, if i take out the netcode package will it start working ok? i added it without thinking, planning to make a single player game
I think so
nice it works! thank you so much
i removed the netcode package
sorry one lastquestion... im trying to find some basic docs/tutes on dots/ecs just so i can learn the basics, is there anyone any of you would recommend?
I can't really recommend anyone as I've never read a tutorial for dots but I would at the very least recommend checking out the samples
I really dislike the idea of having system in Update for sole purpose of doing authoring
just make sure it doesnt run every frame and its fine.
yep
that's what I have been busy with
hmm
is there any reason why during Start of Mono, some entity is not initialized?
var player = inputController.GetSingletonEntity<PlayerTag>();
Trying to get playerEntity during Start
in mono
the subscene hasn't fully streamed yet to the world if you're using subscene authoring?
hm
if subscene is in edit mode it works fine
that's no good
is there a way to get access to GetSingletonEntity method without getting systems first?
yeah, there is
weird one ngl
var player = World.DefaultGameObjectInjectionWorld.EntityManager.CreateEntityQuery(typeof(PlayerTag
))
.GetSingletonEntity();
Is it a practical idea to create system with empty update for each mechanic?
not sure what you mean by empty update? are you talking about making every system reactive?
nah, I literally just use SystemBase for mechanics that don't rely on Update
thus my OnUpdate is empty
should be perfectly fine
Set RequiresSingleton as dependency for the system to update.
some form of yielding in an IEnumerator Start() also works
hmmm, is there a way to run SharedComponent filter in query through excluding?
as in
I have 100 shared component types
I need to query through 99 of them
and only leave 1 untouched
probably best to use an if or a tag
is it possible to disable batching for objects using hybrid renderer?
This sounds like you actually dont want to use a shared comp. should be much better to have a normal component and filter out with an if like @pliant pike suggested. is this about your room sharedComp?
so you probably want to not process the room where the player is at?
well anyways its about an "active room"
yeah, kind of
so like calabi suggested you could filter it with a tag. give all entities that are in the activeroom a tag. that should be really really cheap since you can do that with a batchcommand and a query with your RoomSharedCompData. There wont be any memory copied around since you split up your chunks with the SharedCompData accordingly.
InvalidProgramException: Invalid IL code in WorldGeneration.Systems.WorldTextureCreationSystem:CreateDebuggingTextures
What have I done
bad things π±
ahem
var desc = new EntityQueryDesc()
{
All = new[] {ComponentType.ReadOnly<InSystemComponent>(),},
None = new[] {ComponentType.Exclude<DisableRendering>(), ComponentType.Exclude<StarTag>(),},
Any = new[] {ComponentType.ReadOnly<CompanionLink>(), ComponentType.ReadOnly<RenderMesh>(),}
};
_toDisableQuery = GetEntityQuery(desc);
wat
still having the issue?
from memory you shouldn't use excludes in EntityQueryDesc
though I thought it had a specific error
well I had to split it into 2 different queries
why?
Assert.IsTrue(ComponentType.AccessMode.ReadOnly == type.AccessModeType);
i think it's failing on your None line
because you're using Exclude
oh
does anyone's hybrid renderer take up like 1-2ms per frame even when there are no entities in your scene?
turn off checks
which checks do i disable?
jobsdebugger as well
what does jobs debugger even do?
The JobsDebugger feature detects and reports many classes of concurrency programming errors (e.g. race conditions, missing synchronization, etc.) which are traditionally very difficult to isolate and reproduce. The JobsDebugger can detect these issues statically, so rather than getting a catastrophic bug once every million runs, you get an error 100% of the time saying "hey, this code could potentially produce a catastrophic bug". If it's spamming the console, that's usually a sign of a bug that should be fixed
Thanks, dropped it down to .6ms lol
To answer myself but I must say, I always have it on and never ever had even one message by it. Curious that it should detect race conditions. I had one, nothing was shown. Is the debugger overriden with NativeDisableParallelForRestriction?
dependency warnings are all jobs debugger
NativeDisableParallelForRestriction
yes this turns off the safety
you are telling the jobs debugger that you aren't causing a concurrency issue, ignore it
You are trying to write to X, system Y is using blah blah
alright, then I will turn it off even though it doesn't add too much overhead. Build speed and editor speed with leak/safety checks off is nearly 1:1
So i was searching for a ecs rigidbody constraints implementation, and so after a lot of research i found the solution on this server actually, the soultion it is in the sample projects of unity https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/PhysicsSamples/Assets/Demos/4. Joints/Scripts/Conversion/PhysicsJointConversionSystem.cs
From here you need to 4 files, 1 is the system that converts the constraints to physics joints, and the other 3 are the components and more to perform the game object entity's conversion. The files are :
- Limit DOF Joint.cs
- Base Joint.cs
- Based Body Pair Connector.cs
And the system
- Physic Joint Conversion System
The key concepts are: physics body, constraint, joints.
Also exist another solution, take an SystemBase and use PhysicsMass Component in the ForEach query, next in the loop take the atribute InverseInertia and set all te axis xyz to 0f, and that works fine to, but i dont know the cost on the perfomant, because you are doing this in OnUpdate.
Hope this will help anothers to implement an easy solution on the future :3
how do you make a nativearray of arrays, or some sort of workaround
my job's output is an array
Wait, does my job even need to be parallel? I'm doing this job for each entity that meets certain conditions...
ugh I dont know
I heard a lot about UnsafeContainers for "container in container"
but I never actually looked through them, so can't help
Ok so. I have a system, that checks through a list of entities and if they have a flag that says they need a path recalculated, it recalculates their path. Is an IJob appropriate for the pathfinding job?
to do your actual pathfinding?
probably not unless you only have a couple of things pathfinding per frame
it's potentially one of the costlier operations and benefits the most from separating into threads
oh yeah, I do remember comparison of non-job vs job vs job+ecs vs job+ecs+burst
How to disable SharedComponent filter on query?
I set it and then I want to unset it
InvalidOperationException: The Unity.Collections.NativeList`1[System.Int32] has been declared as [WriteOnly] in the job, but you are reading from it.
what.
how do I uh, make it readable.
how did this even happen.
can you show the code?
ResetFilter
uuh here
NativeList<int> closedList = new NativeList<int>(Allocator.Temp);
//...
closedList.Add(workingNode); //add to closed list
NativeList<int> validConnections = getValidConnections(connectionsSource, workingNode, closedList); //find all open connections
//...
static NativeList<int> getValidConnections(NativeArray<Connection> graph, int source, NativeArray<int> cList)
{
//loops through connections and finds all valid ones that start at source
NativeList<int> vConnections = new NativeList<int>(Allocator.Temp);
foreach (Connection c in graph)
{
//Loop through connections and find valid connections
if ( //HERE
c.from == source && //if right source
c.isTraversable() && //if it is traversable
!cList.Contains(c.to) //if c.to not in the closed list
)
{
Im not sure what the needed code is
poggie woggie
i suspect you're passing a native container inside a pointer
a... pointer?
what about the code outside of Execute?
What about it?
error might be there
No I put a //HERE where the runtime tells me the error is
Although I believe itβs talking about the !cList.Contains()
getValidConnections is defined outside of Execute, but that hasnt been a problem before
What I mean is that your job fields can literally be faulty
closedList is not a job field, it's defined inside of Execute
what about cList
cList is a parameter of a function.
static NativeList<int> getValidConnections(NativeArray<Connection> graph, int source, NativeArray<int> cList)
closedList is passed into cList at NativeList<int> validConnections = getValidConnections(connectionsSource, workingNode, closedList); //find all open connections
and closedList is defined simply as NativeList<int> closedList = new NativeList<int>(Allocator.Temp);
what im saying is how is it defined as readonly
i mean writeonly
Any idea how multiple shared components affect chunks?
If I will use about 4 shared component types just for game logic, is it going to hurt anything in any way?
Mostly I want them for filtering
which I use extensively
well it could
depending how many variations you have
every unique combo will be a different chunk
btw you are limited to 8 shared components max
oh
and by default in a subscene unity adds like 6 ^_^'
feels bad
worse in netcode
Physics - PhysicsWorldIndex
Entities - BlobAssetOwner, SceneSection, SceneTag , EditorRenderData
Netcode - SharedGhostTypeComponent, SubSceneGhostComponentHash, GhostDistancePartitionShared```
create 2 of these in a subscene with netcode
and you hit 9 components and get an exception
π΄
(I've already talked to unity about this)
I believe it's called ISharedComponentData π
so you can for example use enums
Okay, super basic question, sorry I am a noob, but do I have to use the Hybrid Renderer in ECS? Is that the only path to rendering entities?
no, but it's the easiest one
if you want you may just not install it and instead render entities any way you want
or not render them at all
if your goal is to have some ECS subsystem outside of world space
What do you mean when you say any way I want? What are the other options? Thanks a ton for responding π
well, any way you can do render in Unity is your option
attaching GameObjects (which btw hybrid already does for certain kind of components)
rendering through Graphics API
or maybe you have some other 3rd party solution
Hybrid does all of it for you
so I wouldn't be interested in doing it any other way
Oooooh! cool! Thanks I just looked up the graphics api. That looks like the right door to help me understand rendering.
Good luck, it's not simple
Does the hybrid renderer require you use GameObjects? I am interested in a project using no OOP at all. I am still trying to grasp a lot of the nuance
no
but DOTS is considering conversion workflow as crucial part of itself so
basically, authoring through game objects is almost a must
think im going to ditch job system for time being, might try a gpu for my algorithm instead, dealing with pointers is just annoying me
hmm, thats a shame. Sounds like there are some limitations if I do not use GameObjects and the Hybrid Renderer
game objects need to exist only during development
during runtime they cease to exist
unless ofc you tie some system to it
is that just for sanity sake so you can use the other unity tools and so forth?
which I do a lot rn, since there are no alternatives to many classic Unity components
for example LineRenderer
on the roadmap they are going to tie game objects to it for the 1.0 release
what ever that will mean is a mystery however
It should be perfectly fine to spawn do manual setup for the Hybrid Renderer. Conversion kind of only sets up a base set of components, and we have some exposed API you should be using to set that up from code. If it turns out we want to refactor something there (we have done a few times already).
But the simplest way is GO authoring and prefab spawning for sure.
If you don't want to author using GO you need to write a lot of the editor tools yourself somehow
If I'm storing an e.g. UnsafeMultiHashmap inside a component, is it possible to add to that map in parallel? Or do you always need to do AsParallelWriter before scheduling the job?
There is probably no way to get a Generic ChangeFilter for a query going right? im getting this error :
"Type Attribute cannot be used with WithChangeFilter as generic types and parameters are not allowed"
Id like to not filter inside a job with checking whether the Chunk has changed since that would mean id schedule it every frame despite it beeing very rare to occur.
Yeah but if the UnsafeHashMap is on a component, can I do AsParallelWriter inside the job?
e.g. 100 entities reference a single entity that has a component with the hashmap, and I want all 100 entities to write something to the hashmap in parallel
var hashmapFromEntity = GetComponentDataFromEntity<HashMapContainer>(false);
Entities.ForEach((Entity e, in EntityReference reference) =>
{
var referencedEntity = reference.Entity;
var hashmap = hashmapFromEntity[referencedEntity];
var parallel = hashmap.AsParallelWriter();
parallel.TryAdd(...)
})
as an example
I've never looked at how the parallel writers work in detail, but I think it should be fine in theory?
The only thing I'm not 100% sure on is if the code-gen handles setting the thread index properly, but I guess I can just test it
@misty wedge Havent tried any of that so i cant help with that implementation but i know @rotund token made a DynamicHashmap which sounds like what you want
ah alright sry. out of interest what are you building that makes the parallel write necassary?
It's not necessary, I was just wondering π€·
Since it's based on a dynamic buffer it will be on an entity. So I think you actually would need to go out of your way to write to it in parallel. Most likely you will work in parallel on multiple entities but each entities will be worked on in a single thread and so the buffer will. The read/write dependency should take care of the rest.
yeah hes working the other way around though. not looping over the entities with the hashmap.
the dynamichashmap is not writable to in parallel. I was asking about an hashmap inside of a component earlier, and if you can do AsParallelWriter inside a job
i have a very similiar usecase actually. what i do is to loop over all Entities with the Hashmap in a job and then have another manual chunk interation inside of the job that fills the hashmap
that makes it parallel without the need to write to the same hashmap in parallel
i think that was also what @uncut rover meant?
hmm
how large can component be in terms of fields?
I am afraid my Pathfinding component is about to get
5 more fields of float3
kek
var parallel = hashmap.AsParallelWriter(); should be outside the ForEach
that said, UnsafeContainers in IComps are problematic because of disposing them
I would also suggest to go with tertles DynamicHashMap. Did so myself
I use systemstatecomponents to clean up the unsafe containers
Why do you need parallel writing when it's bound to an entity? Do several threads write to the same hashmap of one entity? That might be an issue
Why would that be an issue? ParallelWriter exists
TBH, and I'm sorry to say that but that's bad design and really slow, with lots of stalling
Writing to a container in parallel is bad design?
NativeHashMap, NativeList in naive approach. yes
Then why even have it
I don't know π unity thought why not without any further implications. The problem is the stalling of Interlocked. It's so bad, that even a single thread can be faster
and that doesn't even count the frame timing multiplied by the amount of worker threads
it's bad design because the parallel writer has bad design
For my use case using a single thread is almost assuredly faster (the majority of entities are writing to the same container), I just wanted to know if it was possible
You are right, if all of them write to the same container, there is no way using multiple threads can be faster (since they would all just block each other)
it's possible but yeah, I don't think you'd be happy with the results. alternatives are better
but sadly they are all a bit more complicated/involved
It's not a performance bottleneck or anything like I mentioned further up, I just wanted to know if the code-gen handles setting the thread index if you call AsParallel inside of a job π
there's no codegen involved for [NativeSetThreadIndex] which the parallel writers use
Not sure, technically it could be code-gen or DI. /shrug
Regardless, I think the intention is to use AsParallelWriter outside of the job and pass the struct into it
yes
which is a problem in itself because you don't know which hashmap you're gonna use
hmm
is there a way to pack some kind of simple data
into bytes
and then reinterpret it upon unpacking?
I want to create a dynamic Buffer of action queue
is dynamicbuffer.reinterpret all you need?
probably not
no, it's not that
here what what I think about
I want to have dynamic buffer of struct with 2 fields
ComponentType
ByteArray
So upon Adding to buffer I write some data to that ByteArray
let's say I want to pack 3 floats and 1 Entity in it
then once other system gets to it, it unpacks it
and this way I will have struct based delegate
xD
what i did is to not use ByteArray but define a "GenericAxis" struct (Entity and Score field). then when i want to read from a generic DynamicBuffer i reinterpret it into a GenericAxis first.
nah, it's not about AI
actually
it's more about packing data
this same thing can have usage outside of AI
yes its just where i use it. just wanted to give an example
thing is, my argument list I want to pack is not supposed of certain size
supposed to be*
I want to be able to pack any amount of data, until certain byte limi
well dyncamicBuffer wont let you add ByteArrays with dynamic size i guess
no need for dynamic
I need fixed size
thing is
I have no idea how any of that even works
xD
when the byte array is fixed you can cast it to anything as long as you know what it is. you'd need an additional flag to know that but when the byte array has a dynamic length it can't reside in the bufferElement. You'd need a pointer from the bufferElement to the dynamic byte array
public class MySystemTime
{
[FieldOffset(0)]public ushort wYear;
[FieldOffset(2)]public ushort wMonth;
[FieldOffset(4)]public ushort wDayOfWeek;
[FieldOffset(6)]public ushort wDay;
[FieldOffset(8)]public ushort wHour;
[FieldOffset(10)]public ushort wMinute;
[FieldOffset(12)]public ushort wSecond;
[FieldOffset(14)]public ushort wMilliseconds;
}``` example of fixed size layouts
should you even make it in the first place? π
same method really but it doesn't need any byte arrays
you just take the size of the largest struct you would have
and others are just living inside this block and are reinterpreted
well, yeah. That's kind of how I imagined it
I just write as many bytes as I want, and then read them
upon certain limit ofc
What I ask is what type do I write my arguments
let's say I have 3 float3 and 1 Entity
the common denominator is a byte
when my head math is correct that would be 44 bytes.
so you can allocate 44 bytes and reinterpret to the struct you mentioned
public struct QueuedAction : IBufferElementData
{
public ComponentType type;
public FixedBytes126 args;
}
so kinda like this?
yeah sure
hmmm
and how do I write my argument list to it?
while bursted
and the same way
read
you cast the args to the struct. (best to use a ref) and write the values to the struct. same goes for reading.
writing and reading from more than 1 thread would cause a race condition
in that case Interlocked has to be used
isn't it already thread safe?
since you can't access same component from 2 jobs if one is written to
if you don't use BufferFromEntity for random lookups, it's safe
private struct KekWorks
{
public float3 kek;
public float3 works;
public float3 yep;
public Entity lul;
}
protected override void OnCreate()
{
var queue = new QueuedAction();
queue.type = ComponentType.ReadOnly<GetToPoint>();
var args = new KekWorks()
{
kek = new float3(1,2,3),
works = new float3(1,2,3),
yep = new float3(1,2,3),
lul = Entity.Null
};
queue.args = (FixedBytes126) args;
}
So this doesn't let me cast it just like that
and I need to be able to do it in bursted job
google gives plenty of good answers for casting structs to bytes: ```byte[] getBytes(CIFSPacket str) {
int size = Marshal.SizeOf(str);
byte[] arr = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(str, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Marshal.FreeHGlobal(ptr);
return arr;
}``` code looks different in unity c#. Marshal is UnsafeUtility
so write a method that casts it to FixedBytes126
I am trying to get a generic Effect System to work. I dont want to use PolyComponents for it because i actually want to have control over the ordering of EffectTypes.
What i plan right now is to have an EffecthandlerSys<T> that loops over Effects<T> and calls Update on them. T implements IEffect which contains the Update Method. The Update Method just calls a UpdateFunction inside a static UtilityClass Update<T>. Now in my theory i can implement the diffrent update logic inside the Utility class for each type of effect i create.
Sounds like i should try it?
You could also stackalloc KekWorks with a stackalloc count of 1 & then cast it to a byte* and copy the content into queue.args
good idea, much easier
Sure, why not. Are we talking about entities here? How can you make sure those are better sorted?
No i am talking about the update order of systems. For example I want to be able to update Effects that modify attributes on a character before updating Effects that are based on Attributes on the Character
So PolyComponents that would call Update on any Effects randomly would be bad.
Noob follow up question. If i had an Update<T> and an Update<ConcreteEffect> would Update<T> only always be called if i did not define the ConcreteType?
sry i probably worded that very wrong.
So to say would Update<T> function as a standart implementation?
var kek = stackalloc KekWorks[1];
kek[0] = new KekWorks()
{
kek = new float3(1,2,3),
works = new float3(1,2,3),
yep = new float3(1,2,3),
lul = Entity.Null
};
queue.args = (FixedBytes126) (byte*)kek;
hmmm
as long as ConcreteType exists in your code the according system is created
yes but i mean if i dont define a Update method in my static Utility class for that ConcreteType
otherwise I can't say much about the effect design. I believe you are over complicating it but maybe your game design requires it?
yeah then nothing should be created
I got a generic Ability System where only the Effects are not generic yet.. .so yes my game wouldnt need it but my System kinda does to be a good tool π
try queue.args = *(FixedBytes126*)(byte*)kek
huh
it's a bunch of casting, but i imagine queue.args just stores FixedBytes126 and isn't a pointer
most games now use raw stats. stuff like int -> mana/spell hit or that sort is really oldschool. also quite hard to balance
yes but what i want to do is to implement a slow Effect that affects speed for example. Its not only about attribute buffs
and why not support everything everywhere all at once. what could go wrong
Try UnsafeUtility.As<KekWorks>(ref queue.args) if you don't want to use pointers, otherwise you take a byte* ptr and cast it to KekWorks
a monolith of a system that's hard to maintain and has lots of weird bugs, edge cases because it's so generic
I still say go for it! π
sry discord didnt let me write "/s" π
if it works it'll be cool
What i am really doing right now is coding for a game that i want to make in the future in a game i am making right now xD
The one right now is much easier and could be done non generic but the next one will be huge :S
Its a bad idea i know
Its just some Systems like AI and Abilities i want to do more generic
let's play the question game. you use effects, I want to have an absorb buff for 9 seconds that can absorb 100 damage. when the 100 damage are absorbed i want to have an explosion that damages badies and heals allies. if the buff just expires nothing will happen. how will you handle it in a very capsuled environment?
ok, this works.
Now gotta try it in Burst, kek
huh, looks like it works
KekWorks lul = default;
Job.WithCode(() =>
{
var queue = new QueuedAction();
queue.type = ComponentType.ReadOnly<GetToPoint>();
var kek = stackalloc KekWorks[1];
kek[0] = new KekWorks()
{
kek = new float3(3, 2, 1),
works = new float3(1, 2, 3),
yep = new float3(5, 6, 7),
lul = new Entity() {Version = 2, Index = 500}
};
queue.args = *(FixedBytes126*) (byte*) kek;
lul = UnsafeUtility.As<FixedBytes126, KekWorks>(ref queue.args);
})
.WithBurst()
.Run();
Debug.Log(lul.kek);
Debug.Log(lul.works);
Debug.Log(lul.yep);
Debug.Log(lul.lul);
How can I check whether it gets bursted for real?
lol - you can also look at the burst inspector and find the job
see if the instructions get vectorized
i have a shield ability with a lifetime : 9 Seconds and has 100Hp. With Trigger: on destruction i spawn an ability with AOE Collider, damage : 100, target : enemies and another ability with AOE Collider , heal : 100, Target : allies. The only thing i have not yet ready would be the case that expiring lifetime should not be counted as ondestruction.
i wonder if Job.WithCode(()= > {}) will generate IJobFor structs in the future - can't recall if they're still generating IJob π€
Its not that my AbilitySystem has everything there could ever be yet but it is extremely easy to extend and reuse
so I assume it gets bursted
so problem
good
now the hardest part
how do I read it xD
Let's say I pack KekWorks
into DynamicBuffer
my ActionQueue system reads current index of this buffer and adds component
to entity
now next system needs to read it...
My abilities are structured like a tree with subabilities. and each subability has its own triggerconditions.
@rustic rain damn you're spamming
how does your update from an effect tap into the damage events that someone can receive? guess your approach is not as encapsulated as I would have believed
The effect is applied when an ability hits a target. DamageEvents are in a DynamicBuffer on the Target. The effect could tick every frame if it has tickrate. so i could implement a function that polls for damageevents on the target and for example does another 10 damage. was that the question?
and yes abilties are tied to the damagesystem i use. Dependencies in ECS are a major painpoint for me ATM
Especially when AI gets involved which tends to read from Components splattered around multiple assemblies its really ugly
I havent seen any discussions on how to handle Encapsulation of Systems (in term of big Systems like AI, Abilities, Pathfinding etc). Looking at Physics it doesnt look like i want to do it like that. would be copying around alot of data for each system
for everyone π
I would love if you could somehow define sth like componentAlias. So you could link up Systems with the Same Components but diffrent internal names
idk
Yeah, answered my question. I went a pretty different route because I wanted insane scaling so some things like DynamicBuffers where a no go
does anyone's inspector (game object inspector) mess up / misalign when you add things to do ... particularly ECS related scripts
No, never had that issue. Are CustomEditors involved?
I'm using a few packages so probably but none on that game object
do all GOs look like this then or just this one? also which unity version?
yes if you add/remove components to them, 2020.3.31f1
i'm updating it to 2020.3.34f1 to see if it fixes the issue
I can't remember seeing that in 31f1. Maybe even skipped it, right now I have 33f1 myself. Yeah, try an update, hopefully it will fix it.
yeah seems like it's better now
it was either the version or the act of upgrading that fixed it lol
thanks
hopefully it stays that way. that bug would annoy me to no end
how do you receive damage events in diffrent systems?
because of race conditions I bundled them all. took me quite a while to come to the final implementation. i basically have 3 arrays now. 1 with source entities, 1 with target entities and 1 with the combat events itself. all 3 are then used for 2 hashmaps where the key is source/target-> combat event. then a system goes over the entities and polls events which are then processed. so in that sense, only 1 system is actually receiving damage events. other systems are only aware of damage events because I write trigger flags from this system
So until you get Disable Components you cant skip the polling work right?
even with I wouldn't be able to. the polling itself is stupid fast. no issue there
I cant either because of sth like Dynbuffer.IsEmptyIgnoreFilter not existing
Well but the systemoverhead is what always annoys me
the whole didChange is sketchy anyway. just getting a write handle increases the version so IMO it's useless
yes i agree. alot of work and overhead needed to make it work right
which system overhead? chunk iteration with ComponentTypes has hardly any
hm 0.03-0.05 ms for me most of the time when using dynbuffers. havent looked into it too much
but i definetly got too many systems running π
i mean that can add up but that's not much.
no but would be nice to skip it when those systems are designed to run once every 100 frames π
how many do you have?
AI takes 2ms on main
no idea what componentgroups are π
if you don't need your systems to run every frame that's the way to go. best to look into the FixedUpdate group or whatever they called it
[UpdateAfter(typeof(FixedStepSimulationSystemGroup))]
public class Stage1SystemGroup : ComponentSystemGroup
{
}```
public partial class AIThinkSystem : SystemBase```
oh lol i know about ComponentSystemGroups ^^sry
there's an override for ShouldUpdate in the component group. I used this once when I wanted to create a fast-forward/timelapse in a prototype. Basically have lots of updates in 1 frame
but same goes for something when you want to control the flow how and when you update it
my AI systemgroup updates every frame but a TimeSlicer/Loadbalancer based on ChangeFilters enables only Systems that are needed for a subset of the agents
sounds funky
was super easy and ultra effective π
i have a component "LoadBalanced" which at the start of the frame is written to for all chunks i wanna update. then each AI system has a changeFilter for LoadBalanced
So first frame i write to 10 chunks in loadbalanced. second frame into the next 10
is this a chunk component? you might want to look into those
not necassary i think. i only need to declare write access. i dont have to actually write.
im not sure how to manage chunk components correctly yet.
am afraid of having to have some bookkeeping for them
don't you need the same for the LoadBalanced? How does the system know which chunks to process next?
and if you add/remove the structural change overhead is quite significant
public partial class LoadBalanceTickSys : SystemBase
{
private EntityQuery loadBalanceQuery;
private const int loadBalancedChunkCount = 10;
private NativeList<ArchetypeChunk> loadBalancedChunk;
private EntityQuery alwaysUpdateQuery;
private int updateIndex;
protected override void OnCreate()
{
alwaysUpdateQuery = GetEntityQuery(ComponentType.ReadWrite<DisableLoadBalance>());
loadBalanceQuery = GetEntityQuery(
new EntityQueryDesc
{
All = new[] {ComponentType.ReadWrite<LoadBalanced>()},
None = new[] {ComponentType.ReadOnly<DisableLoadBalance>()}
}
);
loadBalancedChunk = new NativeList<ArchetypeChunk>(Allocator.Persistent);
}
protected override void OnUpdate()
{
var alwaysUpdateChunks = alwaysUpdateQuery.CreateArchetypeChunkArray(Allocator.TempJob);
var chunks = loadBalanceQuery.CreateArchetypeChunkArray(Allocator.TempJob);
loadBalancedChunk.Clear();
for (int i = 0; i < loadBalancedChunkCount; i++)
{
if (updateIndex > chunks.Length - 1)
{
updateIndex = 0;
}
loadBalancedChunk.Add(chunks[updateIndex]);
updateIndex++;
}
loadBalancedChunk.AddRange(alwaysUpdateChunks);
Dependency = new LoadBalanceJob
{
chunks = loadBalancedChunk,
loadBalancedHandle = GetComponentTypeHandle<LoadBalanced>(false)
}.ScheduleParallel(loadBalancedChunk.Length, 1, Dependency);
alwaysUpdateChunks.Dispose(Dependency);
chunks.Dispose(Dependency);
}
protected override void OnDestroy()
{
loadBalancedChunk.Dispose(Dependency);
}
}```
[BurstCompile]
private struct LoadBalanceJob : IJobFor
{
[ReadOnly] public NativeList<ArchetypeChunk> chunks;
public ComponentTypeHandle<LoadBalanced> loadBalancedHandle;
public void Execute(int index)
{
var loadBalanced = chunks[index].GetNativeArray(loadBalancedHandle);
}
}```
literally all
sry its not really cleaned up yet. naming could be much better
np, I see what it does. could be some edge cases where chunks are skipped, processed 2 times when chunks are created/destroyed, no?
yes true. wasnt something i needed to consider. more updates dont produce wrong results in my case
anway, really nice solution
feels hacky but simple
on the topic of chunk comps. they are pretty much the same as icomps, api is nice and straight forward. what one could do is write back the tick when the chunk should be next updated for example. still would require some form of polling though
it would be so cool to be able to write own filters for queries...
imagine the performance gains you could achieve by rejecting chunks super early based on arbitrary logic
CreateArchetypeChunkArray has lots of untapped potential
need to look at it at some point. atm i try to stay as highlevel as possible to not break things on package updates.
So back to my question from earlier :
{
public static void Calculate<T>()
{
Debug.Log("base implementation");
}
public static void Calculate<Speed>()
{
Debug.Log("custom implementation");
}
}```
tried it now but doesnt work as i thought it would π¦
Compiler Error says both functions have the same signiture. that was what i was hoping wouldnt happen.
would renaming Calculate<T> into BaseCalculate<T> make sense?
well that sure is possible but the point is i cannot do a implementation for <Speed>, <Health>,<...>. Noob error. havent understood how Compiler works with Generics yet
I would need to name a CalculateMethod for each implementation. On the other hand when i think about it most implementations are rather similar anyways
generics is like a form of code-gen. instead of writing a method for each type the compiler does it for you. that leaves you with overlaps though like in your case
public struct Attribute<T> : IComponentData where T : IComponentData,IAttribute
{
public float Value;
public float baseValue;
public float previousValue;
public void Calculate()
{
AttributeCalcUtility.Calculate<T>(this);
}
}```
overrides in classes are much easier to handle but then burst doesn't work
seems like a good "base" π
well the problem is i wanted to do some kind of smart switching on the type here. if i have it this way i cannot rename the functions in AttributeCalcUtility to sth like CalculateSpeed
Maybe i am forced to do a switch on the type ?
seems so
switches in burst, as long as every case is implemented are translated to a jump table so super fast
and since every system always takes the same branch it should be np anyway right?
branch prediction will always be right
i think so but I'm no expert on this. I can only say as much that it will be no problem performance wise
Still i hate switches just for the fact that i need to edit in 2 files when i add sth new... wanted to work with a partial static here to be able to implement the function in the same file i define the component. I guess i would have to use codegen to do that now. I havent ever set up Codegenerators so im not sure if it is worth the hassle? PhilSA got it working somehow.
ok im back to work and im still stuck on this
is there some code to look at for this?
yes
I don't see an associated job for this? Would be hard to tell what the problem is π€
hang on i have to stop this code making an infinite loop
he code-gens a switch π
Yes but i wouldnt need to. I could CodeGen the whole System with the exact function id implement in the ConcreteType.
I bet id run into another roadblock i dont see yet though π
I just want to reduce dublicate code as much as possible. if id implement all effects and then it turns out i need to change sth in the architecture i would have to touch every single one of those systems spread across multiple files for each effect...
using generic Systems i can change the Architecture really fast. sure its more complicated to design but i find it more maintainable. It also will enable my gamedesigner to create effects in a EditorTool without me.
@solemn hollow if you do a switch on the type in a generic it will get compiled out to only the correct case
but burst wont allow it π¦
oh
typeof is not allowed in burst
maybe check the latest docs for burst because I remember something about using generics in a special way
All the interesting discussions happen when I'm asleep
hmm cannot find anything that is useful to me in burst docs. but might also be because im not good enough to understand everthing
5:30 atm, really need to sleep in
where are you located? Im from germany
Well good thing programmers Day/Night cycle is random anyways
Can you just use is keyword manarz
Effectively let's you do type checks in burst without boxing
hmm how?
dont i need to do
switch(typeof(T))
case : T is Speed
Let me get out of bed because I'm not going on my phone
hmm ill be here later too. so dont hurry
too late you already got me up
{
public static void Calculate<T>(T attribute)
where T : unmanaged, IAttribute
{
switch (attribute)
{
case Speed speed:
Calculate(speed);
break;
case Meth meth:
Calculate(meth);
break;
default:
// default calcation
break;
}
}
private static void Calculate(Speed speed)
{
Debug.Log("custom implementation");
}
private static void Calculate(Meth meth)
{
Debug.Log("custom implementation");
}
}```
great ill feel bad the rest of the day now because of some guy on the other side of the glode π
or in if form
{
public static void Calculate<T>(T attribute)
where T : unmanaged, IAttribute
{
if (attribute is Speed speed)
{
Calculate(speed);
}
else if (attribute is Meth meth)
{
Calculate(meth);
}
else
{
// default calcuation
}
}
private static void Calculate(Speed speed)
{
Debug.Log("custom implementation");
}
private static void Calculate(Meth meth)
{
Debug.Log("custom implementation");
}
}```
(haven't read your problem just looked at the double generic code issue you posted)
oh damn thats perfect. i was to stupid to pass attribute.
Thats what happens if you don't have a background in Coding π
i dont have abackground in coding π
Im sure at some point u did exactly the same mistake then!
well atleast problemsolving skills are universal i guess
oh yeah problem solving has always been my strength
i actually only recently considered using 'is' to type check in burst
cant remember what my use case was though
I kinda feel bad to not ask some of those questions on the forum. Those discussions will be buried forever.
that's an interesting point
its a little silly how often i've googled something and I find the solution on the forums posted from my past self π
I still cant get it to work..
public partial class AttributeCalculationSys<T> : SystemBase
where T : IComponentData,IAttribute
{
private EntityQuery attributeCalculationQuery;
protected override void OnCreate()
{
attributeCalculationQuery = GetEntityQuery(ComponentType.ReadOnly<Attribute<T>>(),ComponentType.ReadOnly<AttributeModifier<T>>());
attributeCalculationQuery.ResetFilter();
attributeCalculationQuery.AddChangedVersionFilter(ComponentType.ReadOnly<RecalculateAttributes>());
}
protected override void OnUpdate()
{
Dependency = new CalculateAttributesJob
{
attributeHandle = default,
modifierHandle = default
}.ScheduleParallel(attributeCalculationQuery,Dependency);
}
[BurstCompile]
public struct CalculateAttributesJob : IJobEntityBatch
{
public ComponentTypeHandle<Attribute<T>> attributeHandle;
public ComponentTypeHandle<AttributeModifier<T>> modifierHandle;
public void Execute(ArchetypeChunk batchInChunk, int batchIndex)
{
var attributeArr = batchInChunk.GetNativeArray(attributeHandle);
var modifierArr = batchInChunk.GetNativeArray(modifierHandle);
for (int entityInChunkIndex = 0; entityInChunkIndex < batchInChunk.Count; entityInChunkIndex++)
{
var attribute = attributeArr[entityInChunkIndex];
var modifier = modifierArr[entityInChunkIndex];
AttributeCalcUtility.Calculate<T>( attribute);
}
}
}
}
public static class AttributeCalcUtility
{
public static void Calculate<T>(T attribute)
{
if (attribute is Speed)
{
}
}
}```
The problem is that i cannot pass a parameter of Type T
what's the compile error?
you need to restrict T in calculate
where T : IComponentData,IAttribute
attribute is of type Attribute<T>
missing the <T> on CalculateAttributesJob.
public partial class AttributeCalculationSys<T> : SystemBase
where T : IComponentData,IAttribute
i'd definitely put unmanaged on this as well
it's in the system
but how to i "extract" T from attributes to pass along
i'm pretty sure it's still needed. otherwise ignore me π
its not needed. doing it in my AI systems like that too
oh you mean this part
Attribute<T>
where T : unmanaged, IAttribute
{
if (attribute is Attribute<Speed>)
{
}
}```
duh. i should go to bed omg.
Is there a way to create an instance of a generic System in the defaultworld without explicitly adding it? Some Attribute or sth?
you have a generic job in here which needs to be registered with burst
how are you doing that?
I'll just declare it where i create that Concrete Attribute
So basically above in my SpeedAttributeAuthoring
ideally i would like to have a single small file to write to create a new effect. but not sure if i can do that just yet
where T : unmanaged, IComponentData
{
private EntityQuery query;
protected override void OnCreate()
{
this.query = this.GetEntityQuery(ComponentType.ReadOnly<T>());
}
protected abstract GenericJob CreateJob();
protected override void OnUpdate()
{
var job = this.CreateJob();
job.StateType = this.GetComponentTypeHandle<T>(true);
this.Dependency = stateJob.ScheduleParallel(this.query, this.Dependency);
}
[BurstCompile]
public struct GenericJob : IJobEntityBatch
{
internal ComponentTypeHandle<T> StateType;
// Code ...
}
}
public class GenericImplementation : GenericBase<Menu>
{
protected override GenericJob CreateJob() => default;
}```
this is my pattern for how i handle generic jobs/systems
i just give each an implementation and create a default job which is enough to satisfy burst
another developer jumps in, implements a new GenericBase they don't have to worry about setting up bootstraps, or attributes or anything
oh that is so much smarter than i do it in my AI i think.
I use MakeGenericType to create instances for my Systems.
Ah but nvm i cant do it like that for AI since a Scriptable Object defines the Types i need for the Instance
too much hassle to rewrite that now i think^^
hmm in UnityEngine.Object
public int GetInstanceID()
{
this.EnsureRunningOnMainThread();
return this.m_InstanceID;
}```
can anyone think why this needs to be mainthread
i feel like InstanceID doesn't change
lifecycle stuff?
public override int GetHashCode() => this.m_InstanceID;
right below it
its returned without a safety check
via gethashcode
i think instance id only changes between project sessions*
i just want to read Mesh.InstanceID
in a job
just going to work around it with GetHashCode
instead of using some magic
yea i've no idea why it's main thread only π€ dunno what Unity is doing on the native side to create the instance id tho π
My brain is breaking. I have a component that is somehow messing up with parenting after instancing an entity. I've found that if I remove the authoring component it doesn't break, and if I add or replace with another dummy authoring component it doesn't break either. Now I've strapped all usage and references to this authoring component, cleaned the Library folder, and it still messes up. Neither of the authorings are actually even adding any component to the entity.
wdym by messing up parenting?
{
[ReadOnly]
public SharedComponentTypeHandle<RenderMesh> RenderMeshType;
public NativeHashMap<int, int>.ParallelWriter MeshMap;
public EntityManager EntityManager;
public void Execute(ArchetypeChunk batchInChunk, int batchIndex)
{
var meshIndex = batchInChunk.GetSharedComponentIndex(this.RenderMeshType);
var renderMesh = this.EntityManager.GetSharedComponentData<RenderMesh>(meshIndex);
var instanceID = renderMesh.mesh.GetHashCode(); // This returns instanceID it just bypasses unneeded main thread check
this.MeshMap.TryAdd(meshIndex, instanceID); // failure is fine, means already added
}
}```
this solved so many issues for me
so nice being able to pass EntityManager to jobs
anyway jaws those pictures look the same i have no idea what's going on π
oh wait no they dont
there's a hole
without seeing your magic component and related code can't really say much though!
public struct VisualStateDummy : IComponentData
{
}
public class VisualStateAuthoring : MonoBehaviour, IConvertGameObjectToEntity
{
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
dstManager.AddComponentData<VisualStateDummy>(entity);
}
}
Not much to see x)
Is there any System that interacts with VisualStateDummy right now?
Nope. Nothing references the authoring anymore, the dummy was never used but something I just created to see if it's something about not adding any component in the convert step.
Yes .33
But I think this has to be some weird deterministic error which is caused by some other code.
have you cleared the entity cache?
Yes, cleared library, sceneDependencyCache and through the menu to clear entities.
we also support the IRefCounted interface, which (if you're careful) allows you to store a single copy of an underlying resource across all World's in your app.
What's that about?
When Google only has 1750 results you know you are in obscure shit
let's you share resources across worlds via sharedcomponentdata
BlobAssetOwner inherits it for example - check it out for an example
interesting usage, reminds me of how the GC works
for example, moving colliders to a new world doesn't need to duplicate the collider memory
Should there be a Universe Abstraction? :S
Hm, can we use this to make a proper implementation to use UnsafeContainers in IComps?
its only used in ISharedComponentData manage store
the IRefCounted is universal
its only called in ManagedComponentStore
When disposing or creating ISharedComponentData
you can make an interface with the exact same methods
it doesn't mean it magically works π
ah, I thought I have to call them myself
yeah, more like the idea/principle of doing this
you could use your own interface and system for handling this
having the possibility to use unsafe containers in IComps without any worries sounds like a good idea to me
don't really see how you're going to do this
sounds like a challenge!
ISystemStateData can handle that problem
so your strategy is to add a bunch of archetype changes
and if you're just using ISystemStateData can't you just dispose the container
why do you need to ref count it
π¦
also ISystemStateData still doesn't help if you just destroy world or stop play mode etc
the ref counting is for this case
(this is actually a really good use of IRefCounted btw, you can do cleanup on world destruction)
but sure, I get your point. π
it would be close to implement a custom garbage collector
already done that for my AI ^_^'
blobs caused too many issues
just wrote my own memory management
what happened?
nah, I mean what prompted you to write your own memory management
because i couldn't use blobs
and i didn't want to deal with disposing the memory individually
and the memory has a lifecycle of the entire worlds life
so i can just allocate arbitrary then clean it up all at once
so every AI was having their own blob data?
Sounds like another tertleTool comming soon π
@rotund token On the subject of tools: did you manage to get your DynamicHashmap readable in the Inspector?
nah never tried
was an enzi problem π
where i use it at the moment i have no need to inspect
it could be a me problem too
it only exists on a few singleton entities
for fast lookup of prefabs and a few other things
so i had never tried to inspect it
until i run into a case of needing it myself probably too lazy to look into it
np i wont be needing it soon π
just write add the DebuggerTypeProxy and inspect it in code via entity journalling
i love how i can break point on an entity field now and look at all it's components
has dramatically increased debugging ability
unity has not got enough credit for this
true. my problem would be that someone without an IDE would need to inspect it.
I think my AI performance could actually greatly benefit from your DynamicHashMaps if id replace my DynamicBuffers with them.
because i allocate a hashmap in each job i schedule anyways and combine my InputAxis for each Target in there
i really want to write a
FixedHashMap4096 or something
So you can have them in chunkmemory?
nah just so i can have small ones in jobs instead of Temp allocated
you can sometimes get a decent speedup using FixedList instead of a NativeList(Temp)
yeah, not bothering π i debug logged it once to proof my code was working
ah i see
having some form of memory block that isn't allocated all the time is pretty useful
on that note: Who needs more than 640k memory??
@solemn hollow as we were talking before about effects and you mentioned a slow effect. why would you need an update for that? or rather, what would be updated?
Each effect has a TickRate. If it is set to 0 the effect is only applied once. Its not really an Update() but an ApplyEffect(). I simplified a bit earlier
What i try to achieve is having effects that cost nothing while not ticking aside from needing to check if they have to tick.
ah yeah, why not just a component tag?
but I dunno, solving things with tags. it's the same as polling under the hood π
because effects can stack and i need to keep track which effect runs out when
and this
To not have to poll i have a ApplyEffect and an UndoEffect. Effects are Entities with a DynamicBuffer with references to the targets and when the targets got the effect applied
So i just have to loop over all appliedEffects and check whether they timed out. if so i undo the modification of the relevant Component
my effects are all polled by tick (when they even have a tickrate). not sure if i will ever change this as my effects are entities. well more a container, it's just one big comp, every other data is in a blob
i cant remember why i decided to do it with one EffectEntity and a Dynamicbuffer instead of many EffectEntities. I had a point there.
I think both solutions are very valid and both have their pros and cons
some things are easier, some are harder
yep. im sure it was just a convenience thing for me. but what was clear is tagging Targets was not the way to go
my removal of effects sadly needs a structural change with SystemStateData. maybe I get around of not needing this anymore
are you talking about destroying the effect or sth else?
yeah, tagging doesn't work
destroying the effect. well adding too
im too lazy to do entitypooling atm
this is pretty old code but never changed. the need was, does target have effect X, if so do something special. the method to find was so expensive so I made a global lookup table of effect types. now I can just query this hashmap if there's a certain effect on an entity
entity pooling doesn't have much use. my spells were using it once π
way too costly
sadly im making a 2.5D game with 2D Bone animations
so my entites drag around a gameobject
so i guess pooling both would be adviseable
ah I still have it in my codebase
maybe I will use it someday for the effects. But creating > 10k is such a niche case I won't bother with it
not sure I follow what that has to do with pooling?
nice thx ill look into it.
atm i am instanciating entities that spawn a companionobject...
pretty expensive
when you say companion, a gameobject, right?
both depending on the case actually T_T
ok π
a gameobject i spawn myself to make use of animations and sometimes a companiongameobject because i just have an entity with a spriterenderer or vfx
For abilities its actually only the latter
yeah, i see, we all pretty much deal with the same dumb shit π
insane scale and then -> plop some GOs
yep and this scale in the design always makes it so much more complicated than a normal game would be xD
If Id use DOTS for stuff i do with monoB i bet it wouldnt be complicated at all
with stuff i mean reasonable gamedesign
where would the fun be though
hopefully in the game id would have finished by now π
make games not engines -> yeah, hold my beer, I make uhmm something
I have no artist(s) so I'm not making a game anway π
the dream of using asset store art has died long ago
programmer art is a thing. It does not mean your game has to be ugly
soon AI will be good enough to make programmer art beautiful
who knows. I think a lot is picking a style you can manage. Be that by creating stuff yourself or a style thats easily found in the assets store/other libraries for free or little coin.
then again what do I know. I write code for a living (not games) and just dabble in 3d/2d for hobby. Just installed unity for laughs. π€·ββοΈ (don't even know what dots stands for as the channel name) π
Need talented 3D artist looking for a great opportunity on the next big thing. Need AAA realistic graphics. Reimbursed by revenue share.
You telling me, that doesn't work?!
glances up at channel description.. its Data-Oriented Technology Stack appearantly π
haha no.. that looks like blender artist volunteer work section
new way is to have fugly art and sell it as NFTs. Pay the artist a few 1000 $ and then rugpull the millions :S
all idea people who want to make the next MMORPG by themselves.. they just need a team of artists (and coders and animators)
haha I helped someone with a rendering issue in blender a while ago.. he was grateful and was working on NFT and I could get a part or something.. no thanks. I just like solving problems. gl hf lol
that's my programmer art. at one point I just can't stomach it anymore π¦
whoa sorry that got big
that stuff is looking pretty moody dude! Nice π
really? thanks
and dude I recently started playing "forgive me father". Some indie fps that got high praise. Its not that hot and the levels are really effing ugly. Like.. screw blaming that on "retro style". People still made nice stuff back in the day. Still it seems pretty succesful and many people enjoy it
so don't hate on yourself too much, its not productive anyway. π
thanks for the encouragement π would it not be for my day job I'd continue with it
I don't really code "for fun". Its just a job (not gamedev either). But I like dabbling in 3d and well.. Unity is pretty fun for prototyping and mucking about. So not doing anything serious but having fun.
it is fun and oh so time consuming π
beats being bored or wallowing in existential dread right? π€·ββοΈ π
for sure and much better than watching tv all day like the rest does in their free time π
how do you use this iterator from a NativeMultiHashMap ?
want to do a simple for loop through all elements related to the key
but its not clear how to use it
do it with an enumerator var enumerator = threatTargetEvents.GetValuesForKey(mainEntity); { while (enumerator.MoveNext()) { //ref var te = ref enumerator.Current; var te = enumerator.Current;
oh i see
thanks
i thought iterating through data like this was slow for native containers compared to regular for loops
i remember reading some where that using foreach for example was not a good idea
that was a long time ago where forEach produced garbage in mono
well a hashmap is not a linear array
oh is it not ?
i thought the values were in a native array
like key,native array <value>
yeah but it's unsorted and has holes (potentially) so iteration is through the bucket
holes?
if you remove a key
the gist of a hashmap
quite a bit more involved than just 2 arrays
i see
maybe i should opt for a <Key,NativeList<Value>> of my own so i can iterate my values easily
it works really well though, I can assure you that
seems odd they wouldn't just use a list to collect all the values to me
sadly that won't work, only with unsafe containers
yeah, I thought the same. most native containers could be improved in lots of ways
yeh the lack of not being able to have containers within containers without unsafe is one of my biggest complaints π
it would make life so much simpler
but it's still in local space even when some elements are skipped. imagine a huge hashmap and 100s of pointers everywhere in memory
good chance that it will be slower then if you iterate over more values by keys
oh i wouldn't iterate over keys only values
i cant imagine when some one would iterate keys
π π
how can I reverse a native list?
i mean I guess i dont really need to but it would be nice
do you really wanna take the hit of the memory copy or sort? just iterate from the end to the beginning
anyone knows a safe version to get pointers from a MB component like the animator? (unsafe code is okay! haha)
ArgumentException: GCHandle value belongs to a different domain ... meh π¦
it would be easier to just loop through it backwards rather than memory copy / sort
Fair enough
wdym
i want to use a NHM instead of private Dictionary<Entity, Animator> animatorLookup; so I need to get the pointer of the animator because classes won't work in NHM
this failed with the posted error msg
{
[ReadOnly]
public SharedComponentDataFromEntity<RenderMesh> RenderMeshes;```
The code I write sometimes makes me laugh
in a good or bad way? :9
well i wanted to access shared components in jobs in parallel
so i wrote my own SharedComponentDataFromEntity
now i can
yes
its pretty simple
obviously it doesn't work in burst but works fine in a regular job
but i wanted to access shared components in jobs without main thread sync points
{
[ReadOnly]
public SharedComponentTypeHandle<RenderMesh> RenderMeshType;
[ReadOnly]
public SharedComponentDataFromEntity<RenderMesh> RenderMeshes;
public NativeHashMap<int, int>.ParallelWriter MeshMap;
public void Execute(ArchetypeChunk batchInChunk, int batchIndex)
{
var meshIndex = batchInChunk.GetSharedComponentIndex(this.RenderMeshType);
var renderMesh = this.RenderMeshes[meshIndex];
var instanceID = renderMesh.mesh.GetHashCode(); // This returns instanceID it just bypasses unneeded main thread check
this.MeshMap.TryAdd(meshIndex, instanceID); // failure is fine, means already added
}
}```
my nice little job
nice! That looks super handy
public unsafe struct SharedComponentDataFromEntity<T>
where T : struct, ISharedComponentData
{
#if ENABLE_UNITY_COLLECTIONS_CHECKS
private readonly AtomicSafetyHandle m_Safety;
#endif
[NativeDisableUnsafePtrRestriction]
private readonly EntityDataAccess* m_Access;
#if ENABLE_UNITY_COLLECTIONS_CHECKS
internal SharedComponentDataFromEntity(EntityDataAccess* access, AtomicSafetyHandle safety)
{
m_Safety = safety;
m_Access = access;
}
#else
internal SharedComponentDataFromEntity(EntityDataAccess* access)
{
m_Access = access;
}
#endif
public T this[int index]
{
get
{
#if ENABLE_UNITY_COLLECTIONS_CHECKS
AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
#endif
return m_Access->GetSharedComponentData<T>(index);
}
}
}```
this is all it is - have not fleshed it out yet
very simple
technically unsafe because i'm doing a read only check but in theory as the shared component could be managed and store a class etc you could write to it
but yeah that's on you
i need to learn writing my own containers too at some point it seems. I couldnt do it
just like, if you call GetUnsafeReadonlyPtr() and write to it, can't help you. enjoy the crashes
this is not much of a native container
just adding the attribute ensures some checks (aliasing) etc are performed
ah ok. yes i have no clue how all those checks are working. I know nothing about how to use Safetyhandles and dont dare to touch pointers yet
for the most part you dont need to do anything with safetys
store it, make sure it's called m_Safety
in read methods use
AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
in write methods use
AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
that's about it π
assign it with
DisposeSentinel.Create(out m_Safety, out m_DisposeSentinel, disposeSentinelStackDepth, Allocator);
dispose with
DisposeSentinel.Dispose(ref m_Safety, ref m_DisposeSentinel);
thats about the whole safety system setup/use
oh that sound easy enough!
whats that about :
```public T this[int index]````
never seen this syntax
yep i just didnt know you can do it with this[]
i see
never wrote containers π
btw i get this error : Burst error BC1020: Boxing a valuetype Attribute1<Speed>` to a managed object is not supported
from the code we spoke about yesterday
public static void Calculate<T>(Attribute<T> attribute) where T : IComponentData
{
if (attribute is Attribute<Speed>)
{
}
}```
where T : IComponentData
you need to restrict it to unmanaged
where T : unmanaged, IComponentData
otherwise compiling thinks it could be a class
yes i tried it and didnt work. but i think my error was not ristricting it in Attribute<T> struct too
am compiling rn
hmm Error is still there.
welp im giving up on switching over type for now. Going back to good old enums...
sorry bump this up but won't this skip over the first item ?
π€
oh so the iterator starts before the first element
yep
Do you have any idea how to make Action queue in ECS?
I sit for 2 days already, can't figure out the way
I thought of packing it this way. But with this approach I can't figure out how to unpack it, without hard-coding system for it for every possible queued action.
public struct QueuedAction : IBufferElementData
{
public ComponentType type;
public FixedBytes126 args;
}
i mean, why is it the responsibility of more than 1 system to ever unpack it
I'd simply just pack struct into byte array
and then read it fully
then add as component
but I have no idea whether it's possible at all
UnsafeUtility.As<FixedBytes126, KekWorks>(ref queue.args);
Reading it when it's known type is simple
but when it's unknown...
again im not quite sure why you dont try out PhilSA s PolyComponents. I think they work for IBufferElementData too.
I guess I'll have to try
well, I looked through it again - that's not it
My actions work with completely different data structures, so that just not gonna do it
what kind of parameters do your actions actually need?
Literally any
pathfinding action requires one set
some other action requires completely different one
all of my actions just take TargetEntity,AgentEntity and anything else would be handled by other systems.
give an example of action parameters as you would need them
pathfinding will require literally all space related components (ltw, translation, ltp and etc)
target finding action will require HashMap
it's all handled in different systems through different queries
and you want to have a single System that handles Pathfinding,Targetfinding,Moving etc?
no, I want to have system that can queue different actions
let's say I want to do a complex action:
go to target 1, then to target 2, and then do a flip
but you tag your entity with the action that should be executed right?
So why isnt it enough to pass: target 1, type goto ; target 2, type goto; target null, type flip
and your action systems then can read the necassary other data and execute their actions
u dont need to pass pathfinding data to the Action. you can get it from a different Component in the query of your GoToActionSys
that's the thing
I figured how to do chain
but not how to pass arguments
so basically
If I want to do queue of 3 go to actions
Once first go to is done, I only know type of next action
but not argument
as in, where exactly to go to
I can solve this by making unpacker of packed argument list for literally every system of action that can be queued
but I find this approach really meh
I guess I'd need generic abstract system
that will get auto generated
through inheritance
what. im getting more confused by the minute ^^
why dont you have a DynamicBuffer<ActionQueue>
filled with structs : ActionQueue{
actionType,
actionTarget
}
and your AI just fills them
why do you need to pass along arbitrary data. you can always get the data you need when you need it later on in other systems in other components and then read from it
because action queue can consist of different actions
right now I am making mechanic of "jumping between star systems"
where character needs to get to edge of star system it is in right now, teleport to other system, and then do slight movement from edge of target system.
of course I can make a unique queue component that will hold all data required for this action list
but when I'll need another complex action
I'm gonna have to do it again
Yes have the AI decide what targetStarSystem you need to go one after the other.
Let it fill the Buffer with the Targets and the ActionTypes. Add the ActionType of first Action in the buffer to the Entity as a Tag. Then have the MovementSystem get all entities with that MoveAction and move it towards the target specified in The ActionQueueBuffer[0]
oh are you the one who mentioned utlity ai the other day?
i been watching some videos on it - seems like its very similar to goap
it's not for AI
it's for player controls
at very least xD
it does not matter who decides the action though. player or AI
hm
i have implemented it this way. i just skipped the DynamicBuffer part
So you have Entity target?
hm
I do get your point rn
I guess I can try to figure out a way
to create a general argument list
yeah, I see your point
this is what would be your actionqueue
i have more data on there cause of debugging
the thing is you dont want to send data. you just query it
is that I can make a struct with:
float3
Entity
ComponentType
and pack it in any way I want
then target system of ComponentType will get those float3 and Entity
and figure out what to do with it
not the best I hoped for, but still works
allthough...
it still raises a question, of how do I pass that data
I assume, I can just use action queue buffer as base for literally all action systems
every actionsystem has a query like this:
ActionComponentTag,ActionQueue,DataActionNeeds1,DataActionNeeds2...
like the MovementSystem would get MovementSpeed and Path. (Path was created before by PathfindingSys)
same
ok, I like the idea behind using action queue all the time
ive seen this before i just dont remember what
With it I can avoid adding ComponentTypes to Action components
public partial class UAIFleeSys : SystemBase
{
protected override void OnUpdate()
{
Dependency = Entities.ForEach(
(ref FleeAction fleeAction, ref NavDestination navDestination,
in DecisionActionData actionData , in LocalToWorld position) =>
{
if (HasComponent<LocalToWorld>(actionData.targetEntity))
{
float3 directionFloat = GetComponent<LocalToWorld>(actionData.targetEntity).Position - position.Position;
Vector3 direction = new Vector3(directionFloat.x, directionFloat.y, directionFloat.z);
Vector3 targetPos = new Vector3(position.Position.x, position.Position.y, position.Position.z) - direction.normalized;// * speed;
{
navDestination.requestedDestination = targetPos;
}
}
}).ScheduleParallel(Dependency);
}
}
public struct FleeAction : IComponentData
{
public ActionState actionState;
}
this is how flee looks for example
just moving editor elements causes it to error and im not in play mode so it seems ill have to restart the editor at this point
You can see im using the DecisionActionData to read the target and the FleeActionTag to know this system has to execute
sry i was distracted. GOAP is very different. Utility AI does not traverse any PlanningGraphs to plan steps ahead. It just directly reacts to changing environments based on a Score assigned to each individual action. It does not try to maximise a score over multiple actions or sth. But through good setup of the ActionUtilities you can achieve pretty much the same behaviour as if you would plan ahead.
Forgot to mention: GOAP often uses UtilityScores to Decide which goal to persue. So in that sense that Goal choosing can be seen as a form of UtilityAi
does someone already have a working entitypicker? Like at runtime selecting an entity in the scene and showing its Inspector? Cant believe its still not in 0.50 :S
yeah
Just edit GenerateColors
With the query you want to select
assign _camera field to camera you select from
and call OnClick
thanks!
if you want
Will be the next thing ill add. need to first get those pesky AbilityEffects running
i have a significantly improved performance version of that
also with support for hybrid skinned mesh renderers
oh yeah, I wanted to mention that
could you paste it again?
i mean sure i want an improved version π Does it actually work with sprite renderers?
nope xD
arrrg
i only added skinnedmeshrenderers
but you can see how i did htat and probably do it for spriterenderers as well
well thats even better. then ill learn sth along the way
Entities.WithSharedComponentFilter(system)
.WithAll<Selectable>()
.ForEach((Entity e, RenderMesh mesh, ref LocalToWorld localToWorld) =>
{
if (mesh.mesh == null)
{
return;
}
_entityIndexToVersion[e.Index] = e.Version;
_idMaterialPropertyBlock.SetColor(ColorPropertyID, IndexToColor(e.Index));
cmd.DrawMesh(mesh.mesh, localToWorld.Value, _idMaterial, mesh.subMesh, 0, _idMaterialPropertyBlock);
})
.WithoutBurst()
.Run();
Here key code for it
if you can figure out how to do it with sprite renderer
that would be great
{
this.matrices.Clear();
this.colors.Clear();
this.propertyBlock.Clear();
this.colors.AddRangeNative(chunk.Colors.Ptr, chunk.Colors.Length);
this.propertyBlock.SetVectorArray(this.colorPropertyID, this.colors);
this.matrices.AddRangeNative(chunk.Transforms.Ptr, chunk.Transforms.Length);
var matrixArray = NoAllocHelpers.ExtractArrayFromListT(this.matrices);
var mesh = this.system.World.EntityManager.GetSharedComponentData<RenderMesh>(chunk.Mesh);
this.commandBuffer.DrawMeshInstanced(mesh.mesh, mesh.subMesh, this.material, -1, matrixArray, this.matrices.Count, this.propertyBlock);
}```
so yeah i changed it to this
1 per chunk instead of entity
burst job
hm
to generate colors