diff --git a/EXILED/Exiled.API/Features/Draw.cs b/EXILED/Exiled.API/Features/Draw.cs
index b53ef4320..5eb7361b9 100644
--- a/EXILED/Exiled.API/Features/Draw.cs
+++ b/EXILED/Exiled.API/Features/Draw.cs
@@ -8,10 +8,13 @@
namespace Exiled.API.Features
{
using System;
+ using System.Buffers;
using System.Collections.Generic;
using DrawableLine;
+ using Exiled.API.Features.Pools;
+
using Mirror;
using UnityEngine;
@@ -23,6 +26,9 @@ namespace Exiled.API.Features
///
public static class Draw
{
+ // smallest array that fits the largest default segment (17 for sphere)
+ private static readonly Vector3[] ArrayNonAlloc = new Vector3[17];
+
///
/// Draws a line between two specified points.
///
@@ -33,7 +39,10 @@ public static class Draw
/// A collection of s to show the line to.
public static void Line(Vector3 start, Vector3 end, Color color, float duration, IEnumerable players = null)
{
- Send(players, duration, color, start, end);
+ ArrayNonAlloc[0] = start;
+ ArrayNonAlloc[1] = end;
+
+ Send(players, duration, color, ArrayNonAlloc, 2);
}
///
@@ -45,7 +54,7 @@ public static void Line(Vector3 start, Vector3 end, Color color, float duration,
/// A collection of s to show the path to.
public static void Path(Vector3[] points, Color color, float duration, IEnumerable players = null)
{
- Send(players, duration, color, points);
+ Send(players, duration, color, points, points.Length);
}
///
@@ -61,8 +70,7 @@ public static void Path(Vector3[] points, Color color, float duration, IEnumerab
/// The number of line segments used to draw the circle. Higher values result in a smoother circle.
public static void Circle(Vector3 origin, Quaternion rotation, Vector3 scale, Color color, float duration, IEnumerable players = null, bool horizontal = true, int segments = 16)
{
- Vector3[] circlePoints = GetCirclePoints(origin, rotation, scale, segments, horizontal);
- Send(players, duration, color, circlePoints);
+ Send(players, duration, color, GetCirclePoints(origin, rotation, scale, ref segments, horizontal), segments);
}
///
@@ -77,11 +85,16 @@ public static void Circle(Vector3 origin, Quaternion rotation, Vector3 scale, Co
/// The number of segments for the circles. Higher values result in a smoother sphere.
public static void Sphere(Vector3 origin, Quaternion rotation, Vector3 scale, Color color, float duration, IEnumerable players = null, int segments = 16)
{
- Vector3[] horizontal = GetCirclePoints(origin, rotation, scale, segments, true);
- Send(players, duration, color, horizontal);
+ List list = players is null ? null : ListPool.Pool.Get(players);
+
+ Vector3[] array = GetCirclePoints(origin, rotation, scale, ref segments, true);
+ Send(list, duration, color, array, segments);
+
+ array = GetCirclePoints(origin, rotation, scale, ref segments, false);
+ Send(list, duration, color, array, segments);
- Vector3[] vertical = GetCirclePoints(origin, rotation, scale, segments, false);
- Send(players, duration, color, vertical);
+ if (list != null)
+ ListPool.Pool.Return(list);
}
///
@@ -199,24 +212,31 @@ public static void Capsule(Vector3 center, Quaternion rotation, float height, fl
Vector3 bottomCenter = center - (up * halfCylinderHeight);
Vector3 ringScale = new(radius * sX, 1f, radius * sZ);
- Circle(topCenter, rotation, ringScale, color, duration, players, horizontal: true);
- Circle(bottomCenter, rotation, ringScale, color, duration, players, horizontal: true);
+
+ List list = players is null ? null : ListPool.Pool.Get(players);
+
+ Circle(topCenter, rotation, ringScale, color, duration, list);
+ Circle(bottomCenter, rotation, ringScale, color, duration, list);
float rX = radius * sX;
- Line(topCenter + (right * rX), bottomCenter + (right * rX), color, duration, players);
- Line(topCenter - (right * rX), bottomCenter - (right * rX), color, duration, players);
+ Line(topCenter + (right * rX), bottomCenter + (right * rX), color, duration, list);
+ Line(topCenter - (right * rX), bottomCenter - (right * rX), color, duration, list);
float rZ = radius * sZ;
- Line(topCenter + (forward * rZ), bottomCenter + (forward * rZ), color, duration, players);
- Line(topCenter - (forward * rZ), bottomCenter - (forward * rZ), color, duration, players);
+ Line(topCenter + (forward * rZ), bottomCenter + (forward * rZ), color, duration, list);
+ Line(topCenter - (forward * rZ), bottomCenter - (forward * rZ), color, duration, list);
Vector3 arcScaleSide = new(radius * sZ, radius * sY, 1f);
Vector3 arcScaleFront = new(radius * sX, radius * sY, 1f);
- Send(players, duration, color, GetArcPoints(topCenter, rotation, arcScaleSide, 180f));
- Send(players, duration, color, GetArcPoints(topCenter, rotation * Quaternion.Euler(0, 90, 0), arcScaleFront, 180f));
- Send(players, duration, color, GetArcPoints(bottomCenter, rotation * Quaternion.Euler(180, 0, 0), arcScaleSide, 180f));
- Send(players, duration, color, GetArcPoints(bottomCenter, rotation * Quaternion.Euler(180, 90, 0), arcScaleFront, 180f));
+ const int segments = 8;
+ Send(list, duration, color, GetArcPoints(topCenter, rotation, arcScaleSide, 180f, segments), segments);
+ Send(list, duration, color, GetArcPoints(topCenter, rotation * Quaternion.Euler(0, 90, 0), arcScaleFront, 180f, segments), segments);
+ Send(list, duration, color, GetArcPoints(bottomCenter, rotation * Quaternion.Euler(180, 0, 0), arcScaleSide, 180f, segments), segments);
+ Send(list, duration, color, GetArcPoints(bottomCenter, rotation * Quaternion.Euler(180, 90, 0), arcScaleFront, 180f, segments), segments);
+
+ if (list != null)
+ ListPool.Pool.Return(list);
}
///
@@ -232,14 +252,20 @@ public static void Mesh(Mesh mesh, Transform transform, Color color, float durat
int[] triangles = mesh.triangles;
Vector3[] vertices = mesh.vertices;
+ List list = players is null ? null : ListPool.Pool.Get(players);
+
for (int i = 0; i < triangles.Length; i += 3)
{
- Vector3 p1 = transform.TransformPoint(vertices[triangles[i]]);
- Vector3 p2 = transform.TransformPoint(vertices[triangles[i + 1]]);
- Vector3 p3 = transform.TransformPoint(vertices[triangles[i + 2]]);
+ ArrayNonAlloc[0] = transform.TransformPoint(vertices[triangles[i]]);
+ ArrayNonAlloc[1] = transform.TransformPoint(vertices[triangles[i + 1]]);
+ ArrayNonAlloc[2] = transform.TransformPoint(vertices[triangles[i + 2]]);
+ ArrayNonAlloc[3] = ArrayNonAlloc[0];
- Path([p1, p2, p3, p1], color, duration, players);
+ Send(list, duration, color, ArrayNonAlloc, 4);
}
+
+ if (list != null)
+ ListPool.Pool.Return(list);
}
///
@@ -259,31 +285,36 @@ public static void Box(Vector3 center, Vector3 size, Quaternion rotation, Color
float length = extents.z;
float height = extents.y;
- Vector3[] bottomRect = new Vector3[5];
- Vector3[] topRect = new Vector3[5];
+ ArrayNonAlloc[0] = center + (rotation * new Vector3(-width, -height, -length));
+ ArrayNonAlloc[1] = center + (rotation * new Vector3(width, -height, -length));
+ ArrayNonAlloc[2] = center + (rotation * new Vector3(width, -height, length));
+ ArrayNonAlloc[3] = center + (rotation * new Vector3(-width, -height, length));
+ ArrayNonAlloc[4] = ArrayNonAlloc[0];
- bottomRect[0] = center + (rotation * new Vector3(-width, -height, -length));
- bottomRect[1] = center + (rotation * new Vector3(width, -height, -length));
- bottomRect[2] = center + (rotation * new Vector3(width, -height, length));
- bottomRect[3] = center + (rotation * new Vector3(-width, -height, length));
- bottomRect[4] = bottomRect[0];
+ ArrayNonAlloc[5] = center + (rotation * new Vector3(-width, height, -length));
+ ArrayNonAlloc[6] = center + (rotation * new Vector3(width, height, -length));
+ ArrayNonAlloc[7] = center + (rotation * new Vector3(width, height, length));
+ ArrayNonAlloc[8] = center + (rotation * new Vector3(-width, height, length));
+ ArrayNonAlloc[9] = ArrayNonAlloc[5];
- topRect[0] = center + (rotation * new Vector3(-width, height, -length));
- topRect[1] = center + (rotation * new Vector3(width, height, -length));
- topRect[2] = center + (rotation * new Vector3(width, height, length));
- topRect[3] = center + (rotation * new Vector3(-width, height, length));
- topRect[4] = topRect[0];
+ // reduce enumeration
+ List list = players is null ? null : ListPool.Pool.Get(players);
- Send(players, duration, color, bottomRect);
- Send(players, duration, color, topRect);
+ Send(list, duration, color, ArrayNonAlloc, 5);
+ Send(list, duration, color, ArrayNonAlloc, 5, 5);
for (int i = 0; i < 4; i++)
{
- Send(players, duration, color, bottomRect[i], topRect[i]);
+ ArrayNonAlloc[10] = ArrayNonAlloc[i];
+ ArrayNonAlloc[11] = ArrayNonAlloc[i + 5];
+ Send(list, duration, color, ArrayNonAlloc, 2, 10);
}
+
+ if (list != null)
+ ListPool.Pool.Return(list);
}
- private static Vector3[] GetCirclePoints(Vector3 origin, Quaternion rotation, Vector3 scale, int segments, bool horizontal)
+ private static Vector3[] GetCirclePoints(Vector3 origin, Quaternion rotation, Vector3 scale, ref int segments, bool horizontal)
{
if (segments <= 5)
segments = 8;
@@ -291,7 +322,7 @@ private static Vector3[] GetCirclePoints(Vector3 origin, Quaternion rotation, Ve
if (segments % 2 != 0)
segments++;
- Vector3[] array = new Vector3[segments + 1];
+ Vector3[] array = segments < 17 ? ArrayNonAlloc : new Vector3[segments + 1];
float num = MathF.PI * 2f / (float)segments;
for (int i = 0; i < segments; i++)
@@ -309,7 +340,7 @@ private static Vector3[] GetCirclePoints(Vector3 origin, Quaternion rotation, Ve
private static Vector3[] GetArcPoints(Vector3 origin, Quaternion rotation, Vector3 scale, float angle, int segments = 8)
{
- Vector3[] array = new Vector3[segments + 1];
+ Vector3[] array = segments < 17 ? ArrayNonAlloc : new Vector3[segments + 1];
float angleStep = (angle * Mathf.Deg2Rad) / segments;
for (int i = 0; i <= segments; i++)
@@ -324,27 +355,39 @@ private static Vector3[] GetArcPoints(Vector3 origin, Quaternion rotation, Vecto
return array;
}
- private static void Send(IEnumerable players, float duration, Color color, params Vector3[] points)
+ private static void Send(IEnumerable players, float duration, Color color, Vector3[] points, int count, int offset = 0)
{
- if (points == null || points.Length < 2)
+ if (points == null || points.Length - offset < 2 || count - offset < 2)
return;
- DrawableLineMessage msg = new(duration, color, points);
+ ArraySegment data;
+ using (NetworkWriterPooled writer = NetworkWriterPool.Get())
+ {
+ writer.WriteUShort((ushort)typeof(DrawableLineMessage).FullName.GetStableHashCode());
+ writer.WriteFloatNullable(duration);
+ writer.WriteColorNullable(color);
+ writer.WriteInt(count);
+ for (int i = offset; i < count + offset; i++)
+ writer.Write(points[i]);
+ data = writer.ToArraySegment();
+ }
if (players != null)
{
- using NetworkWriterPooled writer = NetworkWriterPool.Get();
- NetworkMessages.Pack(msg, writer);
- ArraySegment segment = writer.ToArraySegment();
-
foreach (Player ply in players)
{
- ply?.Connection.Send(segment);
+ ply.Connection.Send(data);
}
}
else
{
- NetworkServer.SendToReady(msg);
+ foreach (NetworkConnectionToClient connectionToClient in NetworkServer.connections.Values)
+ {
+ if (connectionToClient.isReady)
+ {
+ connectionToClient.Send(data);
+ }
+ }
}
}
}