public void Execute(Entity entity, int index, [ReadOnly] ref Network network)
            {
                var networkCache = NetworkCache.Create(entity);
                var adjusts      = NetAdjusts[entity];

                for (int i = 0; i < adjusts.Length; i++)
                {
                    var adjust = adjusts[i];
                    networkCache.AddConnection(adjust.StartNode, adjust.EndNode,
                                               adjust.Cost, adjust.Connection, adjust.OnlyNext);
                }

                networkCache.Compute(index, CommandBuffer);
                networkCache.Dispose();
                CommandBuffer.AddComponent(index, entity, new NetworkDone());
                CommandBuffer.RemoveComponent <NetAdjust>(index, entity);
            }
Esempio n. 2
0
        protected override JobHandle OnUpdate(JobHandle inputDeps)
        {
            //coloring algo
            //loop through all connection: MultiHashMap<node, out_con_of_node>, MultiHashMap<node, in_con_of_node>
            //start with a node
            //breath first search with its in_con & out_con, add all the node to visited node, the con to one color group
            //all con must have the same level as the first con selected!
            //repeat with remaining nodes & con

            //a node connecting two connections of different levels is an exit node
            //nothing can have two IndexInNetwork comp
            //can a node belong to two networks? and have two indexes?

            //propose 1: treat exit & entrance nodes differently
            //entrance: contain a Next list to all network nodes
            //exit: every node has a Next to every exit node (indexed differently)
            //need a way to connect an exit of this network to an entrance of another
            //
            //path finding algo
            //target:
            //- finalTarget: conEnt
            //- nextTarget: entity
            //- targetIdx: int
            //- curLoc: entity
            //- curLevel: int
            //- curNet: int
            //
            // NetworkGroup[connection].Index
            // Entrances[node].NetId
            // Exits[node].NetId
            //
            // Connection[connection].Level
            // Entrances[node].Level
            // Exits[node].Level
            //
            //curNet = curCon.Network
            //curLevel = curCon.Level
            //curLoc = curCon
            //
            //if curCon == finalTarget: done
            //elseif curCon.endNode == nextTarget:
            //  curNet = Entrances[nextTarget].NetId
            //  curLevel = Entrances[nextTarget].Level
            //  curLoc = nextTarget
            //  find_target

            //if curNet == finalTarget.Network: targetIdx = Indices[finalTarget]
            //else
            //  if curLevel <= finalTarget.Level //climb
            //    nextTarget = curLoc.exit
            //    targetIdx = Exits[nextTarget].Idx
            //  else //descend
            //    nextTarget = finalTarget
            //    do
            //      nextTarget = nextTarget.entrance
            //    while (curLevel > Exits[nextTarget].Level)
            //    var exitInfo = Exits[nextTarget]
            //    if curNet == exitInfo.NetId
            //      targetIdx = exitInfo.Idx
            //    else //climb
            //      nextTarget = nextTarget.exit
            //      targetIdx = Exits[nextTarget].Idx
            //Next[curCon][targetIdx]


            //propose 2: treat exit & entrance like every other con in the network
            //nearest_exit or entrance will have to choose 1 among multiples (also happens with node, but less)
            //the exit/entrance con is still in the same network, it has to be an OnlyNext con to push the agent
            //to the other network => can't have entrance as intersection! must buffer it with a straight road!

            //propose 3: create a new connection with startNode == endNode == exitNode
            //this is not good!

            //compute direct pointer: for connection with 1 exit
            //scan through node with 1 out_con_node: set all connection in in_con_node to has direct pointer

            //compute index in network
            //all con without direct pointer will be indexed incrementally based on network
            //follow the direct_pointer to compute combined-distance to Dist array
            //compute Dist & Next

            //compute node.Exit = nearest_exit_node, node.Entrance = nearest_entrance_node
            //during computation of Dist, record the smallest Dist[i,j] to Exit[i] if j is an exit node

            //path finding:
            //conTarget:
            //- finalTarget: connection
            //- nextNode: Null
            //
            //if Direct[node] != Entity.Null => use Direct[node]
            //if node == conTarget.nextNode => conTarget.nextNode = null
            //if conTarget.nextNode == Null
            //  nextNode = finalTarget.endNode
            //  while (node.network != nextNode.network)
            //    if node.Level == nextNode.Level => nextNode = node.exit; break
            //    elseif node.Level > nextNode.Level => nextNode = nextNode.entrance
            //  conTarget.nextNode = nextNode
            //use Next[node][IndexInNetwork[conTarget.nextNode]]

            _outCons.Clear();
            _inCons.Clear();
            _newCons.Clear();
            var inout = new OutConAndInCon
            {
                OutCons = _outCons.ToConcurrent(),
                InCons  = _inCons.ToConcurrent(),
                NewCons = _newCons.ToConcurrent(),
            }.Schedule(this, inputDeps);

            //fill _outCons and _inCons: multi hash map for each node, storing all outward connections / inward connections
            inout.Complete();

            if (_newCons.Count > 0)
            {
                var addOnlyNext = new AddOnlyNext
                {
                    OutCons = _outCons,
                }.Schedule(this, inputDeps);
                addOnlyNext.Complete();

                EntityManager.AddSharedComponentData(_query, new NetworkGroup());

                _conToNets.Clear();
                _bfsOpen.Clear();
                while (_newCons.Count > 0)
                {
                    //each loop will create a new network group
                    var newCon = _newCons.Dequeue();
                    int level  = EntityManager.GetComponentData <Connection>(newCon).Level;
                    if (_conToNets.TryGetValue(newCon, out int _))
                    {
                        continue;                                                                //already has net group!
                    }
                    //breath-first-search here
                    _networkCount++;

                    _networkCons.Clear();
                    _entrances.Clear();
                    _exits.Clear();

                    _conToNets.TryAdd(newCon, _networkCount);
                    _bfsOpen.Enqueue(newCon);
                    _networkCons.Add(newCon);

                    //use BFS to scan all connections belong to the same network as "newCon"
                    while (_bfsOpen.Count > 0)
                    {
                        var curConEnt  = _bfsOpen.Dequeue();
                        var connection = EntityManager.GetComponentData <Connection>(curConEnt);
                        BFS(ref _outCons, ref _networkCons, connection.EndNode, EntityManager, level, true, ref _exits);
                        BFS(ref _inCons, ref _networkCons, connection.StartNode, EntityManager, level, false,
                            ref _entrances);
                    }

                    var networkEnt = EntityManager.CreateEntity(_networkArchetype);
                    EntityManager.SetComponentData(networkEnt, new Network
                    {
                        Index = _networkCount,
                    });

                    var networkGroup = new NetworkGroup
                    {
                        NetworkId = _networkCount,
                    };
                    var networkGroupState = new NetworkGroupState
                    {
                        NetworkId = _networkCount,
                        Network   = networkEnt,
                    };
                    //add NetworkGroup & assign OnlyNext ==> this apply to ALL connection, jobify this!
                    for (int i = 0; i < _networkCons.Length; i++)
                    {
                        var conEnt = _networkCons[i];
                        EntityManager.SetSharedComponentData(conEnt, networkGroup);
                        EntityManager.SetComponentData(conEnt, networkGroupState);
                    }

                    var networkCache = NetworkCache.Create(networkEnt);
                    for (int i = 0; i < _networkCons.Length; i++)
                    {
                        var conEnt     = _networkCons[i];
                        var connection = EntityManager.GetComponentData <Connection>(conEnt);
                        var conLen     = EntityManager.GetComponentData <ConnectionLengthInt>(conEnt);
                        var conSpeed   = EntityManager.GetComponentData <ConnectionSpeedInt>(conEnt);
                        networkCache.AddConnection(connection.StartNode, connection.EndNode,
                                                   (float)conLen.Length / conSpeed.Speed, conEnt, connection.OnlyNext);
                    }

                    var entrances = _entrances.GetKeyArray(Allocator.Temp);
                    //add entrances
                    EntityManager.AddComponent(entrances, _entranceType);
                    for (int i = 0; i < entrances.Length; i++)
                    {
                        var node = entrances[i];
                        EntityManager.SetComponentData(node, new Entrance
                        {
                            NetIdx  = _networkCount,
                            Network = networkEnt,
                            Level   = level,
                        });
                    }

                    var indexToTarget = EntityManager.AddBuffer <IndexToTargetBuffer>(networkEnt);
                    int conCount      = networkCache.ConnectionCount();
                    for (int i = 0; i < conCount; i++)
                    {
                        indexToTarget.Add(new IndexToTargetBuffer
                        {
                            Target = networkCache.GetConnection(i),
                        });
                    }
                    var exits = _exits.GetKeyArray(Allocator.Temp);
                    for (int i = 0; i < exits.Length; i++)
                    {
                        var exitNode = exits[i];
                        indexToTarget.Add(new IndexToTargetBuffer
                        {
                            Target = exitNode,
                        });
                    }

                    //add exits
                    EntityManager.AddComponent(exits, _exitType);
                    EntityManager.AddComponent(exits, _indexInNetworkType);
                    for (int i = 0; i < exits.Length; i++)
                    {
                        var exitNode = exits[i];
                        EntityManager.SetComponentData(exitNode, new Exit
                        {
                            NetIdx = _networkCount,
                            Level  = level,
                        });
                        EntityManager.SetComponentData(exitNode, new IndexInNetwork
                        {
                            Index = i + conCount,
                        });
                    }

                    networkCache.Compute2(EntityManager, ref entrances, ref exits);
                    networkCache.Dispose();
                    entrances.Dispose();
                    exits.Dispose();
                }
            }

            return(inout);
        }