PalacePal/Pal.Client/Rendering/SimpleRenderer.cs

207 lines
6.7 KiB
C#
Raw Normal View History

2023-03-26 13:47:18 +00:00
using System;
2023-02-08 15:06:43 +00:00
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
2023-10-03 09:08:38 +00:00
using Dalamud.Interface.Utility;
using Dalamud.Plugin.Services;
2023-03-26 13:47:18 +00:00
using ImGuiNET;
2023-02-15 22:17:19 +00:00
using Pal.Client.Configuration;
2023-02-18 20:12:36 +00:00
using Pal.Client.Floors;
2023-02-08 15:06:43 +00:00
2023-03-30 20:01:43 +00:00
namespace Pal.Client.Rendering;
/// <summary>
2023-10-03 09:08:38 +00:00
/// Simple renderer that only draws basic stuff.
///
2023-03-30 20:01:43 +00:00
/// This is based on what SliceIsRight uses, and what PalacePal used before it was
/// remade into PalacePal (which is the third or fourth iteration on the same idea
/// I made, just with a clear vision).
/// </summary>
internal sealed class SimpleRenderer : IRenderer, IDisposable
2023-02-08 15:06:43 +00:00
{
2023-03-30 20:01:43 +00:00
private const int SegmentCount = 20;
2023-02-15 22:17:19 +00:00
2023-10-03 09:08:38 +00:00
private readonly IClientState _clientState;
private readonly IGameGui _gameGui;
2023-03-30 20:01:43 +00:00
private readonly IPalacePalConfiguration _configuration;
private readonly TerritoryState _territoryState;
private readonly ConcurrentDictionary<ELayer, SimpleLayer> _layers = new();
2023-02-08 15:06:43 +00:00
2023-10-03 09:08:38 +00:00
public SimpleRenderer(IClientState clientState, IGameGui gameGui, IPalacePalConfiguration configuration,
2023-03-30 20:01:43 +00:00
TerritoryState territoryState)
{
_clientState = clientState;
_gameGui = gameGui;
_configuration = configuration;
_territoryState = territoryState;
}
2023-02-15 22:17:19 +00:00
2023-03-30 20:01:43 +00:00
public void SetLayer(ELayer layer, IReadOnlyList<IRenderElement> elements)
{
_layers[layer] = new SimpleLayer
2023-02-08 15:06:43 +00:00
{
2023-03-30 20:01:43 +00:00
TerritoryType = _clientState.TerritoryType,
Elements = elements.Cast<SimpleElement>().ToList()
};
}
2023-02-08 15:06:43 +00:00
2023-03-30 20:01:43 +00:00
public void ResetLayer(ELayer layer)
{
if (_layers.Remove(layer, out var l))
l.Dispose();
}
2023-02-08 15:06:43 +00:00
public IRenderElement CreateElement(MemoryLocation.EType type, Vector3 pos, bool enabled, uint color,
bool fill = false)
2023-03-30 20:01:43 +00:00
{
var config = MarkerConfig.ForType(type);
return new SimpleElement
2023-02-08 15:06:43 +00:00
{
2023-03-30 20:01:43 +00:00
Type = type,
Position = pos + new Vector3(0, config.OffsetY, 0),
Enabled = enabled,
2023-03-30 20:01:43 +00:00
Color = color,
Radius = config.Radius,
Fill = fill,
};
}
2023-02-08 15:06:43 +00:00
2023-03-30 20:01:43 +00:00
public void DrawDebugItems(uint trapColor, uint hoardColor)
{
_layers[ELayer.Test] = new SimpleLayer
{
2023-03-30 20:01:43 +00:00
TerritoryType = _clientState.TerritoryType,
Elements = new List<SimpleElement>
{
2023-03-30 20:01:43 +00:00
(SimpleElement)CreateElement(
MemoryLocation.EType.Trap,
_clientState.LocalPlayer?.Position ?? default,
true,
2023-03-30 20:01:43 +00:00
trapColor),
(SimpleElement)CreateElement(
MemoryLocation.EType.Hoard,
_clientState.LocalPlayer?.Position ?? default,
true,
2023-03-30 20:01:43 +00:00
hoardColor)
},
ExpiresAt = Environment.TickCount64 + RenderData.TestLayerTimeout
};
}
2023-03-30 20:01:43 +00:00
public void DrawLayers()
{
if (_layers.Count == 0)
return;
ImGuiHelpers.ForceNextWindowMainViewport();
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
ImGuiHelpers.SetNextWindowPosRelativeMainViewport(Vector2.Zero, ImGuiCond.None, Vector2.Zero);
ImGui.SetNextWindowSize(ImGuiHelpers.MainViewport.Size);
if (ImGui.Begin("###PalacePalSimpleRender",
ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoBackground |
ImGuiWindowFlags.NoInputs | ImGuiWindowFlags.NoSavedSettings |
ImGuiWindowFlags.AlwaysUseWindowPadding))
2023-02-08 15:06:43 +00:00
{
2023-03-30 20:01:43 +00:00
foreach (var layer in _layers.Values.Where(l => l.IsValid(_clientState)))
2023-02-08 15:06:43 +00:00
{
2023-03-30 20:01:43 +00:00
foreach (var e in layer.Elements)
Draw(e);
2023-02-08 15:06:43 +00:00
}
2023-02-15 22:17:19 +00:00
2023-03-30 20:01:43 +00:00
foreach (var key in _layers.Where(l => !l.Value.IsValid(_clientState))
.Select(l => l.Key)
.ToList())
ResetLayer(key);
2023-02-15 22:17:19 +00:00
2023-03-30 20:01:43 +00:00
ImGui.End();
}
2023-02-15 22:17:19 +00:00
2023-03-30 20:01:43 +00:00
ImGui.PopStyleVar();
}
2023-02-15 22:17:19 +00:00
2023-03-30 20:01:43 +00:00
private void Draw(SimpleElement e)
{
if (!e.Enabled)
2023-03-30 20:01:43 +00:00
return;
2023-02-15 22:17:19 +00:00
2023-03-30 20:01:43 +00:00
switch (e.Type)
{
case MemoryLocation.EType.Hoard:
// ignore distance if this is a found hoard coffer
if (_territoryState.PomanderOfIntuition == PomanderState.Active &&
_configuration.DeepDungeons.HoardCoffers.OnlyVisibleAfterPomander)
2023-02-15 22:17:19 +00:00
break;
2023-03-30 20:01:43 +00:00
goto case MemoryLocation.EType.Trap;
2023-02-15 22:17:19 +00:00
2023-03-30 20:01:43 +00:00
case MemoryLocation.EType.Trap:
var playerPos = _clientState.LocalPlayer?.Position;
if (playerPos == null)
return;
2023-02-15 22:17:19 +00:00
2023-03-30 20:01:43 +00:00
if ((playerPos.Value - e.Position).Length() > 65)
return;
break;
2023-02-15 22:17:19 +00:00
}
2023-03-30 20:01:43 +00:00
bool onScreen = false;
for (int index = 0; index < 2 * SegmentCount; ++index)
2023-02-08 15:06:43 +00:00
{
2023-03-30 20:01:43 +00:00
onScreen |= _gameGui.WorldToScreen(new Vector3(
e.Position.X + e.Radius * (float)Math.Sin(Math.PI / SegmentCount * index),
e.Position.Y,
e.Position.Z + e.Radius * (float)Math.Cos(Math.PI / SegmentCount * index)),
out Vector2 vector2);
ImGui.GetWindowDrawList().PathLineTo(vector2);
2023-02-08 15:06:43 +00:00
}
2023-03-30 20:01:43 +00:00
if (onScreen)
2023-02-08 15:06:43 +00:00
{
2023-03-30 20:01:43 +00:00
if (e.Fill)
ImGui.GetWindowDrawList().PathFillConvex(e.Color);
else
ImGui.GetWindowDrawList().PathStroke(e.Color, ImDrawFlags.Closed, 2);
}
else
ImGui.GetWindowDrawList().PathClear();
}
2023-03-30 20:01:43 +00:00
public ERenderer GetConfigValue()
=> ERenderer.Simple;
2023-02-08 15:06:43 +00:00
2023-03-30 20:01:43 +00:00
public void Dispose()
{
foreach (var l in _layers.Values)
l.Dispose();
}
2023-02-08 15:06:43 +00:00
2023-03-30 20:01:43 +00:00
public sealed class SimpleLayer : IDisposable
{
public required ushort TerritoryType { get; init; }
public required IReadOnlyList<SimpleElement> Elements { get; init; }
public long ExpiresAt { get; init; } = long.MaxValue;
2023-10-03 09:08:38 +00:00
public bool IsValid(IClientState clientState) =>
2023-03-30 20:01:43 +00:00
TerritoryType == clientState.TerritoryType && ExpiresAt >= Environment.TickCount64;
public void Dispose()
2023-02-08 15:06:43 +00:00
{
2023-03-30 20:01:43 +00:00
foreach (var e in Elements)
e.IsValid = false;
2023-02-08 15:06:43 +00:00
}
}
2023-03-30 20:01:43 +00:00
public sealed class SimpleElement : IRenderElement
{
public bool IsValid { get; set; } = true;
public required MemoryLocation.EType Type { get; init; }
public required Vector3 Position { get; init; }
public required bool Enabled { get; set; }
2023-03-30 20:01:43 +00:00
public required uint Color { get; set; }
public required float Radius { get; init; }
public required bool Fill { get; init; }
}
2023-02-08 15:06:43 +00:00
}