81 lines
4.2 KiB
C#
81 lines
4.2 KiB
C#
using System.Drawing;
|
|
using CounterStrikeSharp.API;
|
|
using CounterStrikeSharp.API.Core;
|
|
using CounterStrikeSharp.API.Modules.Utils;
|
|
|
|
namespace Outnumbered.Engine;
|
|
|
|
// The one place a point_worldtext entity is created + configured (HUD panel, the 2 shop panels, the draft cards all
|
|
// share it). CreateEntityByName returns a NON-null wrapper even on failure (e.g. the entity limit) with a Zero Handle,
|
|
// so the guard checks the raw handle (no memory deref) before touching schema members. Callers supply the per-use
|
|
// font/justify/colour/border and own the last-text caching; the volatile "SetMessage" input + the Teleport placement
|
|
// go through SetText/Place so every engine touchpoint for this entity lives here.
|
|
internal static class WorldText
|
|
{
|
|
public static CPointWorldText? Create(float fontSize, float worldUnitsPerPx, string fontName, Color color,
|
|
bool drawBackground, float border, PointWorldTextJustifyHorizontal_t justify)
|
|
{
|
|
var e = Utilities.CreateEntityByName<CPointWorldText>(EngineNames.PointWorldText);
|
|
if (e is null || e.Handle == nint.Zero) return null;
|
|
e.MessageText = " ";
|
|
e.Enabled = true;
|
|
e.Fullbright = true;
|
|
e.FontSize = fontSize;
|
|
e.WorldUnitsPerPx = worldUnitsPerPx;
|
|
if (!string.IsNullOrEmpty(fontName)) e.FontName = fontName;
|
|
e.Color = color;
|
|
e.JustifyHorizontal = justify;
|
|
e.JustifyVertical = PointWorldTextJustifyVertical_t.POINT_WORLD_TEXT_JUSTIFY_VERTICAL_CENTER;
|
|
e.ReorientMode = PointWorldTextReorientMode_t.POINT_WORLD_TEXT_REORIENT_NONE;
|
|
e.DrawBackground = drawBackground;
|
|
e.BackgroundBorderHeight = border;
|
|
e.BackgroundBorderWidth = border;
|
|
e.DispatchSpawn();
|
|
return e;
|
|
}
|
|
|
|
// Push new text via the point_worldtext "SetMessage" input (the volatile input-name literal lives here, not at the 4
|
|
// call sites). Callers keep their own last-text cache and only call this on a change.
|
|
public static void SetText(CPointWorldText ent, string text) => ent.AcceptInput("SetMessage", ent, ent, text);
|
|
|
|
// Position + orient a panel. point_worldtext is moved via Teleport (no velocity); callers compute the eye-relative frame.
|
|
public static void Place(CPointWorldText ent, Vector pos, QAngle ang) => ent.Teleport(pos, ang, null);
|
|
|
|
// Tear a panel down: Remove the entity if it's still live, then null the caller's reference. Symmetric with Create —
|
|
// every point_worldtext create + destroy goes through this file.
|
|
public static void Destroy(ref CPointWorldText? ent)
|
|
{
|
|
if (ent is { IsValid: true }) ent.Remove();
|
|
ent = null;
|
|
}
|
|
|
|
public const float EyeZFallback = 64f; // ViewOffset.Z fallback when the pawn doesn't report one
|
|
|
|
// The eye-relative frame for placing a panel in front of a pawn's view: eye position + forward/right/up basis + the
|
|
// panel orientation (yaw+270 / 90-pitch = worldtext faces the player, upright across pitch/yaw). false if AbsOrigin is
|
|
// null. Callers add only their own per-panel offsets. Shared by the HUD + the shop/draft panels.
|
|
public static bool TryEyeFrame(CCSPlayerPawn pawn, out Vector eye, out Vector fwd, out Vector right, out Vector up, out QAngle ang)
|
|
{
|
|
eye = null!; fwd = null!; right = null!; up = null!; ang = null!;
|
|
var origin = pawn.AbsOrigin;
|
|
if (origin is null) return false;
|
|
var ea = pawn.EyeAngles;
|
|
float eyeZ = pawn.ViewOffset?.Z ?? EyeZFallback;
|
|
(fwd, right, up) = AngleVectors(ea);
|
|
eye = new Vector(origin.X, origin.Y, origin.Z + eyeZ);
|
|
ang = new QAngle(0f, ea.Y + 270f, 90f - ea.X);
|
|
return true;
|
|
}
|
|
|
|
// Source-engine AngleVectors with roll assumed 0 (HUD/shop panels never roll).
|
|
private static (Vector forward, Vector right, Vector up) AngleVectors(QAngle a)
|
|
{
|
|
const double d2r = Math.PI / 180.0;
|
|
double p = a.X * d2r, y = a.Y * d2r;
|
|
double sp = Math.Sin(p), cp = Math.Cos(p), sy = Math.Sin(y), cy = Math.Cos(y);
|
|
return (
|
|
new Vector((float)(cp * cy), (float)(cp * sy), (float)(-sp)),
|
|
new Vector((float)sy, (float)(-cy), 0f),
|
|
new Vector((float)(sp * cy), (float)(sp * sy), (float)cp));
|
|
}
|
|
}
|