1
+ using Dalamud . Game ;
2
+ using Dalamud . Logging ;
3
+ using System ;
4
+ using System . Collections . Generic ;
5
+ using System . Runtime . CompilerServices ;
6
+
7
+ namespace Brio . Game . Core ;
8
+
9
+ public class FrameworkUtils : IDisposable
10
+ {
11
+ private List < DeferredTask > _deferredTasks = new ( ) ;
12
+
13
+ public FrameworkUtils ( )
14
+ {
15
+ Dalamud . Framework . Update += Framework_Update ;
16
+ }
17
+
18
+ private void Framework_Update ( Framework framework )
19
+ {
20
+ TickTasks ( ) ;
21
+ }
22
+
23
+ public void RunDeferred (
24
+ Action < bool > action ,
25
+ int delay = 0 ,
26
+ [ CallerFilePath ] string callerFile = "" ,
27
+ [ CallerLineNumber ] int callerLine = 0 ,
28
+ [ CallerMemberName ] string callerMember = ""
29
+ )
30
+ {
31
+ var newTask = new DeferredTask ( )
32
+ {
33
+ ConditionAction = ( task ) => task . TickCount >= task . FrameTarget ,
34
+ CompleteAction = action ,
35
+ FrameTarget = delay ,
36
+ DebugPath = $ "{ callerFile } :{ callerLine } - { callerMember } "
37
+ } ;
38
+
39
+ _deferredTasks . Add ( newTask ) ;
40
+ }
41
+
42
+ public void RunUntilSatisfied (
43
+ Func < bool > condition ,
44
+ Action < bool > onSatisfied ,
45
+ int attempts = 0 ,
46
+ [ CallerFilePath ] string callerFile = "" ,
47
+ [ CallerLineNumber ] int callerLine = 0 ,
48
+ [ CallerMemberName ] string callerMember = ""
49
+ )
50
+ {
51
+ var newTask = new DeferredTask ( )
52
+ {
53
+ ConditionAction = ( _ ) => condition . Invoke ( ) ,
54
+ CompleteAction = onSatisfied . Invoke ,
55
+ FrameTarget = attempts ,
56
+ DebugPath = $ "{ callerFile } :{ callerLine } - { callerMember } "
57
+ } ;
58
+
59
+ _deferredTasks . Add ( newTask ) ;
60
+ }
61
+
62
+ public void Dispose ( )
63
+ {
64
+ Dalamud . Framework . Update -= Framework_Update ;
65
+ _deferredTasks . Clear ( ) ;
66
+ }
67
+
68
+ private void TickTasks ( )
69
+ {
70
+ for ( int i = 0 ; i < _deferredTasks . Count ; i ++ )
71
+ {
72
+ var task = _deferredTasks [ i ] ;
73
+ task . TickCount ++ ;
74
+
75
+ var conditionSatisfied = CheckTask ( task ) ;
76
+
77
+ if ( conditionSatisfied == true )
78
+ {
79
+ _deferredTasks . RemoveAt ( i -- ) ;
80
+ CompleteTask ( task , true ) ;
81
+ }
82
+ else if ( conditionSatisfied == null || task . FrameTarget <= task . TickCount )
83
+ {
84
+ if ( task . FrameTarget <= task . TickCount )
85
+ PluginLog . Warning ( $ "Task timed out. { task } ") ;
86
+
87
+ _deferredTasks . RemoveAt ( i -- ) ;
88
+ CompleteTask ( task , false ) ;
89
+ }
90
+ }
91
+ }
92
+
93
+ private bool ? CheckTask ( DeferredTask task )
94
+ {
95
+ try
96
+ {
97
+ return task . ConditionAction ( task ) ;
98
+ }
99
+ catch ( Exception ex )
100
+ {
101
+ PluginLog . Warning ( ex , $ "Exception running condition action. { task } ") ;
102
+ return null ;
103
+ }
104
+ }
105
+
106
+ private void CompleteTask ( DeferredTask task , bool success )
107
+ {
108
+ try
109
+ {
110
+ task . CompleteAction . Invoke ( success ) ;
111
+ } catch ( Exception ex )
112
+ {
113
+ PluginLog . Warning ( ex , $ "Exception running completion action. { task } ") ;
114
+ }
115
+ }
116
+ }
117
+
118
+ class DeferredTask
119
+ {
120
+ public Func < DeferredTask , bool > ConditionAction { get ; init ; } = null ! ;
121
+ public Action < bool > CompleteAction { get ; init ; } = null ! ;
122
+ public string DebugPath { get ; init ; } = null ! ;
123
+ public int FrameTarget { get ; init ; }
124
+ public int TickCount { get ; set ; } = - 1 ;
125
+
126
+ public override string ToString ( ) => $ "{ DebugPath } . T: { FrameTarget } C: { TickCount } ";
127
+ }
0 commit comments