#archived-dots
1 messages ยท Page 265 of 1
yeah, but I spam it
for every room
irrelevant
whether I have entities at all or not
I can do query check, before actually doing all prep work
and I also can add some tags
to avoid doing it every update
but instead only when required
after all, this is all just find target job, which happens occasionaly
but it is indeed a question, whether it's efficient way to do that
since when I'll have 100 systems
and thousands of entities
it indeed might be spammed all the time
You might wanna look into chunk components if you havent yet.
I think it's already chunk components
considering I do query per SharedComponentData
Chunk components are not the same thing
it might help with filtering entities in your jobs after room for example. then you wouldnt need the sharedfilter
because as far as i understand it you dont really want to filter but kind of sort
you still want to process all entities in your query with one job.
well, my rooms division works based on SharedComponent
yes but as tertle already said if that means you need to schedule each job for each room with the same query but different sharedfilter the performance wont scale. Scheduling is too expensive
I see
so I do need some smort bursted solution on this
I still haven't really looked at tertle's one
cause I don't understand it xD
his solution was a way to not loop over all targetable Entities every time you search for targets. Splitting them up in a grid lets you just search neighbouring cells for entities and run your targeting logic on them.
I still don't understandh
how exactly that splitting
and then looking through that works
it doesnt really matter how you group them i was just providing a suggestion
what really matters is just being able to do it in 1 job
yeah, that part I get
if you want to have a not so efficient array of array you could do that
I want any solution that is better
I just need to understand it first
How to do DisposeOnCompletion with IJobEntity?
hmm i wonder if that is a decent way to go about it:
Run a job on a query containing all chunks of all rooms.
Inside the job sort the chunks based on room (acutally this could be maintained outside).
For each room loop over all chunks of that room....
seems reasonable to investigate
there's definitely going to be multiple ways to tackle this
and i think the best solution is well obviously going to be project specific, but likely also be something re-usable between multiple systems
do you mean deallocateonjobcompletion ?
ah, yes
personally i never use it but i assume the attribute still works?
just like other jobs
personally i think the project sounds a little bit ambitious for a first DOTS learning project.
oh ok sry some of your questions tackled some basics.
@rotund token have you ever found a decent way to use DynamicComponentTypeHandle?
Id really want to somehow have access to a Component on another entity just based on a ComponentType and avoid generics.
yes
its how i save
{
var components = chunk.GetDynamicComponentDataArrayReinterpret<byte>(this.ComponentType, this.ElementSize);
var entities = chunk.GetNativeArray(this.Entity).Slice().SliceWithStride<int>();
entityCount += entities.Length;
var chunkHeader = new HeaderChunk { Length = entities.Length };
this.Serializer.AddNoResize(chunkHeader);
this.Serializer.AddBufferNoResize(entities);
this.Serializer.AddBufferNoResize(components);
}```
is my component specific serializer for example
and yeah, avoided the need for generics
But this is deep in unsafe land isnt it? ๐ im not sure i can tackle that stuff
there's no unsafe code there at all i don't think
yeah this code has no 'unsafe' code
oh nice
TypeManager.GetTypeInfo(this.TypeIndex)
to get element size and that's really all i need apart from typeindex
whenever i tried to use it it required me to do unsafe stuff. i probably did sth wrong then
how are you deserializing it onto entites? I need to write from a component that has a ComponentType Reference to that referenced component on another entity
my deserializer uses unsafe code unfortunately for optimization
but i basically deserialize onto a hashmap
but then i actually just iterate all valid entities and check if save data exists for them
then apply it
var entities = batchInChunk.GetNativeArray(this.EntityType);
for (var i = 0; i < entities.Length; i++)
{
var entity = entities[i];
if (!this.SerializedData.TryGetValue(entity, out var srcStart))
{
continue;
}
var dst = (byte*)components.GetUnsafePtr() + (i * this.ElementSize);
var src = (byte*)srcStart.ToPointer();
UnsafeUtility.MemCpy(dst, src, this.ElementSize);
}```
How do I pass dependency on certain component to job?
I still can't figure it out
pass in dependency handle of the systems should be handling it for you
sounds so easy but im afraid of your code ๐
what dependency do you need?
culled it a bit because the other part was confusing
(it was the code that allowed [SaveIgnore] so it sliced it up)
private partial struct HuggerFindTargetJob : IJobEntity
{
[Unity.Collections.ReadOnly, DeallocateOnJobCompletion]
public NativeArray<LocalToWorld> ltws;
[Unity.Collections.ReadOnly, DeallocateOnJobCompletion]
public NativeArray<Entity> entities;
void Execute(ref HuggerAI hugger, in LocalToWorld ltw)
{
int ind = GetClosestTargetIndex(ltws, ltw.Position);
if (ind != -1)
{
hugger.Target = entities[ind];
}
}
}
private int kek = 0;
protected override void OnUpdate()
{
kek++;
if (kek % 60 != 0)
{
return;
}
HuggerFindTargetJob job = new HuggerFindTargetJob();
foreach (var starSystem in _starSystems)
{
_huggerQuery.SetSharedComponentFilter(starSystem);
_targetQuery.SetSharedComponentFilter(starSystem);
if (_huggerQuery.IsEmpty || _targetQuery.IsEmpty)
{
continue;
}
job.ltws = _targetQuery.ToComponentDataArray<LocalToWorld>(Allocator.TempJob);
job.entities = _targetQuery.ToEntityArrayAsync(Allocator.TempJob, out var dependency);
Dependency = job.Schedule(_huggerQuery, JobHandle.CombineDependencies(Dependency, dependency));
}
}
Here's what I try to do rn
kek
kek
im too tired and tipsy to think about the problem
but just aheads up 1 random issue is
{
continue;
}```
this will cause a potentail sync point
queries with filters can need sync points to do stuff like this
{
get
{
var queryRequiresBatching = _QueryData->DoesQueryRequireBatching;
if (!_Filter.RequiresMatchesFilter && !queryRequiresBatching)
return IsEmptyIgnoreFilter;
SyncFilterTypes(); // HI I'M A SYNC POINT```
i wonder if they can get rid of those at some point somehow... i am reluctant to use ChangeFilters because of it rn
i already chatted to cort on forum about it if you read that thread
and had a quick chat with him afterwards as well and i believe the work he's doing on async methods will remove the sync points in future
yep i read it
for now you can just do your change filtering in the job
but yeah i avoid withchangefilter atm
i suspect though as it's somewhat tied to enable components it won't be till 1.0 (just gut feeling)
@rustic rain i am sry i cannot see the error either.
i dont think we will see anything new till 1.0
but doing it inside the job means i have to schedule the job in the first place ๐ฆ
need to sleep, catch you all later. if you happen to have not solved that dependency problem in 12 hours @rustic rain let me know
gn8!
Is there a way to assign ComponentData to all entities?
in query
kind of like AddComponent
basically I have EntityQuery and I want to assign all entities in that query to certain component
all must have let's say new HuggerAI() component
addcomponent seems to work with an nativearray of entities
then convert the query to nativearray with query.tocomponentdataarray
i think you will also have to use query.copyfromcomponentarray to copy it back after
EntityManager.AddComponent<MyComp>(query)
but will that refresh component on existing entities?
yes
also there is setcomponent
SetComponent doesn't accept query
oh i didnt know it has no batch command. i guess there wouldnt be much performance benefit in that
AddComponent always adds or sets the data
Is there a recommended way to get the Scene View to match the Game View when using the hybrid renderer? Considering writing back to the GameObject transform when debugging
Any idea why this is happening?
ArgumentException: Unknown Type:`Unity.Networking.Transport.NetworkConnection` All ComponentType must be known at compile time. For generic components, each concrete type must be registered with [RegisterGenericComponentType].
Ah wait, I think it's just the wrong struct
what's different about DynamicComponentTypeHandle compared to ComponentTypeHandle?
oh, I see. it doesn't have any type. but you need to get it with a type which could be a variable. is this correct?
You can use it to get any component type
@rotund token You have a byte Value { get; } in IDynamicHashMapBase. Why is that? Does a DynamicBuffer not work with no variable in it?
i need the buffer to have size
enforcing it to be 1 byte makes the maths easy
and i have checks in to make sure someone doesn't add another field increasing size
is this how you expect to set it up then?
you dont need the field
public byte Value {get;} is enough
usually i set it up as
byte IDynamicHashMap<Entity,float>.Value {get;}
you really don't need to access or view this value
ok funky, thanks! had to write byte IDynamicHashMapBase<Entity,float>.Value {get;} for it to compile.
Unless I'm having a brain fart. Any specific reason you don't just return the values* in GetValueArray? you build an array but I don't see the reason without a key.
It mimics the behaviour of NativeHashMap
and you can't just return Values
because it might have holes
if you've removed elements
ah well, reason enough ๐
why i actually recently wrote a custom NativeLookup container recently
which doesn't allow removal
allows addbatch and clear only
single adds are like 3x slower than nmhm though so you'd only want to use if you can batch add
obviously if you know you'll never remove an element you can use the Value field fine
thanks for the heads up. first I need to figure out how this will all work before I start optimizing. currently creating the threat system which puts quite a lot of stress when not done right. and the logic behind it is again quite non-linear, so I hope this works out without slowing everything down. most annoying case is when Player A is fighting Mob B and NPC C is healing A so it generates threat on NPC C.
oh and I have never brought this up here but the arbitrary limit of 128 entities per chunk is quite weird and unexpected that will come in 1.0 or smth
i think dreaming brought up a good point though
in practice it's pretty hard to actually have a chunk with more than 128 entities
that's true. although that's just a limit of the chunk being 16k
so instead of increasing the chunk size, they limit the entities which is a weird solution for the problem
like you can only have 45 entities using a basic physics cube
they're obviously limiting it though because of the bit field for enabled components
lol, good example ๐
in our project at work it's horrible actually, we only have 3-6 entities per chunk
yeah definitely planning my own and future projects not to run into that issue
want to at least have 16 as a bare minimum
I rather have no enabled components tbh
Not sure how much it matters when you'd have like 1k entities per archetype for enabled bits.
I just know that having a huge archetype entity capacity does wonders for performance
if you are simply making giant archetypes and relying on component enabling then you're only going to have 3 entities per chunk like we do ๐คฃ
i look forward to everyone abusing enable bits
and their projects falling apart
yeah, I mean, that's not how to use Entities I think.
i'm just going to avoid giving any advice for a while
and let people figure it out for myself
not a fight i can be fucked with
there are some great uses of these enabled components however i think they're going to get abused just like adding/removing components was originally
hehe, well, somehow we get fucked over because of this feature so ... not sure where I'm standing on this
people can't seem to handle static archetypes
im nearly only going to use enabled bits on tag components
yeah, I know had my difficulties in the beginning but I'm quite comfortable with static archetypes now
obviously i need to get my hands on a more working copy to experiment and find some patterns
but that's currently how i've set things up
i already have a few // replace with enable components comments throughout project to switch some tag components over to it
which will be nice for keeping my chunks together
but apart from that a lot less excited than others
optimized it really hard and that's with LocalToWorld
yeah see the 128 cap isn't really hurting you there ๐ฌ
even if they doubled chunk capacity still would be below it
yep, it's no use with just 16k
have you considered just increasing it? ๐ฑ
I tried in 0.17 but it didn't work so /shrug
i will say, increasing capacity would destroy us on consoles atm
memory costs
you'd be surprised how much memory the storage actually uses
and how small old console memory is
we thankfully finally got rid of our extra archetype requirements
we used to require 2.5-3x
huh, so is it a problem of chunks where not a lot of entities are in?
then 1.5x for ages
and finally we are back to 1x
i think archetype counts are ~6k now, reasonably ok considering the mess it is
jesus
that sounds like quite a mess to clean up ๐
how do you even get so many?
anyway, I feel like the dev should be able to set the chunk size for every archetype. some should be small, some should be large, there's really no good value for everyone
Do y'all get long script reload times?
For me its probably 30-60s each time I change a script.
yeah, sometimes burst spazes out or smth
usually it's quite fast but then I get hit with like a 1.5min reload
nah not in my own project, a few seconds usually
even at work which is a huge mess is only 25-45s
(good cpu though)
hmmm, I wonder what I'm doing wrong
profile the editor
should give you an idea why it takes so long. i never figured it out because it's only happening rarely but when it's happening on every code change it's easier to find out
recompiled a top level assembly and didn't even see that text
What do these do?
That's what I was hoping they did. That is a dream
physics limits this demo too much
going to setup like a 250k boids or something
(this is 50k physics objects but it starts lagging when too many clump while the rollback only takes ~1ms)
it's so beautiful ๐คฉ
How complicated is the rollback? Can you take a snapshot of the world and have an array of snapshots? Or is there a lot more to it than that?
it wasn't really designed as a rollback solution
it's designed as a saving system
i just noticed some discussions on forum about rollback and thought my system would be well suited for it
I wonder if the SerializeUtilityHybrid thing still exists
it can save anything you want, you just put
[Saved] on the component (and can optionally ignore fields with [SaveIgnore]
oh this whole thing started because of a writeup I did on why you should never use that ๐
Oh haha
good night everyone o/
goodnight Enzi
thats so quick... I neeed to trim out the garbage from my project
my project looks like this
i have a lot of asmdef
i know some people have felt like this doesn't help or might even have detrimental effects but personally works for me
I heard mixed things about doing it that way but clearly its working for you
I've got like 2 asmdefs and its not working well for me XD
1 issue, it's a huge pain to setup asmdef
so i made something to do it for me
(scroll down a tiny bit for source)
I saw that, already downloading it lol
anyway i didn't really do this for the compile time
i just like enforcing myself to avoid circular dependencies
i feel long term it makes everything much more manageable
and in particular modular
it's been very useful at times being able to just bring in (or remove things) 1 at a time to track down a bug
how might i make UnsafePtrList readonly as a public property to avoid it being edited from outside of my class
unity hasn't provided any IReadOnly intefaces for them ๐ฆ
make it private then no one can access it ๐
anyway only native containers have safety - by using unsafe you're saying you don't want read only safety
like unity added NativeArray<T>.ReadOnly for this
ah i see
strangely my unsafe ptr list remains length 0 when i add to it
very odd
even with step through
the very next line and it still shows 0
any ideas why that might happen ?
ah i need to pass the list by ref
that fixed it
Hey this is cool thx! I already memorized which dependencies to add, but it is annoying adding 6+ deps each time. Kudos mate!
yeah wrote this thing like 2 years ago been so useful
i tend to just solve any workflow problems i run into
how do I convert a float4x4 representing scale into xyz scale?
is this a bug?
am i using it wrong perhaps ?
because its causes a crash for me
seems to give NullReferenceException: Object reference not set to an instance of an object Unity.Collections.LowLevel.Unsafe.UnsafeUtility.WriteArrayElement[T] (System.Void* destination, System.Int32 index, T value) (at <40205bb2cb25478a9cb0f5e54cf11441>:0) on the Add function line
even though the contains method worked fine
im no expert but i have noticed the contains/add uses void* for the argument not T* could that be causing some issue ?
it internall stores it in an unsafelist<intPtr>
and anything passed in via ptr is converted to IntPtr
as far as i can tell your internal unsafelist container is not setup (hence weird length/capacity values)
as for contains are you sure it's working? it's never going to contain if the internal container doesn't exist
i dont think it is working some times it returns false other times it crashes with similar error
what might cause it to be not setup given i do assign it in the ctor of Node2 (which is a struct)
you're access a node that the constructor wasn't called
ah damn it im so dumb:
private unsafe void Awake()
{
float2 a = new float2(transform.position.x, transform.position.z);
var n = new Node2(a);
_node = &n;
}
i forgot i temporarily localised it
how then do you get the pointer to a node on intialisation and assign it to a field member of the monobehaviour class
i need to use a fixed statement but not sure on the correct syntax
you need to allocate the memory
all you're doing above is getting the pointer in the stack
it's gone as soon as the method returns
yeah thats what i meant by i localised it but not sure how to allocate for it
i guess i would need a native array of size 1 ?
hmm, if I create ISystemStateComponent in some abstract system as protected.
Will that remain same component in inherited systems?
i guess the first question is why you need to store it as a pointer
from memory it will be the same if the abstract is not generic
otherwise it will be unique per generic type
I mean for ECS
I kinda want to use it the way, so all inherited systems will see it as same component in their queries
yeah the type is owned by the class it's created
well i have:
Node struct which connects to segment structs
and segment structs which connect to node structs
linked all via pointers
Then i have a NodeGO : Monobehaviour which has Node* member, so I need to have the pointer to the relevant node struct that it is related to, either so i can update its position by the transform or delete or what ever i want to do at the game object level @rotund token
public class Test2 : Test
{
public void DoTest()
{
Test.A b = default(Test2.A);
}
}```
they're the same thing
Well, hopefully they are
I kind of want to make some kind of Task based AI
i dont really get what you're doing but you need to use malloc
Where every agent does task look up through hierarchy and after suitable task found this task assigned to agent and based on logic from this task, it'll give smaller tasks to agent. Like go to X coordinates and etc
ah okay will look into malloc
and after this big task is done or time outed, new look up is done
hm, is there a way to do component look up on entity through interface?
doubt there is
dont suppose you know what alignment means ?
no docs on the unsafe stuff so am not sure what it is
dont know what you mean by that
let's say I'll have interface ITaskBasedJob
look at existing code is general advice, but what you really want is just UnsafeUtility.AlignOf<T>()
no
yep, that's what I thought
thats oop concepts
just give them a tag?
yeah, I do think rn in a way of tags
thanks, i did look but it was extern uless the code is posted online some where?
hmm
I do have this idea rn:
Basically I create interface for components, where task weight is required to be defined.
Then on big task look up system I find all those component types, and sort them.
And then for each that task component type I do query loop in that exact sorting order.
If task can is suitable to be assigned to entity - it is assigned, and then it's managed by it's own system, where it gives AI orders to agent, through whatever it wants. And once that task is done, or failed or timed out - New look up is done.
Any thoughts on this? I got a feeling I'm reinventing bicycle xD
just dont use square wheels
oh damn i didnt realise they had example scripts
they're not examples they're just usages of the method
best way to learn is look at someone elses code who's already done it
yeh trying to find one similar to mine but not sure any one is doing it my way ๐
maybe my design is wrong
this is the general idea of what i'm trying to do for context:
public unsafe class NodeGO : MonoBehaviour {
private Node _node; // the node data
private Node* _ptr; //pointer to the node
public Node* Ptr => _ptr;
private unsafe void Awake()
{
float2 a = new float2(transform.position.x, transform.position.z);
_node = new Node(a);
_ptr = (Node2*)UnsafeUtility.Malloc(sizeof(Node), UnsafeUtility.AlignOf<Node>(), Allocator.Persistent);
_ptr = &_node;
}
}
this will allow me to update node data by moving game objects once i add the function to do so
yay it works ! ๐
@rotund token thanks for the help
Is it possible to add component to entity by only having Type?
now I am trying to figure out, how to determine which entity is supposed to get which Task
Since not all entities for example will have "X thing", to get a task of "Use X thing".
Can I break IComponentData by adding managed property?
what do you mean
properties are fine
auto properties are just fields under the hood
and other properties just point to a field (usually)
what if I add a getter to IComponentData which will return some managed type
if you want to store managed data on a component you can use a class based IComponentData
obviously no burst then though
public interface ITask
{
public uint Priority { get; }
public EntityQueryDesc QueryDesc { get; }
}
Nah, I only want this
I will attach it to IComponentData
as long as you don't actually store a EntityQueryDesc on whatever inherits that
it's fine
so if I simply add kind of like static getter, it'll fine
gud
public interface ITask
{
public uint Priority { get; }
public EntityQuery Query { get; }
}
public partial class TaskLookupSystem : SystemBase
{
private struct TaskInfo
{
public uint Priority;
public EntityQuery Query;
}
private Dictionary<Type, TaskInfo> tasksList = new Dictionary<Type, TaskInfo>();
protected override void OnCreate()
{
var iTaskType = typeof(ITask);
var iComponentType = typeof(IComponentData);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => iTaskType.IsAssignableFrom(p) && iComponentType.IsAssignableFrom(p));
foreach (var taskType in types)
{
ITask newTask = Activator.CreateInstance(taskType) as ITask;
tasksList.Add(taskType, new TaskInfo() {Priority = newTask.Priority, Query = newTask.Query});
}
}
protected override void OnUpdate() { throw new NotImplementedException(); }
}
So far I have this.
Now I need to create a Job that will run through each of those ITask and add to entities it's tasks
how do smart pointers differ in unreal to the stuff we have in unity ?
was reading on the forums unity is working on something for the lack of smart pointers but curious what that would be
well smart pointers are a c++ feature not really unreal
languages like java/c# don't usually have smart pointers because you have garbage collector/classes which handle memory for you
if you just want something to cleanup memory for you Unity already shipped World/UpdateAllocator as a replacement for TempJob
which does not need disposable (instead disposes/gets reused every 2nd frame automatically)
Sooo, rn I am trying to solve a problem, of how to determine which AI agent wants which Task assigned.
I see several solutions:
- Either I create some kind of algorithm that will automatically on compile create all necessary components for each Task agent might want and it will basically create all unique queries through it, for Task to be assigned.
- Or I create one shared component that will hold
ComponentTypeor simply index of component. And then do queries through shared component filter.
soooo
What do you guys think any of it is viable?
For the part of how AI agent determines the task it wants, I plan on making component with array of tasks types sorted.
And it will run a job, that will go through each one by one, checking through interfaced method, whether Entity can do and wants to do job.
But in this case I run into case, where I either might lack information to determine it or I'd need to do it in sync point
a regular pointer goes straight to the data, smart pointers have an extra level of indirection to a counter/atomic counter that gets incremented/decremented everytime you create/destroy a copy of the smart pointer
this way you can safely free the memory when the counter hits 0
I'm pretty sure I read that blobs use this technique
it might have been something else
there's also a unique_ptr which doesn't have any reference counting and automatically frees the memory when it goes out of scope
@rustic rain honestly don't really understand what your doing to provide any advice
Are you trying to just build a way to dispatch work to different entities?
yeah, so basically if I want to add some new AI behaviour to game
I simply define System that only works with that internal logic of behaviour
And task finding system will automatically assign those behaviours between any sort of AI agent
i use a bit field for state
with auto registered components
{
return;
}
// TODO potentially change this to new component filtering when Unity implements this instead of changing architecture
if (previous.Value != 0)
{
var stateComponent = this.RegisteredStates[previous.Value];
this.CommandBuffer.RemoveComponent(batchIndex, entity, stateComponent);
}
if (state.Value != 0)
{
var stateComponent = this.RegisteredStates[state.Value];
this.CommandBuffer.AddComponent(batchIndex, entity, stateComponent);
}```
unique version basically looks like this
or my flag version looks like this
// ---------
// 0 0 | 0 0
// 0 1 | 1 0
// 1 0 | 0 1
// 1 1 | 0 0
// ---------
// R = !S & P
// A = S & !P
var toRemove = state.Value.BitNot().BitAnd(previous.Value);
var toAdd = state.Value.BitAnd(previous.Value.BitNot());
for (uint r = 0; r < toRemove.Capacity; r++)
{
if (toRemove[r])
{
Debug.Assert(this.RegisteredStates.ContainsKey(r), $"Trying to remove state {r} that was not registered");
var stateComponent = this.RegisteredStates[r];
this.CommandBuffer.RemoveComponent(batchIndex, entity, stateComponent);
}
}
for (uint r = 0; r < toAdd.Capacity; r++)
{
if (toAdd[r])
{
Debug.Assert(this.RegisteredStates.ContainsKey(r), $"Trying to add state {r} that was not registered");
var stateComponent = this.RegisteredStates[r];
this.CommandBuffer.AddComponent(batchIndex, entity, stateComponent);
}
}```
so you just set or unset bit in the field and it will automatically add your component etc
and each system that reacts to the component registers it + the bit it owns
where T : IStateComponent
{
/// <inheritdoc/>
public abstract byte StateKey { get; }
/// <inheritdoc/>
public abstract ComponentType StateInstanceComponent { get; }
}```
with just some abstract properties
not sure this is exactly what you're looking for though
0000
your bit field
0010
adds a component registered in index 1
0110
adds a component registered i index 2
0100
removes component registered in index 1
its just how i control agent states
(actually its how i control a lot more than just agent states, i use it for UI/game/input etc)
basically my version of a ecs state machine
I'm looking for a way, to create an AI with such qualities:
Each AI agent (kind of character) will have it's own defined list of possible tasks (for example characters of kind Robot will do only task in order: "Kill enemies" and "Idle around", while some other agent will do different taskset like: "Heal allies (if they exist)", "Attack enemies" and "Self-destruct if no task".
And this system should be like lego. So nothing is hardcoded, but instead defined by components.
can they change task?
could you elaborate?
Kind of that exact system is used in Rimworld, but it's fully in OOP
so I'm way too influenced by wrong thinking kek
Not sure what AI Architecture Rimworld uses but Utility AI is very suited for DOD.
Utility AI?
Could you elaborate?
In video game AI, a utility system, or utility AI, is a simple but effective way to model behaviors for non-player characters. Using numbers, formulas, and scores to rate the relative benefit of possible actions, one can assign utilities to each action. A behavior can then be selected based on which one scores the highest "utility" or by using t...
in particular infinite axis utility ai is often talked about being a really good fit for entities
yap. implemented a variaton of it myself. works like a charm.
There are alot of talks from Dave Mark in the GDC Vault that are worth a watch.
is that it?
one of them yes
yo sir, what was that kind of job you offered to solve my problem with a lot of entities in different rooms?
Smth about chunks
I'm looking at the following code example from https://docs.unity3d.com/Packages/com.unity.netcode@0.50/manual/getting-started.html#tie-it-together:
// When client has a connection with network id, go in game and tell server to also go in game
[UpdateInGroup(typeof(ClientSimulationSystemGroup))]
public class GoInGameClientSystem : SystemBase
{
protected override void OnCreate()
{
// Make sure we wait with the sub scene containing the prefabs to load before going in-game
RequireSingletonForUpdate<CubeSpawner>();
RequireForUpdate(GetEntityQuery(ComponentType.ReadOnly<NetworkIdComponent>(), ComponentType.Exclude<NetworkStreamInGame>()));
}
protected override void OnUpdate()
{
var commandBuffer = new EntityCommandBuffer(Allocator.Temp);
Entities.WithNone<NetworkStreamInGame>().ForEach((Entity ent, in NetworkIdComponent id) =>
{
commandBuffer.AddComponent<NetworkStreamInGame>(ent);
var req = commandBuffer.CreateEntity();
commandBuffer.AddComponent<GoInGameRequest>(req);
commandBuffer.AddComponent(req, new SendRpcCommandRequestComponent { TargetConnection = ent });
}).Run();
commandBuffer.Playback(EntityManager);
}
}
What's the point of this line?
RequireForUpdate(GetEntityQuery(ComponentType.ReadOnly<NetworkIdComponent>(), ComponentType.Exclude<NetworkStreamInGame>()));
I thought I read somewhere that systems were only updated when Unity/the DOTS runtime/whatever detected that they needed to be.
@covert lagoon
by default systems update when at least one entity exists that matches the components you define in your Entities.ForEach code. in the example above that would be an entity with the components NetworkIdComponent that does not have a NetworkStreamInGame component. This "default" update requirement will be generated automatically. sometimes you might want to run a system if entities exist with other components than the ones you specified in the Entities.ForEach. Then you can do it just like the example above: define a RequireForUpdate to define other conditions when to run your system
But in this case the explicitly defined conditions are the same as the ones deduced from Entities.WithNone<...>().ForEach(...), aren't they?
they have two update conditions: the RequireSingletonForUpdate and the RequireForUpdate. this is done because the default behavior, (that the condition for the ForEach is generated) will be skipped if you specify your own update requirement . so they had to specify the "for each requirement" by hand.
So a call to RequireSingletonForUpdate, or any other Require... method, prevents the implicit generation of requirements?
exactly
Ok, thanks!
hmm, so sync point exists only if there's filters?
I kind of assume that will also be case for calculating size/length
which I need for calculating capacity of hashmap
hmmmm
Is that up-to-date way to iterate over NativeMultiHashMap?
TargetData targetData;
NativeMultiHashMapIterator<int> iterator;
if (hashMap.TryGetFirstValue(starSystem.systemID, out targetData, out iterator))
{
do
{
} while (hashMap.TryGetNextValue(out targetData, ref iterator));
}
or maybe there's more convinient way to do same thing?
๐
is this the up to date documentation to get started https://docs.unity3d.com/Packages/com.unity.entities@0.50/manual/index.html ?
yes
nice, thx
i was suggesting to look into the use of chunk components if i remember correctly
yeah, I looked it up
But then I found NativeMultiHashMap
and it looks like perfect solution kek
if only not this, sadkek
You must use Unity Editor version 2020.3.30 with Entities 0.50.
ho ....
looks like I need to rewrite it
guess i have to downgrade ?
well cant say what the problem is but you can just avoid the codegen with IJobEntityBatch. more boilerplate to write though
yeah, that's kinda what i meant
I never liked struct jobs
ngl
hmm, maybe I can solve it through foreach loop
foreach is not working
why not?
mmmm ๐ค perhaps i should do this on my windows laptop then. trying it on my mac M1 is probably pushing my luck
oh wait im not sure if its not working or if its just not burstable.
im on M1. no problems
even on a unity 2020 ? how nice.
well it doesnt run native if thats what you mean but it doesnt matter.
well yeah of course it doesn't. but as long as it works (c)(r)(tm)
2020.3.34f1 is ok or is it strictly 3.30 ? (can't find 3.30 in the hub)
2020.3.30+ is okay
use an enumerator
eh, same boilerplate basically
then I don't know what you expected
when the SharedComponent has a managed type it's not burstable
hm, it only has int
is it a class?
You must install the Entities Platforms package before you can use this workflow.
but the link to https://docs.unity3d.com/Packages/com.unity.platforms@0.60/index.html is a 404 error
you can install all in one through hybrid renderer
just install last version of it
and it'll automatically install pretty much all ecs related packages
except physics
๐
From the Docs : Shared component values stored as managed objects
not burstable atm
I see
I got stuck with dependecies again
_gatherTargetDataJob.hashMap = hashMap;
var gatherDataDep = _gatherTargetDataJob.Schedule(_targetQuery);
_findTargetJob.hashMap = hashMap;
_findTargetJob.buffer = buffer;
Dependency =
JobHandle.CombineDependencies(_findTargetJob.Schedule(_huggerQuery, gatherDataDep), Dependency);
I need job to run only after gather data job.
and it results in this pepega error
haaa hybrid renderer doesn't support builtin render pipeline. i don't really have any need for advanced rendering technique. URP then ?
yep
great. you guys are being super helpful in this preview maze ๐ฅฐ thx again for the millions times ๐
idk why you have so many dependency problems ^^. the base case should be that you just assign each job to the Dependency of the system one after the other.
Like
Dependency = job1.Schedule(Dependency)
Dependency = job2.Scheducle(Dependency)
and it should work
i literally never used combinedependency even once in my projects 0.o
_gatherTargetDataJob.hashMap = hashMap;
Dependency = _gatherTargetDataJob.Schedule(_targetQuery, Dependency);
_findTargetJob.hashMap = hashMap;
_findTargetJob.buffer = buffer;
Dependency = _findTargetJob.Schedule(_huggerQuery, Dependency);
Same error
really no idea where the error is then. this should be fine
i usually buy as much ram as i can afford. When i bought the Macbook air M1 i was planning to use it for browsing and discording. I didn't expect the M1 to be so good. I'm regretting so much to have only 8GB of ram ... even installing the entities package make it run out of ram ๐ข
in all the test i saw it didnt really matter. the only point where i have problems is with profiling in unity. its a bug unity is aware of and i think 2021 has a fix for it. Unity errors and says you dont have enough ram to profile... really annoying.
i got the 16 GB though
https://docs.unity3d.com/Packages/com.unity.physics@0.50/manual/index.html it doesn't tell the package name. can i assume it's the name in the url ?
ha yes, it works ๐
I usually add it through manifest.json
hmm, now I finally got error that makes sense:
_gatherTargetDataJob.hashMap = hashMap;
Dependency = _gatherTargetDataJob.Schedule(_targetQuery, Dependency);
_findTargetJob.hashMap = hashMap;
_findTargetJob.buffer = buffer;
Dependency = _findTargetJob.Schedule(_huggerQuery, Dependency);
problem is, do I really have to create a sync point?
and i didn't even start Rider yet ๐
hey guys, im wondering how i can futher improve my jobs performance
so im using the c# job system to write data to a compute buffer to use with a compute shader
the job itself is stupid simple,
[BurstCompile(CompileSynchronously = true)]
private struct SetBuffersJob : IJobParallelForTransform
{
[WriteOnly]
public NativeArray<float4x4> BoneArray;
[WriteOnly]
public NativeArray<Quaternion> RotationArray;
public void Execute(int index, TransformAccess transform)
{
BoneArray[index] = transform.localToWorldMatrix;
RotationArray[index] = transform.rotation;
}
}
all it does is set the data
I am using ComputeBuffer.BeginWrite and ComputeBuffer.endwrite
protected override void CalculateSkinning()
{
_boneArray = boneBuffer.BeginWrite<float4x4>(0, bones.Length);
_rotationArray = qBuffer.BeginWrite<float4>(0, bones.Length);
var nativeArrayQuaternion = UnsafeUtility.As<NativeArray<float4>, NativeArray<Quaternion>>(ref _rotationArray);
gatherMatrixJob.BoneArray = _boneArray;
gatherMatrixJob.RotationArray = nativeArrayQuaternion;
gatherMatrixJobHandle = gatherMatrixJob.ScheduleReadOnly(transforms, 128);
}
protected override void ApplySkinning()
{
gatherMatrixJobHandle.Complete();
boneBuffer.EndWrite<Matrix4x4>(bones.Length);
qBuffer.EndWrite<Quaternion>(bones.Length);
//set other buffers to CS and dispatch
}
in order, CalculateSkinning is called for all isntances of this class, then ApplySkinning is called
private void LateUpdate()
{
foreach(BaseCorSkinning s in instances)
{
s.Skin(1);
}
JobHandle.ScheduleBatchedJobs();
foreach (BaseCorSkinning s in instances)
{
s.Apply();
}
}
this is the method that does that
i have a job that does this simple bit of code:
public unsafe void Execute(int index)
{
var path = _currentPath[index]; // native array
_result.Add(path.A); //unsafe ptr list
}
but when i read _result back the contents is empty every time, i ran step through and the job was working correctly. is there some attribute i need to use to get ptr lists to work properly?
what is result
is result an unsafe container?
if so yes it won't have any values if you read it outside the job
theres no workaround for that?
@signal flicker what job are we talking about? SetBuffersJob? Because there's not much space to go there. the only thing would be to ensure all transforms aren't under the same parent so it can run parallel.
I did add NativeDisableUnsafePtrRestriction thinking that would fix it
that doesn't change how a struct works
well thats a spanner in the works then =/
my found path is a native array of a struct which contains pointers
#archived-dots message
specifically warned you about this here!
so the only way to get it back would've been using ref ?
you need to write it back to something that has fixed memory
either a component, a pointer, malloc memory etc
ah ok so even persistent allocator wont be fixed memory in this case?
@rotund token sir, is it possible to run those jobs without sync point?
protected override void UpdateWithBuffer(EntityCommandBuffer buffer)
{
int targetCount = _targetQuery.CalculateEntityCount();
hashMap.Clear();
hashMap.Capacity = targetCount;
_gatherTargetDataJob.hashMap = hashMap;
var gatherDep = _gatherTargetDataJob.Schedule(_targetQuery);
_findTargetJob.hashMap = hashMap;
_findTargetJob.buffer = buffer;
_findTargetJob.Schedule(_huggerQuery, gatherDep);
}
private struct TargetData
{
public Entity entity;
public float3 position;
}
[BurstCompile]
private partial struct GatherTargetDataJob : IJobEntity
{
public NativeMultiHashMap<int, TargetData> hashMap;
void Execute(Entity e, in InSystemComponent starSystem, in LocalToWorld ltw)
{
hashMap.Add(starSystem.systemID, new TargetData() {entity = e, position = ltw.Position});
}
}
[BurstCompile]
private partial struct FindTargetJob : IJobEntity
{
[ReadOnly] public NativeMultiHashMap<int, TargetData> hashMap;
public EntityCommandBuffer buffer;
void Execute(Entity e, in InSystemComponent starSystem, in LocalToWorld ltw)
{
Entity closestTarget = default;
float closestDistance = float.MaxValue;
TargetData targetData;
NativeMultiHashMapIterator<int> iterator;
if (hashMap.TryGetFirstValue(starSystem.systemID, out targetData, out iterator))
{
//kkek
}
if (closestTarget != Entity.Null)
{
buffer.AddComponent(e, new FollowShip() {entity = closestTarget});
}
}
}
I really don't get what's up with dependencies
you''re not passing in a dependency?
var gatherDep = _gatherTargetDataJob.Schedule(_targetQuery);
and you're not writing any dependency back?
_findTargetJob.Schedule(_huggerQuery, gatherDep);
_gatherTargetDataJob.hashMap = hashMap;
var gatherDep = _gatherTargetDataJob.Schedule(_targetQuery, Dependency);
_findTargetJob.hashMap = hashMap;
_findTargetJob.buffer = buffer;
Dependency = _findTargetJob.Schedule(_huggerQuery, gatherDep);
I changed it to this, but I still get same error
you're assigning the dependency after you've scheduled _targetQuery though
the error seems to imply you're using EntityManager in a job
well, I'm not sure I do
where's your JobData struct
what JobData
oh wait that's the codegen part
oh is that a shared component?
yeah, I got that part
so, I can't Schedule such jobs either?
hm
Do I just make that component non-shared?
After all, all it holds is int ID
but I do need their value
you can only use their unique index
and what is it?
void Execute(Entity e, in InSystemComponent starSystem, in LocalToWorld ltw)
{
hashMap.Add(starSystem.systemID, new TargetData() {entity = e, position = ltw.Position});
}
I need to know which ID of room is it
if I write component itself into hashMap, will that work or?
public void Execute()
{
foreach (var chunk in this.Chunks)
{
var sharedComponentIndex = chunk.GetSharedComponentIndex(this.SavablePrefabType);```
I see
you could have a simple hashmap that maps unique index
to room index
then simply look it up
var lookup = new NativeHashMap<SavablePrefab, Entity>(this.savables.Count, allocator);
var currentMap = new NativeHashMap<int, SavablePrefab>(this.savables.Count, allocator);
var savableArray = NoAllocHelpers.ExtractArrayFromListT(this.savables);
var savableIndicesArray = NoAllocHelpers.ExtractArrayFromListT(this.savableIndices);
currentMap.ClearAndAddKeyBatchUnsafe(savableIndicesArray, savableArray, this.savables.Count);```
yeah, whole point of shared component is to hold one int
i do that in my saving
so rn I really wonder, maybe I should just make it non shared
my shared components have 4 uint
but i just build a quick map to make the unique scd index to the unique ID
then i can access the shared component unique ID in jobs
if you aren't using it to actually group entities / filter then yes make it non shared
well, I kind of do I think
alternatively the good old
duplicate components
public struct Team : IComponentData
{
public byte Value; // 0 is no team
}
public struct TeamShared : ISharedComponentData
{
public byte Value; // 0 is no team
}```
// TODO MERGE THIS WHEN UNMANAGED SHARED COMPONENTS EXIST IN 0.50
it's a lie
need to update to 1.0
yes all you can get is the unique shared index
i have so many compilation error that i think i installed & configured it correctly ๐
no I mean, index is fine. It's just that it's only available through chunk. Right?
yeah not sure you can get it via any of the codegen jobs
have to use ijobentitybatch instead
but i think i'll give up. the lack of ram is killing me
just removing TextMeshPro plugin from the package manager make it unresponsive for 10mn. it seems to be recompiling the entire planet. And my scene is just a camera and a directional light, not even a cube
the burst progress bar is there since forever
did you restart unity after installing burst?
no
its kind of a requirement to restart unity after you change your compiler ๐
the main bottleneck right now is writing the data to the compute buffer. i go from 105 fps to 120 when i remove the begin and end write methods. im hoping theres a way i can directly modify the compute buffer from within the job
i had a buddy take a crack at it and he gained +50% fps using pointers, but it crashed often (well more often than not) (in fact it only worked once for some reason)
i think it died. using 0.6% cpu ๐
last attempt. restarting it. i won't bother you forever just because my laptop is underpowered
Hey all
Are there any utilities to serialize an Entity (and its components)?
Currently I do something that feels hacky (a system that grabs every component I need), I'd like to know if there's a more standard approach
that seems reasonable
Hmm maybe it is
go with index or just not scd
i give up. thank you for the help โค๏ธ
https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/ECSSamples/Assets/Advanced/Boids/Scripts/BoidSystem.cs probably has the best learning example for SCD. It also showcases how to get around using SCD data in burst jobs
the gist is to schedule jobs for every SCD variant and have the SCD data as parameter for the job(s)
its a lot of job overhead though if you have a lot of scd
it certainly is. SCDs have their place but most of the times there are better solutions
sorry to hear. 8Gb is really underpowered today sadly. :/
That said, I have a MacBook Pro from a few years ago that I still use for writing out iOS versions. Also has 8Gb. While I don't use it with Burst, I'm very sure it would still run fine. Possible you are having other issues that could be fixed? Too much running apps, low disk space?
Any suggestions for handling deallocations on unsafe containers inside IComps? Seems like I have to save the unsafe container or pointer inside a system state too. Is there a better design?
"regular" unity (even hdrp) works fine. i also do some java development. But burst is too heavy. Having tons of error i don't understand doesn't help either. So the combination of "slow" + "doesn't even compile anyway" is too much for just a toy project that i could do in rust/cpp/java/C#/not-python ๐
Burst compiles in runtime. You don't need to wait for that progress bar to finish. I don't think it's precise at all
that's unusual, is this an empty project?
did you try deleting the library folder?
try that, I think something has gone totally wrong in your project. a total restart with the correct packages should work though
this is exactly why i never put unsafe containers on components
so my suggestion is don't do it ๐
perhaps it would be a good occasion to see if my desktop computer is still working. haven't used it since i bought the M1
threadripper + 32GB ram ^^
actuallt, haven't used it since covid
blasphemy I say!
well it was my video editing machine and there wasn't much to film during the pandemic ๐
Seems like I have to save the unsafe container or pointer inside a system state too. system state
this doesn't work either because quitting play mode won't dispose it (or destroying world etc)
it's highly likely that my old GTX960 died of old age during its 2 year slumber
SystemBase.OnDestroy for global cleanup and systemstate for individual (de)alloaction should be okay though, right?
ah, hardware is way too robust ๐
OnDestroy is a bit problematic
as if the world is destroyed you can't do queries
you kind of need to store them all in the system
anyway this is just why i don't do this
(this is why i wrote stuff like the dynamic hash map - rather stick to automatic memroy management)
yeah good points. sounds annoying to deal with. hm, I REALLY don't want use a DB
haha
guess I have to :/
dynamicbuffer not database
ho lol my bad
yeah, I rather put the data in redis than in a DB ... ok jk
gonna try with a DB - should have written this in a few minutes and then profile against another solution with a HashMap<Entity, struct> where I can store either a list or hashmap. Let's see how this works out
well, well ... the new threat mechanic puts 6ms on my job to around 13ms with a DB hashmap - I have to say, not bad considering when the naive version of a DB with a manual Contains method and for loop took 8 seconds ๐คฃ
nothing like 7 frames a minute
I say thanks again for the DB hashmap. You are always one step ahead of what I need it seems ๐ I'm gonna implement a DB hashset eventually. Don't need values in my current case but first I'm gonna test how fast this will go with a nested hashmap in a system
unitys hashset currently just uses a full nativehashmap
you could slightly reduce memory though by stripping values
and it just looks nicer ๐
lol how lazy is that. gonna roll with the jack dunstan implementation then
only thing that bugs me right now with the DB hashes is no inspection ๐ฆ
have you looked into how hard that would be to integrate?
eh, I'm a dummy. hashset with no values at all doesn't work. how would you get them back from the hash ... and I need the values eventually
not that hard
just need to add [DebuggerTypeProxy] then implement
where TKey : struct, IEquatable<TKey>
where TValue : struct
{
#if !NET_DOTS
UnsafeHashMap<TKey, TValue> m_Target;
public NativeHashMapDebuggerTypeProxy(NativeHashMap<TKey, TValue> target)
{
m_Target = target.m_HashMapData;
}
public List<Pair<TKey, TValue>> Items
{
get
{
var result = new List<Pair<TKey, TValue>>();
using (var kva = m_Target.GetKeyValueArrays(Allocator.Temp))
{
for (var i = 0; i < kva.Length; ++i)
{
result.Add(new Pair<TKey, TValue>(kva.Keys[i], kva.Values[i]));
}
}
return result;
}
}
#endif
}```
what the native hash map one looks like
i could basically just replicate that for db
hm, so the current problem I have is that the DOTS debugger sees the DynamicHashMap as DynamicBuffer and I see no way of overriding this
The docs have exclude all but no exclude any. I want to be able to say hey give me all the objects that have A but don't have B or don't have C
Is Infinite Axis suitable for ECS?
@rustic rain Well any AI Architecture can be done in ECS. IMO Utility AI is just a good fit because its easy to parallize and to have very flexible,robust AI.
yeah, I'v seen this thread
But I can't really find good explanation on Utility AI
xD
you rank the possible Actions based on a Utility function you assign to each action.
then you pick the highest Action with the highest score.
Now the Infinite Axis Model is just one way to implement that.
I just don't understand it enough, since I can't get how it can be applied with unity ECS
trying to watch centaur AI vid rn
but I have trouble understanding it fully
why it is good with ecs is because you can evaluate all the Considerations at the same time. you dont have to traverse a graph
hmm
You discovered UAI Yesterday. Just give yourself a few more days and it will click.
Could you make some super basic example of it?
in ECS
In what exactly will be used, what types
what kind of job
if it can interpreted this way ofc
This heavily depends on how you want to implement it.
I think you can find some infos in the post i linked above. also there are implementations for ECS already. you could look into them. If I were to post examples of my implementation it would probably lead you astray. I had some very specific constraints because of the authoring workflow i wanted. Basically i improved on the Infinite Axis model a bit by making Considerations hierarchical.
https://github.com/DreamersIncStudios/ECS-IAUS-sytstem/tree/Stable-0.7.2-2020LTS/Assets/Systems/IAUS
has an implementation of this built with entities
i've never used it, we have our own at work that is a bit differently implemented
but if you just want to get the concept of implementation should help
@rotund token i saw in the thread that you had 0.5ms mainthread time for your UAI. Is it all done in one scorer System or do you have a system for each consideration?
oh my implementation is vastly different to this
it is graph traversal
but yeah it's a single system / single job
hence main thread performance is very quick
hmm i didnt find a way to make that work for my AI. probably possible but out of my grasp
i have unlimited chained scorers
same 0.o
oh yeah so similar
that's cool, haven't seen anyone else implement it this way in entities so far
there are no resources whatsoever for this yes
i actually wrote this over 18 months ago, i've always wanted to release it but i've never actually hooked up ai to my project yet so it's still proof of concept
and it seems to work but until i can verify that it's actually semi-production ready i'm not willing to release something
i actually wrote it generic so that it can be implemented in any project
you just implement a single interface, and then create your own nodes
i havent ever released anything yet so my biggest hurdle is i dont know when i could. its far from perfect ๐
going from fixed to generic implementation took a lot of effort
especially with UI
so far i'm yet to see any other AI solution in entities that isn't tied to the project
Mine isnt.
i can create considerations in the editor. Codegen creates everything that is needed
originally i was considering codegen but i managed to figure out a way to do it without
i had a version with dynamiccomponenttypehandle stuff but i wanted to switch to dynamic buffers to store considerations on entities
that required codegen afaik
i really want to release at some point in time but its probably years until ready. Debugging and Authoring need to be on point
i have a pretty good debug workflow
i can record all AI state every frame
then play them back in my graph
to show the path an individual entity took
every frame
yes i have nothing like that. i can only show considerations live ingame
i wouldnt even know how to implement sth like yours. the architecture still has some problems not allowing me to do those things easily i think.
but yeah haven't touched it in a year except to update to 0.50
yeah my desire for
a) frame slicing b) visual debug c) design usable
have made me take a bit of a alternate approach to uai
still not sure if that's a good thing
my focus was on authoring. beeing able to stagger considerations to make them more understandbale and more modular. I can reuse calculations alot. In the basic IA model at some point it just becomes a little hard to see what your AI actually thinks
yeah agreed
like 10 Axis in 1 consideration...
our designers and even developers have a hard time updating our AI at work
for the most part most people except the original author
Well AI is never easy i guess ^^
How are you reading data from the world? I got extra systems vectorizing any component i need to a normalized score and safe it on the Entity that scored it.
yeah do something similar
my plan is commonly used components are normalized etc
and anything rarely used is just read in the actual job
i dont save it on entity though
i just have giant arrays
makes sense for alot of values. My problem was vectorizing distance to the target
were every entity has its own value then
due to this my Agent entities are HUGE atm
yeah thats something htat is problematic to me
and something i'm trying to avoid but i haven't solved yet
i really want to minimize entity size unlike the monster entities we have at work
all my buffers already live outside of the chunkmemory but still i only fit 3 entities per chunk^^
guess i need to split them up somehow
yeah thats my work
3-6 entities per chunk
im going to look at something like the dots sample where the split everything into child entities
but then lookup is hugely a pain
at work all our considerations etc are their own components
but the actual actor itself is still huge with stats, states, etc
hmm damn i need to go soon but its interesting ๐
i'm hoping ~soon i can get back to this stuff
i just need to get basics in game to actually utilize some ai
haha my game is more AI than anything else yet. need to do exactly the opposite
my game barely exists
i just spend the whole time writing useful tools instead ๐
๐
Its on the tip of my tongue but i cant remember right now. what was the term for when you essentially gather data in a map to read from? kind of like a flowfield.
do you have an implementation for that or did you skip it because you can read data fast enough anyways?
Is it called InputMap?
@rustic rain btw here is some good lecture : https://gameai.com/
AAAH its InfluenceMap
My head is spinning rn
not sure sorry
xD
oh
don't forget http://www.gameaipro.com/
4 editions of the book online for free, last updated dec 2021
ups that was what i wanted to actually link ๐
the one i linked is the company of Dave Mark. good read too i guess
I found i didnt need Influence maps because i could just create basically the same data on one ManagerAI and pass the data on to the SubAIs
But its more like Infinite Density Influence Maps now.
yeah i haven't setup anything like that atm
but again, i haven't actually got a real game running just test graphs
so we'll see what happens when i have an actual game playing around
out of interest, what type of entity count are you using?
and how's the performance
my mainthread performance depends more on how many diffrent considerations i have since every consideration is an extra system. My thread performance depends on entity count.
atm i run around 100 AIs per frame and around 30 diffrent considerations. On my M1 chip that takes 2.3ms mainthread and 3 ms on workers
i have a timeslicer implemented though. so if i wanted i could run insane amounts of entities that just dont think every single frame. alot of games let their Ai think only like 4 times a sec.
I am pretty sure that if someone more experienced than me would look over my code it could be sped up like 4 times atleast.
how does it scale with entity count
say you just upped it 10x
because yeah the issue i had with our work implementation was that it ended up being too many systems/jobs
and didn't perform that well on consoles
now i'm not going to have this problem (and most people never will) as who is going to target last gen consoles again
but it was still an obvious limitation
i had to merge like 10s of systems into mega system
yep i didnt have consoles in mind. wouldnt run on them.
The timeslicer actually also handles the system count
yeah i mean without the timeslicer
like i assume (hope) if you did 1k entities it wouldn't be 23ms main thread?
i havent tested in latest big iteration. ill do and report back to you
no
but the workerthreads could get quite busy
mainthread is only scheduling stuff. no logic at all
yep what i would expect
i gotta go now. mothersday dinner at parents^^. ill report back
hmmm
so, let's say I want to implement utility AI
I am guessing every time agent is doing nothing - he looks for task
and that means each update there's going to be a consideration math
that will calculate all possible actions and compare them to each other
I don't quite get, where it gets stored (or stored at all?)
and how it gets all those random datas for all sorts of considerations
Does it require new job for each new task?
let's say it does, but then where does all those consideration results go
hmmm
so for every possible Action in AI behaviour, I add some kind of component with that importance value?
oh god, and I definetely would never want to do anything like this xD
I want to figure out some kind of dynamic system
where you can add ANY new behaviour, even through user mods
just by adding new system to assembly
there's no reason all that above can't be data driven
it's basically doing the same thing every time
So:
Let's say each Action will have it's own unique system with it's own interfaced component of current value of importance from 0 to 1.
How do I determine which is highest then, without hardcoding job that will look through all of them
hmmm
so what if instead of writing value of importance
instead I will literally just write that value AND component ID to some other component?
which will be only one per agent
generally you'd do something like
that would solve dynamic problem, but will require
write all the values of id + score to a buffer
all those systems to be linear
but I assume several systems can't write to same buffer at the same time?
I get it, it's just that it might result in poor perfomance
if let's say I'll have 30 different actions
and each will have to wait until buffer is free
all your jobs will be running in parallel
it's not like you can magically add 12341234 cores to the user
either you have enough entities that you're maxed out or you have so few entities that performance isn't an issue anyway
but yeah, just won't want quote myself ^
So rn I imagine update like this:
- I erase all buffers with action importance
- Each action system will write it's value to buffer
- I determine highest value and add component of it's ID to agent along with some other state component
is there even a reason for buffer
I guess there is in case I want to do some sort of modification of values
its useful to have last frame score
its not uncommon to use previous frame contributions on current frame
hm
I'm not sure how to keep track of those contributions
in case
I don't erase them
so I have dynamic buffer
Each update I add new value to it
So that would mean data from last update will overlap
hmm
So if I have ComponentType
can I somehow instantiate it
hmm, doubt
I just thought, maybe I could instantiate it
and then get interfaced property from it
hm, so the current problem I have is that the DOTS debugger sees the DynamicHashMap as DynamicBuffer and I see no way of overriding this
@rotund token, any idea for this? gonna ask on the forum. maybe they know somethin
How do I make a job to clear all dynamic buffers?
Hi guys, it's possible to use dots netcode with relay and lobby ?
dont know how u do the rest right now. I am clearing the buffer just before i need to write to it again. no extra job to clear them. i had that before but scheduling costs for that are just too high. i do as much as possible in as few as possible jobs
oh
I didn't realise I could do that
lol
hmm, I'm trying to figure out how to solve this algorithm
I have a tag HasJob which prevents entity from looking for new job
but I can't figure out how to get rid of it
once job is done
i think you shouldnt have that actually. One of the really nice things about utility AI is that it adapts to changing situations fluently
rn it's simplest task:
I assign MoveTarget which makes Entity to go to that position in space
so you kind of want to give it the possiblility to change its mind even after it decided to do sth
I'd like that, but first I'm trying to solve the easiest
basically you should split it up into making a decision and executing it
make my first algorithm
well that is the easiest way anyways.
dont look at it as a task. look at it as a decision
and how the decision is then translated into an action can be a diffrent thing
hmmm
this AI is for simulated NPCs, that live their own life with their personal economies
so basically I do kind of need tasks
as in
agent must go to X point, do Y thing and then do Z action.
first task is simple: go to next quadrant
around center
and getting there uses other subsystems
hmmmm
i need the same. I for example have a Decision for GoToTargetEntity and then another one for AttackTarget
AttackTarget will score higher as soon as i am in range of the Target
that way you get chains of actions
but imagine your target dies while the agent runs there. You dont even need to check for that because then another Decision just takes over
if you still want actions that cant be interupted you have multiple ways of implementing them. either you give decisions huge "momentum" (they get bonus score if the decision is taken and it decays over time) or you for example implement a statemachine that executes the decision and only takes a new Action if the old one is done
no reason to couple Actions to Decisions
hmm, is structural journaling is a thing yet?
I can't figure out whether my task assigning system works or I simply got bugged loop on task
xD
sry havent looked into entity journals yet. shoud be there i think
Hey folks. I'm currently trying to upgrade my dots project to entities 0.50. So far most of it is pretty straight forward, but one issue I'm running into is that it seems IJobNativeMultiHashMapVisitKeyValue got either renamed, removed or is no longer exposed. I think it was previously part of unity.rendering and I can still find it in older docs, but no longer in the latest. Is there an alternative I can use to this? I basically need a burstable job that will iterate over a NativeMultiHashMap visiting each value exactly once.
yes i think that got removed. (no idea why) Can't you just copy it into your project from an old package version?
hm true. I was just wondering if there might be a better alternative instead. I guess there is a reason it got removed
I think i remember someone asking the same question in forum once
yeah I found this thread, but wasn't sure how up to date it is, as it was posted before entities 0.50: https://forum.unity.com/threads/job-that-iterates-in-parallel-all-unique-keys-from-a-nativemultihashmap.806418/ is this the one you mean as well?
even though this goes over keys it seems, not values
i thought there was another one aswell where they said you should just copy over the old deprecated job into your code.
hm, I see. I guess I will do that for now, thank you.
I hope they will release a replacement for this, though. I feel basic iterator jobs for the native collections should be present for 1.0 whenever that will be ๐
but anyway, thank you very much ๐
@rotund token You asked about the AI Performance if i 10x my units and disable the TimeSlicing:
Seems like there is an unoptimized Vectorization going on. there should be no idle time on worker threads. The ConsiderationUpdategroup is where all the AI is happening
sry in that screenshot i dont have my mouse over it. it takes 1.98 ms.
that is 60 systems. not 30 as i said before. seems my gamedesigner got a bit out of control there
so thats 900 entities updating every frame. mainthread: 2ms
Workers: around 6ms (with obvious bug in there)
With TimeSliceing / Loadbalancing (not sure what to call it. its kind of both) i had 0 performance difference and i would still update 900 Agents in 30 frames
and its f* 60 systems scheduling... i should really look into that.
I think this is what you're looking for
๐
at least I got a pattern that seems reasonable
im curious what you chose. is your system already handling per Target scoring?
it kinda looks like this:
Each agent has buffer with ActionWeight elements which contain ComponentType and weight on current update
for every action I create new system where I have job to set weight, it adds those ActionWeight to buffer which will be read later
Once system chose the action to perform, it simply adds couple of tags: action tag and HasJob tag which indicates, that agent doesn't want to look for job anymore rn.
And each action then determines itself under what circumstances agents will get their action tag HasJob removed.
Meanwhile with those 2 tags, it performs action.
kinda like this
I like it because it lets me add any new action just by declaring new system, thus any potential user mods will be easy to implement
I have a feeling target finding will be huuuuuuuuge pain in future
I'll need some kind of huge bookkeeper
yes thats why i was asking. its not that hard to find a working architecture to solve scoring Decisions. the problem (at least for me) was to find a way to score every consideration for each possible target
i handle that in hashmaps allocated inside my jobs. with VERY complex cases to handle...
So that seems to scale well
kinda shocked myself tbh ^^
that one big hole in my workerthreads is caused by that one consideration beeing authored wrong. if done right its not there at all. What that one long consideration does is vectorizing the distance of 900 agents to about 8k entities lol
someone forgot to put a filter in there
Do you mean like the inspector?
Because unfortunately it is a dynamic buffer I'm just manipulating it to be something else
Not sure if the custom IInspect interface would work to create a custom drawer
DynamicHashMapDebuggerTypePro
Oh this is not for the inspector, it's for your ide inspecting
Oh, I assumed that the dots debugger uses the DebuggerTypeProxy. Does it need another implemenation then?
you can implement custom inspectors in the dots inspector implementing Inspector<T>
however this is just for fields, i haven't looked into how to do it for actual base types (IComponentData etc) or if it'd be possible to override existing behaviour
think you'd need to edit entities package
in particular EntityContainer line 96 is where it's setup
unless ๐ค
you know
i could probably rewrite this a little to make it work
hmm maybe not
i'd have to remove ability to remove elements or just leave some holes
OR just make the last element in the buffer garbage
would hurt performance a bit though hmm
don't bother, it's not that important to screw with the base implementation
but maybe I find a way too hook into the debug view implementation of the DynamicBuffer itself
a simple check if the buffer is just a byte buffer and redirect to another debug view
need to edit the package
and you wouldn't even need to check for byte buffer you could just check the interface
Property = CreateInstance(typeof(SharedComponentProperty<>));
else if (typeof(IBufferElementData).IsAssignableFrom(type))
Property = CreateInstance(typeof(DynamicBufferProperty<>));
else if (typeof(UnityEngine.Object).IsAssignableFrom(type))
Property = CreateInstance(typeof(ManagedComponentProperty<>));
else```
like you'd just inject it i here before IBufferElementData
ah cool
seems to me that's not even needed or can be skipped. the final implementation is in EntityIMGUIVisitor.cs in protected override void VisitList<TContainer, TList, TElement>(Property<TContainer, TList> property, ref TContainer container, ref TList value) if (IsDynamicBufferContainer(value.GetType()) && value.Count > kBufferPageLength)
or that's just the pager
interesting stuff: https://github.com/OndrejPetrzilka/EntityComponentInspector
this is very old
all you need to do now in 0.50 to render a custom struct is inherit from Inspector<T>
{
UnityEngine.Debug.Log("catched");
Property = CreateInstance(typeof(DynamicBufferProperty<>));
}``` I don't get the debug log :/
did you put it before the buffer line?
yes
i'd probably add a non-generic implementation of IDynamicHashMap just for inspector convenience if you were doing this
on it, yes the buffer is hit instead. if doesn't evaluate as true
yeah i don't think open generics can match like that
Type g2 = typeof(generic2<>);
Console.WriteLine("g1.IsAssignableFrom(g2): {0}", g1.IsAssignableFrom(g2));```
returns false
> The difference is that open generic types cannot have instances, so one is not "assignable" to the other.
but yeah just use a non generic base interface
I was pretty sure there's a way to get the generic one but not a problem, I just use another interface
way too much work haha
so the needed code seems to be now to setup a class DynamicHashMapBufferProperty and an appropriate container
have fun ๐
i find anything to do with the properties package to be a pain
like, it's super powerful but it's so abstracted it hurts my head
need a phd in it to do anything
I agree, it's like, what is all this?? Does it really need to be this complicated to show/edit some damn values. And all that after my initial cheering where I thought they hooked into the MS DebuggerProxy. How cool would that be if they used that