1-
21import Config from '../libs/Config' ;
32import { Key } from '../libs/KeyManager' ;
43import { CommandManager } from '../libs/CommandBuilderWrapper' ;
54
65interface AntiAFKConfig {
76 enabled : boolean ;
7+ triggerSlot : number ;
88}
99
1010export class AntiAFK {
1111 private readonly configPath = './config/jayc331-antiafk.json' ;
1212 private readonly scriptId = 'antiafk' ;
1313 private readonly defaultConfig : AntiAFKConfig = {
1414 enabled : true ,
15+ triggerSlot : 15 ,
1516 } ;
1617
1718 private config : AntiAFKConfig ;
18- private readonly triggerSlot = 15 ;
1919 private isActive = false ;
2020 private lastTitleTime = 0 ;
2121
@@ -24,9 +24,14 @@ export class AntiAFK {
2424 sneak : new Key ( 'key.keyboard.left.shift' ) ,
2525 attack : new Key ( 'key.mouse.left' ) ,
2626 } ;
27-
27+
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
34+
3035 constructor ( onActivityChange ?: ( active : boolean ) => void ) {
3136 this . onActivityChange = onActivityChange ;
3237 this . config = Config . readConfig ( this . configPath , this . defaultConfig , this . scriptId ) ;
@@ -35,20 +40,69 @@ export class AntiAFK {
3540 }
3641
3742 private registerListeners ( ) {
38- JsMacros . on ( 'OpenScreen' , JavaWrapper . methodToJava ( ( event ) => this . onOpenScreen ( event ) ) ) ;
39- JsMacros . on ( 'Tick' , JavaWrapper . methodToJava ( ( event ) => this . onTick ( event ) ) ) ;
40- this . listenForTitle ( ) ;
43+ JsMacros . on (
44+ 'OpenScreen' ,
45+ JavaWrapper . methodToJava ( ( event ) => this . onOpenScreen ( event as Events . OpenScreen ) )
46+ ) ;
47+ JsMacros . on (
48+ 'Tick' ,
49+ JavaWrapper . methodToJava ( ( event ) => this . onTick ( event as Events . Tick ) )
50+ ) ;
51+ JsMacros . on (
52+ 'Title' ,
53+ JavaWrapper . methodToJava ( ( event ) => this . onTitleEvent ( event ) )
54+ ) ;
55+ }
56+
57+ private onTitleEvent ( event : any ) {
58+ if ( ! this . config . enabled ) return ;
59+ // event.message is an IChatComponent, check docs if getString() is correct.
60+ // Usually getString() or getUnformattedText() work.
61+ const text = event . message ? event . message . getString ( ) : '' ;
62+ if ( ! text ) return ;
63+
64+ const lowerText = text . toLowerCase ( ) ;
65+ // If we are already active, we process everything. If not, we only process triggers.
66+ if ( ! this . isActive && ! this . isRelevantTitle ( lowerText ) ) return ;
67+
68+ this . actionQueue . push ( text ) ;
69+ this . processQueue ( ) ;
70+ }
71+
72+ private isRelevantTitle ( lowerText : string ) : boolean {
73+ return (
74+ lowerText . includes ( 'look' ) ||
75+ lowerText . includes ( 'jump' ) ||
76+ lowerText . includes ( 'sneak' ) ||
77+ lowerText . includes ( 'punch' ) ||
78+ lowerText . includes ( 'attack' )
79+ ) ;
4180 }
4281
43- private listenForTitle ( ) {
44- JsMacros . once ( 'Title' , JavaWrapper . methodToJava ( ( event ) => {
45- new ( Packages . java . lang . Thread as any ) ( ( ) => {
46- this . onTitle ( event ) ;
47- this . listenForTitle ( ) ;
48- } ) . start ( ) ;
49- } ) ) ;
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 ( ) ;
50104 }
51-
105+
52106 private setActive ( active : boolean ) {
53107 if ( this . isActive === active ) return ;
54108 this . isActive = active ;
@@ -65,6 +119,7 @@ export class AntiAFK {
65119 // 10 seconds timeout
66120 if ( Date . now ( ) - this . lastTitleTime > 10000 ) {
67121 this . setActive ( false ) ;
122+ this . actionQueue = [ ] ; // Clear queue on timeout
68123 }
69124 }
70125
@@ -75,59 +130,46 @@ export class AntiAFK {
75130 private onOpenScreen ( event : Events . OpenScreen ) {
76131 if ( ! this . config . enabled ) return ;
77132
78- // We could add a check for specific GUI title if known, but for now rely on slot click
79- // Use a small delay to ensure the GUI is fully ready and item is present
80- const screen = event . screen ;
81- // Note: strict typings might be tricky with screen, check actual API if needed.
82- // But usually we can access inventory from player context once screen is open.
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+ }
83142
84- // We wait a bit then click
143+ private handleOpenScreenLogic ( event : Events . OpenScreen ) {
144+ // Wait a bit for GUI to populate
85145 Client . waitTick ( 5 ) ;
86-
87- // Check if screen is still open (user might have closed it quickly)
88- if ( ! Hud . getOpenScreen ( ) ) return ;
89146
90- // Check player to avoid NPE
147+ if ( ! Hud . getOpenScreen ( ) ) return ;
91148 if ( ! Player . getPlayer ( ) ) return ;
92-
149+
93150 const inv = Player . openInventory ( ) ;
94151 if ( ! inv ) return ;
95-
96- // Filter for "Activity Check" GUI
97- if ( ! inv . getRawContainer ( ) . getTitleText ( ) . includes ( 'Activity Check' ) ) return ;
98-
99- // We assume if the GUI opens and we are enabled, we try to start the check.
100- // In a real scenario, we should probably check the container name or item name.
101- // But based on prompt: "A gui is opened containing an item... click to begin"
102-
103- // Double check if slot is valid for this inventory?
104- // inv.getSlot(this.config.triggerSlot) might throw or return null?
105-
152+
153+ const title = inv . getRawContainer ( ) . getTitleText ( ) ;
154+ if ( ! title || ! title . toString ( ) . includes ( 'Activity Check' ) ) return ;
155+
106156 try {
107- inv . click ( this . triggerSlot ) ;
108- this . lastTitleTime = Date . now ( ) ; // Set time before activating to avoid instant timeout
157+ inv . click ( this . config . triggerSlot ) ;
158+ this . lastTitleTime = Date . now ( ) ;
109159 this . setActive ( true ) ;
110160 Chat . log ( '§aAntiAFK: §7Clicking start slot...' ) ;
111161 } catch ( e ) {
112162 Chat . log ( '§cAntiAFK Error clicking slot: ' + e ) ;
113163 }
114164 }
115165
116- private onTitle ( event : Events . Title ) {
117- if ( ! this . config . enabled ) return ;
118-
119- if ( ! event . message ) return ;
120- const text = event . message . getString ( ) . trim ( ) ;
121- const lowerText = text . toLowerCase ( ) ;
122-
123- // If we receive a title, and we are (or should be) active, update time
124- if ( this . isActive || lowerText . includes ( 'look' ) || lowerText . includes ( 'jump' ) || lowerText . includes ( 'sneak' ) || lowerText . includes ( 'punch' ) ) {
125- this . lastTitleTime = Date . now ( ) ;
126- if ( ! this . isActive ) this . setActive ( true ) ;
127- }
166+ private onTitle ( text : string ) {
167+ const textStr = text . trim ( ) ;
168+ const lowerText = textStr . toLowerCase ( ) ;
128169
129- // Logging for debug
130- // Chat.log('§7Title: ' + text);
170+ // Update activity timestamp
171+ this . lastTitleTime = Date . now ( ) ;
172+ if ( ! this . isActive ) this . setActive ( true ) ;
131173
132174 const player = Player . getPlayer ( ) ;
133175 if ( ! player ) return ;
@@ -140,30 +182,30 @@ export class AntiAFK {
140182 player . lookAt ( yaw - 90 , player . getPitch ( ) ) ;
141183 matched = true ;
142184 } else if ( lowerText . includes ( 'look right' ) ) {
143- Chat . log ( '§aAntiAFK: §7Looking RIGHT' ) ;
185+ Chat . log ( '§aAntiAFK: §7Looking RIGHT' ) ;
144186 const yaw = player . getYaw ( ) ;
145187 player . lookAt ( yaw + 90 , player . getPitch ( ) ) ;
146188 matched = true ;
147189 } else if ( lowerText . includes ( 'look down' ) ) {
148- Chat . log ( '§aAntiAFK: §7Looking DOWN' ) ;
190+ Chat . log ( '§aAntiAFK: §7Looking DOWN' ) ;
149191 player . lookAt ( player . getYaw ( ) , 90 ) ;
150192 matched = true ;
151193 } else if ( lowerText . includes ( 'look up' ) ) {
152- Chat . log ( '§aAntiAFK: §7Looking UP' ) ;
194+ Chat . log ( '§aAntiAFK: §7Looking UP' ) ;
153195 player . lookAt ( player . getYaw ( ) , - 90 ) ;
154196 matched = true ;
155197 } else if ( lowerText . includes ( 'jump' ) ) {
156- Chat . log ( '§aAntiAFK: §7Jumping' ) ;
198+ Chat . log ( '§aAntiAFK: §7Jumping' ) ;
157199 this . keys . jump . click ( ) ;
158200 matched = true ;
159201 } else if ( lowerText . includes ( 'sneak' ) ) {
160- Chat . log ( '§aAntiAFK: §7Sneaking' ) ;
202+ Chat . log ( '§aAntiAFK: §7Sneaking' ) ;
161203 this . keys . sneak . set ( true ) ;
162204 Client . waitTick ( 10 ) ;
163205 this . keys . sneak . set ( false ) ;
164206 matched = true ;
165207 } else if ( lowerText . includes ( 'punch' ) || lowerText . includes ( 'attack' ) ) {
166- Chat . log ( '§aAntiAFK: §7Punching' ) ;
208+ Chat . log ( '§aAntiAFK: §7Punching' ) ;
167209 this . keys . attack . click ( ) ;
168210 matched = true ;
169211 }
@@ -176,11 +218,20 @@ export class AntiAFK {
176218 private registerCommands ( ) {
177219 const cmd = CommandManager . create ( 'antiafk' ) ;
178220
179- cmd . literal ( 'toggle' )
180- . executes ( ( ) => {
181- this . config . enabled = ! this . config . enabled ;
221+ cmd . literal ( 'toggle' ) . executes ( ( ) => {
222+ this . config . enabled = ! this . config . enabled ;
223+ this . saveConfig ( ) ;
224+ Chat . log ( `§7AntiAFK is now ${ this . config . enabled ? '§aENABLED' : '§cDISABLED' } ` ) ;
225+ } ) ;
226+
227+ cmd . literal ( 'set' )
228+ . literal ( 'slot' )
229+ . argument ( 'slot' , 'int' )
230+ . executes ( ( ctx ) => {
231+ const slot = ctx . getArg ( 'slot' ) ;
232+ this . config . triggerSlot = slot ;
182233 this . saveConfig ( ) ;
183- Chat . log ( `§7AntiAFK is now ${ this . config . enabled ? '§aENABLED' : '§cDISABLED' } ` ) ;
234+ Chat . log ( `§7AntiAFK trigger slot set to §a ${ slot } ` ) ;
184235 } ) ;
185236
186237 cmd . register ( ) ;
0 commit comments