using System.Numerics;
using System.Runtime.CompilerServices;
using Robust.Shared.Serialization;
namespace Content.Shared.Atmos
{
///
/// The reason we use this over is that we are going to do some heavy bitflag usage.
///
[Flags, Serializable]
[FlagsFor(typeof(AtmosDirectionFlags))]
public enum AtmosDirection
{
Invalid = 0, // 0
North = 1 << 0, // 1
South = 1 << 1, // 2
East = 1 << 2, // 4
West = 1 << 3, // 8
// If more directions are added, note that AtmosDirectionHelpers.ToOppositeIndex() expects opposite directions
// to come in pairs
NorthEast = North | East, // 5
SouthEast = South | East, // 6
NorthWest = North | West, // 9
SouthWest = South | West, // 10
All = North | South | East | West, // 15
}
public static class AtmosDirectionHelpers
{
public static AtmosDirection GetOpposite(this AtmosDirection direction)
{
return direction switch
{
AtmosDirection.North => AtmosDirection.South,
AtmosDirection.South => AtmosDirection.North,
AtmosDirection.East => AtmosDirection.West,
AtmosDirection.West => AtmosDirection.East,
AtmosDirection.NorthEast => AtmosDirection.SouthWest,
AtmosDirection.NorthWest => AtmosDirection.SouthEast,
AtmosDirection.SouthEast => AtmosDirection.NorthWest,
AtmosDirection.SouthWest => AtmosDirection.NorthEast,
_ => throw new ArgumentOutOfRangeException(nameof(direction))
};
}
///
/// This returns the index that corresponds to the opposite direction of some other direction index.
/// I.e., 1<<OppositeIndex(i) == (1<<i).GetOpposite()
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int ToOppositeIndex(this int index)
{
return index ^ 1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static AtmosDirection ToOppositeDir(this int index)
{
return (AtmosDirection) (1 << (index ^ 1));
}
public static Direction ToDirection(this AtmosDirection direction)
{
return direction switch
{
AtmosDirection.North => Direction.North,
AtmosDirection.South => Direction.South,
AtmosDirection.East => Direction.East,
AtmosDirection.West => Direction.West,
AtmosDirection.NorthEast => Direction.NorthEast,
AtmosDirection.NorthWest => Direction.NorthWest,
AtmosDirection.SouthEast => Direction.SouthEast,
AtmosDirection.SouthWest => Direction.SouthWest,
AtmosDirection.Invalid => Direction.Invalid,
_ => throw new ArgumentOutOfRangeException(nameof(direction))
};
}
public static AtmosDirection ToAtmosDirection(this Direction direction)
{
return direction switch
{
Direction.North => AtmosDirection.North,
Direction.South => AtmosDirection.South,
Direction.East => AtmosDirection.East,
Direction.West => AtmosDirection.West,
Direction.NorthEast => AtmosDirection.NorthEast,
Direction.NorthWest => AtmosDirection.NorthWest,
Direction.SouthEast => AtmosDirection.SouthEast,
Direction.SouthWest => AtmosDirection.SouthWest,
Direction.Invalid => AtmosDirection.Invalid,
_ => throw new ArgumentOutOfRangeException(nameof(direction))
};
}
///
/// Converts a direction to an angle, where angle is -PI to +PI.
///
///
///
public static Angle ToAngle(this AtmosDirection direction)
{
return direction switch
{
AtmosDirection.South => Angle.Zero,
AtmosDirection.East => new Angle(MathHelper.PiOver2),
AtmosDirection.North => new Angle(Math.PI),
AtmosDirection.West => new Angle(-MathHelper.PiOver2),
AtmosDirection.NorthEast => new Angle(Math.PI*3/4),
AtmosDirection.NorthWest => new Angle(-Math.PI*3/4),
AtmosDirection.SouthWest => new Angle(-MathHelper.PiOver4),
AtmosDirection.SouthEast => new Angle(MathHelper.PiOver4),
_ => throw new ArgumentOutOfRangeException(nameof(direction), $"It was {direction}."),
};
}
///
/// Converts an angle to a cardinal AtmosDirection
///
///
///
public static AtmosDirection ToAtmosDirectionCardinal(this Angle angle)
{
return angle.GetCardinalDir().ToAtmosDirection();
}
///
/// Converts an angle to an AtmosDirection
///
///
///
public static AtmosDirection ToAtmosDirection(this Angle angle)
{
return angle.GetDir().ToAtmosDirection();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int ToIndex(this AtmosDirection direction)
{
// This will throw if you pass an invalid direction. Not this method's fault, but yours!
return BitOperations.Log2((uint)direction);
}
public static AtmosDirection WithFlag(this AtmosDirection direction, AtmosDirection other)
{
return direction | other;
}
public static AtmosDirection WithoutFlag(this AtmosDirection direction, AtmosDirection other)
{
return direction & ~other;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsFlagSet(this AtmosDirection direction, AtmosDirection other)
{
return (direction & other) == other;
}
public static Vector2i CardinalToIntVec(this AtmosDirection dir)
{
switch (dir)
{
case AtmosDirection.North:
return new Vector2i(0, 1);
case AtmosDirection.East:
return new Vector2i(1, 0);
case AtmosDirection.South:
return new Vector2i(0, -1);
case AtmosDirection.West:
return new Vector2i(-1, 0);
default:
throw new ArgumentException($"Direction dir {dir} is not a cardinal direction", nameof(dir));
}
}
public static Vector2i Offset(this Vector2i pos, AtmosDirection dir)
{
return pos + dir.CardinalToIntVec();
}
}
public sealed class AtmosDirectionFlags { }
}