Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: NpcNameFinder split into multiple files, and small changes. #545

Merged
merged 1 commit into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions SharedLib/NpcFinder/LineSegment.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
namespace SharedLib.NpcFinder;

public readonly struct LineSegment
public readonly record struct LineSegment
{
public readonly int XStart;
public readonly int X;
public readonly int Y;
public readonly int XEnd;
public readonly int XCenter;

public readonly int XStart => X & 0xFFFF;
public readonly int XEnd => X >> 16;
public readonly int XCenter => XStart + ((XEnd - XStart) / 2);

public LineSegment(int xStart, int xEnd, int y)
{
this.XStart = xStart;
this.Y = y;
this.XEnd = xEnd;
XCenter = XStart + ((XEnd - XStart) / 2);
X = (xEnd << 16) | (xStart & 0xFFFF);
Y = y;
}
}
39 changes: 39 additions & 0 deletions SharedLib/NpcFinder/NpcNameColors.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
namespace SharedLib.NpcFinder;

public static class NpcNameColors
{
public const byte fBase = 230;

public const byte fE_R = fBase;
public const byte fE_G = 0;
public const byte fE_B = 0;

public const byte fF_R = 0;
public const byte fF_G = fBase;
public const byte fF_B = 0;

public const byte fN_R = fBase;
public const byte fN_G = fBase;
public const byte fN_B = 0;

public const byte fuzzCorpse = 18;
public const byte fC_RGB = 128;

public const byte sE_R = 240;
public const byte sE_G = 35;
public const byte sE_B = 35;

public const byte sF_R = 0;
public const byte sF_G = 250;
public const byte sF_B = 0;

public const byte sN_R = 250;
public const byte sN_G = 250;
public const byte sN_B = 0;

public const byte sNamePlate_N = 254;

public const byte sNamePlate_H_R = 254;
public const byte sNamePlate_H_G = 254;
public const byte sNamePlate_H_B = 0;
}
183 changes: 41 additions & 142 deletions SharedLib/NpcFinder/NpcNameFinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,65 +8,20 @@
using System.Runtime.CompilerServices;
using System.Buffers;
using System.Collections.Generic;
using System.Threading;

#pragma warning disable 162
using static SharedLib.NpcFinder.NpcNameColors;

namespace SharedLib.NpcFinder;

[Flags]
public enum NpcNames
{
None = 0,
Enemy = 1,
Friendly = 2,
Neutral = 4,
Corpse = 8,
NamePlate = 16
}

public static class NpcNames_Extension
{
public static string ToStringF(this NpcNames value) => value switch
{
NpcNames.None => nameof(NpcNames.None),
NpcNames.Enemy => nameof(NpcNames.Enemy),
NpcNames.Friendly => nameof(NpcNames.Friendly),
NpcNames.Neutral => nameof(NpcNames.Neutral),
NpcNames.Corpse => nameof(NpcNames.Corpse),
NpcNames.NamePlate => nameof(NpcNames.NamePlate),
_ => nameof(NpcNames.None),
};

public static bool HasFlagF(this NpcNames value, NpcNames flag)
{
return (value & flag) != 0;
}
}

public enum SearchMode
{
Simple = 0,
Fuzzy = 1
}

public static class SearchMode_Extension
{
public static string ToStringF(this SearchMode value) => value switch
{
SearchMode.Simple => nameof(SearchMode.Simple),
SearchMode.Fuzzy => nameof(SearchMode.Fuzzy),
_ => nameof(SearchMode.Simple),
};
}

