Skip to content

Commit 0e97b8f

Browse files
committed
refactor(skyblock): replace threading with tick-based scheduling for AntiAFK
- Remove explicit java.lang.Thread usage to prevent PolyglotEngineException and context access issues. - Implement tick-based delays for unsneaking and GUI interaction. - Use 'processingActionUntil' timestamp to debounce repetitive title packets instead of thread locks.
1 parent 2109cca commit 0e97b8f

File tree

1 file changed

+80
-99
lines changed

1 file changed

+80
-99
lines changed

src/skyblock/AntiAFK.ts

Lines changed: 80 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)