Exemplo n.º 1
0
 public bool ContainsJunction(FreightTrackJunction junction)
 {
     lock (JunLock)
     {
         return(this.TrackJunctions.Contains(junction));
     }
 }
 public FreightTrackSegment(FreightTrackJunction junction1, FreightTrackJunction junction2, int length)
 {
     this.ConnectedJunctions.Add(junction1);
     this.ConnectedJunctions.Add(junction2);
     this.Length = length;
     this.MergeNetworks(junction1, junction2);
 }
    /// <summary>
    ///     Finds all junctions connected to the provided junction
    /// </summary>
    /// <param name="junction">Junction to find connections for</param>
    /// <returns>The list of all connecting junctions</returns>
    public List <FreightTrackJunction> JunctionNetMap(FreightTrackJunction junction)
    {
        if (junction == null)
        {
            return(null);
        }
        List <FreightTrackJunction>  connectedjunctions = new List <FreightTrackJunction>();
        Queue <FreightTrackJunction> junctionstocheck   = new Queue <FreightTrackJunction>();

        connectedjunctions.Add(junction);
        junctionstocheck.Enqueue(junction);

        while (junctionstocheck.Count > 0)
        {
            FreightTrackJunction testjunction = junctionstocheck.Dequeue();
            for (int n = 0; n < 4; n++)
            {
                FreightTrackJunction jun = testjunction.ConnectedJunctions[n];
                if (jun == null)
                {
                    continue;
                }
                if (!connectedjunctions.Contains(jun))
                {
                    connectedjunctions.Add(jun);
                    junctionstocheck.Enqueue(jun);
                }
            }
        }
        return(connectedjunctions);
    }
 public static void ResetJunction(FreightTrackJunction junction)
 {
     junction.ResetJunction();
     if (!WorldScript.mbIsServer)
     {
         NetworkManager.instance.SendInterfaceCommand(InterfaceName, InterfaceResetJunction, null, null, junction, 0f);
     }
 }
Exemplo n.º 5
0
 /// <summary>
 ///     Returns the direction corresponding with the route out of this junction to get to the destination junction
 /// </summary>
 /// <param name="junction">Destination junction</param>
 /// <returns>Direction integer</returns>
 public int GetConnectedDirection(FreightTrackJunction junction)
 {
     for (int n = 0; n < 4; n++)
     {
         if (this.ConnectedJunctions[n] == junction)
         {
             return(n);
         }
     }
     return(-1);
 }
 public void MergeNetworks(FreightTrackJunction junction1, FreightTrackJunction junction2)
 {
     //Debug.LogWarning("FTSeg junction1 ID: " + junction1.JunctionID.ToString() + " junction2 ID: " + junction2.JunctionID.ToString());
     if (junction1.TrackNetwork != junction2.TrackNetwork)
     {
         //Merge in smaller network into the larger one for efficiency
         FreightTrackNetwork oldnetwork = junction1.TrackNetwork.TrackJunctions.Count > junction2.TrackNetwork.TrackJunctions.Count ? junction2.TrackNetwork : junction1.TrackNetwork;
         FreightTrackNetwork newnetwork = junction1.TrackNetwork.TrackJunctions.Count > junction2.TrackNetwork.TrackJunctions.Count ? junction1.TrackNetwork : junction2.TrackNetwork;
         this.TransferOwnership(oldnetwork, newnetwork);
     }
     this.TrackNetwork = junction1.TrackNetwork;
     this.TrackNetwork.TrackSegments.Add(this);
 }
 public FreightTrackNetwork(FreightTrackJunction junction)
 {
     this.NetworkID = Networks;
     Networks++;
     this.TrackJunctions.Add(junction);
     if (FreightCartManager.instance != null)
     {
         FreightCartManager.instance.GlobalTrackNetworks.Add(this);
     }
     else
     {
         Debug.LogWarning("Attempted to create FreightTrackNetwork before FRM was initialized.  Network won't be registered to the global list!");
     }
 }
Exemplo n.º 8
0
    /// <summary>
    ///     Construct a network from a list of junctions (for when a network is found to have been broken)
    ///     Includes only the segments valid for the list of junctions
    /// </summary>
    /// <param name="junctions">List of juctions to build the new network</param>
    public void ReconstructNetwork(List <FreightTrackJunction> junctions)
    {
        if (junctions == null || junctions.Count == 0)
        {
            return;
        }
        FreightTrackNetwork network = new FreightTrackNetwork(junctions[0]);

        for (int n = 0; n < junctions.Count; n++)
        {
            FreightTrackJunction junction = junctions[n];
            for (int m = 0; m < 4; m++)
            {
                FreightTrackSegment trackseg = junction.ConnectedSegments[m];
                if (trackseg == null)
                {
                    continue;
                }
                if (!network.ContainsTrackSegment(trackseg))
                {
                    network.TrackSegments.Add(trackseg);
                    trackseg.TrackNetwork = network;
                }
            }
            lock (JunLock)
            {
                junction.TrackNetwork.TrackJunctions.Remove(junction);
            }
            if (junction.TrackNetwork.TrackJunctions.Count == 0)
            {
                FreightCartManager.instance.GlobalTrackNetworks.Remove(junction.TrackNetwork);
            }
            junction.TrackNetwork = network;
            lock (JunLock)
            {
                if (!network.TrackJunctions.Contains(junction))
                {
                    network.TrackJunctions.Add(junction);
                }
            }
        }
        network.ResetJunctionIndices();
        network.ReassignTourCartStations(this);
        if (!FreightCartManager.instance.GlobalTrackNetworks.Contains(network))
        {
            FreightCartManager.instance.GlobalTrackNetworks.Add(network);
        }
    }
