protected override void OnUpdate()
    {
        float deltaTime = Time.DeltaTime;
        int   i         = 0;

        Entities.
        WithNone <Unit_Routed>().
        WithoutBurst().
        WithStructuralChanges().
        ForEach((Entity e, ref Unit_Component uc, ref DynamicBuffer <Unit_Buffer> ub) =>
        {
            if (i <= UnitManager.instance.maxEntitiesRoutedPerFrame)
            {
                int fromKey = ((int)uc.fromLocation.x + (int)uc.fromLocation.y + (int)uc.fromLocation.z) * UnitManager.instance.maxPathSize;
                int toKey   = ((int)uc.toLocation.x + (int)uc.toLocation.y + (int)uc.toLocation.z) * UnitManager.instance.maxPathSize;
                int key     = fromKey + toKey;
                //Cached path
                if (UnitManager.instance.useCache && allPaths.ContainsKey(key) && !uc.routed)
                {
                    allPaths.TryGetValue(key, out float3[] cachedPath);
                    for (int h = 0; h < cachedPath.Length; h++)
                    {
                        ub.Add(new Unit_Buffer {
                            wayPoints = cachedPath[h]
                        });
                    }
                    uc.routed          = true;
                    uc.usingCachedPath = true;
                    EntityManager.AddComponent <Unit_Routed>(e);
                    return;
                }
                //Job
                else if (!uc.routed)
                {
                    NavMeshQuery currentQuery = new NavMeshQuery(navMeshWorld, Allocator.Persistent, UnitManager.instance.maxPathNodePoolSize);
                    SinglePathFindingJob spfj = new SinglePathFindingJob()
                    {
                        query            = currentQuery,
                        nml_FromLocation = uc.nml_FromLocation,
                        nml_ToLocation   = uc.nml_ToLocation,
                        fromLocation     = uc.fromLocation,
                        toLocation       = uc.toLocation,
                        extents          = extents,
                        maxIteration     = UnitManager.instance.maxIterations,
                        result           = results[i],
                        statusOutput     = statusOutputs[i],
                        maxPathSize      = UnitManager.instance.maxPathSize,
                        ub = ub
                    };
                    routedEntities.Add(e);
                    queries.Add(currentQuery);
                    jobHandles.Add(spfj.Schedule());
                }
                i++;
            }
            else
            {
                return;
            }
        }).Run();

        int n = 0;
        NativeArray <JobHandle> jhs = new NativeArray <JobHandle>(jobHandles.Count, Allocator.Temp);

        foreach (JobHandle jh in jobHandles)
        {
            jhs[n] = jh;
            n++;
        }
        JobHandle.CompleteAll(jhs);
        jhs.Dispose();

        int j = 0;

        foreach (JobHandle jh in jobHandles)
        {
            if (statusOutputs[j][0] == 1)
            {
                if (UnitManager.instance.useCache && !allPaths.ContainsKey(statusOutputs[j][1]))
                {
                    float3[] wayPoints = new float3[statusOutputs[j][2]];
                    for (int k = 0; k < statusOutputs[j][2]; k++)
                    {
                        wayPoints[k] = results[j][k];
                    }
                    if (wayPoints.Length > 0)
                    {
                        allPaths.Add(statusOutputs[j][1], wayPoints);
                    }
                }
                Unit_Component uc = EntityManager.GetComponentData <Unit_Component>(routedEntities[j]);
                uc.routed = true;
                EntityManager.SetComponentData <Unit_Component>(routedEntities[j], uc);
                EntityManager.AddComponent <Unit_Routed>(routedEntities[j]);
            }
            queries[j].Dispose();
            j++;
        }
        routedEntities.Clear();
        jobHandles.Clear();
        queries.Clear();

        //Movement
        Entities
        .WithAll <Unit_Routed>().ForEach((ref Unit_Component uc, ref DynamicBuffer <Unit_Buffer> ub, ref Translation trans) =>
        {
            if (ub.Length > 0 && uc.routed)
            {
                uc.waypointDirection = math.normalize(ub[uc.currentBufferIndex].wayPoints - trans.Value);
                trans.Value         += uc.waypointDirection * uc.speed * deltaTime;
                if (!uc.reached && math.distance(trans.Value, ub[uc.currentBufferIndex].wayPoints) <= uc.minDistanceReached && uc.currentBufferIndex < ub.Length - 1)
                {
                    uc.currentBufferIndex = uc.currentBufferIndex + 1;
                    if (uc.currentBufferIndex == ub.Length - 1)
                    {
                        uc.reached = true;
                    }
                }
                else if (uc.reached && math.distance(trans.Value, ub[uc.currentBufferIndex].wayPoints) <= uc.minDistanceReached && uc.currentBufferIndex > 0)
                {
                    uc.currentBufferIndex = uc.currentBufferIndex - 1;
                    if (uc.currentBufferIndex == 0)
                    {
                        uc.reached = false;
                    }
                }
            }
        }).ScheduleParallel();
    }
