@@ -27,10 +27,10 @@ export class AntiAFK {
2727
2828 private onActivityChange ?: ( active : boolean ) => void ;
2929
30- // Queue system
31- private actionQueue : string [ ] = [ ] ;
32- private isProcessingQueue = false ;
33- private processingThread : any = null ; // Java Thread
30+ // State management for tick-based logic
31+ private processingActionUntil = 0 ;
32+ private unsneakAt = 0 ;
33+ private checkScreenAt = 0 ;
3434
3535 constructor ( onActivityChange ?: ( active : boolean ) => void ) {
3636 this . onActivityChange = onActivityChange ;
@@ -56,17 +56,20 @@ export class AntiAFK {
5656
5757 private onTitleEvent ( event : any ) {
5858 if ( ! this . config . enabled ) return ;
59- // event.message is an IChatComponent, check docs if getString() is correct.
60- // Usually getString() or getUnformattedText() work.
59+
60+ // If we are already busy processing a command (waiting for delay), ignore spam
61+ if ( this . processingActionUntil > Date . now ( ) ) return ;
62+
6163 const text = event . message ? event . message . getString ( ) : '' ;
6264 if ( ! text ) return ;
6365
6466 const lowerText = text . toLowerCase ( ) ;
65- // If we are already active, we process everything. If not, we only process triggers.
67+
68+ // If we are NOT active, we only listen for triggers.
69+ // If we ARE active, we listen for everything (but only one at a time due to flag).
6670 if ( ! this . isActive && ! this . isRelevantTitle ( lowerText ) ) return ;
6771
68- this . actionQueue . push ( text ) ;
69- this . processQueue ( ) ;
72+ this . processAction ( text ) ;
7073 }
7174
7275 private isRelevantTitle ( lowerText : string ) : boolean {
@@ -79,93 +82,8 @@ export class AntiAFK {
7982 ) ;
8083 }
8184
82- private processQueue ( ) {
83- if ( this . isProcessingQueue ) return ;
84- if ( this . actionQueue . length === 0 ) return ;
85-
86- this . isProcessingQueue = true ;
87-
88- this . processingThread = new ( Packages . java . lang . Thread as any ) ( ( ) => {
89- try {
90- while ( this . actionQueue . length > 0 ) {
91- const text = this . actionQueue . shift ( ) ;
92- if ( text ) this . onTitle ( text ) ;
93- // Small delay between actions to prevent overlapping inputs
94- Client . waitTick ( 2 ) ;
95- }
96- } catch ( e ) {
97- Chat . log ( '§cAntiAFK Thread Error: ' + e ) ;
98- } finally {
99- this . isProcessingQueue = false ;
100- this . processingThread = null ;
101- }
102- } ) ;
103- this . processingThread . start ( ) ;
104- }
105-
106- private setActive ( active : boolean ) {
107- if ( this . isActive === active ) return ;
108- this . isActive = active ;
109- if ( this . onActivityChange ) {
110- this . onActivityChange ( active ) ;
111- }
112- if ( ! active ) {
113- Chat . log ( '§aAntiAFK: §7Check finished/timed out.' ) ;
114- }
115- }
116-
117- private onTick ( event : Events . Tick ) {
118- if ( ! this . isActive ) return ;
119- // 10 seconds timeout
120- if ( Date . now ( ) - this . lastTitleTime > 10000 ) {
121- this . setActive ( false ) ;
122- this . actionQueue = [ ] ; // Clear queue on timeout
123- }
124- }
125-
126- private saveConfig ( ) {
127- Config . writeConfig ( this . configPath , this . config , this . scriptId ) ;
128- }
129-
130- private onOpenScreen ( event : Events . OpenScreen ) {
131- if ( ! this . config . enabled ) return ;
132-
133- // Run logic in a thread because we use waitTick/sleep
134- new ( Packages . java . lang . Thread as any ) ( ( ) => {
135- try {
136- this . handleOpenScreenLogic ( event ) ;
137- } catch ( e ) {
138- Chat . log ( '§cAntiAFK Screen Error: ' + e ) ;
139- }
140- } ) . start ( ) ;
141- }
142-
143- private handleOpenScreenLogic ( event : Events . OpenScreen ) {
144- // Wait a bit for GUI to populate
145- Client . waitTick ( 5 ) ;
146-
147- if ( ! Hud . getOpenScreen ( ) ) return ;
148- if ( ! Player . getPlayer ( ) ) return ;
149-
150- const inv = Player . openInventory ( ) ;
151- if ( ! inv ) return ;
152-
153- const title = inv . getRawContainer ( ) . getTitleText ( ) ;
154- if ( ! title || ! title . toString ( ) . includes ( 'Activity Check' ) ) return ;
155-
156- try {
157- inv . click ( this . config . triggerSlot ) ;
158- this . lastTitleTime = Date . now ( ) ;
159- this . setActive ( true ) ;
160- Chat . log ( '§aAntiAFK: §7Clicking start slot...' ) ;
161- } catch ( e ) {
162- Chat . log ( '§cAntiAFK Error clicking slot: ' + e ) ;
163- }
164- }
165-
166- private onTitle ( text : string ) {
167- const textStr = text . trim ( ) ;
168- const lowerText = textStr . toLowerCase ( ) ;
85+ private processAction ( text : string ) {
86+ const lowerText = text . toLowerCase ( ) ;
16987
17088 // Update activity timestamp
17189 this . lastTitleTime = Date . now ( ) ;
@@ -175,6 +93,7 @@ export class AntiAFK {
17593 if ( ! player ) return ;
17694
17795 let matched = false ;
96+ let actionDuration = 500 ; // Default 500ms delay (10 ticks)
17897
17998 if ( lowerText . includes ( 'look left' ) ) {
18099 Chat . log ( '§aAntiAFK: §7Looking LEFT' ) ;
@@ -201,8 +120,7 @@ export class AntiAFK {
201120 } else if ( lowerText . includes ( 'sneak' ) ) {
202121 Chat . log ( '§aAntiAFK: §7Sneaking' ) ;
203122 this . keys . sneak . set ( true ) ;
204- Client . waitTick ( 10 ) ;
205- this . keys . sneak . set ( false ) ;
123+ this . unsneakAt = Date . now ( ) + 500 ; // Schedule unsneak
206124 matched = true ;
207125 } else if ( lowerText . includes ( 'punch' ) || lowerText . includes ( 'attack' ) ) {
208126 Chat . log ( '§aAntiAFK: §7Punching' ) ;
@@ -211,7 +129,70 @@ export class AntiAFK {
211129 }
212130
213131 if ( matched ) {
214- Client . waitTick ( 10 ) ;
132+ this . processingActionUntil = Date . now ( ) + actionDuration ;
133+ }
134+ }
135+
136+ private setActive ( active : boolean ) {
137+ if ( this . isActive === active ) return ;
138+ this . isActive = active ;
139+ if ( this . onActivityChange ) {
140+ this . onActivityChange ( active ) ;
141+ }
142+ if ( ! active ) {
143+ Chat . log ( '§aAntiAFK: §7Check finished/timed out.' ) ;
144+ }
145+ }
146+
147+ private onTick ( event : Events . Tick ) {
148+ if ( this . isActive ) {
149+ // 10 seconds timeout
150+ if ( Date . now ( ) - this . lastTitleTime > 10000 ) {
151+ this . setActive ( false ) ;
152+ this . processingActionUntil = 0 ;
153+ }
154+ }
155+
156+ // Handle Delayed Unsneak
157+ if ( this . unsneakAt > 0 && Date . now ( ) > this . unsneakAt ) {
158+ this . keys . sneak . set ( false ) ;
159+ this . unsneakAt = 0 ;
160+ }
161+
162+ // Handle Delayed Screen Check
163+ if ( this . checkScreenAt > 0 && Date . now ( ) > this . checkScreenAt ) {
164+ this . handleOpenScreenLogic ( ) ;
165+ this . checkScreenAt = 0 ;
166+ }
167+ }
168+
169+ private saveConfig ( ) {
170+ Config . writeConfig ( this . configPath , this . config , this . scriptId ) ;
171+ }
172+
173+ private onOpenScreen ( event : Events . OpenScreen ) {
174+ if ( ! this . config . enabled ) return ;
175+ // Schedule check for 250ms (5 ticks) later
176+ this . checkScreenAt = Date . now ( ) + 250 ;
177+ }
178+
179+ private handleOpenScreenLogic ( ) {
180+ if ( ! Hud . getOpenScreen ( ) ) return ;
181+ if ( ! Player . getPlayer ( ) ) return ;
182+
183+ const inv = Player . openInventory ( ) ;
184+ if ( ! inv ) return ;
185+
186+ const title = inv . getRawContainer ( ) . getTitleText ( ) ;
187+ if ( ! title || ! title . toString ( ) . includes ( 'Activity Check' ) ) return ;
188+
189+ try {
190+ inv . click ( this . config . triggerSlot ) ;
191+ this . lastTitleTime = Date . now ( ) ;
192+ this . setActive ( true ) ;
193+ Chat . log ( '§aAntiAFK: §7Clicking start slot...' ) ;
194+ } catch ( e ) {
195+ Chat . log ( '§cAntiAFK Error clicking slot: ' + e ) ;
215196 }
216197 }
217198
0 commit comments