public sealed partial class NpcNameFinder : IDisposable
{
private readonly ILogger logger;
private readonly IBitmapProvider bitmapProvider;
private readonly PixelFormat pixelFormat;
private readonly INpcResetEvent resetEvent;

private readonly int bytesPerPixel;
private const int bytesPerPixel = 4;

private readonly Pen whitePen;
private readonly Pen greyPen;
Expand Down Expand Up @@ -104,76 +59,23 @@ public sealed partial class NpcNameFinder : IDisposable

private readonly NpcPositionComparer npcPosComparer;

#region variables

public float colorFuzziness { get; set; } = 15f;

private const int colorFuzz = 40;

public int topOffset { get; set; } = 117;
private const int topOffset = 117;
public int WidthDiff { get; set; } = 4;

private float heightMul;
public int HeightMulti { get; set; }

public int MaxWidth { get; set; } = 250;

public int MinHeight { get; set; } = 16;

public int WidthDiff { get; set; } = 4;

public int HeightOffset1 { get; set; } = 10;

public int HeightOffset2 { get; set; } = 2;

#endregion

#region Colors

public const byte fBase = 230;

public const byte fE_R = fBase;
public const byte fE_G = 0;
public const byte fE_B = 0;

public const byte fF_R = 0;
public const byte fF_G = fBase;
public const byte fF_B = 0;

public const byte fN_R = fBase;
public const byte fN_G = fBase;
public const byte fN_B = 0;

public const byte fuzzCorpse = 18;
public const byte fC_RGB = 128;

public const byte sE_R = 240;
public const byte sE_G = 35;
public const byte sE_B = 35;

public const byte sF_R = 0;
public const byte sF_G = 250;
public const byte sF_B = 0;

public const byte sN_R = 250;
public const byte sN_G = 250;
public const byte sN_B = 0;

public const byte sNamePlate_N = 254;

public const byte sNamePlate_H_R = 254;
public const byte sNamePlate_H_G = 254;
public const byte sNamePlate_H_B = 0;

#endregion

public NpcNameFinder(ILogger logger, IBitmapProvider bitmapProvider,
INpcResetEvent resetEvent)
{
this.logger = logger;
this.bitmapProvider = bitmapProvider;
this.pixelFormat = bitmapProvider.Bitmap.PixelFormat;
this.resetEvent = resetEvent;
this.bytesPerPixel = Bitmap.GetPixelFormatSize(pixelFormat) / 8;

UpdateSearchMode();

Expand Down Expand Up @@ -447,7 +349,7 @@ public void Update()
resetEvent.Reset();

ReadOnlySpan<LineSegment> lineSegments =
PopulateLines(bitmapProvider.Bitmap, Area);
PopulateLines(bitmapProvider.Bitmap, Area, colorMatcher, Area, ScaleWidth(MinHeight), ScaleWidth(WidthDiff));
Npcs = DetermineNpcs(lineSegments);

TargetCount = Npcs.Count(TargetsCount);
Expand Down Expand Up @@ -515,42 +417,42 @@ private ArraySegment<NpcPosition> DetermineNpcs(ReadOnlySpan<LineSegment> data)
group[gc++] = laterNpcLine;
}

if (gc > 0)
{
ref LineSegment n = ref group[0];
Rectangle rect = new(n.XStart, n.Y, n.XEnd - n.XStart, 1);
if (gc <= 0)
continue;

for (int g = 1; g < gc; g++)
{
n = group[g];
ref LineSegment n = ref group[0];
Rectangle rect = new(n.XStart, n.Y, n.XEnd - n.XStart, 1);

rect.X = Math.Min(rect.X, n.XStart);
rect.Y = Math.Min(rect.Y, n.Y);
for (int g = 1; g < gc; g++)
{
n = group[g];

if (rect.Right < n.XEnd)
rect.Width = n.XEnd - n.XStart;
rect.X = Math.Min(rect.X, n.XStart);
rect.Y = Math.Min(rect.Y, n.Y);

if (rect.Bottom < n.Y)
rect.Height = n.Y - rect.Y;
}
int yOffset = YOffset(Area, rect);
npcs[c++] = new NpcPosition(
rect.Location, rect.Max(), yOffset, heightMul);
if (rect.Right < n.XEnd)
rect.Width = n.XEnd - n.XStart;

if (rect.Bottom < n.Y)
rect.Height = n.Y - rect.Y;
}
int yOffset = YOffset(Area, rect);
npcs[c++] = new NpcPosition(
rect.Location, rect.Max(), yOffset, heightMul);
}

int lineHeight = 2 * (int)ScaleHeight(MinHeight);

for (int i = 0; i < c; i++)
for (int i = 0; i < c - 1; i++)
{
ref readonly NpcPosition ii = ref npcs[i];
if (ii.Equals(NpcPosition.Empty))
continue;

for (int j = 0; j < c; j++)
for (int j = i + 1; j < c; j++)
{
ref readonly NpcPosition jj = ref npcs[j];
if (i == j || jj.Equals(NpcPosition.Empty))
if (jj.Equals(NpcPosition.Empty))
continue;

Point pi = ii.Rect.Centre();
Expand Down Expand Up @@ -608,7 +510,7 @@ private bool TargetsCount(NpcPosition c)
Math.Abs(c.ClickPoint.X - screenMid) < screenTargetBuffer;
}

private bool IsAdd(NpcPosition c)
public bool IsAdd(NpcPosition c)
{
return
(c.ClickPoint.X < screenMid - screenTargetBuffer &&
Expand All @@ -623,21 +525,19 @@ private int YOffset(Rectangle area, Rectangle npc)
}

[SkipLocalsInit]
private ReadOnlySpan<LineSegment> PopulateLines(Bitmap bitmap, Rectangle rect)
private ReadOnlySpan<LineSegment> PopulateLines(Bitmap bitmap, Rectangle rect,
Func<byte, byte, byte, bool> colorMatcher, Rectangle area, float minLength, float lengthDiff)
{
Rectangle area = this.Area;
int bytesPerPixel = this.bytesPerPixel;

int width = (area.Right - area.Left) / 32;
int height = (area.Bottom - area.Top) / 32;
const int RESOLUTION = 64;
int width = (area.Right - area.Left) / RESOLUTION;
int height = (area.Bottom - area.Top) / RESOLUTION;
int size = width * height;

var pooler = ArrayPool<LineSegment>.Shared;
LineSegment[] segments = pooler.Rent(size);
int i = 0;

Func<byte, byte, byte, bool> colorMatcher = this.colorMatcher;
float minLength = ScaleWidth(MinHeight);
float lengthDiff = ScaleWidth(WidthDiff);
int end = area.Right;
float minEndLength = minLength - lengthDiff;

BitmapData bitmapData =
Expand All @@ -647,9 +547,8 @@ private ReadOnlySpan<LineSegment> PopulateLines(Bitmap bitmap, Rectangle rect)
[SkipLocalsInit]
unsafe void body(int y)
{
int xStart = -1;
int xEnd = -1;
int end = area.Right;
int xStart = int.MinValue;
int xEnd = int.MinValue;

byte* currentLine = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride);
for (int x = area.Left; x < end; x++)
Expand All @@ -662,28 +561,28 @@ unsafe void body(int y)
currentLine[xi]))
continue;

if (xStart > -1 && (x - xEnd) < minLength)
if (xStart > int.MinValue && (x - xEnd) < minLength)
{
xEnd = x;
}
else
{
if (xStart > -1 && xEnd - xStart > minEndLength)
if (xStart > int.MinValue && xEnd - xStart > minEndLength)
{
if (i + 1 >= size)
return;

segments[i++] = new LineSegment(xStart, xEnd, y);
segments[Interlocked.Add(ref i, 1)] = new LineSegment(xStart, xEnd, y);
}

xStart = x;
}
xEnd = x;
}

if (i < size && xStart > -1 && xEnd - xStart > minEndLength)
if (xStart > int.MinValue && xEnd - xStart > minEndLength)
{
segments[i++] = new LineSegment(xStart, xEnd, y);
segments[Interlocked.Add(ref i, 1)] = new LineSegment(xStart, xEnd, y);
}
}
_ = Parallel.For(area.Top, area.Height, body);
Expand Down
Loading
Loading