Exemplo n.º 9
0
 public void TravelTo(TourCartStation station, FreightTrackJunction start)
 {
     if (station != null && station.JunctionDirection != -1 && station.ClosestJunction != null)
     {
         string mobtype = this.GetSpawnedCartType();
         if (string.IsNullOrEmpty(mobtype))
         {
             return;
         }
         FreightCartMob tourcart = MobManager.instance.SpawnMob(MobType.Mod, mobtype, this.mSegment, this.mnX, this.mnY + (long)this.mForwards.y + 1L, this.mnZ, new Vector3(0.0f, 0.0f, 0.0f), this.mForwards) as FreightCartMob;
         ManagerSync.TourCart          = tourcart;
         tourcart.DestinationJunction  = station.ClosestJunction;
         tourcart.DestinationDirection = station.JunctionDirection;
         tourcart.JunctionRoute        = station.TrackNetwork.RouteFind(start, station.ClosestJunction);
         tourcart.NextJunction         = start;
     }
 }
Exemplo n.º 10
0
 public override void LowFrequencyUpdate()
 {
     if (this.hopper == null)
     {
         this.UpdateAttachedHoppers();
     }
     if (this.ClosestJunction != null && this.TrackNetwork != null && this.ClosestJunction.TrackNetwork != this.TrackNetwork)
     {
         if (this.TrackNetwork.TourCartStations.ContainsKey(this.StationName))
         {
             this.TrackNetwork.TourCartStations.Remove(this.StationName);
         }
         this.TrackNetwork = null;
         this.ClosestJunction.ConnectedSegments[this.JunctionDirection]  = null;
         this.ClosestJunction.ConnectedJunctions[this.JunctionDirection] = null;
         this.ClosestJunction   = null;
         this.JunctionDirection = -1;
     }
 }
Exemplo n.º 11
0
    public static NetworkInterfaceResponse HandleNetworkCommand(Player player, NetworkInterfaceCommand nic)
    {
        FreightTrackJunction junction = nic.target as FreightTrackJunction;

        string command = nic.command;

        if (command != null)
        {
            if (command == InterfaceResetJunction)
            {
                TrackJunctionWindow.ResetJunction(junction);
            }
        }

        return(new NetworkInterfaceResponse
        {
            entity = junction,
            inventory = player.mInventory
        });
    }
Exemplo n.º 12
0
    /// <summary>
    ///     Checks for all combinations of connections between up to four junctions and, if necessary, constructs new networks to contain isolated junctions
    /// </summary>
    /// <param name="junction1"></param>
    /// <param name="junction2"></param>
    /// <param name="junction3"></param>
    /// <param name="junction4"></param>
    public void NetworkIntegrityCheck(FreightTrackJunction junction1, FreightTrackJunction junction2, FreightTrackJunction junction3, FreightTrackJunction junction4)
    {
        //Flag when this network is compromised by threading
        lock (safety)
        {
            //Map entire network of junctions from one and check if any other junctions exist in it
            //Repeat with other networks that aren't found in the first
            List <FreightTrackJunction> junctions1 = new List <FreightTrackJunction>();
            List <FreightTrackJunction> junctions2 = new List <FreightTrackJunction>();
            List <FreightTrackJunction> junctions3 = new List <FreightTrackJunction>();
            List <FreightTrackJunction> junctions4 = new List <FreightTrackJunction>();

            //If we have junction1 build it's network of junctions - we need at least one to compare to
            if (junction1 != null)
            {
                junctions1 = this.JunctionNetMap(junction1);
                this.ReconstructNetwork(junctions1);
            }

            //Build net of junctions only if we're not already in the first junctions network
            if (junction2 != null && !junctions1.Contains(junction2))
            {
                junctions2 = this.JunctionNetMap(junction2);
                this.ReconstructNetwork(junctions2);
            }

            //Check if junction 3 isn't in either 1 or 2
            if (junction3 != null && (!junctions1.Contains(junction3) && !junctions2.Contains(junction3)))
            {
                junctions3 = this.JunctionNetMap(junction3);
                this.ReconstructNetwork(junctions3);
            }

            //Check if 4 isn't a part of any of the previously constructed nets and build it if needed
            if (junction4 != null && (!junctions1.Contains(junction4) && !junctions2.Contains(junction4) && !junctions3.Contains(junction4)))
            {
                junctions4 = this.JunctionNetMap(junction4);
                this.ReconstructNetwork(junctions4);
            }
        }
    }
Exemplo n.º 13
0
 public void InvalidConnection(FreightTrackJunction missingtarget)
 {
     for (int n = 0; n < 4; n++)
     {
         //Remove this from connected junctions/segments from all connected neighbors
         FreightTrackJunction junc = this.ConnectedJunctions[n];
         if (junc == null || junc != missingtarget)
         {
             continue;
         }
         for (int m = 0; m < 4; m++)
         {
             FreightTrackJunction junc2 = missingtarget.ConnectedJunctions[m];
             if (junc2 == null)
             {
                 continue;
             }
             if (junc2 == this)
             {
                 junc.ConnectedJunctions[m] = null;
                 junc.LinkStatusDirty       = true;
             }
         }
         for (int m = 0; m < 4; m++)
         {
             FreightTrackSegment seg = missingtarget.ConnectedSegments[m];
             if (seg == null)
             {
                 continue;
             }
             if (seg.ConnectedJunctions.Contains(this))
             {
                 junc.ConnectedSegments[m] = null;
             }
         }
         this.ConnectedJunctions[n] = null;
         this.ConnectedSegments[n]  = null;
     }
 }
Exemplo n.º 14
0
 private void ClearConnections()
 {
     for (int n = 0; n < 4; n++)
     {
         //Remove this from connected junctions/segments from all connected neighbors
         FreightTrackJunction junc = this.ConnectedJunctions[n];
         if (junc == null)
         {
             continue;
         }
         for (int m = 0; m < 4; m++)
         {
             FreightTrackJunction junc2 = junc.ConnectedJunctions[m];
             if (junc2 == null)
             {
                 continue;
             }
             if (junc2 == this)
             {
                 junc.ConnectedJunctions[m] = null;
                 junc.LinkStatusDirty       = true;
             }
         }
         for (int m = 0; m < 4; m++)
         {
             FreightTrackSegment seg = junc.ConnectedSegments[m];
             if (seg == null)
             {
                 continue;
             }
             if (seg.ConnectedJunctions.Contains(this))
             {
                 junc.ConnectedSegments[m] = null;
             }
         }
     }
     this.TrackNetwork.TrackJunctions.Remove(this);
     this.TrackNetwork.NetworkIntegrityCheck(this.ConnectedJunctions.ToList());
 }
Exemplo n.º 15
0
    /// <summary>
    ///     Returns the direction corresponding with the route out of this junction to get to the destination junction
    ///     Ensures shortest route by checking for duplicate paths to the same junction and takes the shortest.
    /// </summary>
    /// <param name="junction">Destination junction</param>
    /// <returns>Direction integer</returns>
    public int GetConnectedDirection(FreightTrackJunction junction)
    {
        int shortestroute = -1;

        for (int n = 0; n < 4; n++)
        {
            if (this.ConnectedJunctions[n] == junction)
            {
                if (shortestroute == -1)
                {
                    shortestroute = n;
                }
                else
                {
                    if (this.ConnectedSegments[n].Length < this.ConnectedSegments[shortestroute].Length)
                    {
                        shortestroute = n;
                    }
                }
            }
        }
        return(shortestroute);
    }
