8
8
using System . Runtime . CompilerServices ;
9
9
using System . Buffers ;
10
10
using System . Collections . Generic ;
11
+ using System . Threading ;
11
12
12
- #pragma warning disable 162
13
+ using static SharedLib . NpcFinder . NpcNameColors ;
13
14
14
15
namespace SharedLib . NpcFinder ;
15
16
16
- [ Flags ]
17
- public enum NpcNames
18
- {
19
- None = 0 ,
20
- Enemy = 1 ,
21
- Friendly = 2 ,
22
- Neutral = 4 ,
23
- Corpse = 8 ,
24
- NamePlate = 16
25
- }
26
-
27
- public static class NpcNames_Extension
28
- {
29
- public static string ToStringF ( this NpcNames value ) => value switch
30
- {
31
- NpcNames . None => nameof ( NpcNames . None ) ,
32
- NpcNames . Enemy => nameof ( NpcNames . Enemy ) ,
33
- NpcNames . Friendly => nameof ( NpcNames . Friendly ) ,
34
- NpcNames . Neutral => nameof ( NpcNames . Neutral ) ,
35
- NpcNames . Corpse => nameof ( NpcNames . Corpse ) ,
36
- NpcNames . NamePlate => nameof ( NpcNames . NamePlate ) ,
37
- _ => nameof ( NpcNames . None ) ,
38
- } ;
39
-
40
- public static bool HasFlagF ( this NpcNames value , NpcNames flag )
41
- {
42
- return ( value & flag ) != 0 ;
43
- }
44
- }
45
-
46
- public enum SearchMode
47
- {
48
- Simple = 0 ,
49
- Fuzzy = 1
50
- }
51
-
52
- public static class SearchMode_Extension
53
- {
54
- public static string ToStringF ( this SearchMode value ) => value switch
55
- {
56
- SearchMode . Simple => nameof ( SearchMode . Simple ) ,
57
- SearchMode . Fuzzy => nameof ( SearchMode . Fuzzy ) ,
58
- _ => nameof ( SearchMode . Simple ) ,
59
- } ;
60
- }
61
-
62
17
public sealed partial class NpcNameFinder : IDisposable
63
18
{
64
19
private readonly ILogger logger ;
65
20
private readonly IBitmapProvider bitmapProvider ;
66
21
private readonly PixelFormat pixelFormat ;
67
22
private readonly INpcResetEvent resetEvent ;
68
23
69
- private readonly int bytesPerPixel ;
24
+ private const int bytesPerPixel = 4 ;
70
25
71
26
private readonly Pen whitePen ;
72
27
private readonly Pen greyPen ;
@@ -104,76 +59,23 @@ public sealed partial class NpcNameFinder : IDisposable
104
59
105
60
private readonly NpcPositionComparer npcPosComparer ;
106
61
107
- #region variables
108
-
109
- public float colorFuzziness { get ; set ; } = 15f ;
110
-
111
62
private const int colorFuzz = 40 ;
112
-
113
- public int topOffset { get ; set ; } = 117 ;
63
+ private const int topOffset = 117 ;
64
+ public int WidthDiff { get ; set ; } = 4 ;
114
65
115
66
private float heightMul ;
116
67
public int HeightMulti { get ; set ; }
117
-
118
- public int MaxWidth { get ; set ; } = 250 ;
119
-
120
68
public int MinHeight { get ; set ; } = 16 ;
121
-
122
- public int WidthDiff { get ; set ; } = 4 ;
123
-
124
69
public int HeightOffset1 { get ; set ; } = 10 ;
125
-
126
70
public int HeightOffset2 { get ; set ; } = 2 ;
127
71
128
- #endregion
129
-
130
- #region Colors
131
-
132
- public const byte fBase = 230 ;
133
-
134
- public const byte fE_R = fBase ;
135
- public const byte fE_G = 0 ;
136
- public const byte fE_B = 0 ;
137
-
138
- public const byte fF_R = 0 ;
139
- public const byte fF_G = fBase ;
140
- public const byte fF_B = 0 ;
141
-
142
- public const byte fN_R = fBase ;
143
- public const byte fN_G = fBase ;
144
- public const byte fN_B = 0 ;
145
-
146
- public const byte fuzzCorpse = 18 ;
147
- public const byte fC_RGB = 128 ;
148
-
149
- public const byte sE_R = 240 ;
150
- public const byte sE_G = 35 ;
151
- public const byte sE_B = 35 ;
152
-
153
- public const byte sF_R = 0 ;
154
- public const byte sF_G = 250 ;
155
- public const byte sF_B = 0 ;
156
-
157
- public const byte sN_R = 250 ;
158
- public const byte sN_G = 250 ;
159
- public const byte sN_B = 0 ;
160
-
161
- public const byte sNamePlate_N = 254 ;
162
-
163
- public const byte sNamePlate_H_R = 254 ;
164
- public const byte sNamePlate_H_G = 254 ;
165
- public const byte sNamePlate_H_B = 0 ;
166
-
167
- #endregion
168
-
169
72
public NpcNameFinder ( ILogger logger , IBitmapProvider bitmapProvider ,
170
73
INpcResetEvent resetEvent )
171
74
{
172
75
this . logger = logger ;
173
76
this . bitmapProvider = bitmapProvider ;
174
77
this . pixelFormat = bitmapProvider . Bitmap . PixelFormat ;
175
78
this . resetEvent = resetEvent ;
176
- this . bytesPerPixel = Bitmap . GetPixelFormatSize ( pixelFormat ) / 8 ;
177
79
178
80
UpdateSearchMode ( ) ;
179
81
@@ -447,7 +349,7 @@ public void Update()
447
349
resetEvent . Reset ( ) ;
448
350
449
351
ReadOnlySpan < LineSegment > lineSegments =
450
- PopulateLines ( bitmapProvider . Bitmap , Area ) ;
352
+ PopulateLines ( bitmapProvider . Bitmap , Area , colorMatcher , Area , ScaleWidth ( MinHeight ) , ScaleWidth ( WidthDiff ) ) ;
451
353
Npcs = DetermineNpcs ( lineSegments ) ;
452
354
453
355
TargetCount = Npcs . Count ( TargetsCount ) ;
@@ -515,42 +417,42 @@ private ArraySegment<NpcPosition> DetermineNpcs(ReadOnlySpan<LineSegment> data)
515
417
group [ gc ++ ] = laterNpcLine ;
516
418
}
517
419
518
- if ( gc > 0 )
519
- {
520
- ref LineSegment n = ref group [ 0 ] ;
521
- Rectangle rect = new ( n . XStart , n . Y , n . XEnd - n . XStart , 1 ) ;
420
+ if ( gc <= 0 )
421
+ continue ;
522
422
523
- for ( int g = 1 ; g < gc ; g ++ )
524
- {
525
- n = group [ g ] ;
423
+ ref LineSegment n = ref group [ 0 ] ;
424
+ Rectangle rect = new ( n . XStart , n . Y , n . XEnd - n . XStart , 1 ) ;
526
425
527
- rect . X = Math . Min ( rect . X , n . XStart ) ;
528
- rect . Y = Math . Min ( rect . Y , n . Y ) ;
426
+ for ( int g = 1 ; g < gc ; g ++ )
427
+ {
428
+ n = group [ g ] ;
529
429
530
- if ( rect . Right < n . XEnd )
531
- rect . Width = n . XEnd - n . XStart ;
430
+ rect . X = Math . Min ( rect . X , n . XStart ) ;
431
+ rect . Y = Math . Min ( rect . Y , n . Y ) ;
532
432
533
- if ( rect . Bottom < n . Y )
534
- rect . Height = n . Y - rect . Y ;
535
- }
536
- int yOffset = YOffset ( Area , rect ) ;
537
- npcs [ c ++ ] = new NpcPosition (
538
- rect . Location , rect . Max ( ) , yOffset , heightMul ) ;
433
+ if ( rect . Right < n . XEnd )
434
+ rect . Width = n . XEnd - n . XStart ;
435
+
436
+ if ( rect . Bottom < n . Y )
437
+ rect . Height = n . Y - rect . Y ;
539
438
}
439
+ int yOffset = YOffset ( Area , rect ) ;
440
+ npcs [ c ++ ] = new NpcPosition (
441
+ rect . Location , rect . Max ( ) , yOffset , heightMul ) ;
540
442
}
541
443
542
444
int lineHeight = 2 * ( int ) ScaleHeight ( MinHeight ) ;
543
445
544
- for ( int i = 0 ; i < c ; i ++ )
446
+ for ( int i = 0 ; i < c - 1 ; i ++ )
545
447
{
546
448
ref readonly NpcPosition ii = ref npcs [ i ] ;
547
449
if ( ii . Equals ( NpcPosition . Empty ) )
548
450
continue ;
549
451
550
- for ( int j = 0 ; j < c ; j ++ )
452
+ for ( int j = i + 1 ; j < c ; j ++ )
551
453
{
552
454
ref readonly NpcPosition jj = ref npcs [ j ] ;
553
- if ( i == j || jj . Equals ( NpcPosition . Empty ) )
455
+ if ( jj . Equals ( NpcPosition . Empty ) )
554
456
continue ;
555
457
556
458
Point pi = ii . Rect . Centre ( ) ;
@@ -608,7 +510,7 @@ private bool TargetsCount(NpcPosition c)
608
510
Math . Abs ( c . ClickPoint . X - screenMid ) < screenTargetBuffer ;
609
511
}
610
512
611
- private bool IsAdd ( NpcPosition c )
513
+ public bool IsAdd ( NpcPosition c )
612
514
{
613
515
return
614
516
( c . ClickPoint . X < screenMid - screenTargetBuffer &&
@@ -623,21 +525,19 @@ private int YOffset(Rectangle area, Rectangle npc)
623
525
}
624
526
625
527
[ SkipLocalsInit ]
626
- private ReadOnlySpan < LineSegment > PopulateLines ( Bitmap bitmap , Rectangle rect )
528
+ private ReadOnlySpan < LineSegment > PopulateLines ( Bitmap bitmap , Rectangle rect ,
529
+ Func < byte , byte , byte , bool > colorMatcher , Rectangle area , float minLength , float lengthDiff )
627
530
{
628
- Rectangle area = this . Area ;
629
- int bytesPerPixel = this . bytesPerPixel ;
630
-
631
- int width = ( area . Right - area . Left ) / 32 ;
632
- int height = ( area . Bottom - area . Top ) / 32 ;
531
+ const int RESOLUTION = 64 ;
532
+ int width = ( area . Right - area . Left ) / RESOLUTION ;
533
+ int height = ( area . Bottom - area . Top ) / RESOLUTION ;
633
534
int size = width * height ;
535
+
634
536
var pooler = ArrayPool < LineSegment > . Shared ;
635
537
LineSegment [ ] segments = pooler . Rent ( size ) ;
636
538
int i = 0 ;
637
539
638
- Func < byte , byte , byte , bool > colorMatcher = this . colorMatcher ;
639
- float minLength = ScaleWidth ( MinHeight ) ;
640
- float lengthDiff = ScaleWidth ( WidthDiff ) ;
540
+ int end = area . Right ;
641
541
float minEndLength = minLength - lengthDiff ;
642
542
643
543
BitmapData bitmapData =
@@ -647,9 +547,8 @@ private ReadOnlySpan<LineSegment> PopulateLines(Bitmap bitmap, Rectangle rect)
647
547
[ SkipLocalsInit ]
648
548
unsafe void body ( int y )
649
549
{
650
- int xStart = - 1 ;
651
- int xEnd = - 1 ;
652
- int end = area . Right ;
550
+ int xStart = int . MinValue ;
551
+ int xEnd = int . MinValue ;
653
552
654
553
byte * currentLine = ( byte * ) bitmapData . Scan0 + ( y * bitmapData . Stride ) ;
655
554
for ( int x = area . Left ; x < end ; x ++ )
@@ -662,28 +561,28 @@ unsafe void body(int y)
662
561
currentLine [ xi ] ) )
663
562
continue ;
664
563
665
- if ( xStart > - 1 && ( x - xEnd ) < minLength )
564
+ if ( xStart > int . MinValue && ( x - xEnd ) < minLength )
666
565
{
667
566
xEnd = x ;
668
567
}
669
568
else
670
569
{
671
- if ( xStart > - 1 && xEnd - xStart > minEndLength )
570
+ if ( xStart > int . MinValue && xEnd - xStart > minEndLength )
672
571
{
673
572
if ( i + 1 >= size )
674
573
return ;
675
574
676
- segments [ i ++ ] = new LineSegment ( xStart , xEnd , y ) ;
575
+ segments [ Interlocked . Add ( ref i , 1 ) ] = new LineSegment ( xStart , xEnd , y ) ;
677
576
}
678
577
679
578
xStart = x ;
680
579
}
681
580
xEnd = x ;
682
581
}
683
582
684
- if ( i < size && xStart > - 1 && xEnd - xStart > minEndLength )
583
+ if ( xStart > int . MinValue && xEnd - xStart > minEndLength )
685
584
{
686
- segments [ i ++ ] = new LineSegment ( xStart , xEnd , y ) ;
585
+ segments [ Interlocked . Add ( ref i , 1 ) ] = new LineSegment ( xStart , xEnd , y ) ;
687
586
}
688
587
}
689
588
_ = Parallel . For ( area . Top , area . Height , body ) ;
0 commit comments