// Decompiled with JetBrains decompiler // Type: Terraria.GameContent.Generation.TrackGenerator // Assembly: Terraria, Version=1.4.0.5, Culture=neutral, PublicKeyToken=null // MVID: 67F9E73E-0A81-4937-A22C-5515CD405A83 // Assembly location: C:\Users\mikeyisbaeyt\Downloads\depotdownloader-2.4.5\depots\105601\6707058\Terraria.exe using Microsoft.Xna.Framework; using System; using System.Diagnostics; using Terraria.ID; using Terraria.WorldBuilding; namespace Terraria.GameContent.Generation { public class TrackGenerator { private static readonly ushort[] InvalidWalls = new ushort[20] { (ushort) 7, (ushort) 94, (ushort) 95, (ushort) 8, (ushort) 98, (ushort) 99, (ushort) 9, (ushort) 96, (ushort) 97, (ushort) 3, (ushort) 83, (ushort) 68, (ushort) 62, (ushort) 78, (ushort) 87, (ushort) 86, (ushort) 42, (ushort) 74, (ushort) 27, (ushort) 149 }; private static readonly ushort[] InvalidTiles = new ushort[22] { (ushort) 383, (ushort) 384, (ushort) 15, (ushort) 304, (ushort) 30, (ushort) 321, (ushort) 245, (ushort) 246, (ushort) 240, (ushort) 241, (ushort) 242, (ushort) 16, (ushort) 34, (ushort) 158, (ushort) 377, (ushort) 94, (ushort) 10, (ushort) 19, (ushort) 86, (ushort) 219, (ushort) 484, (ushort) 190 }; private readonly TrackGenerator.TrackHistory[] _history = new TrackGenerator.TrackHistory[4096]; private readonly TrackGenerator.TrackHistory[] _rewriteHistory = new TrackGenerator.TrackHistory[25]; private int _xDirection; private int _length; private int playerHeight = 6; public bool Place(Point origin, int minLength, int maxLength) { if (!TrackGenerator.FindSuitableOrigin(ref origin)) return false; this.CreateTrackStart(origin); if (!this.FindPath(minLength, maxLength)) return false; this.PlacePath(); return true; } private void PlacePath() { bool[] flagArray = new bool[this._length]; for (int index1 = 0; index1 < this._length; ++index1) { if (WorldGen.genRand.Next(7) == 0) this.playerHeight = WorldGen.genRand.Next(5, 9); for (int index2 = 0; index2 < this.playerHeight; ++index2) { if (Main.tile[(int) this._history[index1].X, (int) this._history[index1].Y - index2 - 1].wall == (ushort) 244) Main.tile[(int) this._history[index1].X, (int) this._history[index1].Y - index2 - 1].wall = (ushort) 0; if (Main.tile[(int) this._history[index1].X, (int) this._history[index1].Y - index2].wall == (ushort) 244) Main.tile[(int) this._history[index1].X, (int) this._history[index1].Y - index2].wall = (ushort) 0; if (Main.tile[(int) this._history[index1].X, (int) this._history[index1].Y - index2 + 1].wall == (ushort) 244) Main.tile[(int) this._history[index1].X, (int) this._history[index1].Y - index2 + 1].wall = (ushort) 0; if (Main.tile[(int) this._history[index1].X, (int) this._history[index1].Y - index2].type == (ushort) 135) flagArray[index1] = true; WorldGen.KillTile((int) this._history[index1].X, (int) this._history[index1].Y - index2, noItem: true); } } for (int index3 = 0; index3 < this._length; ++index3) { if (WorldGen.genRand.Next(7) == 0) this.playerHeight = WorldGen.genRand.Next(5, 9); TrackGenerator.TrackHistory trackHistory = this._history[index3]; Tile.SmoothSlope((int) trackHistory.X, (int) trackHistory.Y + 1); Tile.SmoothSlope((int) trackHistory.X, (int) trackHistory.Y - this.playerHeight); bool wire = Main.tile[(int) trackHistory.X, (int) trackHistory.Y].wire(); if (flagArray[index3] && index3 < this._length && index3 > 0 && (int) this._history[index3 - 1].Y == (int) trackHistory.Y && (int) this._history[index3 + 1].Y == (int) trackHistory.Y) { Main.tile[(int) trackHistory.X, (int) trackHistory.Y].ClearEverything(); WorldGen.PlaceTile((int) trackHistory.X, (int) trackHistory.Y, 314, forced: true, style: 1); } else Main.tile[(int) trackHistory.X, (int) trackHistory.Y].ResetToType((ushort) 314); Main.tile[(int) trackHistory.X, (int) trackHistory.Y].wire(wire); if (index3 != 0) { for (int index4 = 0; index4 < 8; ++index4) WorldUtils.TileFrame((int) this._history[index3 - 1].X, (int) this._history[index3 - 1].Y - index4, true); if (index3 == this._length - 1) { for (int index5 = 0; index5 < this.playerHeight; ++index5) WorldUtils.TileFrame((int) trackHistory.X, (int) trackHistory.Y - index5, true); } } } } private void CreateTrackStart(Point origin) { this._xDirection = origin.X > Main.maxTilesX / 2 ? -1 : 1; this._length = 1; for (int index = 0; index < this._history.Length; ++index) this._history[index] = new TrackGenerator.TrackHistory(origin.X + index * this._xDirection, origin.Y + index, TrackGenerator.TrackSlope.Down); } private bool FindPath(int minLength, int maxLength) { int length = this._length; while (this._length < this._history.Length - 100) { this.AppendToHistory(this._history[this._length - 1].Slope == TrackGenerator.TrackSlope.Up ? TrackGenerator.TrackSlope.Straight : TrackGenerator.TrackSlope.Down); TrackGenerator.TrackPlacementState avoidTiles = this.TryRewriteHistoryToAvoidTiles(); if (avoidTiles != TrackGenerator.TrackPlacementState.Invalid) { length = this._length; TrackGenerator.TrackPlacementState trackPlacementState = avoidTiles; while (trackPlacementState != TrackGenerator.TrackPlacementState.Available) { trackPlacementState = this.CreateTunnel(); if (trackPlacementState != TrackGenerator.TrackPlacementState.Invalid) length = this._length; else break; } if (this._length >= maxLength) break; } else break; } this._length = Math.Min(maxLength, length); if (this._length < minLength) return false; this.SmoothTrack(); return this.GetHistorySegmentPlacementState(0, this._length) != TrackGenerator.TrackPlacementState.Invalid; } private TrackGenerator.TrackPlacementState CreateTunnel() { TrackGenerator.TrackSlope trackSlope1 = TrackGenerator.TrackSlope.Straight; int num = 10; TrackGenerator.TrackPlacementState trackPlacementState1 = TrackGenerator.TrackPlacementState.Invalid; int x = (int) this._history[this._length - 1].X; int y = (int) this._history[this._length - 1].Y; for (TrackGenerator.TrackSlope trackSlope2 = TrackGenerator.TrackSlope.Up; trackSlope2 <= TrackGenerator.TrackSlope.Down; ++trackSlope2) { TrackGenerator.TrackPlacementState trackPlacementState2 = TrackGenerator.TrackPlacementState.Invalid; for (int index = 1; index < num; ++index) { trackPlacementState2 = TrackGenerator.CalculateStateForLocation(x + index * this._xDirection, y + index * (int) trackSlope2); switch (trackPlacementState2) { case TrackGenerator.TrackPlacementState.Obstructed: continue; case TrackGenerator.TrackPlacementState.Invalid: goto label_6; default: trackSlope1 = trackSlope2; num = index; trackPlacementState1 = trackPlacementState2; goto label_6; } } label_6: if (trackPlacementState1 != TrackGenerator.TrackPlacementState.Available && trackPlacementState2 == TrackGenerator.TrackPlacementState.Obstructed && (trackPlacementState1 != TrackGenerator.TrackPlacementState.Obstructed || trackSlope1 != TrackGenerator.TrackSlope.Straight)) { trackSlope1 = trackSlope2; num = 10; trackPlacementState1 = trackPlacementState2; } } if (this._length == 0 || !TrackGenerator.CanSlopesTouch(this._history[this._length - 1].Slope, trackSlope1)) this.RewriteSlopeDirection(this._length - 1, TrackGenerator.TrackSlope.Straight); this._history[this._length - 1].Mode = TrackGenerator.TrackMode.Tunnel; for (int index = 1; index < num; ++index) this.AppendToHistory(trackSlope1, TrackGenerator.TrackMode.Tunnel); return trackPlacementState1; } private void AppendToHistory(TrackGenerator.TrackSlope slope, TrackGenerator.TrackMode mode = TrackGenerator.TrackMode.Normal) { this._history[this._length] = new TrackGenerator.TrackHistory((int) this._history[this._length - 1].X + this._xDirection, (int) ((sbyte) this._history[this._length - 1].Y + slope), slope); this._history[this._length].Mode = mode; ++this._length; } private TrackGenerator.TrackPlacementState TryRewriteHistoryToAvoidTiles() { int index1 = this._length - 1; int length = Math.Min(this._length, this._rewriteHistory.Length); for (int index2 = 0; index2 < length; ++index2) this._rewriteHistory[index2] = this._history[index1 - index2]; for (; index1 >= this._length - length; --index1) { if (this._history[index1].Slope == TrackGenerator.TrackSlope.Down) { TrackGenerator.TrackPlacementState segmentPlacementState = this.GetHistorySegmentPlacementState(index1, this._length - index1); if (segmentPlacementState == TrackGenerator.TrackPlacementState.Available) return segmentPlacementState; this.RewriteSlopeDirection(index1, TrackGenerator.TrackSlope.Straight); } } if (this.GetHistorySegmentPlacementState(index1 + 1, this._length - (index1 + 1)) == TrackGenerator.TrackPlacementState.Available) return TrackGenerator.TrackPlacementState.Available; int index3; for (index3 = this._length - 1; index3 >= this._length - length + 1; --index3) { if (this._history[index3].Slope == TrackGenerator.TrackSlope.Straight) { TrackGenerator.TrackPlacementState segmentPlacementState = this.GetHistorySegmentPlacementState(this._length - length, length); if (segmentPlacementState == TrackGenerator.TrackPlacementState.Available) return segmentPlacementState; this.RewriteSlopeDirection(index3, TrackGenerator.TrackSlope.Up); } } for (int index4 = 0; index4 < length; ++index4) this._history[this._length - 1 - index4] = this._rewriteHistory[index4]; this.RewriteSlopeDirection(this._length - 1, TrackGenerator.TrackSlope.Straight); return this.GetHistorySegmentPlacementState(index3 + 1, this._length - (index3 + 1)); } private void RewriteSlopeDirection(int index, TrackGenerator.TrackSlope slope) { int num = (int) (slope - this._history[index].Slope); this._history[index].Slope = slope; for (int index1 = index; index1 < this._length; ++index1) this._history[index1].Y += (short) num; } private TrackGenerator.TrackPlacementState GetHistorySegmentPlacementState( int startIndex, int length) { TrackGenerator.TrackPlacementState trackPlacementState = TrackGenerator.TrackPlacementState.Available; for (int index = startIndex; index < startIndex + length; ++index) { TrackGenerator.TrackPlacementState stateForLocation = TrackGenerator.CalculateStateForLocation((int) this._history[index].X, (int) this._history[index].Y); switch (stateForLocation) { case TrackGenerator.TrackPlacementState.Obstructed: if (this._history[index].Mode != TrackGenerator.TrackMode.Tunnel) { trackPlacementState = stateForLocation; break; } break; case TrackGenerator.TrackPlacementState.Invalid: return stateForLocation; } } return trackPlacementState; } private void SmoothTrack() { int val2 = this._length - 1; bool flag = false; for (int index1 = this._length - 1; index1 >= 0; --index1) { if (flag) { val2 = Math.Min(index1 + 15, val2); if ((int) this._history[index1].Y >= (int) this._history[val2].Y) { for (int index2 = index1 + 1; (int) this._history[index2].Y > (int) this._history[index1].Y; ++index2) { this._history[index2].Y = this._history[index1].Y; this._history[index2].Slope = TrackGenerator.TrackSlope.Straight; } if ((int) this._history[index1].Y == (int) this._history[val2].Y) flag = false; } } else if ((int) this._history[index1].Y > (int) this._history[val2].Y) flag = true; else val2 = index1; } } private static bool CanSlopesTouch( TrackGenerator.TrackSlope leftSlope, TrackGenerator.TrackSlope rightSlope) { return leftSlope == rightSlope || leftSlope == TrackGenerator.TrackSlope.Straight || rightSlope == TrackGenerator.TrackSlope.Straight; } private static bool FindSuitableOrigin(ref Point origin) { TrackGenerator.TrackPlacementState stateForLocation; while ((stateForLocation = TrackGenerator.CalculateStateForLocation(origin.X, origin.Y)) != TrackGenerator.TrackPlacementState.Obstructed) { ++origin.Y; if (stateForLocation == TrackGenerator.TrackPlacementState.Invalid) return false; } --origin.Y; return TrackGenerator.CalculateStateForLocation(origin.X, origin.Y) == TrackGenerator.TrackPlacementState.Available; } private static TrackGenerator.TrackPlacementState CalculateStateForLocation( int x, int y) { for (int index = 0; index < 6; ++index) { if (TrackGenerator.IsLocationInvalid(x, y - index)) return TrackGenerator.TrackPlacementState.Invalid; } for (int index = 0; index < 6; ++index) { if (TrackGenerator.IsMinecartTrack(x, y + index)) return TrackGenerator.TrackPlacementState.Invalid; } for (int index = 0; index < 6; ++index) { if (WorldGen.SolidTile(x, y - index)) return TrackGenerator.TrackPlacementState.Obstructed; } return WorldGen.IsTileNearby(x, y, 314, 30) ? TrackGenerator.TrackPlacementState.Invalid : TrackGenerator.TrackPlacementState.Available; } private static bool IsMinecartTrack(int x, int y) => Main.tile[x, y].active() && Main.tile[x, y].type == (ushort) 314; private static bool IsLocationInvalid(int x, int y) { if (y > Main.UnderworldLayer || x < 5 || y < (int) Main.worldSurface || x > Main.maxTilesX - 5 || WorldGen.oceanDepths(x, y)) return true; ushort wall = Main.tile[x, y].wall; for (int index = 0; index < TrackGenerator.InvalidWalls.Length; ++index) { if ((int) wall == (int) TrackGenerator.InvalidWalls[index] && (!WorldGen.notTheBees || wall != (ushort) 108)) return true; } ushort type = Main.tile[x, y].type; for (int index = 0; index < TrackGenerator.InvalidTiles.Length; ++index) { if ((int) type == (int) TrackGenerator.InvalidTiles[index]) return true; } for (int index = -1; index <= 1; ++index) { if (Main.tile[x + index, y].active() && (Main.tile[x + index, y].type == (ushort) 314 || !TileID.Sets.GeneralPlacementTiles[(int) Main.tile[x + index, y].type]) && (!WorldGen.notTheBees || Main.tile[x + index, y].type != (ushort) 225)) return true; } return false; } [Conditional("DEBUG")] private void DrawPause() { } private enum TrackPlacementState { Available, Obstructed, Invalid, } private enum TrackSlope : sbyte { Up = -1, // 0xFF Straight = 0, Down = 1, } private enum TrackMode : byte { Normal, Tunnel, } [DebuggerDisplay("X = {X}, Y = {Y}, Slope = {Slope}")] private struct TrackHistory { public short X; public short Y; public TrackGenerator.TrackSlope Slope; public TrackGenerator.TrackMode Mode; public TrackHistory(int x, int y, TrackGenerator.TrackSlope slope) { this.X = (short) x; this.Y = (short) y; this.Slope = slope; this.Mode = TrackGenerator.TrackMode.Normal; } } } }