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); } }
/// <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!"); } }
/// <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); } }
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; } }
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; } }
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 }); }
/// <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); } } }
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; } }
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()); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }