Core/AreaTriggers: Refactor AreaTriggerShapeInfo to use std::variant instead of union

Port From (https://github.com/TrinityCore/TrinityCore/commit/dac548a305c1509240ff6a923ccce8359c98915a)
This commit is contained in:
Hondacrx
2025-12-07 23:07:54 -05:00
parent b022cd1cc4
commit 8cc270b895
4 changed files with 240 additions and 199 deletions
@@ -72,7 +72,7 @@ namespace Game.DataStorage
{
do
{
AreaTriggerId createPropertiesId = new (vertices.Read<uint>(0), vertices.Read<bool>(1));
AreaTriggerId createPropertiesId = new(vertices.Read<uint>(0), vertices.Read<bool>(1));
verticesByCreateProperties.Add(createPropertiesId, new Vector2(vertices.Read<float>(3), vertices.Read<float>(4)));
@@ -149,7 +149,7 @@ namespace Game.DataStorage
continue;
}
if (shape >= AreaTriggerShapeType.Max)
if (shape == AreaTriggerShapeType.Unk || shape >= AreaTriggerShapeType.Max)
{
Log.outError(LogFilter.Sql, $"Table `areatrigger_create_properties` has listed AreaTriggerCreatePropertiesId (Id: {createPropertiesId.Id}, IsCustom: {createPropertiesId.IsCustom}) with invalid shape {shape}.");
continue;
@@ -188,33 +188,55 @@ namespace Game.DataStorage
createProperties.TimeToTargetScale = areatriggerCreateProperties.Read<uint>(13);
createProperties.Speed = areatriggerCreateProperties.Read<float>(14);
createProperties.Shape.TriggerType = shape;
unsafe
float[] shapeData = new float[SharedConst.MaxAreatriggerEntityData];
for (byte i = 0; i < SharedConst.MaxAreatriggerEntityData; ++i)
shapeData[i] = areatriggerCreateProperties.Read<float>(16 + i);
switch (shape)
{
for (byte i = 0; i < SharedConst.MaxAreatriggerEntityData; ++i)
createProperties.Shape.DefaultDatas.Data[i] = areatriggerCreateProperties.Read<float>(16 + i);
case AreaTriggerShapeType.Sphere:
createProperties.Shape.Data = new AreaTriggerShapeInfo.Sphere(shapeData);
break;
case AreaTriggerShapeType.Box:
createProperties.Shape.Data = new AreaTriggerShapeInfo.Box(shapeData);
break;
case AreaTriggerShapeType.Polygon:
AreaTriggerShapeInfo.Polygon polygon = new AreaTriggerShapeInfo.Polygon(shapeData);
if (polygon.Height <= 0.0f)
{
polygon.Height = 1.0f;
if (polygon.HeightTarget <= 0.0f)
polygon.HeightTarget = 1.0f;
}
var vertices1 = verticesByCreateProperties.LookupByKey(createProperties.Id);
if (vertices1 != null)
polygon.PolygonVertices = vertices1;
vertices1 = verticesTargetByCreateProperties.LookupByKey(createProperties.Id);
if (vertices != null)
polygon.PolygonVerticesTarget = vertices1;
if (!polygon.PolygonVerticesTarget.Empty() && polygon.PolygonVertices.Count != polygon.PolygonVerticesTarget.Count)
{
Log.outError(LogFilter.Sql, $"Table `areatrigger_create_properties_polygon_vertex` has invalid target vertices, either all or none vertices must have a corresponding target vertex (AreaTriggerCreatePropertiesId: (Id: {createPropertiesId.Id}, IsCustom: {createPropertiesId.IsCustom})).");
polygon.PolygonVerticesTarget.Clear();
}
createProperties.Shape.Data = polygon;
break;
case AreaTriggerShapeType.Cylinder:
createProperties.Shape.Data = new AreaTriggerShapeInfo.Cylinder(shapeData);
break;
case AreaTriggerShapeType.Disk:
createProperties.Shape.Data = new AreaTriggerShapeInfo.Disk(shapeData);
break;
case AreaTriggerShapeType.BoundedPlane:
createProperties.Shape.Data = new AreaTriggerShapeInfo.BoundedPlane(shapeData);
break;
default:
break;
}
createProperties.ScriptId = Global.ObjectMgr.GetScriptId(areatriggerCreateProperties.Read<string>(24));
if (shape == AreaTriggerShapeType.Polygon)
{
if (createProperties.Shape.PolygonDatas.Height <= 0.0f)
{
createProperties.Shape.PolygonDatas.Height = 1.0f;
if (createProperties.Shape.PolygonDatas.HeightTarget <= 0.0f)
createProperties.Shape.PolygonDatas.HeightTarget = 1.0f;
}
}
createProperties.Shape.PolygonVertices = verticesByCreateProperties[createProperties.Id];
createProperties.Shape.PolygonVerticesTarget = verticesTargetByCreateProperties[createProperties.Id];
if (!createProperties.Shape.PolygonVerticesTarget.Empty() && createProperties.Shape.PolygonVertices.Count != createProperties.Shape.PolygonVerticesTarget.Count)
{
Log.outError(LogFilter.Sql, $"Table `areatrigger_create_properties_polygon_vertex` has invalid target vertices, either all or none vertices must have a corresponding target vertex (AreaTriggerCreatePropertiesId: (Id: {createPropertiesId.Id}, IsCustom: {createPropertiesId.IsCustom})).");
createProperties.Shape.PolygonVerticesTarget.Clear();
}
var spline = splinesByCreateProperties.LookupByKey(createProperties.Id);
if (spline != null)
createProperties.SplinePoints = spline;
@@ -384,7 +406,7 @@ namespace Game.DataStorage
public AreaTriggerTemplate GetAreaTriggerTemplate(AreaTriggerId areaTriggerId)
{
return _areaTriggerTemplateStore.LookupByKey(areaTriggerId);
return _areaTriggerTemplateStore.LookupByKey(areaTriggerId);
}
public AreaTriggerCreateProperties GetAreaTriggerCreateProperties(AreaTriggerId areaTriggerCreatePropertiesId)
+40 -48
View File
@@ -229,7 +229,7 @@ namespace Game.Entities
InitOrbit(orbit, GetCreateProperties().Speed);
}
else if (GetCreateProperties().HasSplines())
else if (GetCreateProperties().SplinePoints != null)
{
InitSplineOffsets(GetCreateProperties().SplinePoints);
}
@@ -933,81 +933,73 @@ namespace Game.Entities
return 0;
}
unsafe void SetShape(AreaTriggerShapeInfo shape)
void SetShape(AreaTriggerShapeInfo shape)
{
var areaTriggerData = m_values.ModifyValue(m_areaTriggerData);
switch (shape.TriggerType)
{
case AreaTriggerShapeType.Sphere:
shape.Data.Switch
(
sphereInfo =>
{
SetUpdateFieldValue(areaTriggerData.ModifyValue(m_areaTriggerData.ShapeType), (byte)0);
var sphere = areaTriggerData.ModifyValue<AreaTriggerSphere>(m_areaTriggerData.ShapeData);
SetUpdateFieldValue(sphere.ModifyValue(sphere.Radius), shape.SphereDatas.Radius);
SetUpdateFieldValue(sphere.ModifyValue(sphere.RadiusTarget), shape.SphereDatas.RadiusTarget);
break;
}
case AreaTriggerShapeType.Box:
SetUpdateFieldValue(sphere.ModifyValue(sphere.Radius), sphereInfo.Radius);
SetUpdateFieldValue(sphere.ModifyValue(sphere.RadiusTarget), sphereInfo.RadiusTarget);
},
boxInfo =>
{
SetUpdateFieldValue(areaTriggerData.ModifyValue(m_areaTriggerData.ShapeType), (byte)1);
var box = areaTriggerData.ModifyValue<AreaTriggerBox>(m_areaTriggerData.ShapeData);
SetUpdateFieldValue(box.ModifyValue(box.Extents), new Vector3(shape.BoxDatas.Extents[0], shape.BoxDatas.Extents[1], shape.BoxDatas.Extents[2]));
SetUpdateFieldValue(box.ModifyValue(box.ExtentsTarget), new Vector3(shape.BoxDatas.ExtentsTarget[0], shape.BoxDatas.ExtentsTarget[1], shape.BoxDatas.ExtentsTarget[2]));
break;
}
case AreaTriggerShapeType.Polygon:
SetUpdateFieldValue(box.ModifyValue(box.Extents), boxInfo.Extents);
SetUpdateFieldValue(box.ModifyValue(box.ExtentsTarget), boxInfo.ExtentsTarget);
},
polygonInfo =>
{
SetUpdateFieldValue(areaTriggerData.ModifyValue(m_areaTriggerData.ShapeType), (byte)3);
var polygon = areaTriggerData.ModifyValue<AreaTriggerPolygon>(m_areaTriggerData.ShapeData);
var vertices = polygon.ModifyValue(polygon.Vertices);
ClearDynamicUpdateFieldValues(vertices);
foreach (Vector2 vertex in shape.PolygonVertices)
foreach (Vector2 vertex in polygonInfo.PolygonVertices)
AddDynamicUpdateFieldValue(vertices, vertex);
var verticesTarget = polygon.ModifyValue(polygon.VerticesTarget);
ClearDynamicUpdateFieldValues(verticesTarget);
foreach (Vector2 vertex in shape.PolygonVerticesTarget)
foreach (Vector2 vertex in polygonInfo.PolygonVerticesTarget)
AddDynamicUpdateFieldValue(verticesTarget, vertex);
SetUpdateFieldValue(polygon.ModifyValue(polygon.Height), shape.PolygonDatas.Height);
SetUpdateFieldValue(polygon.ModifyValue(polygon.HeightTarget), shape.PolygonDatas.HeightTarget);
break;
}
case AreaTriggerShapeType.Cylinder:
SetUpdateFieldValue(polygon.ModifyValue(polygon.Height), polygonInfo.Height);
SetUpdateFieldValue(polygon.ModifyValue(polygon.HeightTarget), polygonInfo.HeightTarget);
},
cylinderInfo =>
{
SetUpdateFieldValue(areaTriggerData.ModifyValue(m_areaTriggerData.ShapeType), (byte)4);
var cylinder = areaTriggerData.ModifyValue<AreaTriggerCylinder>(m_areaTriggerData.ShapeData);
SetUpdateFieldValue(cylinder.ModifyValue(cylinder.Radius), shape.CylinderDatas.Radius);
SetUpdateFieldValue(cylinder.ModifyValue(cylinder.RadiusTarget), shape.CylinderDatas.RadiusTarget);
SetUpdateFieldValue(cylinder.ModifyValue(cylinder.Height), shape.CylinderDatas.Height);
SetUpdateFieldValue(cylinder.ModifyValue(cylinder.HeightTarget), shape.CylinderDatas.HeightTarget);
SetUpdateFieldValue(cylinder.ModifyValue(cylinder.LocationZOffset), shape.CylinderDatas.LocationZOffset);
SetUpdateFieldValue(cylinder.ModifyValue(cylinder.LocationZOffsetTarget), shape.CylinderDatas.LocationZOffsetTarget);
break;
}
case AreaTriggerShapeType.Disk:
SetUpdateFieldValue(cylinder.ModifyValue(cylinder.Radius), cylinderInfo.Radius);
SetUpdateFieldValue(cylinder.ModifyValue(cylinder.RadiusTarget), cylinderInfo.RadiusTarget);
SetUpdateFieldValue(cylinder.ModifyValue(cylinder.Height), cylinderInfo.Height);
SetUpdateFieldValue(cylinder.ModifyValue(cylinder.HeightTarget), cylinderInfo.HeightTarget);
SetUpdateFieldValue(cylinder.ModifyValue(cylinder.LocationZOffset), cylinderInfo.LocationZOffset);
SetUpdateFieldValue(cylinder.ModifyValue(cylinder.LocationZOffsetTarget), cylinderInfo.LocationZOffsetTarget);
},
diskInfo =>
{
SetUpdateFieldValue(areaTriggerData.ModifyValue(m_areaTriggerData.ShapeType), (byte)7);
var disk = areaTriggerData.ModifyValue<AreaTriggerDisk>(m_areaTriggerData.ShapeData);
SetUpdateFieldValue(disk.ModifyValue(disk.InnerRadius), shape.DiskDatas.InnerRadius);
SetUpdateFieldValue(disk.ModifyValue(disk.InnerRadiusTarget), shape.DiskDatas.InnerRadiusTarget);
SetUpdateFieldValue(disk.ModifyValue(disk.OuterRadius), shape.DiskDatas.OuterRadius);
SetUpdateFieldValue(disk.ModifyValue(disk.OuterRadiusTarget), shape.DiskDatas.OuterRadiusTarget);
SetUpdateFieldValue(disk.ModifyValue(disk.Height), shape.DiskDatas.Height);
SetUpdateFieldValue(disk.ModifyValue(disk.HeightTarget), shape.DiskDatas.HeightTarget);
SetUpdateFieldValue(disk.ModifyValue(disk.LocationZOffset), shape.DiskDatas.LocationZOffset);
SetUpdateFieldValue(disk.ModifyValue(disk.LocationZOffsetTarget), shape.DiskDatas.LocationZOffsetTarget);
break;
}
case AreaTriggerShapeType.BoundedPlane:
SetUpdateFieldValue(disk.ModifyValue(disk.InnerRadius), diskInfo.InnerRadius);
SetUpdateFieldValue(disk.ModifyValue(disk.InnerRadiusTarget), diskInfo.InnerRadiusTarget);
SetUpdateFieldValue(disk.ModifyValue(disk.OuterRadius), diskInfo.OuterRadius);
SetUpdateFieldValue(disk.ModifyValue(disk.OuterRadiusTarget), diskInfo.OuterRadiusTarget);
SetUpdateFieldValue(disk.ModifyValue(disk.Height), diskInfo.Height);
SetUpdateFieldValue(disk.ModifyValue(disk.HeightTarget), diskInfo.HeightTarget);
SetUpdateFieldValue(disk.ModifyValue(disk.LocationZOffset), diskInfo.LocationZOffset);
SetUpdateFieldValue(disk.ModifyValue(disk.LocationZOffsetTarget), diskInfo.LocationZOffsetTarget);
},
boundedPlaneInfo =>
{
SetUpdateFieldValue(areaTriggerData.ModifyValue(m_areaTriggerData.ShapeType), (byte)8);
var boundedPlane = areaTriggerData.ModifyValue<AreaTriggerBoundedPlane>(m_areaTriggerData.ShapeData);
SetUpdateFieldValue(boundedPlane.ModifyValue(boundedPlane.Extents), new Vector2(shape.BoundedPlaneDatas.Extents[0], shape.BoundedPlaneDatas.Extents[1]));
SetUpdateFieldValue(boundedPlane.ModifyValue(boundedPlane.ExtentsTarget), new Vector2(shape.BoundedPlaneDatas.ExtentsTarget[0], shape.BoundedPlaneDatas.ExtentsTarget[1]));
break;
SetUpdateFieldValue(boundedPlane.ModifyValue(boundedPlane.Extents), boundedPlaneInfo.Extents);
SetUpdateFieldValue(boundedPlane.ModifyValue(boundedPlane.ExtentsTarget), boundedPlaneInfo.ExtentsTarget);
}
default:
break;
}
);
}
public float GetMaxSearchRadius()
@@ -3,94 +3,13 @@
using Framework.Constants;
using Game.Maps;
using Game.Networking;
using OneOf;
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Runtime.InteropServices;
namespace Game.Entities
{
[StructLayout(LayoutKind.Explicit)]
public unsafe class AreaTriggerData
{
[FieldOffset(0)]
public defaultdatas DefaultDatas;
[FieldOffset(0)]
public spheredatas SphereDatas;
[FieldOffset(0)]
public boxdatas BoxDatas;
[FieldOffset(0)]
public polygondatas PolygonDatas;
[FieldOffset(0)]
public cylinderdatas CylinderDatas;
[FieldOffset(0)]
public diskDatas DiskDatas;
[FieldOffset(0)]
public boundedPlaneDatas BoundedPlaneDatas;
public struct defaultdatas
{
public fixed float Data[SharedConst.MaxAreatriggerEntityData];
}
// AREATRIGGER_TYPE_SPHERE
public struct spheredatas
{
public float Radius;
public float RadiusTarget;
}
// AREATRIGGER_TYPE_BOX
public struct boxdatas
{
public fixed float Extents[3];
public fixed float ExtentsTarget[3];
}
// AREATRIGGER_TYPE_POLYGON
public struct polygondatas
{
public float Height;
public float HeightTarget;
}
// AREATRIGGER_TYPE_CYLINDER
public struct cylinderdatas
{
public float Radius;
public float RadiusTarget;
public float Height;
public float HeightTarget;
public float LocationZOffset;
public float LocationZOffsetTarget;
}
// AREATRIGGER_TYPE_DISK
public struct diskDatas
{
public float InnerRadius;
public float InnerRadiusTarget;
public float OuterRadius;
public float OuterRadiusTarget;
public float Height;
public float HeightTarget;
public float LocationZOffset;
public float LocationZOffsetTarget;
}
// AREATRIGGER_TYPE_BOUNDED_PLANE
public struct boundedPlaneDatas
{
public fixed float Extents[2];
public fixed float ExtentsTarget[2];
}
}
public struct AreaTriggerId
{
public uint Id;
@@ -122,59 +41,166 @@ namespace Game.Entities
}
}
public class AreaTriggerShapeInfo : AreaTriggerData
interface IShapeInfo
{
public AreaTriggerShapeType TriggerType;
public List<Vector2> PolygonVertices;
public List<Vector2> PolygonVerticesTarget;
float GetMaxSearchRadius();
}
public AreaTriggerShapeInfo()
{
TriggerType = AreaTriggerShapeType.Max;
PolygonVertices = new();
PolygonVerticesTarget = new();
}
public class AreaTriggerShapeInfo
{
public OneOf<Sphere, Box, Polygon, Cylinder, Disk, BoundedPlane> Data;
public unsafe float GetMaxSearchRadius()
public bool IsSphere() { return Data.IsT0; }
public bool IsBox() { return Data.IsT1; }
public bool IsPolygon() { return Data.IsT2; }
public bool IsCylinder() { return Data.IsT3; }
public bool IsDisk() { return Data.IsT4; }
public bool IsBoundedPlane() { return Data.IsT5; }
public float GetMaxSearchRadius() { return ((IShapeInfo)Data.Value).GetMaxSearchRadius(); }
public struct Sphere : IShapeInfo
{
switch (TriggerType)
public float Radius;
public float RadiusTarget;
public Sphere() { }
public Sphere(float[] raw)
{
case AreaTriggerShapeType.Sphere:
return Math.Max(SphereDatas.Radius, SphereDatas.RadiusTarget);
case AreaTriggerShapeType.Box:
return MathF.Sqrt(Math.Max(BoxDatas.Extents[0] * BoxDatas.Extents[0] + BoxDatas.Extents[1] * BoxDatas.Extents[1],
BoxDatas.ExtentsTarget[0] * BoxDatas.ExtentsTarget[0] + BoxDatas.ExtentsTarget[1] * BoxDatas.ExtentsTarget[1]));
case AreaTriggerShapeType.Polygon:
{
Position center = new(0.0f, 0.0f);
float maxSearchRadius = 0.0f;
foreach (var vertex in PolygonVertices)
maxSearchRadius = Math.Max(maxSearchRadius, center.GetExactDist2d(vertex.X, vertex.Y));
foreach (var vertex in PolygonVerticesTarget)
maxSearchRadius = Math.Max(maxSearchRadius, center.GetExactDist2d(vertex.X, vertex.Y));
return maxSearchRadius;
}
case AreaTriggerShapeType.Cylinder:
return Math.Max(CylinderDatas.Radius, CylinderDatas.RadiusTarget);
case AreaTriggerShapeType.Disk:
return Math.Max(DiskDatas.OuterRadius, DiskDatas.OuterRadiusTarget);
case AreaTriggerShapeType.BoundedPlane:
return MathF.Sqrt(Math.Max(BoundedPlaneDatas.Extents[0] * BoundedPlaneDatas.Extents[0] / 4 + BoundedPlaneDatas.Extents[1] * BoundedPlaneDatas.Extents[1] / 4,
BoundedPlaneDatas.ExtentsTarget[0] * BoundedPlaneDatas.ExtentsTarget[0] / 4 + BoundedPlaneDatas.ExtentsTarget[1] * BoundedPlaneDatas.ExtentsTarget[1] / 4));
Radius = raw[0];
RadiusTarget = raw[1];
}
return 0.0f;
public float GetMaxSearchRadius()
{
return Math.Max(Radius, RadiusTarget);
}
}
public bool IsSphere() { return TriggerType == AreaTriggerShapeType.Sphere; }
public bool IsBox() { return TriggerType == AreaTriggerShapeType.Box; }
public bool IsPolygon() { return TriggerType == AreaTriggerShapeType.Polygon; }
public bool IsCylinder() { return TriggerType == AreaTriggerShapeType.Cylinder; }
public bool IsDisk() { return TriggerType == AreaTriggerShapeType.Disk; }
public bool IsBoundedPlane() { return TriggerType == AreaTriggerShapeType.BoundedPlane; }
public struct Box : IShapeInfo
{
public Vector3 Extents;
public Vector3 ExtentsTarget;
public Box() { }
public Box(float[] raw)
{
Extents = new(raw[0], raw[1], raw[2]);
ExtentsTarget = new(raw[3], raw[4], raw[5]);
}
public float GetMaxSearchRadius()
{
return MathF.Sqrt(MathF.Max(
Extents.X * Extents.X + Extents.Y * Extents.Y,
ExtentsTarget.X * ExtentsTarget.X + ExtentsTarget.Y * ExtentsTarget.Y));
}
}
public struct Polygon : IShapeInfo
{
public List<Vector2> PolygonVertices = new();
public List<Vector2> PolygonVerticesTarget = new();
public float Height;
public float HeightTarget;
public Polygon() { }
public Polygon(float[] raw)
{
Height = raw[0];
HeightTarget = raw[1];
}
public float GetMaxSearchRadius()
{
Position center = new(0.0f, 0.0f);
float maxSearchRadius = 0.0f;
foreach (var vertex in PolygonVertices)
maxSearchRadius = Math.Max(maxSearchRadius, center.GetExactDist2d(vertex.X, vertex.Y));
foreach (var vertex in PolygonVerticesTarget)
maxSearchRadius = Math.Max(maxSearchRadius, center.GetExactDist2d(vertex.X, vertex.Y));
return maxSearchRadius;
}
}
public struct Cylinder : IShapeInfo
{
public float Radius;
public float RadiusTarget;
public float Height;
public float HeightTarget;
public float LocationZOffset;
public float LocationZOffsetTarget;
public Cylinder() { }
public Cylinder(float[] raw)
{
Radius = raw[0];
RadiusTarget = raw[1];
Height = raw[2];
HeightTarget = raw[3];
LocationZOffset = raw[4];
LocationZOffsetTarget = raw[5];
}
public float GetMaxSearchRadius()
{
return Math.Max(Radius, RadiusTarget);
}
}
public struct Disk : IShapeInfo
{
public float InnerRadius;
public float InnerRadiusTarget;
public float OuterRadius;
public float OuterRadiusTarget;
public float Height;
public float HeightTarget;
public float LocationZOffset;
public float LocationZOffsetTarget;
public Disk() { }
public Disk(float[] raw)
{
InnerRadius = raw[0];
InnerRadiusTarget = raw[1];
OuterRadius = raw[2];
OuterRadiusTarget = raw[3];
Height = raw[4];
HeightTarget = raw[5];
LocationZOffset = raw[6];
LocationZOffsetTarget = raw[7];
}
public float GetMaxSearchRadius()
{
return Math.Max(OuterRadius, OuterRadiusTarget);
}
}
public struct BoundedPlane : IShapeInfo
{
public Vector2 Extents;
public Vector2 ExtentsTarget;
public BoundedPlane() { }
public BoundedPlane(float[] raw)
{
Extents = new(raw[0], raw[1]);
ExtentsTarget = new(raw[2], raw[3]);
}
public float GetMaxSearchRadius()
{
return MathF.Sqrt(Math.Max(
Extents.X * Extents.X / 4 + Extents.Y * Extents.Y / 4,
ExtentsTarget.X * ExtentsTarget.X / 4 + ExtentsTarget.Y * ExtentsTarget.Y / 4));
}
}
}
public class AreaTriggerOrbitInfo