Exemple #2
0
    //---------------------- Collision Avoidance ---------------------------

    protected override void OnUpdate()
    {
        float innerProbabilityOfInfectionWithMaskWait = probabilityOfInfectionWithMaskWait;
        float innerProbabilityOfInfectionWait         = probabilityOfInfectionWait;
        float innerProbabilityOfInfectionWithMask     = probabilityOfInfectionWithMask;
        float innerProbabilityOfInfection             = probabilityOfInfection;
        float innerInfectionDistance     = infectionDistance;
        float innerInfectionDistanceWait = infectionDistanceWait;

        frameCounter++;

        totalCurrentNumberOfStudents      = 0;
        totalCurrentNumberOfStudentsCovid = 0;

        float deltaTime = Time.DeltaTime;

        var ecb = bi_ECB.CreateCommandBuffer();
        var ecbParallel = bi_ECB.CreateCommandBuffer().AsParallelWriter();
        var randomArray = World.GetExistingSystem <RandomSystem>().RandomArray;
        int i = 0, counter = 0;

        Entities.
        WithNone <WaitComponent>().
        WithoutBurst().
        WithStructuralChanges().
        ForEach((Entity e, ref UnitComponent uc, ref DynamicBuffer <UnitBuffer> ub, ref Translation trans, ref PersonComponent pc) =>
        {
            if (i <= UnitManager.Instance.MaxEntitiesRoutedPerFrame)
            {
                string key = uc.fromLocation.x + "_" + uc.fromLocation.z + "_" + uc.toLocation.x + "_" + uc.toLocation.z;

                //Cached path
                if (UnitManager.Instance.UseCache && allPaths.ContainsKey(key) && (!uc.routed || ub.Length == 0))
                {
                    allPaths.TryGetValue(key, out float3[] cachedPath);
                    for (int h = 0; h < cachedPath.Length; h++)
                    {
                        ub.Add(new UnitBuffer {
                            wayPoints = cachedPath[h]
                        });
                    }
                    uc.routed          = true;
                    uc.usingCachedPath = true;
                    EntityManager.AddComponent <UnitRoutedComponent>(e);
                    return;
                }
                //Job
                else if (!uc.routed || ub.Length == 0)
                {
                    keys[counter]             = key;
                    NavMeshQuery currentQuery = new NavMeshQuery(navMeshWorld, Allocator.Persistent, UnitManager.Instance.MaxPathNodePoolSize);
                    SinglePathFindingJob spfj = new SinglePathFindingJob()
                    {
                        query            = currentQuery,
                        nml_FromLocation = uc.nml_FromLocation,
                        nml_ToLocation   = uc.nml_ToLocation,
                        fromLocation     = uc.fromLocation,
                        toLocation       = uc.toLocation,
                        extents          = extents,
                        maxIteration     = UnitManager.Instance.MaxIterations,
                        result           = results[counter],
                        statusOutput     = statusOutputs[counter],
                        maxPathSize      = UnitManager.Instance.MaxPathSize,
                        ub = ub
                    };
                    routedEntities.Add(e);
                    queries.Add(currentQuery);
                    jobHandles.Add(spfj.Schedule());
                    counter++;
                }
                i++;
            }
            else
            {
                return;
            }
        }).Run();

        //Waiting for the completion of jobs
        int n                       = 0;
        NativeArray <JobHandle> jhs = new NativeArray <JobHandle>(jobHandles.Count, Allocator.Temp);

        foreach (JobHandle jh in jobHandles)
        {
            jhs[n] = jh;
            n++;
        }
        JobHandle.CompleteAll(jhs);
        jhs.Dispose();

        int j = 0;

        foreach (JobHandle jh in jobHandles)
        {
            if (statusOutputs[j][0] == 1)
            {
                if (UnitManager.Instance.UseCache && !allPaths.ContainsKey(keys[j]))
                {
                    float3[] wayPoints = new float3[statusOutputs[j][1]];
                    for (int k = 0; k < statusOutputs[j][1]; k++)
                    {
                        wayPoints[k] = results[j][k];
                    }
                    if (wayPoints.Length > 0)
                    {
                        allPaths.Add(keys[j], wayPoints);
                    }
                }

                UnitComponent uc = EntityManager.GetComponentData <UnitComponent>(routedEntities[j]);
                uc.routed = true;
                EntityManager.SetComponentData <UnitComponent>(routedEntities[j], uc);
                EntityManager.AddComponent <UnitRoutedComponent>(routedEntities[j]);
            }
            queries[j].Dispose();
            j++;
        }
        routedEntities.Clear();
        jobHandles.Clear();
        queries.Clear();

        //----------- Collision Avoidance Code -----------------

        EntityQuery eq = GetEntityQuery(typeof(UnitComponent));

        cellVsEntityPositions.Clear();
        if (eq.CalculateEntityCount() > cellVsEntityPositions.Capacity)
        {
            cellVsEntityPositions.Capacity = eq.CalculateEntityCount();
        }

        NativeMultiHashMap <int, CovidPos> .ParallelWriter cellVsEntityPositionsParallel = cellVsEntityPositions.AsParallelWriter();
        Entities
        .WithNone <WaitComponent>()
        .WithBurst(synchronousCompilation: true)
        .ForEach((ref UnitComponent uc, ref Translation trans, ref PersonComponent pc) =>
        {
            cellVsEntityPositionsParallel.Add(GetUniqueKeyForPosition(trans.Value, 5), new CovidPos {
                pos = trans.Value, hasCovid = pc.hasCovid
            });
        }).ScheduleParallel();



        NativeMultiHashMap <int, CovidPos> cellVsEntityPositionsForJob = cellVsEntityPositions;

        Entities
        .WithNone <WaitComponent>()
        .WithBurst(synchronousCompilation: true)
        .WithReadOnly(cellVsEntityPositionsForJob)
        .WithNativeDisableParallelForRestriction(randomArray)
        .ForEach((Entity e, int entityInQueryIndex, int nativeThreadIndex, ref UnitComponent uc, ref Translation trans, ref PersonComponent pc) =>
        {
            var random = randomArray[nativeThreadIndex];
            int key    = GetUniqueKeyForPosition(trans.Value, 5);
            NativeMultiHashMapIterator <int> nmhKeyIterator;
            CovidPos otherEntityData;
            float3 otherEntityPos;
            bool otherEntityHasCovid;
            float currentDistance = 0.3f;
            uc.avoidanceDirection = float3.zero;
            int total             = 0;
            int totalInCell       = 0;

            if (cellVsEntityPositionsForJob.TryGetFirstValue(key, out otherEntityData, out nmhKeyIterator))
            {
                otherEntityPos      = otherEntityData.pos;
                otherEntityHasCovid = otherEntityData.hasCovid;

                do
                {
                    if (!trans.Value.Equals(otherEntityPos))
                    {
                        totalInCell++;

                        if (currentDistance > math.sqrt(math.lengthsq(trans.Value - otherEntityPos)))
                        {
                            currentDistance       = math.sqrt(math.lengthsq(trans.Value - otherEntityPos));
                            float3 distanceFromTo = trans.Value - otherEntityPos;
                            uc.avoidanceDirection = math.normalize(distanceFromTo / currentDistance);
                            total++;
                        }
                    }
                } while (cellVsEntityPositionsForJob.TryGetNextValue(out otherEntityData, ref nmhKeyIterator) && totalInCell < 20);
                if (total > 0)
                {
                    uc.avoidanceDirection /= total;
                }
            }
            randomArray[nativeThreadIndex] = random;
        }).ScheduleParallel();

        //----------- Collision Avoidance Code -----------------

        cellVsEntityPositionsForJob = cellVsEntityPositions;

        if (frameCounter % 30 == 0)
        {
            Entities
            .WithoutBurst()
            .WithReadOnly(cellVsEntityPositionsForJob)
            .WithNativeDisableParallelForRestriction(randomArray)
            .WithNone <WaitComponent>()
            .ForEach((Entity e, int entityInQueryIndex, int nativeThreadIndex, ref UnitComponent uc, ref Translation trans, ref PersonComponent pc) =>
            {
                if (!pc.hasCovid)
                {
                    var random = randomArray[nativeThreadIndex];
                    int key    = GetUniqueKeyForPosition(trans.Value, 5);
                    NativeMultiHashMapIterator <int> nmhKeyIterator;
                    CovidPos otherEntityData;
                    float3 otherEntityPos;
                    bool otherEntityHasCovid;
                    float contagionPercentageValue = 0;
                    float covidPercentage          = 0;
                    //int totalInCell = 0;
                    if (cellVsEntityPositionsForJob.TryGetFirstValue(key, out otherEntityData, out nmhKeyIterator))
                    {
                        otherEntityPos      = otherEntityData.pos;
                        otherEntityHasCovid = otherEntityData.hasCovid;

                        do
                        {
                            if (!trans.Value.Equals(otherEntityPos))
                            {
                                if (otherEntityHasCovid && math.abs(otherEntityPos.x - trans.Value.x) < innerInfectionDistanceWait && math.abs(otherEntityPos.z - trans.Value.z) < innerInfectionDistanceWait)
                                {
                                    contagionPercentageValue = random.NextInt(0, 100);

                                    if (pc.wearMask)
                                    {
                                        covidPercentage = innerProbabilityOfInfectionWithMask;
                                    }
                                    else
                                    {
                                        covidPercentage = innerProbabilityOfInfection;
                                    }

                                    if (contagionPercentageValue <= covidPercentage)
                                    {
                                        pc.hasCovid = true;

                                        ecbParallel.SetSharedComponent(entityInQueryIndex, e, new RenderMesh
                                        {
                                            mesh     = UnitManager.Instance.unitMesh,
                                            material = UnitManager.Instance.covidMoveMaterial
                                        });

                                        break;
                                    }
                                }
                            }
                        } while (cellVsEntityPositionsForJob.TryGetNextValue(out otherEntityData, ref nmhKeyIterator));
                    }
                    randomArray[nativeThreadIndex] = random;
                }
            }).ScheduleParallel();

            Entities
            .WithoutBurst()
            .WithReadOnly(cellVsEntityPositionsForJob)
            .WithNativeDisableParallelForRestriction(randomArray)
            .WithAll <WaitComponent>().ForEach((Entity e, int entityInQueryIndex, int nativeThreadIndex, ref UnitComponent uc, ref Translation trans, ref PersonComponent pc) =>
            {
                if (!pc.hasCovid)
                {
                    var random = randomArray[nativeThreadIndex];
                    int key    = GetUniqueKeyForPosition(trans.Value, 5);
                    NativeMultiHashMapIterator <int> nmhKeyIterator;
                    CovidPos otherEntityData;
                    float3 otherEntityPos;
                    bool otherEntityHasCovid;
                    float contagionPercentageValue = 0;
                    float covidPercentage          = 0;
                    int totalInCell = 0;

                    if (cellVsEntityPositionsForJob.TryGetFirstValue(key, out otherEntityData, out nmhKeyIterator))
                    {
                        otherEntityPos      = otherEntityData.pos;
                        otherEntityHasCovid = otherEntityData.hasCovid;

                        do
                        {
                            if (!trans.Value.Equals(otherEntityPos))
                            {
                                totalInCell++;

                                if (otherEntityHasCovid && math.abs(otherEntityPos.x - trans.Value.x) < innerInfectionDistanceWait || math.abs(otherEntityPos.z - trans.Value.z) < innerInfectionDistanceWait)
                                {
                                    contagionPercentageValue = random.NextInt(0, 100);

                                    if (pc.wearMask)
                                    {
                                        covidPercentage = innerProbabilityOfInfectionWithMaskWait;
                                    }
                                    else
                                    {
                                        covidPercentage = innerProbabilityOfInfectionWait;
                                    }

                                    if (contagionPercentageValue <= covidPercentage)
                                    {
                                        pc.hasCovid = true;

                                        ecbParallel.SetSharedComponent(entityInQueryIndex, e, new RenderMesh
                                        {
                                            mesh     = UnitManager.Instance.unitMesh,
                                            material = UnitManager.Instance.covidWaitMaterial
                                        });

                                        break;
                                    }
                                }
                            }
                        } while (cellVsEntityPositionsForJob.TryGetNextValue(out otherEntityData, ref nmhKeyIterator) && totalInCell < 30);
                    }
                    randomArray[nativeThreadIndex] = random;
                }
            }).ScheduleParallel();
        }


        //Movement
        Entities
        .WithoutBurst()
        .WithNone <WaitComponent>()
        .WithAll <UnitRoutedComponent>().ForEach((Entity e, int entityInQueryIndex, ref UnitComponent uc, ref DynamicBuffer <UnitBuffer> ub, ref DynamicBuffer <ScheduleBuffer> sb, ref Translation trans, ref PersonComponent pc, in RenderMesh rm) =>
        {
            UnityEngine.AI.NavMeshHit outResult;
            Translation newTrans = trans;

            if (ub.Length > 0 && uc.routed)
            {
                uc.waypointDirection    = math.normalize(ub[uc.currentBufferIndex].wayPoints - trans.Value);
                uc.avoidanceDirection.y = 0;
                uc.waypointDirection.y  = 0;
                uc.waypointDirection    = uc.waypointDirection + uc.avoidanceDirection;

                newTrans.Value   = trans.Value + uc.waypointDirection * uc.speed * deltaTime;
                newTrans.Value.y = 1.791667f;

                if (!UnityEngine.AI.NavMesh.SamplePosition(newTrans.Value, out outResult, 0.8f, NavMesh.AllAreas))
                {
                    uc.waypointDirection -= uc.avoidanceDirection;
                }

                trans.Value         += uc.waypointDirection * uc.speed * deltaTime;
                float3 finalWayPoint = uc.toLocation;
                finalWayPoint.y      = ub[uc.currentBufferIndex].wayPoints.y;

                if (math.distance(trans.Value, ub[uc.currentBufferIndex].wayPoints) <= uc.minDistanceReached)
                {
                    if (uc.currentBufferIndex < ub.Length - 1 && !ub[uc.currentBufferIndex].wayPoints.Equals(finalWayPoint))
                    {
                        uc.currentBufferIndex = uc.currentBufferIndex + 1;
                    }

                    else if (uc.count < sb.Length - 1)
                    {
                        uc.count             += 1;
                        uc.fromLocation       = uc.toLocation;
                        uc.toLocation         = sb[uc.count].destination;
                        uc.routed             = false;
                        uc.usingCachedPath    = false;
                        uc.currentBufferIndex = 0;
                        ub.Clear();
                        ecb.RemoveComponent <UnitRoutedComponent>(e);
                        ecb.AddComponent(e, new WaitComponent
                        {
                            slotsToWait = sb[uc.count - 1].duration,
                            waitEndTime = 0
                        });

                        ecb.SetSharedComponent(e, new RenderMesh
                        {
                            mesh     = UnitManager.Instance.unitMesh,
                            material = pc.hasCovid ? UnitManager.Instance.covidWaitMaterial : UnitManager.Instance.healthyWaitMaterial
                        });
                    }
                    else if (uc.count == sb.Length - 1)
                    {
                        ecb.DestroyEntity(e);

                        totalNumberOfStudentsExit++;
                        if (pc.hasCovid)
                        {
                            totalNumberOfCovidExit++;
                        }
                    }
                }
            }
        }).Run();

        Entities.
        WithoutBurst().
        ForEach((PersonComponent pc) =>
        {
            totalCurrentNumberOfStudents++;

            if (pc.hasCovid)
            {
                totalCurrentNumberOfStudentsCovid++;
            }
        }).Run();

        UnitManager.Instance.TotNumberOfStudentsExit = totalNumberOfStudentsExit;
        UnitManager.Instance.TotNumberOfCovidExit    = totalNumberOfCovidExit;
        UnitManager.Instance.CurrentNumberOfStudents = totalCurrentNumberOfStudents;
        UnitManager.Instance.CurrentNumberOfCovid    = totalCurrentNumberOfStudentsCovid;
    }