Exemplo n.º 16
0
    /// <summary>
    ///     Follows a track segment to find all containing stations until it reaches another junction or determines track is invalid
    /// </summary>
    /// <param name="direction">0 - 3 representing the four directions out of the junction</param>
    /// <returns>True if it found complete segment</returns>
    public bool TrackFollow(int direction)
    {
        //Initialize the check from the junction
        long    nextX    = this.mnX;
        long    nextY    = this.mnY;
        long    nextZ    = this.mnZ;
        Vector3 dirvec   = new Vector3();
        bool    mirrorOk = true;

        //Store the initial junction direction for later recording which direction the connected junction is associated with
        int initialdirection = direction;

        //There are many ways to derail, so set that result now, and assume it later. Saves much repeat of these lines.
        this.DirectionResults [initialdirection]   = FreightTrackDirectionResults.Bad;
        this.ConnectedJunctions [initialdirection] = null;
        this.ConnectedSegments [initialdirection]  = null;

        //List of freight cart stations found on this segment -> to be written to the final constructed FreightTrackSegment
        List <FreightCartStation> SegmentStations = new List <FreightCartStation>();

        //Store visited track pieces for catching when the segment enters a closed loop
        //We're only testing for a unique key here, so no Tvalue will be used.
        StringDictionary VisitedTracks = new StringDictionary();

        //Begin loop here.  Direction can be set and used to check the next location each time through the loop
        //Allow segments only up to 512m long due to cost of loop checking - may revise after testing
        for (this.SegmentDistances[initialdirection] = 0; this.SegmentDistances[initialdirection] < 2048; this.SegmentDistances[initialdirection]++)
        {
            switch (direction)
            {
            case 0:
                nextX++;
                dirvec = Vector3.right;
                break;

            case 1:
                nextZ++;
                dirvec = Vector3.forward;
                break;

            case 2:
                nextX--;
                dirvec = Vector3.left;
                break;

            case 3:
                nextZ--;
                dirvec = Vector3.back;
                break;

            default:
                nextX++;
                break;
            }

            ushort lValue1 = 0;
            byte   lFlags1 = 0;
            ushort type    = this.GetCube(nextX, nextY, nextZ, out lValue1, out lFlags1);
            this.mUnderSegment = this.mPrevGetSeg;
            //Debug.LogWarning("GetCube type: " + type.ToString() + " value: " + lValue1);
            bool foundslope = false;

            //Found air and need to check for a downward slope under it
            if (type == 1)
            {
                ushort  lValue2 = 0;
                byte    lFlags2 = 0;
                ushort  cube    = this.GetCube(nextX, nextY - 1L, nextZ, out lValue2, out lFlags2);
                Segment segment = this.mPrevGetSeg;
                type    = cube;
                lFlags1 = lFlags2;
                lValue1 = lValue2;
                if ((type == 538 && lValue1 == 2) || (type == ScrapTrackType && lValue1 == ScrapSlopeVal))
                {
                    foundslope = true;
                    nextY--; //decrement Y level for next loop through!
                }
                else
                {
                    if (type == 0)
                    {
                        Debug.LogError("Error, track follower has null under segment!");
                    }
                    if (this.mPrevGetSeg == null)
                    {
                        Debug.LogError("Error, prevseg was null!");
                    }
                    if (segment == null)
                    {
                        Debug.LogError("Error, old was null!");
                    }
                    if (this.mPrevGetSeg != segment)
                    {
                        Debug.LogWarning(("Track follower is looking for a slope, and has had to check across segment boundaries for this![Old/New" + segment.GetName() + " -> " + this.mPrevGetSeg.GetName()));
                    }
                    return(false);
                }
            }

            Vector3 trackvec = SegmentCustomRenderer.GetRotationQuaternion(lFlags1) * Vector3.forward;
            trackvec.Normalize();
            trackvec.x = trackvec.x >= -0.5 ? (trackvec.x <= 0.5 ? 0.0f : 1f) : -1f;
            trackvec.y = trackvec.y >= -0.5 ? (trackvec.y <= 0.5 ? 0.0f : 1f) : -1f;
            trackvec.z = trackvec.z >= -0.5 ? (trackvec.z <= 0.5 ? 0.0f : 1f) : -1f;
            //Begin checking track type
            if (type == TRACKTYPE || type == ScrapTrackType)
            {
                if ((type == TRACKTYPE && (lValue1 == TRACKSTRAIGHT || lValue1 == TRACKEMPTY || lValue1 == TRACKFULL)) || (type == ScrapTrackType && lValue1 == ScrapStraightVal))
                {
                    if (trackvec.y > 0.5 || trackvec.y < -0.5)
                    {
                        return(false);
                    }
                    else if (!(trackvec == dirvec) && !(trackvec == -dirvec))
                    {
                        // Came in from the side, this path is one-way.
                        mirrorOk = false;
                        dirvec   = new Vector3(trackvec.x, 0f, trackvec.z);
                    }
                }
                if ((type == TRACKTYPE && lValue1 == TRACKCORNER) || (type == ScrapTrackType && lValue1 == ScrapCornerVal))
                {
                    if (dirvec == new Vector3(-trackvec.z, 0.0f, trackvec.x))
                    {
                        dirvec = new Vector3(dirvec.z, 0.0f, -dirvec.x);
                    }
                    else if (trackvec == -dirvec)
                    {
                        dirvec = new Vector3(-dirvec.z, 0.0f, dirvec.x);
                    }
                    else
                    {
                        return(false);
                    }
                }
                if ((type == TRACKTYPE && lValue1 == TRACKSLOPE) || (type == ScrapTrackType && lValue1 == ScrapSlopeVal))
                {
                    Vector3 vector3_2 = trackvec;
                    dirvec.y = 0.0f;
                    dirvec.Normalize();
                    if (dirvec == trackvec)
                    {
                        if (foundslope)
                        {
                            return(false);
                        }
                        else
                        {
                            nextY++;
                        }
                    }
                    else if (dirvec == -trackvec)
                    {
                        ;
                    }
                }
                if (type == TRACKTYPE && lValue1 == TRACKBUFFER)
                {
                    dirvec = new Vector3(-dirvec.x, 0f, -dirvec.z);
                }
            }
            //Begin checking special types
            else if (type == CONTROLTYPE)
            {
                if (lValue1 == CONTROLLOAD || lValue1 == CONTROLUNLOAD || lValue1 == CONTROLTURBO)
                {
                    if ((trackvec == dirvec) || (trackvec == -dirvec))
                    {
                        //Do nothing... direction doesn't change
                    }
                    else
                    {
                        return(false);
                    }
                }
            }
            //Check for freight stations
            else if (type == FREIGHTSTATIONTYPE)
            {
                if ((trackvec == dirvec) || (trackvec == -dirvec))
                {
                    Segment segment = this.AttemptGetSegment(nextX, nextY, nextZ);
                    if (segment == null)
                    {
                        segment = WorldScript.instance.GetSegment(nextX, nextY, nextZ);
                        if (segment == null)
                        {
                            Debug.Log((object)"Track junction track follower did not find segment");
                            return(false);
                        }
                    }
                    FreightCartStation fcs = segment.FetchEntity(eSegmentEntity.Mod, nextX, nextY, nextZ) as FreightCartStation;
                    if (fcs == null)
                    {
                        Debug.LogWarning("Track Junction Track Follower tried to get a freight cart station but got other mod machine instead?");
                        return(false);
                    }
                    if (!SegmentStations.Contains(fcs))
                    {
                        SegmentStations.Add(fcs);
                    }
                    fcs.ClosestJunction   = this;
                    fcs.JunctionDirection = initialdirection;
                }
                else
                {
                    return(false);
                }
            }
            //Is it a junction?
            else if (type == JUNCTIONTYPE)
            {
                //Debug.LogWarning("Track follower success!  Found another junction!");
                Segment segment = this.AttemptGetSegment(nextX, nextY, nextZ);
                if (segment == null)
                {
                    segment = WorldScript.instance.GetSegment(nextX, nextY, nextZ);
                    if (segment == null)
                    {
                        Debug.Log((object)"Track junction track follower did not find segment");
                        return(false);
                    }
                }
                FreightTrackJunction junction = segment.FetchEntity(eSegmentEntity.Mod, nextX, nextY, nextZ) as FreightTrackJunction;
                if (junction == null)
                {
                    Debug.LogWarning("Track Junction Track Follower tried to get a track junction but got other mod machine instead?");
                    return(false);
                }

                //Mark this segment as a loop coming back to ourselves.
                if (junction == this)
                {
                    this.DirectionResults[initialdirection] = FreightTrackDirectionResults.Self;
                }
                else
                {
                    this.DirectionResults[initialdirection] = FreightTrackDirectionResults.Good;
                }

                this.SegmentDistances[initialdirection]  += 1; // We're going to exit the loop here, messing with loop variable OK'd.
                this.ConnectedJunctions[initialdirection] = junction;
                FreightTrackSegment tracksegment = new FreightTrackSegment(this, junction, this.SegmentDistances[initialdirection]);
                tracksegment.Stations = SegmentStations;
                //Debug.LogWarning("trackseg station count: " + tracksegment.Stations.Count);
                this.ConnectedSegments[initialdirection] = tracksegment;
                this.LinkStatusDirty = true;

                //If path is bi-directional, handle the connection for the other junction so we don't need to double the work
                if (mirrorOk)
                {
                    //Mirror the direction to reflect the correct side of the connecting junction
                    int mirroreddir = direction += 2;
                    if (mirroreddir > 3)
                    {
                        mirroreddir -= 4;
                    }
                    junction.ConnectedJunctions [mirroreddir] = this;
                    junction.ConnectedSegments [mirroreddir]  = tracksegment;
                    junction.SegmentDistances [mirroreddir]   = this.SegmentDistances[initialdirection];
                    junction.DirectionResults[mirroreddir]    = this.DirectionResults[initialdirection];//Either "Good
                    junction.LinkStatusDirty = true;
                }
                return(true);
            }
            else if (type == TOURSTATIONTYPE)
            {
                if (trackvec != -dirvec)
                {
                    return(false);
                }
                Segment segment = this.AttemptGetSegment(nextX, nextY, nextZ);
                if (segment == null)
                {
                    segment = WorldScript.instance.GetSegment(nextX, nextY, nextZ);
                    if (segment == null)
                    {
                        Debug.Log((object)"Track junction track follower did not find segment");
                        return(false);
                    }
                }
                TourCartStation station = segment.FetchEntity(eSegmentEntity.Mod, nextX, nextY, nextZ) as TourCartStation;
                station.TrackNetwork      = this.TrackNetwork;
                station.ClosestJunction   = this;
                station.JunctionDirection = initialdirection;
                this.ConnectedJunctions[initialdirection] = this;
                FreightTrackSegment tracksegment = new FreightTrackSegment(this, this, 2 * this.SegmentDistances[initialdirection] + 1);
                this.SegmentDistances[initialdirection] *= 2;
                this.SegmentDistances[initialdirection] += 1;
                this.ConnectedSegments[initialdirection] = tracksegment;
                this.LinkStatusDirty = true;
                if (!string.IsNullOrEmpty(station.StationName) && !this.TrackNetwork.TourCartStations.ContainsKey(station.StationName))
                {
                    this.TrackNetwork.TourCartStations.Add(station.StationName, station);
                }
                return(true);
            }
            else
            {
                return(false);   //Not a track type
            }
            //Update the direction int based on the changed direction vector
            if (dirvec == Vector3.right)
            {
                direction = 0;
            }
            else if (dirvec == Vector3.forward)
            {
                direction = 1;
            }
            else if (dirvec == Vector3.left)
            {
                direction = 2;
            }
            else if (dirvec == Vector3.back)
            {
                direction = 3;
            }

            //Store a hash of every track piece to check for getting stuck in endless loops.
            //HACK Construct a string to be our HashTable Key.
            //We could implement a fancy struct or something, but this works, and we don't have to make a custom GetHashTag function
            //(Struct.gethash() is apparently very inefficient)
            //And the try/catch construct means we only do one hash lookup even.
            try{
                //Build a string which will be unique for this particular track segment and travel direction. Lots and Lots of implicit casting to string on this line.
                VisitedTracks.Add((nextX - this.mnX) + "," + (nextY - this.mnY) + "," + (nextZ - this.mnZ) + "," + direction, null);
            }
            catch {
                Debug.LogWarning("TrackJunction followed track route and found an infinite loop. Ending search.");
                this.DirectionResults [initialdirection] = FreightTrackDirectionResults.Trap;
                return(false);
            }
        }
        Debug.LogWarning("Track Junction Found track length > 512m -> ending search.");
        return(false);
    }
