Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
341
Scripts/SubSystem/VitaNex/Core/Geometry/Angle.cs
Normal file
341
Scripts/SubSystem/VitaNex/Core/Geometry/Angle.cs
Normal file
@@ -0,0 +1,341 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
[Parsable, PropertyObject]
|
||||
public struct Angle
|
||||
: IEquatable<Angle>, IEquatable<int>, IEquatable<double>, IComparable<Angle>, IComparable<int>, IComparable<double>
|
||||
{
|
||||
public const double D2R = Math.PI / 180.0;
|
||||
public const double R2D = 180.0 / Math.PI;
|
||||
|
||||
public static readonly Angle Zero = 0;
|
||||
|
||||
public static readonly Angle MinValue = -360;
|
||||
public static readonly Angle MaxValue = 360;
|
||||
|
||||
public static Angle FromDirection(Direction dir)
|
||||
{
|
||||
int x = 0, y = 0;
|
||||
|
||||
Movement.Movement.Offset(dir & Direction.Mask, ref x, ref y);
|
||||
|
||||
return FromPoints(0, 0, x, y);
|
||||
}
|
||||
|
||||
public static Angle FromPoints(IPoint2D p1, IPoint2D p2)
|
||||
{
|
||||
return FromPoints(p1.X, p1.Y, p2.X, p2.Y);
|
||||
}
|
||||
|
||||
public static Angle FromPoints(IPoint2D p1, IPoint2D p2, IPoint2D p3)
|
||||
{
|
||||
return FromPoints(p1.X, p1.Y, p2.X, p2.Y, p3.X, p3.Y);
|
||||
}
|
||||
|
||||
public static Angle FromPoints(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
return Math.Atan2(y2, x2) - Math.Atan2(y1, x1);
|
||||
}
|
||||
|
||||
public static Angle FromPoints(int x1, int y1, int x2, int y2, int x3, int y3)
|
||||
{
|
||||
return FromPoints(x2, y2, x1, y1) - FromPoints(x2, y2, x3, y3);
|
||||
}
|
||||
|
||||
public static Angle FromDegrees(int degrees)
|
||||
{
|
||||
return degrees;
|
||||
}
|
||||
|
||||
public static Angle FromRadians(double radians)
|
||||
{
|
||||
return radians;
|
||||
}
|
||||
|
||||
public static Angle GetPitch(IPoint3D p1, IPoint3D p2)
|
||||
{
|
||||
int x = p2.X - p1.X, y = p2.Y - p1.Y, z = p2.Z - p1.Z;
|
||||
|
||||
return -Math.Atan2(z, Math.Sqrt((x * x) + (y * y)));
|
||||
}
|
||||
|
||||
public static Angle GetYaw(IPoint2D p, IPoint2D left, IPoint2D right)
|
||||
{
|
||||
return Math.Abs(FromPoints(p, left) - FromPoints(p, right));
|
||||
}
|
||||
|
||||
public static bool InLOS(IPoint2D p1, IPoint2D target, Direction d, Angle yaw, double distance)
|
||||
{
|
||||
return GetLOS(p1, d, yaw, distance).Contains(target);
|
||||
}
|
||||
|
||||
public static Triangle2D GetLOS(IPoint2D p, Direction d, Angle yaw, double distance)
|
||||
{
|
||||
var a = FromDirection(d);
|
||||
|
||||
var p2 = GetPoint2D(p.X, p.Y, a - yaw, distance);
|
||||
var p3 = GetPoint2D(p.X, p.Y, a + yaw, distance);
|
||||
|
||||
return new Triangle2D(p, p2, p3);
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> PlotLOS(IPoint2D p, Direction d, Angle yaw, double distance)
|
||||
{
|
||||
var a = FromDirection(d);
|
||||
|
||||
var p2 = GetPoint2D(p.X, p.Y, a - yaw, distance);
|
||||
var p3 = GetPoint2D(p.X, p.Y, a + yaw, distance);
|
||||
|
||||
return Triangle2D.Plot(p, p2, p3);
|
||||
}
|
||||
|
||||
public static void Transform(ref Point3D p, Angle angle, double offset)
|
||||
{
|
||||
int x = p.X, y = p.Y, z = p.Z;
|
||||
|
||||
Transform(ref x, ref y, angle, offset);
|
||||
|
||||
p = new Point3D(x, y, z);
|
||||
}
|
||||
|
||||
public static void Transform(ref Point2D p, Angle angle, double offset)
|
||||
{
|
||||
int x = p.X, y = p.Y;
|
||||
|
||||
Transform(ref x, ref y, angle, offset);
|
||||
|
||||
p = new Point2D(x, y);
|
||||
}
|
||||
|
||||
public static void Transform(ref int x, ref int y, Angle angle, double offset)
|
||||
{
|
||||
x += (int)(offset * Math.Cos(angle._Radians));
|
||||
y += (int)(offset * Math.Sin(angle._Radians));
|
||||
}
|
||||
|
||||
public static Point2D GetPoint2D(int x, int y, Angle angle, double distance)
|
||||
{
|
||||
return new Point2D(x + (int)(distance * Math.Cos(angle._Radians)), y + (int)(distance * Math.Sin(angle._Radians)));
|
||||
}
|
||||
|
||||
public static Point3D GetPoint3D(int x, int y, int z, Angle angle, double distance)
|
||||
{
|
||||
return new Point3D(
|
||||
x + (int)(distance * Math.Cos(angle._Radians)),
|
||||
y + (int)(distance * Math.Sin(angle._Radians)),
|
||||
z);
|
||||
}
|
||||
|
||||
public static bool TryParse(string value, out Angle angle)
|
||||
{
|
||||
try
|
||||
{
|
||||
angle = Parse(value);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
angle = Zero;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static Angle Parse(string value)
|
||||
{
|
||||
value = value ?? String.Empty;
|
||||
value = value.Trim();
|
||||
|
||||
int d;
|
||||
double r;
|
||||
|
||||
if (!value.Contains(","))
|
||||
{
|
||||
if (Int32.TryParse(value, out d))
|
||||
{
|
||||
return d;
|
||||
}
|
||||
|
||||
if (Double.TryParse(value, out r))
|
||||
{
|
||||
return r;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = value.Trim('(', ')', ' ');
|
||||
|
||||
var i = value.IndexOf(',');
|
||||
|
||||
if (Int32.TryParse(value.Substring(0, i).Trim(), out d))
|
||||
{
|
||||
return d;
|
||||
}
|
||||
|
||||
if (Double.TryParse(value.Substring(i + 1).Trim(), out r))
|
||||
{
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
throw new FormatException(
|
||||
"The specified angle must be represented by Int32 (Degrees) or Double (Radians) using the format " + //
|
||||
"'###', '#.##', or '(###, #.##)'");
|
||||
}
|
||||
|
||||
private readonly int _Degrees;
|
||||
private readonly double _Radians;
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public int Degrees => _Degrees;
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public double Radians => _Radians;
|
||||
|
||||
public Angle(Angle angle)
|
||||
{
|
||||
_Degrees = angle._Degrees;
|
||||
_Radians = angle._Radians;
|
||||
}
|
||||
|
||||
public Angle(int degrees)
|
||||
{
|
||||
_Degrees = degrees;
|
||||
_Radians = _Degrees * D2R;
|
||||
}
|
||||
|
||||
public Angle(double radians)
|
||||
: this((int)(radians * R2D))
|
||||
{ }
|
||||
|
||||
public Angle(int x1, int y1, int x2, int y2)
|
||||
: this(Math.Atan2(y2, x2) - Math.Atan2(y1, x1))
|
||||
{ }
|
||||
|
||||
public Angle(IPoint2D p1, IPoint2D p2)
|
||||
: this(p1.X, p1.Y, p2.X, p2.Y)
|
||||
{ }
|
||||
|
||||
public void Transform(ref Point3D p, double offset)
|
||||
{
|
||||
Transform(ref p, this, offset);
|
||||
}
|
||||
|
||||
public void Transform(ref Point2D p, double offset)
|
||||
{
|
||||
Transform(ref p, this, offset);
|
||||
}
|
||||
|
||||
public void Transform(ref int x, ref int y, double offset)
|
||||
{
|
||||
Transform(ref x, ref y, this, offset);
|
||||
}
|
||||
|
||||
public Point2D GetPoint2D(int x, int y, double distance)
|
||||
{
|
||||
return GetPoint2D(x, y, this, distance);
|
||||
}
|
||||
|
||||
public Point3D GetPoint3D(int x, int y, int z, double distance)
|
||||
{
|
||||
return GetPoint3D(x, y, z, this, distance);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _Degrees;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return (obj is Angle && Equals((Angle)obj)) || (obj is int && Equals((int)obj)) ||
|
||||
(obj is double && Equals((double)obj));
|
||||
}
|
||||
|
||||
public bool Equals(Angle angle)
|
||||
{
|
||||
return _Degrees == angle._Degrees;
|
||||
}
|
||||
|
||||
public bool Equals(int degrees)
|
||||
{
|
||||
return _Degrees == degrees;
|
||||
}
|
||||
|
||||
public bool Equals(double radians)
|
||||
{
|
||||
return _Radians == radians;
|
||||
}
|
||||
|
||||
public int CompareTo(Angle angle)
|
||||
{
|
||||
return _Degrees.CompareTo(angle._Degrees);
|
||||
}
|
||||
|
||||
public int CompareTo(int degrees)
|
||||
{
|
||||
return _Degrees.CompareTo(degrees);
|
||||
}
|
||||
|
||||
public int CompareTo(double radians)
|
||||
{
|
||||
return _Radians.CompareTo(radians);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("({0}, {1})", _Degrees, _Radians);
|
||||
}
|
||||
|
||||
public Angle Normalize()
|
||||
{
|
||||
return _Degrees % 360;
|
||||
}
|
||||
|
||||
#region Operators
|
||||
public static Angle operator --(Angle a)
|
||||
{
|
||||
return a._Degrees - 1;
|
||||
}
|
||||
|
||||
public static Angle operator ++(Angle a)
|
||||
{
|
||||
return a._Degrees + 1;
|
||||
}
|
||||
|
||||
public static implicit operator int(Angle a)
|
||||
{
|
||||
return a._Degrees;
|
||||
}
|
||||
|
||||
public static implicit operator double(Angle a)
|
||||
{
|
||||
return a._Radians;
|
||||
}
|
||||
|
||||
public static implicit operator Angle(int d)
|
||||
{
|
||||
return new Angle(d);
|
||||
}
|
||||
|
||||
public static implicit operator Angle(double r)
|
||||
{
|
||||
return new Angle(r);
|
||||
}
|
||||
#endregion Operators
|
||||
}
|
||||
}
|
||||
338
Scripts/SubSystem/VitaNex/Core/Geometry/Block3D.cs
Normal file
338
Scripts/SubSystem/VitaNex/Core/Geometry/Block3D.cs
Normal file
@@ -0,0 +1,338 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Server.Targeting;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public interface IBlock3D : IPoint3D, IEquatable<IBlock3D>, IEnumerable<IPoint3D>
|
||||
{
|
||||
int H { get; set; }
|
||||
|
||||
bool Intersects(Item e);
|
||||
bool Intersects(Mobile e);
|
||||
bool Intersects(IEntity e);
|
||||
bool Intersects(IPoint3D p);
|
||||
bool Intersects(IBlock3D b);
|
||||
bool Intersects(int z);
|
||||
bool Intersects(int x, int y, int z);
|
||||
bool Intersects(int x, int y, int z, int h);
|
||||
|
||||
IEnumerable<IPoint3D> Scan();
|
||||
}
|
||||
|
||||
public struct Block3D : IBlock3D
|
||||
{
|
||||
public static readonly Block3D Empty = new Block3D(0, 0, 0, 0);
|
||||
|
||||
public static bool Intersects(IPoint3D a, IPoint3D b)
|
||||
{
|
||||
return Create(a).Intersects(Create(b));
|
||||
}
|
||||
|
||||
public static Block3D Create(IPoint3D o)
|
||||
{
|
||||
if (o is Mobile)
|
||||
{
|
||||
return new Block3D(o, 18);
|
||||
}
|
||||
|
||||
if (o is Item)
|
||||
{
|
||||
return new Block3D(o, Math.Max(1, ((Item)o).ItemData.CalcHeight));
|
||||
}
|
||||
|
||||
if (o is LandTarget)
|
||||
{
|
||||
return new Block3D(o, 1);
|
||||
}
|
||||
|
||||
if (o is StaticTarget)
|
||||
{
|
||||
return new Block3D(o, TileData.ItemTable[((StaticTarget)o).ItemID].CalcHeight);
|
||||
}
|
||||
|
||||
return new Block3D(o, 5);
|
||||
}
|
||||
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
public int Z { get; set; }
|
||||
public int H { get; set; }
|
||||
|
||||
public Block3D(IBlock3D b)
|
||||
: this(b.X, b.Y, b.Z, b.H)
|
||||
{ }
|
||||
|
||||
public Block3D(IPoint3D p, int h)
|
||||
: this(p.X, p.Y, p.Z, h)
|
||||
{ }
|
||||
|
||||
public Block3D(int x, int y, int z, int h)
|
||||
: this()
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
H = h;
|
||||
}
|
||||
|
||||
public bool Intersects(IEntity e)
|
||||
{
|
||||
if (e is Item)
|
||||
{
|
||||
return Intersects((Item)e);
|
||||
}
|
||||
|
||||
if (e is Mobile)
|
||||
{
|
||||
return Intersects((Mobile)e);
|
||||
}
|
||||
|
||||
return Intersects(e.X, e.Y, e.Z);
|
||||
}
|
||||
|
||||
public bool Intersects(IPoint3D p)
|
||||
{
|
||||
if (p is Item)
|
||||
{
|
||||
return Intersects((Item)p);
|
||||
}
|
||||
|
||||
if (p is Mobile)
|
||||
{
|
||||
return Intersects((Mobile)p);
|
||||
}
|
||||
|
||||
if (p is LandTarget)
|
||||
{
|
||||
return Intersects((LandTarget)p);
|
||||
}
|
||||
|
||||
if (p is StaticTarget)
|
||||
{
|
||||
return Intersects((StaticTarget)p);
|
||||
}
|
||||
|
||||
return Intersects(p.X, p.Y, p.Z);
|
||||
}
|
||||
|
||||
public bool Intersects(Point3D p, int h)
|
||||
{
|
||||
return Intersects(p.X, p.Y, p.Z, h);
|
||||
}
|
||||
|
||||
public bool Intersects(LandTarget o)
|
||||
{
|
||||
return Intersects(o.X, o.Y, o.Z, 1);
|
||||
}
|
||||
|
||||
public bool Intersects(StaticTarget o)
|
||||
{
|
||||
return Intersects(o.X, o.Y, o.Z, Math.Max(1, TileData.ItemTable[o.ItemID].CalcHeight));
|
||||
}
|
||||
|
||||
public bool Intersects(Mobile m)
|
||||
{
|
||||
return Intersects(m.X, m.Y, m.Z, 18);
|
||||
}
|
||||
|
||||
public bool Intersects(Item i)
|
||||
{
|
||||
return Intersects(i.X, i.Y, i.Z, Math.Max(1, i.ItemData.CalcHeight));
|
||||
}
|
||||
|
||||
public bool Intersects(Block3D b)
|
||||
{
|
||||
return Intersects(b.X, b.Y, b.Z, b.H);
|
||||
}
|
||||
|
||||
public bool Intersects(IBlock3D b)
|
||||
{
|
||||
return Intersects(b.X, b.Y, b.Z, b.H);
|
||||
}
|
||||
|
||||
public bool Intersects(int z)
|
||||
{
|
||||
return Intersects(X, Y, z);
|
||||
}
|
||||
|
||||
public bool Intersects(int z, int h)
|
||||
{
|
||||
return Intersects(X, Y, z, h);
|
||||
}
|
||||
|
||||
public bool Intersects(int x, int y, int z)
|
||||
{
|
||||
return Intersects(x, y, z, 0);
|
||||
}
|
||||
|
||||
public bool Intersects(Rectangle2D b, int z, int h)
|
||||
{
|
||||
return X >= b.Start.X && X < b.End.X && Y >= b.Start.Y && Y < b.End.Y && Intersects(X, Y, z, h);
|
||||
}
|
||||
|
||||
public bool Intersects(Rectangle3D b)
|
||||
{
|
||||
var z = Math.Min(b.Start.Z, b.End.Z);
|
||||
var h = Math.Abs(b.Depth);
|
||||
|
||||
return X >= b.Start.X && X < b.End.X && Y >= b.Start.Y && Y < b.End.Y && Intersects(X, Y, z, h);
|
||||
}
|
||||
|
||||
public bool Intersects(int x, int y, int z, int h)
|
||||
{
|
||||
if (x != X || y != Y)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (z == Z || z + h == Z + H)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (z >= Z && z <= Z + H)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Z >= z && Z <= z + h)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (z <= Z && z + h >= Z)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Z <= z && Z + H >= z)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Block3D Offset(int x = 0, int y = 0, int z = 0, int h = 0)
|
||||
{
|
||||
X += x;
|
||||
Y += y;
|
||||
Z += z;
|
||||
H += h;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Block3D Delta(int x = 0, int y = 0, int z = 0, int h = 0)
|
||||
{
|
||||
X -= x;
|
||||
Y -= y;
|
||||
Z -= z;
|
||||
H -= h;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Block3D Normalize(int x = 0, int y = 0, int z = 0, int h = 0)
|
||||
{
|
||||
X = x - X;
|
||||
Y = y - Y;
|
||||
Z = z - Z;
|
||||
H = h - H;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public IEnumerator<IPoint3D> GetEnumerator()
|
||||
{
|
||||
return Scan().GetEnumerator();
|
||||
}
|
||||
|
||||
public IEnumerable<IPoint3D> Scan()
|
||||
{
|
||||
for (var z = Z; z <= Z + H; z++)
|
||||
{
|
||||
yield return this.ToPoint3D(z);
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0}, {1}, {2}, {3}", X, Y, Z, H);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = 0;
|
||||
hash = (hash * 397) ^ X;
|
||||
hash = (hash * 397) ^ Y;
|
||||
hash = (hash * 397) ^ Z;
|
||||
hash = (hash * 397) ^ H;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is IBlock3D && Equals((IBlock3D)obj);
|
||||
}
|
||||
|
||||
public bool Equals(IBlock3D b)
|
||||
{
|
||||
return !ReferenceEquals(b, null) && X == b.X && Y == b.Y && Z == b.Z && H == b.H;
|
||||
}
|
||||
|
||||
public static bool operator ==(Block3D a, IBlock3D b)
|
||||
{
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
public static bool operator !=(Block3D a, IBlock3D b)
|
||||
{
|
||||
return !a.Equals(b);
|
||||
}
|
||||
|
||||
public static bool operator ==(IBlock3D a, Block3D b)
|
||||
{
|
||||
return b.Equals(a);
|
||||
}
|
||||
|
||||
public static bool operator !=(IBlock3D a, Block3D b)
|
||||
{
|
||||
return !b.Equals(a);
|
||||
}
|
||||
|
||||
public static implicit operator Block3D(Point3D p)
|
||||
{
|
||||
return new Block3D(p, 0);
|
||||
}
|
||||
|
||||
public static implicit operator Point3D(Block3D p)
|
||||
{
|
||||
return new Point3D(p.X, p.Y, p.Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
21
Scripts/SubSystem/VitaNex/Core/Geometry/Direction4.cs
Normal file
21
Scripts/SubSystem/VitaNex/Core/Geometry/Direction4.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public enum Direction4
|
||||
{
|
||||
North = Direction.North,
|
||||
East = Direction.East,
|
||||
South = Direction.South,
|
||||
West = Direction.West
|
||||
}
|
||||
}
|
||||
21
Scripts/SubSystem/VitaNex/Core/Geometry/Direction45.cs
Normal file
21
Scripts/SubSystem/VitaNex/Core/Geometry/Direction45.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public enum Direction45
|
||||
{
|
||||
Up = Direction.Up,
|
||||
Right = Direction.Right,
|
||||
Down = Direction.Down,
|
||||
Left = Direction.Left
|
||||
}
|
||||
}
|
||||
339
Scripts/SubSystem/VitaNex/Core/Geometry/Line2D.cs
Normal file
339
Scripts/SubSystem/VitaNex/Core/Geometry/Line2D.cs
Normal file
@@ -0,0 +1,339 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
[NoSort, Parsable, PropertyObject]
|
||||
public struct Line2D : IPoint2D
|
||||
{
|
||||
public static readonly Line2D Empty = new Line2D(0, 0, 0, 0);
|
||||
|
||||
private static void Swap<T>(ref T a, ref T b)
|
||||
{
|
||||
var t = a;
|
||||
a = b;
|
||||
b = t;
|
||||
}
|
||||
|
||||
private static IEnumerable<Point2D> Plot(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
var delta = Math.Abs(y2 - y1) > Math.Abs(x2 - x1);
|
||||
|
||||
if (delta)
|
||||
{
|
||||
Swap(ref x1, ref y1);
|
||||
Swap(ref x2, ref y2);
|
||||
}
|
||||
|
||||
if (x1 > x2)
|
||||
{
|
||||
Swap(ref x1, ref x2);
|
||||
Swap(ref y1, ref y2);
|
||||
}
|
||||
|
||||
var dX = x2 - x1;
|
||||
var dY = Math.Abs(y2 - y1);
|
||||
var eX = dX / 2;
|
||||
var sY = y1 < y2 ? 1 : -1;
|
||||
|
||||
var y = y1;
|
||||
|
||||
for (var x = x1; x <= x2; x++)
|
||||
{
|
||||
if (delta)
|
||||
{
|
||||
yield return new Point2D(y, x);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new Point2D(x, y);
|
||||
}
|
||||
|
||||
eX -= dY;
|
||||
|
||||
if (eX < 0)
|
||||
{
|
||||
y += sY;
|
||||
eX += dX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> Plot(IPoint2D start, IPoint2D end)
|
||||
{
|
||||
return Plot(start.X, start.Y, end.X, end.Y).OrderBy(p => GetLength(start, p));
|
||||
}
|
||||
|
||||
public static double GetLength(IPoint2D start, IPoint2D end)
|
||||
{
|
||||
return Math.Abs(Math.Sqrt(Math.Pow(end.X - start.X, 2) + Math.Pow(end.Y - start.Y, 2)));
|
||||
}
|
||||
|
||||
public static double GetLength(Line2D line)
|
||||
{
|
||||
return GetLength(line.Start, line.End);
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> Intersect(Line2D[] lines1, Line2D[] lines2)
|
||||
{
|
||||
return lines1.Ensure().SelectMany(l => Intersect(l, lines2));
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> Intersect(Line2D line, Line2D[] lines)
|
||||
{
|
||||
return lines.Ensure().Select(l => Intersect(line, l)).Where(p => p != null).Select(p => p.Value);
|
||||
}
|
||||
|
||||
public static Point2D? Intersect(IPoint2D a1, IPoint2D b1, IPoint2D a2, IPoint2D b2)
|
||||
{
|
||||
if ((a1.X == a2.X && a1.Y == a2.Y) || (a1.X == b2.X && a1.Y == b2.Y))
|
||||
{
|
||||
return new Point2D(a1.X, a1.Y);
|
||||
}
|
||||
|
||||
if ((b1.X == b2.X && b1.Y == b2.Y) || (b1.X == a2.X && b1.Y == a2.Y))
|
||||
{
|
||||
return new Point2D(b1.X, b1.Y);
|
||||
}
|
||||
|
||||
var da1 = b1.Y - a1.Y;
|
||||
var da2 = a1.X - b1.X;
|
||||
var da3 = da1 * a1.X + da2 * a1.Y;
|
||||
|
||||
var db1 = b2.Y - a2.Y;
|
||||
var db2 = a2.X - b2.X;
|
||||
var db3 = db1 * a2.X + db2 * a2.Y;
|
||||
|
||||
var delta = da1 * db2 - db1 * da2;
|
||||
|
||||
if (delta != 0)
|
||||
{
|
||||
return new Point2D((db2 * da3 - da2 * db3) / delta, (da1 * db3 - db1 * da3) / delta);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Point2D? Intersect(Line2D line, IPoint2D a, IPoint2D b)
|
||||
{
|
||||
return Intersect(line._Start, line._End, a, b);
|
||||
}
|
||||
|
||||
public static Point2D? Intersect(Line2D l1, Line2D l2)
|
||||
{
|
||||
return Intersect(l1._Start, l1._End, l2._Start, l2._End);
|
||||
}
|
||||
|
||||
public static bool Intersects(Line2D[] lines1, Line2D[] lines2)
|
||||
{
|
||||
return Intersect(lines1, lines2).Any();
|
||||
}
|
||||
|
||||
public static bool Intersects(Line2D line, Line2D[] lines)
|
||||
{
|
||||
return Intersect(line, lines).Any();
|
||||
}
|
||||
|
||||
public static bool Intersects(Line2D line, IPoint2D a, IPoint2D b)
|
||||
{
|
||||
return Intersect(line, a, b) != null;
|
||||
}
|
||||
|
||||
public static bool Intersects(IPoint2D a1, IPoint2D b1, IPoint2D a2, IPoint2D b2)
|
||||
{
|
||||
return Intersect(a1, b1, a2, b2) != null;
|
||||
}
|
||||
|
||||
public static bool Intersects(Line2D l1, Line2D l2)
|
||||
{
|
||||
return Intersect(l1, l2) != null;
|
||||
}
|
||||
|
||||
public static bool TryParse(string value, out Line2D l)
|
||||
{
|
||||
try
|
||||
{
|
||||
l = Parse(value);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
l = Empty;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static Line2D Parse(string value)
|
||||
{
|
||||
var param = value.Split('+');
|
||||
|
||||
if (param.Length >= 2 && param.All(p => p.Contains(',')))
|
||||
{
|
||||
return new Line2D(Point2D.Parse(param[0]), Point2D.Parse(param[1]));
|
||||
}
|
||||
|
||||
throw new FormatException(
|
||||
"The specified line must be represented by two Point2D coords using the format " + //
|
||||
"'(x1,y1)+(x2,y2)'");
|
||||
}
|
||||
|
||||
private Point2D _Start, _End;
|
||||
|
||||
private Angle _Rotation;
|
||||
private double _Length;
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public int X
|
||||
{
|
||||
get => _Start.X;
|
||||
set
|
||||
{
|
||||
_Start.X = value;
|
||||
|
||||
_Rotation = Angle.FromPoints(_Start, _End);
|
||||
_Length = _Start.GetDistance(_End);
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public int Y
|
||||
{
|
||||
get => _Start.Y;
|
||||
set
|
||||
{
|
||||
_Start.Y = value;
|
||||
|
||||
_Rotation = Angle.FromPoints(_Start, _End);
|
||||
_Length = _Start.GetDistance(_End);
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public Point2D Start
|
||||
{
|
||||
get => _Start;
|
||||
set
|
||||
{
|
||||
_Start = value;
|
||||
|
||||
_Rotation = Angle.FromPoints(_Start, _End);
|
||||
_Length = _Start.GetDistance(_End);
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public Point2D End
|
||||
{
|
||||
get => _End;
|
||||
set
|
||||
{
|
||||
_End = value;
|
||||
|
||||
_Rotation = Angle.FromPoints(_Start, _End);
|
||||
_Length = _Start.GetDistance(_End);
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public Angle Rotation
|
||||
{
|
||||
get => _Rotation;
|
||||
set
|
||||
{
|
||||
_Rotation = value;
|
||||
_End = _Rotation.GetPoint2D(_Start.X, _Start.Y, _Length);
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public double Length
|
||||
{
|
||||
get => _Length;
|
||||
set
|
||||
{
|
||||
_Length = value;
|
||||
_End = _Rotation.GetPoint2D(_Start.X, _Start.Y, _Length);
|
||||
}
|
||||
}
|
||||
|
||||
public Line2D(IPoint2D start, IPoint2D end)
|
||||
{
|
||||
_Start = new Point2D(start);
|
||||
_End = new Point2D(end);
|
||||
|
||||
_Rotation = Angle.FromPoints(_Start, _End);
|
||||
_Length = _Start.GetDistance(_End);
|
||||
}
|
||||
|
||||
public Line2D(int xStart, int yStart, int xEnd, int yEnd)
|
||||
{
|
||||
_Start = new Point2D(xStart, yStart);
|
||||
_End = new Point2D(xEnd, yEnd);
|
||||
|
||||
_Rotation = Angle.FromPoints(_Start, _End);
|
||||
_Length = _Start.GetDistance(_End);
|
||||
}
|
||||
|
||||
public Line2D(IPoint2D start, Angle angle, double length)
|
||||
{
|
||||
_Rotation = angle;
|
||||
_Length = length;
|
||||
|
||||
_Start = new Point2D(start.X, start.Y);
|
||||
_End = _Rotation.GetPoint2D(start.X, start.Y, _Length);
|
||||
}
|
||||
|
||||
public Line2D(int xStart, int yStart, Angle angle, double length)
|
||||
{
|
||||
_Rotation = angle;
|
||||
_Length = length;
|
||||
|
||||
_Start = new Point2D(xStart, yStart);
|
||||
_End = _Rotation.GetPoint2D(xStart, yStart, _Length);
|
||||
}
|
||||
|
||||
public IEnumerable<Point2D> Intersect(Line2D[] lines)
|
||||
{
|
||||
return Intersect(this, lines);
|
||||
}
|
||||
|
||||
public Point2D? Intersect(Line2D line)
|
||||
{
|
||||
return Intersect(this, line);
|
||||
}
|
||||
|
||||
public bool Intersects(Line2D line)
|
||||
{
|
||||
return Intersects(this, line);
|
||||
}
|
||||
|
||||
public bool Intersects(Line2D[] lines)
|
||||
{
|
||||
return Intersects(this, lines);
|
||||
}
|
||||
|
||||
public bool Intersects(IPoint2D a2, IPoint2D b2)
|
||||
{
|
||||
return Intersects(this, a2, b2);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0}+{1}", _Start, _End);
|
||||
}
|
||||
}
|
||||
}
|
||||
113
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Cube3D.cs
Normal file
113
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Cube3D.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using Server;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Geometry
|
||||
{
|
||||
public class Cube3D : Shape3D
|
||||
{
|
||||
private int _Radius;
|
||||
private bool _Hollow;
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public int Radius
|
||||
{
|
||||
get => _Radius;
|
||||
set
|
||||
{
|
||||
if (_Radius == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_Radius = value;
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public bool Hollow
|
||||
{
|
||||
get => _Hollow;
|
||||
set
|
||||
{
|
||||
if (_Hollow == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_Hollow = value;
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
public Cube3D(int radius)
|
||||
: this(Point3D.Zero, radius)
|
||||
{ }
|
||||
|
||||
public Cube3D(IPoint3D center, int radius)
|
||||
: this(center, radius, false)
|
||||
{ }
|
||||
|
||||
public Cube3D(IPoint3D center, int radius, bool hollow)
|
||||
: base(center)
|
||||
{
|
||||
_Radius = radius;
|
||||
_Hollow = hollow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This cube always has an odd width, height and depth, never even.
|
||||
/// This preserves the center point.
|
||||
/// </summary>
|
||||
protected override void OnRender()
|
||||
{
|
||||
const int h = 5;
|
||||
|
||||
for (var z = -Radius; z <= Radius; z++)
|
||||
{
|
||||
for (var x = -Radius; x <= Radius; x++)
|
||||
{
|
||||
for (var y = -Radius; y <= Radius; y++)
|
||||
{
|
||||
if (!Hollow || (z == -Radius || z == Radius || x == -Radius || x == Radius || y == -Radius || y == Radius))
|
||||
{
|
||||
Add(new Block3D(Center.Clone3D(x, y, z * h), h));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.SetVersion(0);
|
||||
|
||||
writer.Write(_Radius);
|
||||
writer.Write(_Hollow);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
reader.GetVersion();
|
||||
|
||||
_Radius = reader.ReadInt();
|
||||
_Hollow = reader.ReadBool();
|
||||
}
|
||||
}
|
||||
}
|
||||
148
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Cylinder3D.cs
Normal file
148
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Cylinder3D.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using Server;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Geometry
|
||||
{
|
||||
public class Cylinder3D : Shape3D
|
||||
{
|
||||
private int _Radius;
|
||||
private bool _Hollow;
|
||||
private bool _EndCaps;
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public int Radius
|
||||
{
|
||||
get => _Radius;
|
||||
set
|
||||
{
|
||||
if (_Radius == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_Radius = value;
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public bool Hollow
|
||||
{
|
||||
get => _Hollow;
|
||||
set
|
||||
{
|
||||
if (_Hollow == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_Hollow = value;
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public bool EndCaps
|
||||
{
|
||||
get => _EndCaps;
|
||||
set
|
||||
{
|
||||
if (_EndCaps == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_EndCaps = value;
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
public Cylinder3D(int radius)
|
||||
: this(Point3D.Zero, radius)
|
||||
{ }
|
||||
|
||||
public Cylinder3D(IPoint3D center, int radius)
|
||||
: this(center, radius, false)
|
||||
{ }
|
||||
|
||||
public Cylinder3D(IPoint3D center, int radius, bool hollow)
|
||||
: this(center, radius, hollow, true)
|
||||
{
|
||||
Hollow = hollow;
|
||||
}
|
||||
|
||||
public Cylinder3D(IPoint3D center, int radius, bool hollow, bool endCaps)
|
||||
: base(center)
|
||||
{
|
||||
_Radius = radius;
|
||||
_Hollow = hollow;
|
||||
_EndCaps = endCaps;
|
||||
}
|
||||
|
||||
public Cylinder3D(GenericReader reader)
|
||||
: base(reader)
|
||||
{ }
|
||||
|
||||
protected override void OnRender()
|
||||
{
|
||||
const int h = 5;
|
||||
|
||||
for (var z = -Radius; z <= Radius; z++)
|
||||
{
|
||||
if (Hollow && !EndCaps && (z == -Radius || z == Radius))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var x = -Radius; x <= Radius; x++)
|
||||
{
|
||||
for (var y = -Radius; y <= Radius; y++)
|
||||
{
|
||||
var dist = (int)Math.Sqrt(x * x + y * y);
|
||||
|
||||
if ((!Hollow || z == -Radius || z == Radius || dist >= Radius) && dist <= Radius)
|
||||
{
|
||||
Add(new Block3D(Center.Clone3D(x, y, z * h), h));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.SetVersion(0);
|
||||
|
||||
writer.Write(_Radius);
|
||||
writer.Write(_Hollow);
|
||||
writer.Write(_EndCaps);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
reader.GetVersion();
|
||||
|
||||
_Radius = reader.ReadInt();
|
||||
_Hollow = reader.ReadBool();
|
||||
_EndCaps = reader.ReadBool();
|
||||
}
|
||||
}
|
||||
}
|
||||
114
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Disc3D.cs
Normal file
114
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Disc3D.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using Server;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Geometry
|
||||
{
|
||||
public class Disc3D : Shape3D
|
||||
{
|
||||
private int _Radius;
|
||||
private bool _Hollow;
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public int Radius
|
||||
{
|
||||
get => _Radius;
|
||||
set
|
||||
{
|
||||
if (_Radius == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_Radius = value;
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public bool Hollow
|
||||
{
|
||||
get => _Hollow;
|
||||
set
|
||||
{
|
||||
if (_Hollow == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_Hollow = value;
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
public Disc3D(int radius)
|
||||
: this(Point3D.Zero, radius)
|
||||
{ }
|
||||
|
||||
public Disc3D(IPoint3D center, int radius)
|
||||
: this(center, radius, false)
|
||||
{ }
|
||||
|
||||
public Disc3D(IPoint3D center, int radius, bool hollow)
|
||||
: base(center)
|
||||
{
|
||||
_Radius = radius;
|
||||
_Hollow = hollow;
|
||||
}
|
||||
|
||||
public Disc3D(GenericReader reader)
|
||||
: base(reader)
|
||||
{ }
|
||||
|
||||
protected override void OnRender()
|
||||
{
|
||||
const int h = 5;
|
||||
|
||||
for (var x = -Radius; x <= Radius; x++)
|
||||
{
|
||||
for (var y = -Radius; y <= Radius; y++)
|
||||
{
|
||||
var dist = (int)Math.Sqrt(x * x + y * y);
|
||||
|
||||
if ((!Hollow || dist >= Radius) && dist <= Radius)
|
||||
{
|
||||
Add(new Block3D(Center.Clone3D(x, y), h));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.SetVersion(0);
|
||||
|
||||
writer.Write(_Radius);
|
||||
writer.Write(_Hollow);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
reader.GetVersion();
|
||||
|
||||
_Radius = reader.ReadInt();
|
||||
_Hollow = reader.ReadBool();
|
||||
}
|
||||
}
|
||||
}
|
||||
110
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Plane3D.cs
Normal file
110
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Plane3D.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using Server;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Geometry
|
||||
{
|
||||
public class Plane3D : Shape3D
|
||||
{
|
||||
private int _Radius;
|
||||
private bool _Hollow;
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public int Radius
|
||||
{
|
||||
get => _Radius;
|
||||
set
|
||||
{
|
||||
if (_Radius == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_Radius = value;
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public bool Hollow
|
||||
{
|
||||
get => _Hollow;
|
||||
set
|
||||
{
|
||||
if (_Hollow == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_Hollow = value;
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
public Plane3D(int radius)
|
||||
: this(Point3D.Zero, radius)
|
||||
{ }
|
||||
|
||||
public Plane3D(IPoint3D center, int radius)
|
||||
: this(center, radius, false)
|
||||
{ }
|
||||
|
||||
public Plane3D(IPoint3D center, int radius, bool hollow)
|
||||
: base(center)
|
||||
{
|
||||
_Radius = radius;
|
||||
_Hollow = hollow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This plane always has an odd width, height and depth, never even.
|
||||
/// This preserves the center point.
|
||||
/// </summary>
|
||||
protected override void OnRender()
|
||||
{
|
||||
const int h = 5;
|
||||
|
||||
for (var x = -Radius; x <= Radius; x++)
|
||||
{
|
||||
for (var y = -Radius; y <= Radius; y++)
|
||||
{
|
||||
if (!Hollow || (x == -Radius || x == Radius || y == -Radius || y == Radius))
|
||||
{
|
||||
Add(new Block3D(Center.Clone3D(x, y), h));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.SetVersion(0);
|
||||
|
||||
writer.Write(_Radius);
|
||||
writer.Write(_Hollow);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
reader.GetVersion();
|
||||
|
||||
_Radius = reader.ReadInt();
|
||||
_Hollow = reader.ReadBool();
|
||||
}
|
||||
}
|
||||
}
|
||||
121
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Ring3D.cs
Normal file
121
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Ring3D.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using Server;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Geometry
|
||||
{
|
||||
public class Ring3D : Shape3D
|
||||
{
|
||||
private int _RadiusMin;
|
||||
private int _RadiusMax;
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public int RadiusMin
|
||||
{
|
||||
get => _RadiusMin;
|
||||
set
|
||||
{
|
||||
if (_RadiusMin == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_RadiusMin = value;
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public int RadiusMax
|
||||
{
|
||||
get => _RadiusMax;
|
||||
set
|
||||
{
|
||||
if (_RadiusMax == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_RadiusMax = value;
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
public Ring3D(int radius)
|
||||
: this(radius, radius)
|
||||
{ }
|
||||
|
||||
public Ring3D(int radiusMin, int radiusMax)
|
||||
: this(Point3D.Zero, radiusMin, radiusMax)
|
||||
{ }
|
||||
|
||||
public Ring3D(IPoint3D center, int radius)
|
||||
: this(center, radius, radius)
|
||||
{ }
|
||||
|
||||
public Ring3D(IPoint3D center, int radiusMin, int radiusMax)
|
||||
: base(center)
|
||||
{
|
||||
_RadiusMin = Math.Min(radiusMin, radiusMax);
|
||||
_RadiusMax = Math.Max(radiusMin, radiusMax);
|
||||
}
|
||||
|
||||
public Ring3D(GenericReader reader)
|
||||
: base(reader)
|
||||
{ }
|
||||
|
||||
protected override void OnRender()
|
||||
{
|
||||
var min = Math.Min(RadiusMin, RadiusMax);
|
||||
var max = Math.Max(RadiusMin, RadiusMax);
|
||||
|
||||
const int h = 5;
|
||||
|
||||
for (var x = -max; x <= max; x++)
|
||||
{
|
||||
for (var y = -max; y <= max; y++)
|
||||
{
|
||||
var dist = (int)Math.Sqrt(x * x + y * y);
|
||||
|
||||
if (dist >= min && dist <= max)
|
||||
{
|
||||
Add(new Block3D(Center.Clone3D(x, y), h));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.SetVersion(0);
|
||||
|
||||
writer.Write(_RadiusMin);
|
||||
writer.Write(_RadiusMax);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
reader.GetVersion();
|
||||
|
||||
_RadiusMin = reader.ReadInt();
|
||||
_RadiusMax = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
276
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Shape3D.cs
Normal file
276
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Shape3D.cs
Normal file
@@ -0,0 +1,276 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Server;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Geometry
|
||||
{
|
||||
[PropertyObject]
|
||||
public abstract class Shape3D : DynamicWireframe, IPoint3D
|
||||
{
|
||||
private bool _InitialRender;
|
||||
|
||||
public override List<Block3D> Blocks
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_InitialRender)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
|
||||
return base.Blocks;
|
||||
}
|
||||
set => base.Blocks = value;
|
||||
}
|
||||
|
||||
public override int Volume
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_InitialRender)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
|
||||
return base.Volume;
|
||||
}
|
||||
}
|
||||
|
||||
protected Point3D _Center;
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public Point3D Center
|
||||
{
|
||||
get => _Center;
|
||||
set
|
||||
{
|
||||
if (_Center == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_Center = value;
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public int X
|
||||
{
|
||||
get => _Center.X;
|
||||
set
|
||||
{
|
||||
if (_Center.X == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_Center.X = value;
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public int Y
|
||||
{
|
||||
get => _Center.Y;
|
||||
set
|
||||
{
|
||||
if (_Center.Z == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_Center.Y = value;
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public int Z
|
||||
{
|
||||
get => _Center.Z;
|
||||
set
|
||||
{
|
||||
if (_Center.Z == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_Center.Z = value;
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
public Shape3D()
|
||||
: this(Point3D.Zero)
|
||||
{ }
|
||||
|
||||
public Shape3D(IPoint3D center)
|
||||
{
|
||||
_Center = center.Clone3D();
|
||||
}
|
||||
|
||||
public Shape3D(GenericReader reader)
|
||||
: base(reader)
|
||||
{ }
|
||||
|
||||
public void Render()
|
||||
{
|
||||
if (Rendering)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_InitialRender = Rendering = true;
|
||||
|
||||
Clear();
|
||||
OnRender();
|
||||
|
||||
Rendering = false;
|
||||
}
|
||||
|
||||
protected abstract void OnRender();
|
||||
|
||||
public override void Add(Block3D item)
|
||||
{
|
||||
if (!_InitialRender)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
|
||||
base.Add(item);
|
||||
}
|
||||
|
||||
public override void AddRange(IEnumerable<Block3D> collection)
|
||||
{
|
||||
if (!_InitialRender)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
|
||||
base.AddRange(collection);
|
||||
}
|
||||
|
||||
public override bool Remove(Block3D item)
|
||||
{
|
||||
if (!_InitialRender)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
|
||||
return base.Remove(item);
|
||||
}
|
||||
|
||||
public override int RemoveAll(Predicate<Block3D> match)
|
||||
{
|
||||
if (!_InitialRender)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
|
||||
return base.RemoveAll(match);
|
||||
}
|
||||
|
||||
public override void RemoveAt(int index)
|
||||
{
|
||||
if (!_InitialRender)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
|
||||
base.RemoveAt(index);
|
||||
}
|
||||
|
||||
public override void RemoveRange(int index, int count)
|
||||
{
|
||||
if (!_InitialRender)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
|
||||
base.RemoveRange(index, count);
|
||||
}
|
||||
|
||||
public override void ForEach(Action<Block3D> action)
|
||||
{
|
||||
if (!_InitialRender)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
|
||||
base.ForEach(action);
|
||||
}
|
||||
|
||||
public override IEnumerator<Block3D> GetEnumerator()
|
||||
{
|
||||
if (!_InitialRender)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
|
||||
return base.GetEnumerator();
|
||||
}
|
||||
|
||||
public override Block3D this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_InitialRender)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
|
||||
return base[index];
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!_InitialRender)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
|
||||
base[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
if (!_InitialRender)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.SetVersion(0);
|
||||
|
||||
writer.Write(_Center);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
_InitialRender = true;
|
||||
|
||||
base.Deserialize(reader);
|
||||
|
||||
reader.GetVersion();
|
||||
|
||||
_Center = reader.ReadPoint3D();
|
||||
}
|
||||
}
|
||||
}
|
||||
136
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Sphere3D.cs
Normal file
136
Scripts/SubSystem/VitaNex/Core/Geometry/Shapes/Sphere3D.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using Server;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Geometry
|
||||
{
|
||||
public class Sphere3D : Shape3D
|
||||
{
|
||||
private int _Radius;
|
||||
private bool _Hollow;
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public int Radius
|
||||
{
|
||||
get => _Radius;
|
||||
set
|
||||
{
|
||||
if (_Radius == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_Radius = value;
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public bool Hollow
|
||||
{
|
||||
get => _Hollow;
|
||||
set
|
||||
{
|
||||
if (_Hollow == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_Hollow = value;
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
public Sphere3D(int radius)
|
||||
: this(Point3D.Zero, radius)
|
||||
{ }
|
||||
|
||||
public Sphere3D(IPoint3D center, int radius)
|
||||
: this(center, radius, false)
|
||||
{ }
|
||||
|
||||
public Sphere3D(IPoint3D center, int radius, bool hollow)
|
||||
: base(center)
|
||||
{
|
||||
_Radius = radius;
|
||||
_Hollow = hollow;
|
||||
}
|
||||
|
||||
public Sphere3D(GenericReader reader)
|
||||
: base(reader)
|
||||
{ }
|
||||
|
||||
protected override void OnRender()
|
||||
{
|
||||
const int h = 5;
|
||||
|
||||
var layers = Radius * 2;
|
||||
|
||||
for (var z = -layers; z <= layers; z++)
|
||||
{
|
||||
var p = z / Math.Max(1.0, layers);
|
||||
|
||||
var r = 2 * Radius;
|
||||
|
||||
if (p < 0.5)
|
||||
{
|
||||
r = (int)Math.Ceiling(r * p);
|
||||
}
|
||||
else if (p > 0.5)
|
||||
{
|
||||
r = (int)Math.Ceiling(r - (r * p));
|
||||
}
|
||||
else
|
||||
{
|
||||
r = Radius;
|
||||
}
|
||||
|
||||
for (var x = -r; x <= r; x++)
|
||||
{
|
||||
for (var y = -r; y <= r; y++)
|
||||
{
|
||||
var dist = (int)Math.Sqrt(x * x + y * y);
|
||||
|
||||
if ((!Hollow || z == -layers || z == layers || dist >= r) && dist <= r)
|
||||
{
|
||||
Add(new Block3D(Center.Clone3D(x, y, z * h), h));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.SetVersion(0);
|
||||
|
||||
writer.Write(_Radius);
|
||||
writer.Write(_Hollow);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
reader.GetVersion();
|
||||
|
||||
_Radius = reader.ReadInt();
|
||||
_Hollow = reader.ReadBool();
|
||||
}
|
||||
}
|
||||
}
|
||||
315
Scripts/SubSystem/VitaNex/Core/Geometry/Triangle2D.cs
Normal file
315
Scripts/SubSystem/VitaNex/Core/Geometry/Triangle2D.cs
Normal file
@@ -0,0 +1,315 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
[NoSort, Parsable, PropertyObject]
|
||||
public struct Triangle2D : IPoint2D
|
||||
{
|
||||
public static readonly Triangle2D Empty = new Triangle2D(0, 0, 0, 0, 0, 0);
|
||||
|
||||
public static IEnumerable<Point2D> Plot(IPoint2D a, IPoint2D b, IPoint2D c)
|
||||
{
|
||||
foreach (var p in Line2D.Plot(a, b).Skip(1))
|
||||
{
|
||||
yield return p;
|
||||
}
|
||||
|
||||
foreach (var p in Line2D.Plot(b, c).Skip(1))
|
||||
{
|
||||
yield return p;
|
||||
}
|
||||
|
||||
foreach (var p in Line2D.Plot(c, a).Skip(1))
|
||||
{
|
||||
yield return p;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Contains(IPoint2D p, IPoint2D a, IPoint2D b, IPoint2D c)
|
||||
{
|
||||
var x = p.X - a.X;
|
||||
var y = p.Y - a.Y;
|
||||
|
||||
var delta = (b.X - a.X) * y - (b.Y - a.Y) * x > 0;
|
||||
|
||||
if ((c.X - a.X) * y - (c.Y - a.Y) * x > 0 == delta)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((c.X - b.X) * (p.Y - b.Y) - (c.Y - b.Y) * (p.X - b.X) > 0 != delta)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool Contains(int x, int y, IPoint2D a, IPoint2D b, IPoint2D c)
|
||||
{
|
||||
return Contains(new Point2D(x, y), a, b, c);
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> Intersect(Triangle2D t1, Triangle2D t2)
|
||||
{
|
||||
return Line2D.Intersect(new[] { t1._AB, t1._BC, t1._CA }, new[] { t2._AB, t2._BC, t2._CA });
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> Intersect(Triangle2D t, Rectangle2D r)
|
||||
{
|
||||
return Line2D.Intersect(
|
||||
new[] { t._AB, t._BC, t._CA },
|
||||
new[]
|
||||
{
|
||||
new Line2D(r.X, r.Y, r.X + r.Width, r.Y), new Line2D(r.X + r.Width, r.Y, r.X + r.Width, r.Y + r.Height),
|
||||
new Line2D(r.X, r.Y, r.X, r.Y + r.Height), new Line2D(r.X, r.Y + r.Height, r.X + r.Width, r.Y + r.Height)
|
||||
});
|
||||
}
|
||||
|
||||
public static bool Intersects(Triangle2D t1, Triangle2D t2)
|
||||
{
|
||||
return Intersect(t1, t2).Any();
|
||||
}
|
||||
|
||||
public static bool Intersects(Triangle2D t, Rectangle2D r)
|
||||
{
|
||||
return Intersect(t, r).Any();
|
||||
}
|
||||
|
||||
public static bool TryParse(string value, out Triangle2D t)
|
||||
{
|
||||
try
|
||||
{
|
||||
t = Parse(value);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
t = Empty;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static Triangle2D Parse(string value)
|
||||
{
|
||||
var param = value.Split('+');
|
||||
|
||||
if (param.Length >= 3 && param.All(p => p.Contains(',')))
|
||||
{
|
||||
return new Triangle2D(Point2D.Parse(param[0]), Point2D.Parse(param[1]), Point2D.Parse(param[2]));
|
||||
}
|
||||
|
||||
throw new FormatException(
|
||||
"The specified triangle must be represented by three Point2D coords using the format " + //
|
||||
"'(x1,y1)+(x2,y2)+(x3,y3)'");
|
||||
}
|
||||
|
||||
private Point2D _A, _B, _C;
|
||||
|
||||
private Line2D _AB, _BC, _CA;
|
||||
private Line2D _AC, _CB, _BA;
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public int X
|
||||
{
|
||||
get => _A.X;
|
||||
set
|
||||
{
|
||||
_A.X = value;
|
||||
_AB.Start = _BA.End = _AC.Start = _CA.End = _A;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public int Y
|
||||
{
|
||||
get => _A.Y;
|
||||
set
|
||||
{
|
||||
_A.Y = value;
|
||||
_AB.Start = _BA.End = _AC.Start = _CA.End = _A;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public Point2D A { get => _A; set => _A = _AB.Start = _BA.End = _AC.Start = _CA.End = value; }
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public Point2D B { get => _B; set => _B = _BC.Start = _CB.End = _BA.Start = _AB.End = value; }
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public Point2D C { get => _C; set => _C = _CA.Start = _AC.End = _CB.Start = _BC.End = value; }
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public Line2D AB
|
||||
{
|
||||
get => _AB;
|
||||
set
|
||||
{
|
||||
_AB = value;
|
||||
|
||||
_A = _BA.End = _AB.Start;
|
||||
_B = _BA.Start = _AB.End;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public Line2D BC
|
||||
{
|
||||
get => _BC;
|
||||
set
|
||||
{
|
||||
_BC = value;
|
||||
|
||||
_B = _CB.End = _BC.Start;
|
||||
_C = _CB.Start = _BC.End;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public Line2D CA
|
||||
{
|
||||
get => _CA;
|
||||
set
|
||||
{
|
||||
_CA = value;
|
||||
|
||||
_C = _AC.End = _CA.Start;
|
||||
_A = _AC.Start = _CA.End;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public Line2D AC
|
||||
{
|
||||
get => _AC;
|
||||
set
|
||||
{
|
||||
_AC = value;
|
||||
|
||||
_A = _CA.End = _AC.Start;
|
||||
_C = _CA.Start = _AC.End;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public Line2D CB
|
||||
{
|
||||
get => _CB;
|
||||
set
|
||||
{
|
||||
_CB = value;
|
||||
|
||||
_C = _BC.End = _CB.Start;
|
||||
_B = _BC.Start = _CB.End;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public Line2D BA
|
||||
{
|
||||
get => _BA;
|
||||
set
|
||||
{
|
||||
_BA = value;
|
||||
|
||||
_B = _AB.End = _BA.Start;
|
||||
_A = _AB.Start = _BA.End;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public Angle ABC => Angle.FromPoints(_A, _B, _C);
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public Angle BCA => Angle.FromPoints(_B, _C, _A);
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public Angle CAB => Angle.FromPoints(_C, _A, _B);
|
||||
|
||||
public Triangle2D(IPoint2D a, IPoint2D b, IPoint2D c)
|
||||
{
|
||||
_A = new Point2D(a);
|
||||
_B = new Point2D(b);
|
||||
_C = new Point2D(c);
|
||||
|
||||
_AB = new Line2D(_A, _B);
|
||||
_BC = new Line2D(_B, _C);
|
||||
_CA = new Line2D(_C, _A);
|
||||
|
||||
_AC = new Line2D(_A, _C);
|
||||
_CB = new Line2D(_C, _B);
|
||||
_BA = new Line2D(_B, _A);
|
||||
}
|
||||
|
||||
public Triangle2D(int x1, int y1, int x2, int y2, int x3, int y3)
|
||||
{
|
||||
_A = new Point2D(x1, y1);
|
||||
_B = new Point2D(x2, y2);
|
||||
_C = new Point2D(x3, y3);
|
||||
|
||||
_AB = new Line2D(_A, _B);
|
||||
_BC = new Line2D(_B, _C);
|
||||
_CA = new Line2D(_C, _A);
|
||||
|
||||
_AC = new Line2D(_A, _C);
|
||||
_CB = new Line2D(_C, _B);
|
||||
_BA = new Line2D(_B, _A);
|
||||
}
|
||||
|
||||
public bool Contains(IPoint2D p)
|
||||
{
|
||||
return Contains(p, _A, _B, _C);
|
||||
}
|
||||
|
||||
public bool Contains(int x, int y)
|
||||
{
|
||||
return Contains(x, y, _A, _B, _C);
|
||||
}
|
||||
|
||||
public IEnumerable<Point2D> Intersect(Triangle2D t)
|
||||
{
|
||||
return Intersect(this, t);
|
||||
}
|
||||
|
||||
public IEnumerable<Point2D> Intersect(Rectangle2D r)
|
||||
{
|
||||
return Intersect(this, r);
|
||||
}
|
||||
|
||||
public bool Intersects(Triangle2D t)
|
||||
{
|
||||
return Intersects(this, t);
|
||||
}
|
||||
|
||||
public bool Intersects(Rectangle2D r)
|
||||
{
|
||||
return Intersects(this, r);
|
||||
}
|
||||
|
||||
public IEnumerable<Point2D> Plot()
|
||||
{
|
||||
return Plot(_A, _B, _C);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0}+{1}+{2}", _A, _B, _C);
|
||||
}
|
||||
}
|
||||
}
|
||||
469
Scripts/SubSystem/VitaNex/Core/Geometry/Wireframe.cs
Normal file
469
Scripts/SubSystem/VitaNex/Core/Geometry/Wireframe.cs
Normal file
@@ -0,0 +1,469 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using VitaNex.Collections;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public interface IWireframe : IEnumerable<Block3D>
|
||||
{
|
||||
bool Intersects(IBlock3D b);
|
||||
bool Intersects(int x, int y, int z);
|
||||
bool Intersects(int x, int y, int z, int h);
|
||||
bool Intersects(IWireframe frame);
|
||||
Rectangle3D GetBounds();
|
||||
IEnumerable<Block3D> Offset(int x = 0, int y = 0, int z = 0, int h = 0);
|
||||
}
|
||||
|
||||
public sealed class Wireframe : IEquatable<Wireframe>, IWireframe
|
||||
{
|
||||
public static readonly Wireframe Empty = new Wireframe(0);
|
||||
|
||||
public Block3D[] Blocks { get; private set; }
|
||||
|
||||
public int Volume => Blocks.Length;
|
||||
|
||||
public int Length => Blocks.Length;
|
||||
|
||||
public Wireframe(params IBlock3D[] blocks)
|
||||
: this(blocks.Ensure().Select(b => new Block3D(b)))
|
||||
{ }
|
||||
|
||||
public Wireframe(IEnumerable<IBlock3D> blocks)
|
||||
: this(blocks.Ensure().Select(b => new Block3D(b)))
|
||||
{ }
|
||||
|
||||
public Wireframe(Wireframe frame)
|
||||
: this(frame.Blocks)
|
||||
{ }
|
||||
|
||||
public Wireframe(int capacity)
|
||||
{
|
||||
Blocks = new Block3D[capacity];
|
||||
}
|
||||
|
||||
public Wireframe(params Block3D[] blocks)
|
||||
{
|
||||
Blocks = blocks.Ensure().ToArray();
|
||||
}
|
||||
|
||||
public Wireframe(IEnumerable<Block3D> blocks)
|
||||
{
|
||||
Blocks = blocks.Ensure().ToArray();
|
||||
}
|
||||
|
||||
public bool Intersects(IPoint3D p)
|
||||
{
|
||||
return Intersects(p.X, p.Y, p.Z);
|
||||
}
|
||||
|
||||
public bool Intersects(IPoint3D p, int h)
|
||||
{
|
||||
return Intersects(p.X, p.Y, p.Z, h);
|
||||
}
|
||||
|
||||
public bool Intersects(IBlock3D b)
|
||||
{
|
||||
return Intersects(b.X, b.Y, b.Z, b.H);
|
||||
}
|
||||
|
||||
public bool Intersects(int x, int y, int z)
|
||||
{
|
||||
return Intersects(x, y, z, 0);
|
||||
}
|
||||
|
||||
public bool Intersects(int x, int y, int z, int h)
|
||||
{
|
||||
return Blocks.Any(b => b.Intersects(x, y, z, h));
|
||||
}
|
||||
|
||||
public bool Intersects(IWireframe frame)
|
||||
{
|
||||
return frame != null && Blocks.Any(b => frame.Intersects(b));
|
||||
}
|
||||
|
||||
public Rectangle3D GetBounds()
|
||||
{
|
||||
Point3D min = Point3D.Zero, max = Point3D.Zero;
|
||||
|
||||
foreach (var b in Blocks)
|
||||
{
|
||||
min.X = Math.Min(min.X, b.X);
|
||||
min.Y = Math.Min(min.Y, b.Y);
|
||||
min.Z = Math.Min(min.Z, b.Z);
|
||||
|
||||
max.X = Math.Max(max.X, b.X);
|
||||
max.Y = Math.Max(max.Y, b.Y);
|
||||
max.Z = Math.Max(max.Z, b.Z + b.H);
|
||||
}
|
||||
|
||||
return new Rectangle3D(min, max);
|
||||
}
|
||||
|
||||
public IEnumerable<Block3D> Offset(int x = 0, int y = 0, int z = 0, int h = 0)
|
||||
{
|
||||
return Blocks.Select(b => b.Offset(x, y, z, h));
|
||||
}
|
||||
|
||||
public IEnumerator<Block3D> GetEnumerator()
|
||||
{
|
||||
return Blocks.AsEnumerable().GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public Block3D this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index < 0 || index >= Blocks.Length)
|
||||
{
|
||||
return Block3D.Empty;
|
||||
}
|
||||
|
||||
return Blocks[index];
|
||||
}
|
||||
set
|
||||
{
|
||||
if (index >= 0 && index < Blocks.Length)
|
||||
{
|
||||
Blocks[index] = value;
|
||||
|
||||
_Hash = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int? _Hash;
|
||||
|
||||
public int HashCode => _Hash ?? (_Hash = Blocks.GetContentsHashCode(true)).Value;
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Wireframe && Equals((Wireframe)obj);
|
||||
}
|
||||
|
||||
public bool Equals(Wireframe other)
|
||||
{
|
||||
return !ReferenceEquals(other, null) && (ReferenceEquals(this, other) || GetHashCode() == other.GetHashCode());
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("Wireframe ({0:#,0} blocks)", Length);
|
||||
}
|
||||
|
||||
public static bool operator ==(Wireframe l, Wireframe r)
|
||||
{
|
||||
return ReferenceEquals(l, null) ? ReferenceEquals(r, null) : l.Equals(r);
|
||||
}
|
||||
|
||||
public static bool operator !=(Wireframe l, Wireframe r)
|
||||
{
|
||||
return ReferenceEquals(l, null) ? !ReferenceEquals(r, null) : !l.Equals(r);
|
||||
}
|
||||
}
|
||||
|
||||
public class DynamicWireframe : IEquatable<DynamicWireframe>, IWireframe
|
||||
{
|
||||
public bool Rendering { get; protected set; }
|
||||
|
||||
public virtual List<Block3D> Blocks { get; set; }
|
||||
|
||||
public virtual int Volume => Blocks.Count;
|
||||
|
||||
public int Count => Blocks.Count;
|
||||
|
||||
public DynamicWireframe(params IBlock3D[] blocks)
|
||||
: this(blocks.Ensure().Select(b => new Block3D(b)))
|
||||
{ }
|
||||
|
||||
public DynamicWireframe(IEnumerable<IBlock3D> blocks)
|
||||
: this(blocks.Ensure().Select(b => new Block3D(b)))
|
||||
{ }
|
||||
|
||||
public DynamicWireframe(Wireframe frame)
|
||||
: this(frame.Blocks)
|
||||
{ }
|
||||
|
||||
public DynamicWireframe()
|
||||
: this(0x100)
|
||||
{ }
|
||||
|
||||
public DynamicWireframe(int capacity)
|
||||
{
|
||||
Blocks = new List<Block3D>(capacity);
|
||||
}
|
||||
|
||||
public DynamicWireframe(params Block3D[] blocks)
|
||||
{
|
||||
Blocks = blocks.Ensure().ToList();
|
||||
}
|
||||
|
||||
public DynamicWireframe(IEnumerable<Block3D> blocks)
|
||||
{
|
||||
Blocks = blocks.Ensure().ToList();
|
||||
}
|
||||
|
||||
public DynamicWireframe(GenericReader reader)
|
||||
{
|
||||
Rendering = true;
|
||||
Deserialize(reader);
|
||||
Rendering = false;
|
||||
}
|
||||
|
||||
public void Flatten()
|
||||
{
|
||||
var list = ListPool<Block3D>.AcquireObject();
|
||||
|
||||
list.AddRange(this);
|
||||
|
||||
Clear();
|
||||
|
||||
AddRange(list.Flatten());
|
||||
|
||||
ObjectPool.Free(ref list);
|
||||
}
|
||||
|
||||
public bool Intersects(IPoint3D p)
|
||||
{
|
||||
return Intersects(p.X, p.Y, p.Z);
|
||||
}
|
||||
|
||||
public bool Intersects(IBlock3D b)
|
||||
{
|
||||
return Intersects(b.X, b.Y, b.Z, b.H);
|
||||
}
|
||||
|
||||
public bool Intersects(int x, int y, int z)
|
||||
{
|
||||
return Intersects(x, y, z, 0);
|
||||
}
|
||||
|
||||
public bool Intersects(int x, int y, int z, int h)
|
||||
{
|
||||
return Blocks.Any(b => b.Intersects(x, y, z, h));
|
||||
}
|
||||
|
||||
public bool Intersects(IWireframe frame)
|
||||
{
|
||||
return frame != null && Blocks.Any(b => frame.Intersects(b));
|
||||
}
|
||||
|
||||
public Rectangle3D GetBounds()
|
||||
{
|
||||
Point3D min = Point3D.Zero, max = Point3D.Zero;
|
||||
|
||||
foreach (var b in Blocks)
|
||||
{
|
||||
min.X = Math.Min(min.X, b.X);
|
||||
min.Y = Math.Min(min.Y, b.Y);
|
||||
min.Z = Math.Min(min.Z, b.Z);
|
||||
|
||||
max.X = Math.Max(max.X, b.X);
|
||||
max.Y = Math.Max(max.Y, b.Y);
|
||||
max.Z = Math.Max(max.Z, b.Z + b.H);
|
||||
}
|
||||
|
||||
return new Rectangle3D(min, max);
|
||||
}
|
||||
|
||||
public IEnumerable<Block3D> Offset(int x = 0, int y = 0, int z = 0, int h = 0)
|
||||
{
|
||||
return Blocks.Select(b => b.Offset(x, y, z, h));
|
||||
}
|
||||
|
||||
public virtual void Clear()
|
||||
{
|
||||
Blocks.Free(true);
|
||||
|
||||
_Hash = null;
|
||||
}
|
||||
|
||||
public virtual void Add(Block3D item)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
Blocks.Add(item);
|
||||
|
||||
_Hash = null;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void AddRange(IEnumerable<Block3D> collection)
|
||||
{
|
||||
if (collection != null)
|
||||
{
|
||||
Blocks.AddRange(collection);
|
||||
|
||||
_Hash = null;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool Remove(Block3D item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var success = Blocks.Remove(item);
|
||||
|
||||
Blocks.Free(false);
|
||||
|
||||
_Hash = null;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
public virtual int RemoveAll(Predicate<Block3D> match)
|
||||
{
|
||||
if (match == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var success = Blocks.RemoveAll(match);
|
||||
|
||||
Blocks.Free(false);
|
||||
|
||||
_Hash = null;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
public virtual void RemoveAt(int index)
|
||||
{
|
||||
if (!Blocks.InBounds(index))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Blocks.RemoveAt(index);
|
||||
Blocks.Free(false);
|
||||
|
||||
_Hash = null;
|
||||
}
|
||||
|
||||
public virtual void RemoveRange(int index, int count)
|
||||
{
|
||||
if (!Blocks.InBounds(index))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Blocks.RemoveRange(index, count);
|
||||
Blocks.Free(false);
|
||||
|
||||
_Hash = null;
|
||||
}
|
||||
|
||||
public virtual void ForEach(Action<Block3D> action)
|
||||
{
|
||||
Blocks.ForEach(action);
|
||||
}
|
||||
|
||||
public virtual IEnumerator<Block3D> GetEnumerator()
|
||||
{
|
||||
return Blocks.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public virtual Block3D this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index < 0 || index >= Blocks.Count)
|
||||
{
|
||||
return Block3D.Empty;
|
||||
}
|
||||
|
||||
return Blocks[index];
|
||||
}
|
||||
set
|
||||
{
|
||||
if (index >= 0 && index < Blocks.Count)
|
||||
{
|
||||
Blocks[index] = value;
|
||||
|
||||
_Hash = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int? _Hash;
|
||||
|
||||
public int HashCode => _Hash ?? (_Hash = Blocks.GetContentsHashCode(true)).Value;
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is DynamicWireframe && Equals((DynamicWireframe)obj);
|
||||
}
|
||||
|
||||
public bool Equals(DynamicWireframe other)
|
||||
{
|
||||
return !ReferenceEquals(other, null) && (ReferenceEquals(this, other) || GetHashCode() == other.GetHashCode());
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("DynamicWireframe ({0:#,0} blocks)", Count);
|
||||
}
|
||||
|
||||
public virtual void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.SetVersion(0);
|
||||
|
||||
writer.WriteList(Blocks, (w, b) => w.WriteBlock3D(b));
|
||||
}
|
||||
|
||||
public virtual void Deserialize(GenericReader reader)
|
||||
{
|
||||
reader.GetVersion();
|
||||
|
||||
Blocks = reader.ReadList(r => reader.ReadBlock3D());
|
||||
}
|
||||
|
||||
public static bool operator ==(DynamicWireframe l, DynamicWireframe r)
|
||||
{
|
||||
return ReferenceEquals(l, null) ? ReferenceEquals(r, null) : l.Equals(r);
|
||||
}
|
||||
|
||||
public static bool operator !=(DynamicWireframe l, DynamicWireframe r)
|
||||
{
|
||||
return ReferenceEquals(l, null) ? !ReferenceEquals(r, null) : !l.Equals(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user