// Decompiled with JetBrains decompiler // Type: Terraria.GameContent.PortalHelper // 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.Collections.Generic; using Terraria.ID; namespace Terraria.GameContent { public class PortalHelper { public const int PORTALS_PER_PERSON = 2; private static int[,] FoundPortals = new int[256, 2]; private static int[] PortalCooldownForPlayers = new int[256]; private static int[] PortalCooldownForNPCs = new int[200]; private static readonly Vector2[] EDGES = new Vector2[4] { new Vector2(0.0f, 1f), new Vector2(0.0f, -1f), new Vector2(1f, 0.0f), new Vector2(-1f, 0.0f) }; private static readonly Vector2[] SLOPE_EDGES = new Vector2[4] { new Vector2(1f, -1f), new Vector2(-1f, -1f), new Vector2(1f, 1f), new Vector2(-1f, 1f) }; private static readonly Point[] SLOPE_OFFSETS = new Point[4] { new Point(1, -1), new Point(-1, -1), new Point(1, 1), new Point(-1, 1) }; private static bool anyPortalAtAll = false; static PortalHelper() { for (int index = 0; index < PortalHelper.SLOPE_EDGES.Length; ++index) PortalHelper.SLOPE_EDGES[index].Normalize(); for (int index = 0; index < PortalHelper.FoundPortals.GetLength(0); ++index) { PortalHelper.FoundPortals[index, 0] = -1; PortalHelper.FoundPortals[index, 1] = -1; } } public static void UpdatePortalPoints() { PortalHelper.anyPortalAtAll = false; for (int index = 0; index < PortalHelper.FoundPortals.GetLength(0); ++index) { PortalHelper.FoundPortals[index, 0] = -1; PortalHelper.FoundPortals[index, 1] = -1; } for (int index = 0; index < PortalHelper.PortalCooldownForPlayers.Length; ++index) { if (PortalHelper.PortalCooldownForPlayers[index] > 0) --PortalHelper.PortalCooldownForPlayers[index]; } for (int index = 0; index < PortalHelper.PortalCooldownForNPCs.Length; ++index) { if (PortalHelper.PortalCooldownForNPCs[index] > 0) --PortalHelper.PortalCooldownForNPCs[index]; } for (int index = 0; index < 1000; ++index) { Projectile projectile = Main.projectile[index]; if (projectile.active && projectile.type == 602 && (double) projectile.ai[1] >= 0.0 && (double) projectile.ai[1] <= 1.0 && projectile.owner >= 0 && projectile.owner <= (int) byte.MaxValue) { PortalHelper.FoundPortals[projectile.owner, (int) projectile.ai[1]] = index; if (PortalHelper.FoundPortals[projectile.owner, 0] != -1 && PortalHelper.FoundPortals[projectile.owner, 1] != -1) PortalHelper.anyPortalAtAll = true; } } } public static void TryGoingThroughPortals(Entity ent) { if (!PortalHelper.anyPortalAtAll) return; float collisionPoint = 0.0f; Vector2 velocity = ent.velocity; int width = ent.width; int height = ent.height; int gravDir = 1; if (ent is Player) gravDir = (int) ((Player) ent).gravDir; for (int index1 = 0; index1 < PortalHelper.FoundPortals.GetLength(0); ++index1) { if (PortalHelper.FoundPortals[index1, 0] != -1 && PortalHelper.FoundPortals[index1, 1] != -1 && (!(ent is Player) || index1 < PortalHelper.PortalCooldownForPlayers.Length && PortalHelper.PortalCooldownForPlayers[index1] <= 0) && (!(ent is NPC) || index1 < PortalHelper.PortalCooldownForNPCs.Length && PortalHelper.PortalCooldownForNPCs[index1] <= 0)) { for (int index2 = 0; index2 < 2; ++index2) { Projectile projectile1 = Main.projectile[PortalHelper.FoundPortals[index1, index2]]; Vector2 start; Vector2 end; PortalHelper.GetPortalEdges(projectile1.Center, projectile1.ai[0], out start, out end); if (Collision.CheckAABBvLineCollision(ent.position + ent.velocity, ent.Size, start, end, 2f, ref collisionPoint)) { Projectile projectile2 = Main.projectile[PortalHelper.FoundPortals[index1, 1 - index2]]; float num1 = ent.Hitbox.Distance(projectile1.Center); int bonusX; int bonusY; Vector2 newPos = PortalHelper.GetPortalOutingPoint(ent.Size, projectile2.Center, projectile2.ai[0], out bonusX, out bonusY) + Vector2.Normalize(new Vector2((float) bonusX, (float) bonusY)) * num1; Vector2 Velocity1 = Vector2.UnitX * 16f; if (!(Collision.TileCollision(newPos - Velocity1, Velocity1, width, height, true, true, gravDir) != Velocity1)) { Vector2 Velocity2 = -Vector2.UnitX * 16f; if (!(Collision.TileCollision(newPos - Velocity2, Velocity2, width, height, true, true, gravDir) != Velocity2)) { Vector2 Velocity3 = Vector2.UnitY * 16f; if (!(Collision.TileCollision(newPos - Velocity3, Velocity3, width, height, true, true, gravDir) != Velocity3)) { Vector2 Velocity4 = -Vector2.UnitY * 16f; if (!(Collision.TileCollision(newPos - Velocity4, Velocity4, width, height, true, true, gravDir) != Velocity4)) { float num2 = 0.1f; if (bonusY == -gravDir) num2 = 0.1f; if (ent.velocity == Vector2.Zero) ent.velocity = (projectile1.ai[0] - 1.570796f).ToRotationVector2() * num2; if ((double) ent.velocity.Length() < (double) num2) { ent.velocity.Normalize(); ent.velocity *= num2; } Vector2 vec = Vector2.Normalize(new Vector2((float) bonusX, (float) bonusY)); if (vec.HasNaNs() || vec == Vector2.Zero) vec = Vector2.UnitX * (float) ent.direction; ent.velocity = vec * ent.velocity.Length(); if (bonusY == -gravDir && Math.Sign(ent.velocity.Y) != -gravDir || (double) Math.Abs(ent.velocity.Y) < 0.100000001490116) ent.velocity.Y = (float) -gravDir * 0.1f; int extraInfo = (int) ((double) (projectile2.owner * 2) + (double) projectile2.ai[1]); int num3 = extraInfo + (extraInfo % 2 == 0 ? 1 : -1); switch (ent) { case Player _: Player player = (Player) ent; player.lastPortalColorIndex = num3; player.Teleport(newPos, 4, extraInfo); if (Main.netMode == 1) { NetMessage.SendData(96, number: player.whoAmI, number2: newPos.X, number3: newPos.Y, number4: ((float) extraInfo)); NetMessage.SendData(13, number: player.whoAmI); } PortalHelper.PortalCooldownForPlayers[index1] = 10; return; case NPC _: NPC npc = (NPC) ent; npc.lastPortalColorIndex = num3; npc.Teleport(newPos, 4, extraInfo); if (Main.netMode == 2) { NetMessage.SendData(100, number: npc.whoAmI, number2: newPos.X, number3: newPos.Y, number4: ((float) extraInfo)); NetMessage.SendData(23, number: npc.whoAmI); } PortalHelper.PortalCooldownForPlayers[index1] = 10; if (bonusY != -1 || (double) ent.velocity.Y <= -3.0) return; ent.velocity.Y = -3f; return; default: return; } } } } } } } } } } public static int TryPlacingPortal( Projectile theBolt, Vector2 velocity, Vector2 theCrashVelocity) { Vector2 vector2_1 = velocity / velocity.Length(); Point tileCoordinates = PortalHelper.FindCollision(theBolt.position, theBolt.position + velocity + vector2_1 * 32f).ToTileCoordinates(); Tile tile = Main.tile[tileCoordinates.X, tileCoordinates.Y]; Vector2 vector2_2 = new Vector2((float) (tileCoordinates.X * 16 + 8), (float) (tileCoordinates.Y * 16 + 8)); if (!WorldGen.SolidOrSlopedTile(tile)) return -1; int num = (int) tile.slope(); bool flag = tile.halfBrick(); for (int index = 0; index < (flag ? 2 : PortalHelper.EDGES.Length); ++index) { Point bestPosition; if ((double) Vector2.Dot(PortalHelper.EDGES[index], vector2_1) > 0.0 && PortalHelper.FindValidLine(tileCoordinates, (int) PortalHelper.EDGES[index].Y, (int) -(double) PortalHelper.EDGES[index].X, out bestPosition)) return PortalHelper.AddPortal(new Vector2((float) (bestPosition.X * 16 + 8), (float) (bestPosition.Y * 16 + 8)) - PortalHelper.EDGES[index] * (flag ? 0.0f : 8f), (float) Math.Atan2((double) PortalHelper.EDGES[index].Y, (double) PortalHelper.EDGES[index].X) + 1.570796f, (int) theBolt.ai[0], theBolt.direction); } if (num != 0) { Vector2 vector2_3 = PortalHelper.SLOPE_EDGES[num - 1]; Point bestPosition; if ((double) Vector2.Dot(vector2_3, -vector2_1) > 0.0 && PortalHelper.FindValidLine(tileCoordinates, -PortalHelper.SLOPE_OFFSETS[num - 1].Y, PortalHelper.SLOPE_OFFSETS[num - 1].X, out bestPosition)) return PortalHelper.AddPortal(new Vector2((float) (bestPosition.X * 16 + 8), (float) (bestPosition.Y * 16 + 8)), (float) Math.Atan2((double) vector2_3.Y, (double) vector2_3.X) - 1.570796f, (int) theBolt.ai[0], theBolt.direction); } return -1; } private static bool FindValidLine( Point position, int xOffset, int yOffset, out Point bestPosition) { bestPosition = position; if (PortalHelper.IsValidLine(position, xOffset, yOffset)) return true; Point position1 = new Point(position.X - xOffset, position.Y - yOffset); if (PortalHelper.IsValidLine(position1, xOffset, yOffset)) { bestPosition = position1; return true; } Point position2 = new Point(position.X + xOffset, position.Y + yOffset); if (!PortalHelper.IsValidLine(position2, xOffset, yOffset)) return false; bestPosition = position2; return true; } private static bool IsValidLine(Point position, int xOffset, int yOffset) { Tile tile = Main.tile[position.X, position.Y]; Tile t1 = Main.tile[position.X - xOffset, position.Y - yOffset]; Tile t2 = Main.tile[position.X + xOffset, position.Y + yOffset]; return !PortalHelper.BlockPortals(Main.tile[position.X + yOffset, position.Y - xOffset]) && !PortalHelper.BlockPortals(Main.tile[position.X + yOffset - xOffset, position.Y - xOffset - yOffset]) && !PortalHelper.BlockPortals(Main.tile[position.X + yOffset + xOffset, position.Y - xOffset + yOffset]) && PortalHelper.CanPlacePortalOn(tile) && PortalHelper.CanPlacePortalOn(t1) && PortalHelper.CanPlacePortalOn(t2) && t1.HasSameSlope(tile) && t2.HasSameSlope(tile); } private static bool CanPlacePortalOn(Tile t) => PortalHelper.DoesTileTypeSupportPortals(t.type) && WorldGen.SolidOrSlopedTile(t); private static bool DoesTileTypeSupportPortals(ushort tileType) => tileType != (ushort) 496; private static bool BlockPortals(Tile t) => t.active() && !Main.tileCut[(int) t.type] && !TileID.Sets.BreakableWhenPlacing[(int) t.type] && Main.tileSolid[(int) t.type]; private static Vector2 FindCollision(Vector2 startPosition, Vector2 stopPosition) { int lastX = 0; int lastY = 0; Utils.PlotLine(startPosition.ToTileCoordinates(), stopPosition.ToTileCoordinates(), (Utils.TileActionAttempt) ((x, y) => { lastX = x; lastY = y; return !WorldGen.SolidOrSlopedTile(x, y); }), false); return new Vector2((float) lastX * 16f, (float) lastY * 16f); } private static int AddPortal(Vector2 position, float angle, int form, int direction) { if (!PortalHelper.SupportedTilesAreFine(position, angle)) return -1; PortalHelper.RemoveMyOldPortal(form); PortalHelper.RemoveIntersectingPortals(position, angle); int index = Projectile.NewProjectile(position.X, position.Y, 0.0f, 0.0f, 602, 0, 0.0f, Main.myPlayer, angle, (float) form); Main.projectile[index].direction = direction; Main.projectile[index].netUpdate = true; return index; } private static void RemoveMyOldPortal(int form) { for (int index = 0; index < 1000; ++index) { Projectile projectile = Main.projectile[index]; if (projectile.active && projectile.type == 602 && projectile.owner == Main.myPlayer && (double) projectile.ai[1] == (double) form) { projectile.Kill(); break; } } } private static void RemoveIntersectingPortals(Vector2 position, float angle) { Vector2 start1; Vector2 end1; PortalHelper.GetPortalEdges(position, angle, out start1, out end1); for (int index = 0; index < 1000; ++index) { Projectile projectile = Main.projectile[index]; if (projectile.active && projectile.type == 602) { Vector2 start2; Vector2 end2; PortalHelper.GetPortalEdges(projectile.Center, projectile.ai[0], out start2, out end2); if (Collision.CheckLinevLine(start1, end1, start2, end2).Length != 0) { if (projectile.owner != Main.myPlayer && Main.netMode != 2) NetMessage.SendData(95, number: projectile.owner, number2: ((float) (int) projectile.ai[1])); projectile.Kill(); } } } } public static Color GetPortalColor(int colorIndex) => PortalHelper.GetPortalColor(colorIndex / 2, colorIndex % 2); public static Color GetPortalColor(int player, int portal) { Color white = Color.White; Color color; if (Main.netMode == 0) { color = portal != 0 ? Main.hslToRgb(0.52f, 1f, 0.6f) : Main.hslToRgb(0.12f, 1f, 0.5f); } else { float num = 0.08f; color = Main.hslToRgb((float) ((0.5 + (double) player * ((double) num * 2.0) + (double) portal * (double) num) % 1.0), 1f, 0.5f); } color.A = (byte) 66; return color; } private static void GetPortalEdges( Vector2 position, float angle, out Vector2 start, out Vector2 end) { Vector2 rotationVector2 = angle.ToRotationVector2(); start = position + rotationVector2 * -22f; end = position + rotationVector2 * 22f; } private static Vector2 GetPortalOutingPoint( Vector2 objectSize, Vector2 portalPosition, float portalAngle, out int bonusX, out int bonusY) { int num = (int) Math.Round((double) MathHelper.WrapAngle(portalAngle) / 0.785398185253143); switch (num) { case -3: case 3: bonusX = num == -3 ? 1 : -1; bonusY = -1; return portalPosition + new Vector2(num == -3 ? 0.0f : -objectSize.X, -objectSize.Y); case -2: case 2: bonusX = num == 2 ? -1 : 1; bonusY = 0; return portalPosition + new Vector2(num == 2 ? -objectSize.X : 0.0f, (float) (-(double) objectSize.Y / 2.0)); case -1: case 1: bonusX = num == -1 ? 1 : -1; bonusY = 1; return portalPosition + new Vector2(num == -1 ? 0.0f : -objectSize.X, 0.0f); case 0: case 4: bonusX = 0; bonusY = num == 0 ? 1 : -1; return portalPosition + new Vector2((float) (-(double) objectSize.X / 2.0), num == 0 ? 0.0f : -objectSize.Y); default: bonusX = 0; bonusY = 0; return portalPosition; } } public static void SyncPortalsOnPlayerJoin( int plr, int fluff, List dontInclude, out List portals, out List portalCenters) { portals = new List(); portalCenters = new List(); for (int index = 0; index < 1000; ++index) { Projectile projectile = Main.projectile[index]; if (projectile.active && (projectile.type == 602 || projectile.type == 601)) { Vector2 center = projectile.Center; int sectionX = Netplay.GetSectionX((int) ((double) center.X / 16.0)); int sectionY = Netplay.GetSectionY((int) ((double) center.Y / 16.0)); for (int x = sectionX - fluff; x < sectionX + fluff + 1; ++x) { for (int y = sectionY - fluff; y < sectionY + fluff + 1; ++y) { if (x >= 0 && x < Main.maxSectionsX && y >= 0 && y < Main.maxSectionsY && !Netplay.Clients[plr].TileSections[x, y] && !dontInclude.Contains(new Point(x, y))) { portals.Add(new Point(x, y)); if (!portalCenters.Contains(new Point(sectionX, sectionY))) portalCenters.Add(new Point(sectionX, sectionY)); } } } } } } public static void SyncPortalSections(Vector2 portalPosition, int fluff) { for (int playerIndex = 0; playerIndex < (int) byte.MaxValue; ++playerIndex) { if (Main.player[playerIndex].active) RemoteClient.CheckSection(playerIndex, portalPosition, fluff); } } public static bool SupportedTilesAreFine(Vector2 portalCenter, float portalAngle) { Point tileCoordinates = portalCenter.ToTileCoordinates(); int num1 = (int) Math.Round((double) MathHelper.WrapAngle(portalAngle) / 0.785398185253143); int num2; int num3; switch (num1) { case -3: case 3: num2 = num1 == -3 ? 1 : -1; num3 = -1; break; case -2: case 2: num2 = num1 == 2 ? -1 : 1; num3 = 0; break; case -1: case 1: num2 = num1 == -1 ? 1 : -1; num3 = 1; break; case 0: case 4: num2 = 0; num3 = num1 == 0 ? 1 : -1; break; default: Main.NewText("Broken portal! (over4s = " + (object) num1 + " , " + (object) portalAngle + ")"); return false; } if (num2 != 0 && num3 != 0) { int num4 = 3; if (num2 == -1 && num3 == 1) num4 = 5; if (num2 == 1 && num3 == -1) num4 = 2; if (num2 == 1 && num3 == 1) num4 = 4; int slope = num4 - 1; return PortalHelper.SupportedSlope(tileCoordinates.X, tileCoordinates.Y, slope) && PortalHelper.SupportedSlope(tileCoordinates.X + num2, tileCoordinates.Y - num3, slope) && PortalHelper.SupportedSlope(tileCoordinates.X - num2, tileCoordinates.Y + num3, slope); } switch (num2) { case 0: switch (num3) { case 0: return true; case 1: --tileCoordinates.Y; break; } if (PortalHelper.SupportedNormal(tileCoordinates.X, tileCoordinates.Y) && PortalHelper.SupportedNormal(tileCoordinates.X + 1, tileCoordinates.Y) && PortalHelper.SupportedNormal(tileCoordinates.X - 1, tileCoordinates.Y)) return true; return PortalHelper.SupportedHalfbrick(tileCoordinates.X, tileCoordinates.Y) && PortalHelper.SupportedHalfbrick(tileCoordinates.X + 1, tileCoordinates.Y) && PortalHelper.SupportedHalfbrick(tileCoordinates.X - 1, tileCoordinates.Y); case 1: --tileCoordinates.X; break; } return PortalHelper.SupportedNormal(tileCoordinates.X, tileCoordinates.Y) && PortalHelper.SupportedNormal(tileCoordinates.X, tileCoordinates.Y - 1) && PortalHelper.SupportedNormal(tileCoordinates.X, tileCoordinates.Y + 1); } private static bool SupportedSlope(int x, int y, int slope) { Tile tile = Main.tile[x, y]; return tile != null && tile.nactive() && !Main.tileCut[(int) tile.type] && !TileID.Sets.BreakableWhenPlacing[(int) tile.type] && Main.tileSolid[(int) tile.type] && (int) tile.slope() == slope && PortalHelper.DoesTileTypeSupportPortals(tile.type); } private static bool SupportedHalfbrick(int x, int y) { Tile tile = Main.tile[x, y]; return tile != null && tile.nactive() && !Main.tileCut[(int) tile.type] && !TileID.Sets.BreakableWhenPlacing[(int) tile.type] && Main.tileSolid[(int) tile.type] && tile.halfBrick() && PortalHelper.DoesTileTypeSupportPortals(tile.type); } private static bool SupportedNormal(int x, int y) { Tile tile = Main.tile[x, y]; return tile != null && tile.nactive() && !Main.tileCut[(int) tile.type] && !TileID.Sets.BreakableWhenPlacing[(int) tile.type] && Main.tileSolid[(int) tile.type] && !TileID.Sets.NotReallySolid[(int) tile.type] && !tile.halfBrick() && tile.slope() == (byte) 0 && PortalHelper.DoesTileTypeSupportPortals(tile.type); } } }