Exemplo n.º 17
0
    /// <summary>
    ///     Dijkstra's Algorithm pathfinding along track junctions
    /// </summary>
    /// <param name="start">Starting track junction</param>
    /// <param name="destination">Destination track junction</param>
    /// <returns>A stack containing the junctions the cart must visit to reach the destination</returns>
    public Stack <FreightTrackJunction> RouteFind(FreightTrackJunction start, FreightTrackJunction destination)
    {
        //Address the trivial case
        if (start == null || destination == null || start == destination)
        {
            return(new Stack <FreightTrackJunction>());
        }

        //Use a local copy of the junction list to avoid potential nasty consequences should the network change
        Stack <FreightTrackJunction> CartRoute = new Stack <FreightTrackJunction>();

        lock (safety)
        {
            List <FreightTrackJunction> localjunctions = this.TrackJunctions;

            if (!localjunctions.Contains(start) || !localjunctions.Contains(destination))
            {
                Debug.LogWarning("FreightTrackNetwork RouteFind attempted to rount to/from inaccessible junction\n start id " + start.JunctionID + " destination id " + destination.JunctionID + " trackjunctions count: " + localjunctions.Count);
                return(CartRoute);
            }
            int junctioncount = localjunctions.Count;

            //Initialize priority queue with only 0 distance for the start
            SimplePriorityQueue <FreightTrackJunction> tentativedistances = new SimplePriorityQueue <FreightTrackJunction>();
            for (int n = 0; n < junctioncount; n++)
            {
                tentativedistances.Enqueue(localjunctions[n], float.MaxValue);
            }
            tentativedistances.UpdatePriority(start, 0);

            //Initialize a separate array of distances for pulling the tentative distances, initialize the start to 0
            int[] distances   = Enumerable.Repeat(int.MaxValue, junctioncount).ToArray();
            int   currentnode = start.JunctionIndex;
            if (currentnode >= distances.Length)
            {
                Debug.LogWarning("FreightTrackNetwork RouteFind trying to navigate from junction outside of range");
                this.ResetJunctionIndices();
                return(new Stack <FreightTrackJunction>());
            }
            distances[currentnode] = 0;

            //Initialize an array for storing the parent junction for the path finding to later trace back to the beginning, indexed to JunctionIndex
            //Start node previous is marked -1 to flag completion of the route trace
            int[] previousnode = new int[junctioncount];
            previousnode[currentnode] = -1;

            //Initialize variables used in the core algorithm
            int neighborindex;          //Index of neighbor junction as found in JunctionIndex
            int initialdis;             //Distance to neighbor from start (tentative)
            int currentdis;             //Distance to active junction
            int tryroute;               //Distance to route to neighbor through active junction
            FreightTrackJunction freightnode = tentativedistances.Dequeue();
            FreightTrackJunction neighbor;
            //Debug.LogWarning("FreightTrackNetwork RouteFind DEBUG - prior to loop");
            for (int m = 0; m < junctioncount; m++)
            {
                for (int n = 0; n < 4; n++)
                {
                    neighbor = freightnode.ConnectedJunctions[n];

                    //Skip the neighbor if it is null or previously visited
                    if (neighbor == null || !tentativedistances.Contains(neighbor))
                    {
                        continue;
                    }
                    neighborindex = neighbor.JunctionIndex;
                    if (neighborindex >= distances.Length || currentnode >= distances.Length)
                    {
                        Debug.LogWarning("FreightTrackNetwork RouteFind checking neighbor junction outside of range");
                        this.ResetJunctionIndices();
                        return(new Stack <FreightTrackJunction>());
                    }
                    initialdis = distances[neighborindex];
                    currentdis = distances[currentnode];
                    tryroute   = currentdis + neighbor.SegmentDistances[n];
                    //If the newly calculated distance to the neighbor is shorter than the previous replace it and update pathing accordingly
                    if (tryroute < initialdis)
                    {
                        distances[neighborindex] = tryroute;
                        tentativedistances.UpdatePriority(neighbor, tryroute);
                        previousnode[neighborindex] = currentnode;
                    }
                }
                //I feel like this check should come after dequeue... if the dequeue is the destination is there really any value in calculating for all its neighbors?
                //GASP!  Wikipedia might be wrong!!?
                if (!tentativedistances.Contains(destination))
                {
                    break;
                }
                freightnode = tentativedistances.Dequeue();
                currentnode = freightnode.JunctionIndex;
            }
            //Debug.LogWarning("FreightTrackNetwork RouteFind DEBUG - after loop");
            if (freightnode != destination)
            {
                Debug.LogWarning("FreightTrackNetwork RouteFind completed path finding with junction other than the destination?");
                return(new Stack <FreightTrackJunction>());
            }
            if (currentnode >= previousnode.Length)
            {
                Debug.LogWarning("FreightTrackNetwork RouteFind trying to trace back previousnode out of range");
                this.ResetJunctionIndices();
                return(new Stack <FreightTrackJunction>());
            }
            //Push the destination onto the route stack and get the first previous junction
            CartRoute.Push(freightnode);
            int prevnode    = previousnode[currentnode];
            int safetycount = 0;
            //Trace back to the start by each of the previous junctions anding with the starting junction
            while (prevnode != -1)
            {
                freightnode = localjunctions[prevnode];
                CartRoute.Push(freightnode);
                prevnode = previousnode[prevnode];
                if (prevnode >= previousnode.Length)
                {
                    Debug.LogWarning("FreightTrackNetwork RouteFind trying to trace back previousnode out of range on path");
                    this.ResetJunctionIndices();
                    return(new Stack <FreightTrackJunction>());
                }
                safetycount++;
                if (safetycount > 255)
                {
                    Debug.LogWarning("FreightTrackNetwork RouteFind failed construction or path has over 255 visited junctions!");
                    CartRoute = null;
                    return(new Stack <FreightTrackJunction>());
                }
            }
            //The above loop automatically pushes the start junction and since the cart is assumed to be there we'll just toss it out as part of a sanity check
            if (CartRoute.Pop() != start)
            {
                Debug.LogWarning("FreightTrackNetwork RouteFind returned a path that didn't start with original start junction!");
                return(new Stack <FreightTrackJunction>());
            }
        }
        return(CartRoute);
    }
