- Home /
SystemBase ECS unity doesnt let me acess NativeMultiHashMap because it isnt readonly?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;
using Unity.Transforms;
using Unity.Mathematics;
using Unity.Collections;
using Unity.Rendering;
using Unity.Burst;
using Unity.Jobs;
public struct QuadrantData {
public Entity entity;
public Soldier soldier;
}
public class QuadrantSystem : SystemBase {
EntityQuery entityQuery;
public static NativeMultiHashMap<int, QuadrantData> quadrantMultiHashMap;
public const int quadrantYMultiplier = 1000;
private const int quadrantCellSize = 3;
public static int GetPositionHashMapKey(int2 position) {
return ((position.x / quadrantCellSize) + (quadrantYMultiplier * (position.y / quadrantCellSize)));
}
private static void DebugDrawQuadrant(float3 position) {
Vector3 lowerLeft = new Vector3(math.floor(position.x / quadrantCellSize) * quadrantCellSize,0, math.floor(position.z / quadrantCellSize) * quadrantCellSize);
Debug.DrawLine(lowerLeft, lowerLeft + new Vector3(+1,0, +0) * quadrantCellSize);
Debug.DrawLine(lowerLeft, lowerLeft + new Vector3(+0,0, +1) * quadrantCellSize);
Debug.DrawLine(lowerLeft + new Vector3(+1,0, +0) * quadrantCellSize, lowerLeft + new Vector3(+1,0, +1) * quadrantCellSize);
Debug.DrawLine(lowerLeft + new Vector3(+0,0, +1) * quadrantCellSize, lowerLeft + new Vector3(+1,0, +1) * quadrantCellSize);
//Debug.Log(GetPositionHashMapKey(position) + " " + position);
}
private static int GetEntityCountInHashMap(NativeMultiHashMap<int, QuadrantData> quadrantMultiHashMap, int hashMapKey) {
QuadrantData quadrantData;
NativeMultiHashMapIterator<int> nativeMultiHashMapIterator;
int count = 0;
if (quadrantMultiHashMap.TryGetFirstValue(hashMapKey, out quadrantData, out nativeMultiHashMapIterator)) {
do {
count++;
} while (quadrantMultiHashMap.TryGetNextValue(out quadrantData, ref nativeMultiHashMapIterator));
}
return count;
}
protected override void OnCreate()
{
quadrantMultiHashMap = new NativeMultiHashMap<int, QuadrantData>(0, Allocator.Persistent);
base.OnCreate();
}
protected override void OnDestroy() {
quadrantMultiHashMap.Dispose();
base.OnDestroy();
}
protected override void OnUpdate() {
entityQuery = GetEntityQuery(typeof(Translation), typeof(Soldier));
quadrantMultiHashMap.Clear();
if (entityQuery.CalculateEntityCount() > quadrantMultiHashMap.Capacity) {
quadrantMultiHashMap.Capacity = entityQuery.CalculateEntityCount();
}
Entities.ForEach((Entity entity,in Soldier soldier) =>
{
int hashMapKey = GetPositionHashMapKey(soldier.Index);
quadrantMultiHashMap.Add(hashMapKey, new QuadrantData
{
entity = entity,
soldier = soldier,
});
}).WithStoreEntityQueryInField(ref entityQuery)
.ScheduleParallel();
this.CompleteDependency();
}
}
I recieve this error?
C:\Dev\ECS Massive Battle\Assets\Scripts\QuadrantSystem.cs(74,13): Burst error BC1042: The managed class type Unity.Collections.NativeMultiHashMap
2*` is not supported. Loading from a non-readonly static field QuadrantSystem.quadrantMultiHashMap
is not supported
Answer by andrew-lukasik · Jun 03, 2021 at 06:06 PM
It won't let you access it because you are referencing a managed field from inside a job. This is not allowed. Thankfully, solution to this is very simple - make a local alias variable for jobs to copy by value.
var quadrants = quadrantMultiHashMap.AsParallelWriter();
Entities
.ForEach( ( Entity entity ,in Soldier soldier ) =>
{
int hashMapKey = GetPositionHashMapKey(soldier.Index);
quadrants.Add( hashMapKey , new QuadrantData{ entity = entity, soldier = soldier, });
} )
.ScheduleParallel();
Thanks for answering! I tried it but now it says that
InvalidOperationException: <>c__DisplayClass_OnUpdate_LambdaJob0.JobData.quadrants is not declared [ReadOnly] in a IJobParallelFor job. The container does not support parallel writing. Please use a more suitable container type.
Replace ScheduleParallel
with Schedule
(single thread)
OR use parallel writer:
var quadrants = quadrantMultiHashMap.AsParallelWriter();
look at the answer below though am i supposed to access quadrants? I need a way for unity to read the static variable quadrantMultiHashMap without making it readonly as i can change the size without an error.
It often is, but it introduces thread-safety considerations
One question on how to use this method do i acess the var quadrants
that you recomended instead of the quadrantMultiHashMap
like i did below?
Use aliases when inside a job (and Entities.ForEach
is one). You can access QuadrantSystem.quadrantMultiHashMap
normally otherwise (given there is no dependency issues)
It works if i use withoutburst but i know this can limit my performance thricefold so could you give me an example of what my changed quadrantsystem should be?
Do you mean this code you posted in second answer? I.e.:
int hashMapKey = QuadrantSystem.GetPositionHashMapKey(soldierComponent.Index - 1);
QuadrantData quadrantData;
NativeMultiHashMapIterator<int> nativeMultiHashMapIterator;
if (QuadrantSystem.quadrantMultiHashMap.TryGetFirstValue(hashMapKey, out quadrantData, out nativeMultiHashMapIterator))
{
do
{
if (soldierComponent.id != quadrantData.soldier.id)
{
if (soldierComponent.Index.x - 1 == quadrantData.soldier.Index.x && soldierComponent.Index.y == quadrantData.soldier.Index.y)
{
TargetIsBlocked = true;
}
}
} while (QuadrantSystem.quadrantMultiHashMap.TryGetNextValue(out quadrantData, ref nativeMultiHashMapIterator) && !TargetIsBlocked);
}
If yes - is it part of a job too?
no i meant the quadrant system class in the first one and yes the second system also inherits from systembase.
Answer by critterawesome · Jun 03, 2021 at 06:58 PM
If it helps you i access the hashmap by doing this
int hashMapKey = QuadrantSystem.GetPositionHashMapKey(soldierComponent.Index - 1);
QuadrantData quadrantData;
NativeMultiHashMapIterator<int> nativeMultiHashMapIterator;
if (QuadrantSystem.quadrantMultiHashMap.TryGetFirstValue(hashMapKey, out quadrantData, out nativeMultiHashMapIterator))
{
do
{
if (soldierComponent.id != quadrantData.soldier.id)
{
if (soldierComponent.Index.x - 1 == quadrantData.soldier.Index.x && soldierComponent.Index.y == quadrantData.soldier.Index.y)
{
TargetIsBlocked = true;
}
}
} while (QuadrantSystem.quadrantMultiHashMap.TryGetNextValue(out quadrantData, ref nativeMultiHashMapIterator) && !TargetIsBlocked);
}
Your answer
Follow this Question
Related Questions
Need Help With My GAME! 3 Answers
Static variables 1 Answer
Change static variable in JS through Csharp 1 Answer
What's the better practice to use common variable? 0 Answers
Use Of Static Variables 1 Answer