Exemplo n.º 18
0
    /// <summary>
    ///     Follows a track segment to find all containing stations until it reaches another junction or determines track is invalid
    /// </summary>
    /// <param name="direction">0 - 3 representing the four directions out of the junction</param>
    /// <returns>True if it found complete segment</returns>
    public bool TrackFollow(int direction)
    {
        //Initialize the check from the junction
        long    nextX  = this.mnX;
        long    nextY  = this.mnY;
        long    nextZ  = this.mnZ;
        Vector3 dirvec = new Vector3();

        //Store the initial junction direction for later recording which direction the connected junction is associated with
        int initialdirection = direction;

        //List of freight cart stations found on this segment -> to be written to the final constructed FreightTrackSegment
        List <FreightCartStation> SegmentStations = new List <FreightCartStation>();

        //Store visited track pieces for catching when the segment enters a closed loop
        List <TrackPiece> VisitedTracks = new List <TrackPiece>();

        //Add a penalty for pathfinding in certain directions to avoid stations and other undesirable routes
        int PathfindPenalty = 0;

        //Begin loop here.  Direction can be set and used to check the next location each time through the loop
        //Allow segments only up to 2048 long due to cost of loop checking - may revise after testing
        for (int n = 0; n < 2048; n++)
        {
            switch (direction)
            {
            case 0:
                nextX++;
                dirvec = Vector3.right;
                break;

            case 1:
                nextZ++;
                dirvec = Vector3.forward;
                break;

            case 2:
                nextX--;
                dirvec = Vector3.left;
                break;

            case 3:
                nextZ--;
                dirvec = Vector3.back;
                break;

            default:
                nextX++;
                break;
            }

            ushort lValue1 = 0;
            byte   lFlags1 = 0;
            ushort type    = this.GetCube(nextX, nextY, nextZ, out lValue1, out lFlags1);
            this.mUnderSegment = this.mPrevGetSeg;
            //Debug.LogWarning("GetCube type: " + type.ToString() + " value: " + lValue1);
            bool foundslope = false;

            //Found air and need to check for a downward slope under it
            if (type == 1)
            {
                ushort  lValue2 = 0;
                byte    lFlags2 = 0;
                ushort  cube    = this.GetCube(nextX, nextY - 1L, nextZ, out lValue2, out lFlags2);
                Segment segment = this.mPrevGetSeg;
                type    = cube;
                lFlags1 = lFlags2;
                lValue1 = lValue2;
                if ((type == 538 && lValue1 == 2) || (type == ScrapTrackType && lValue1 == ScrapSlopeVal))
                {
                    foundslope = true;
                    nextY--; //decrement Y level for next loop through!
                }
                else
                {
                    if (type == 0)
                    {
                        Debug.LogError("Error, track follower has null under segment!");
                    }
                    if (this.mPrevGetSeg == null)
                    {
                        Debug.LogError("Error, prevseg was null!");
                    }
                    if (segment == null)
                    {
                        Debug.LogError("Error, old was null!");
                    }
                    if (this.mPrevGetSeg != segment)
                    {
                        Debug.LogWarning(("Track follower is looking for a slope, and has had to check across segment boundaries for this![Old/New" + segment.GetName() + " -> " + this.mPrevGetSeg.GetName()));
                    }
                    return(false);
                }
            }

            Vector3 trackvec = SegmentCustomRenderer.GetRotationQuaternion(lFlags1) * Vector3.forward;
            bool    oneway   = false;
            trackvec.Normalize();
            trackvec.x = trackvec.x >= -0.5 ? (trackvec.x <= 0.5 ? 0.0f : 1f) : -1f;
            trackvec.y = trackvec.y >= -0.5 ? (trackvec.y <= 0.5 ? 0.0f : 1f) : -1f;
            trackvec.z = trackvec.z >= -0.5 ? (trackvec.z <= 0.5 ? 0.0f : 1f) : -1f;
            //Begin checking track type
            if (type == TRACKTYPE || type == ScrapTrackType)
            {
                if ((type == TRACKTYPE && (lValue1 == TRACKSTRAIGHT || lValue1 == TRACKEMPTY || lValue1 == TRACKFULL)) || (type == ScrapTrackType && lValue1 == ScrapStraightVal))
                {
                    if (trackvec.y > 0.5 || trackvec.y < -0.5)
                    {
                        return(false);
                    }
                    else if (!(trackvec == dirvec) && !(trackvec == -dirvec))
                    {
                        dirvec = new Vector3(trackvec.x, 0f, trackvec.z);
                        oneway = true; // Can't set return path as the same -> they're different!
                    }
                }
                if ((type == TRACKTYPE && lValue1 == TRACKCORNER) || (type == ScrapTrackType && lValue1 == ScrapCornerVal))
                {
                    if (dirvec == new Vector3(-trackvec.z, 0.0f, trackvec.x))
                    {
                        dirvec = new Vector3(dirvec.z, 0.0f, -dirvec.x);
                    }
                    else if (trackvec == -dirvec)
                    {
                        dirvec = new Vector3(-dirvec.z, 0.0f, dirvec.x);
                    }
                    else
                    {
                        return(false);
                    }
                }
                if ((type == TRACKTYPE && lValue1 == TRACKSLOPE) || (type == ScrapTrackType && lValue1 == ScrapSlopeVal))
                {
                    Vector3 vector3_2 = trackvec;
                    dirvec.y = 0.0f;
                    dirvec.Normalize();
                    if (dirvec == trackvec)
                    {
                        if (foundslope)
                        {
                            return(false);
                        }
                        else
                        {
                            nextY++;
                        }
                    }
                    else if (dirvec == -trackvec)
                    {
                        ;
                    }
                }
                if (type == TRACKTYPE && lValue1 == TRACKBUFFER)
                {
                    dirvec = new Vector3(-dirvec.x, 0f, -dirvec.z);
                }
            }
            //Begin checking special types
            else if (type == CONTROLTYPE)
            {
                if (lValue1 == CONTROLLOAD || lValue1 == CONTROLUNLOAD || lValue1 == CONTROLTURBO)
                {
                    if ((trackvec == dirvec) || (trackvec == -dirvec))
                    {
                        //Do nothing... direction doesn't change
                        //Except turbo... reduce the penalty for this path!
                        if (lValue1 == CONTROLTURBO)
                        {
                            PathfindPenalty--;
                        }
                    }
                    else
                    {
                        return(false);
                    }
                }
            }
            //Check for freight stations
            else if (type == FREIGHTSTATIONTYPE)
            {
                if ((trackvec == dirvec) || (trackvec == -dirvec))
                {
                    Segment segment = this.AttemptGetSegment(nextX, nextY, nextZ);
                    if (segment == null)
                    {
                        segment = WorldScript.instance.GetSegment(nextX, nextY, nextZ);
                        if (segment == null)
                        {
                            Debug.Log((object)"Track junction track follower did not find segment");
                            return(false);
                        }
                    }
                    FreightCartStation fcs = segment.FetchEntity(eSegmentEntity.Mod, nextX, nextY, nextZ) as FreightCartStation;
                    if (fcs == null)
                    {
                        Debug.LogWarning("Track Junction Track Follower tried to get a freight cart station but got other mod machine instead?");
                        return(false);
                    }
                    if (!SegmentStations.Contains(fcs))
                    {
                        SegmentStations.Add(fcs);
                    }
                    fcs.ClosestJunction   = this;
                    fcs.JunctionDirection = initialdirection;
                    // Penalize this route for multidirection pathfinding due to the station
                    PathfindPenalty += 5;
                }
                else
                {
                    return(false);
                }
            }
            //Is it a junction?
            else if (type == JUNCTIONTYPE)
            {
                //Debug.LogWarning("Track follower success!  Found another junction!");
                Segment segment = this.AttemptGetSegment(nextX, nextY, nextZ);
                if (segment == null)
                {
                    segment = WorldScript.instance.GetSegment(nextX, nextY, nextZ);
                    if (segment == null)
                    {
                        Debug.Log((object)"Track junction track follower did not find segment");
                        return(false);
                    }
                }
                FreightTrackJunction junction = segment.FetchEntity(eSegmentEntity.Mod, nextX, nextY, nextZ) as FreightTrackJunction;
                if (junction == null)
                {
                    Debug.LogWarning("Track Junction Track Follower tried to get a track junction but got other mod machine instead?");
                    return(false);
                }
                this.ConnectedJunctions[initialdirection] = junction;
                //Don't let segment distance be negative just to be safe!  This should rarely happen...
                if (PathfindPenalty < 0 && Math.Abs(PathfindPenalty) > n)
                {
                    PathfindPenalty = -n;
                }
                FreightTrackSegment tracksegment = new FreightTrackSegment(this, junction, n + 1 + PathfindPenalty);
                tracksegment.Stations = SegmentStations;
                //Debug.LogWarning("trackseg station count: " + tracksegment.Stations.Count);
                this.ConnectedSegments[initialdirection] = tracksegment;
                this.SegmentDistances[initialdirection]  = n + 1;
                this.LinkStatusDirty = true;

                //handle the connection for the other junction so we don't need to double the work - only if return path is valid!
                //Mirror the direction to reflect the correct side of the connecting junction
                if (!oneway)
                {
                    int mirroreddir = direction += 2;
                    if (mirroreddir > 3)
                    {
                        mirroreddir -= 4;
                    }
                    junction.ConnectedJunctions[mirroreddir] = this;
                    junction.ConnectedSegments[mirroreddir]  = tracksegment;
                    junction.SegmentDistances[mirroreddir]   = n + 1;
                    junction.LinkStatusDirty = true;
                }
                return(true);
            }
            else if (type == TOURSTATIONTYPE)
            {
                if (trackvec != -dirvec)
                {
                    return(false);
                }
                Segment segment = this.AttemptGetSegment(nextX, nextY, nextZ);
                if (segment == null)
                {
                    segment = WorldScript.instance.GetSegment(nextX, nextY, nextZ);
                    if (segment == null)
                    {
                        Debug.Log((object)"Track junction track follower did not find segment");
                        return(false);
                    }
                }
                TourCartStation station = segment.FetchEntity(eSegmentEntity.Mod, nextX, nextY, nextZ) as TourCartStation;
                station.TrackNetwork      = this.TrackNetwork;
                station.ClosestJunction   = this;
                station.JunctionDirection = initialdirection;
                this.ConnectedJunctions[initialdirection] = this;
                FreightTrackSegment tracksegment = new FreightTrackSegment(this, this, 2 * n + 1);
                this.SegmentDistances[initialdirection]  = 2 * n + 1;
                this.ConnectedSegments[initialdirection] = tracksegment;
                this.LinkStatusDirty = true;
                if (!string.IsNullOrEmpty(station.StationName) && !this.TrackNetwork.TourCartStations.ContainsKey(station.StationName))
                {
                    this.TrackNetwork.TourCartStations.Add(station.StationName, station);
                }
                return(true);
            }
            else
            {
                return(false);   //Not a track type
            }
            //Update the direction int based on the changed direction vector
            if (dirvec == Vector3.right)
            {
                direction = 0;
            }
            else if (dirvec == Vector3.forward)
            {
                direction = 1;
            }
            else if (dirvec == Vector3.left)
            {
                direction = 2;
            }
            else if (dirvec == Vector3.back)
            {
                direction = 3;
            }

            TrackPiece visitedpiece = new TrackPiece(new Vector3(nextX - this.mnX, nextY - this.mnY, nextZ - this.mnZ), direction);
            //Debug.LogWarning("Visited track piece: " + new Vector4(nextX - this.mnX, nextY - mnY, nextZ - mnZ, direction).ToString());
            //Store every track piece and check every 10th for monitoring for closed, endless loops of track
            if (n % 10 == 0)
            {
                int count = VisitedTracks.Count;
                for (int m = 0; m < count; m++)
                {
                    TrackPiece piece = VisitedTracks[m];
                    if (piece.Position == visitedpiece.Position && piece.Direction == visitedpiece.Direction)
                    {
                        //Debug.LogWarning("piece position: " + piece.Position.ToString() + " visited: " + visitedpiece.Position.ToString());
                        Debug.LogWarning("TrackJunction followed track route and found a closed loop.  Ending search.");
                        return(false);
                    }
                }
            }
            VisitedTracks.Add(visitedpiece);
            if (n == 2047)
            {
                Debug.LogWarning("Track Junction Found track length > 2048m -> ending search.");
            }
        }
        return(false);
    }