|
| 1 | + |
| 2 | +import Config from '../libs/Config'; |
| 3 | +import { Key } from '../libs/KeyManager'; |
| 4 | +import { CommandManager } from '../libs/CommandBuilderWrapper'; |
| 5 | + |
| 6 | +interface AntiAFKConfig { |
| 7 | + enabled: boolean; |
| 8 | +} |
| 9 | + |
| 10 | +export class AntiAFK { |
| 11 | + private readonly configPath = './config/jayc331-antiafk.json'; |
| 12 | + private readonly scriptId = 'antiafk'; |
| 13 | + private readonly defaultConfig: AntiAFKConfig = { |
| 14 | + enabled: true, |
| 15 | + }; |
| 16 | + |
| 17 | + private config: AntiAFKConfig; |
| 18 | + private readonly triggerSlot = 15; |
| 19 | + private isActive = false; |
| 20 | + private lastTitleTime = 0; |
| 21 | + |
| 22 | + private readonly keys = { |
| 23 | + jump: new Key('key.keyboard.space'), |
| 24 | + sneak: new Key('key.keyboard.left.shift'), |
| 25 | + attack: new Key('key.mouse.left'), |
| 26 | + }; |
| 27 | + |
| 28 | + private onActivityChange?: (active: boolean) => void; |
| 29 | + |
| 30 | + constructor(onActivityChange?: (active: boolean) => void) { |
| 31 | + this.onActivityChange = onActivityChange; |
| 32 | + this.config = Config.readConfig(this.configPath, this.defaultConfig, this.scriptId); |
| 33 | + this.registerListeners(); |
| 34 | + this.registerCommands(); |
| 35 | + } |
| 36 | + |
| 37 | + private registerListeners() { |
| 38 | + JsMacros.on('OpenScreen', JavaWrapper.methodToJava((event) => this.onOpenScreen(event))); |
| 39 | + JsMacros.on('Title', JavaWrapper.methodToJava((event) => this.onTitle(event))); |
| 40 | + JsMacros.on('Tick', JavaWrapper.methodToJava(() => this.onTick())); |
| 41 | + } |
| 42 | + |
| 43 | + private setActive(active: boolean) { |
| 44 | + if (this.isActive === active) return; |
| 45 | + this.isActive = active; |
| 46 | + if (this.onActivityChange) { |
| 47 | + this.onActivityChange(active); |
| 48 | + } |
| 49 | + if (!active) { |
| 50 | + Chat.log('§aAntiAFK: §7Check finished/timed out.'); |
| 51 | + } |
| 52 | + } |
| 53 | + |
| 54 | + private onTick() { |
| 55 | + if (!this.isActive) return; |
| 56 | + // 5 seconds timeout |
| 57 | + if (Date.now() - this.lastTitleTime > 5000) { |
| 58 | + this.setActive(false); |
| 59 | + } |
| 60 | + } |
| 61 | + |
| 62 | + private saveConfig() { |
| 63 | + Config.writeConfig(this.configPath, this.config, this.scriptId); |
| 64 | + } |
| 65 | + |
| 66 | + private onOpenScreen(event: Events.OpenScreen) { |
| 67 | + if (!this.config.enabled) return; |
| 68 | + |
| 69 | + // We could add a check for specific GUI title if known, but for now rely on slot click |
| 70 | + // Use a small delay to ensure the GUI is fully ready and item is present |
| 71 | + const screen = event.screen; |
| 72 | + // Note: strict typings might be tricky with screen, check actual API if needed. |
| 73 | + // But usually we can access inventory from player context once screen is open. |
| 74 | + |
| 75 | + // We wait a bit then click |
| 76 | + Client.waitTick(5); |
| 77 | + |
| 78 | + // Check if screen is still open (user might have closed it quickly) |
| 79 | + if (!Hud.getOpenScreen()) return; |
| 80 | + |
| 81 | + // Check player to avoid NPE |
| 82 | + if (!Player.getPlayer()) return; |
| 83 | + |
| 84 | + const inv = Player.openInventory(); |
| 85 | + if (!inv) return; |
| 86 | + |
| 87 | + // Filter for "Activity Check" GUI |
| 88 | + if (!inv.getContainerTitle().includes('Activity Check')) return; |
| 89 | + |
| 90 | + // We assume if the GUI opens and we are enabled, we try to start the check. |
| 91 | + // In a real scenario, we should probably check the container name or item name. |
| 92 | + // But based on prompt: "A gui is opened containing an item... click to begin" |
| 93 | + |
| 94 | + // Double check if slot is valid for this inventory? |
| 95 | + // inv.getSlot(this.config.triggerSlot) might throw or return null? |
| 96 | + |
| 97 | + try { |
| 98 | + inv.click(this.triggerSlot); |
| 99 | + this.lastTitleTime = Date.now(); // Set time before activating to avoid instant timeout |
| 100 | + this.setActive(true); |
| 101 | + Chat.log('§aAntiAFK: §7Clicking start slot...'); |
| 102 | + } catch (e) { |
| 103 | + Chat.log('§cAntiAFK Error clicking slot: ' + e); |
| 104 | + } |
| 105 | + } |
| 106 | + |
| 107 | + private onTitle(event: Events.Title) { |
| 108 | + if (!this.config.enabled) return; |
| 109 | + // If we haven't clicked start recently, maybe we shouldn't auto-react? |
| 110 | + // But the prompt implies "a series of titles appear... macro should follow". |
| 111 | + // So even if we didn't trigger the start (maybe user did), we should help if enabled. |
| 112 | + |
| 113 | + if (!event.message) return; |
| 114 | + const text = event.message.getString().trim(); |
| 115 | + const lowerText = text.toLowerCase(); |
| 116 | + |
| 117 | + // If we receive a title, and we are (or should be) active, update time |
| 118 | + if (this.isActive || lowerText.includes('look') || lowerText.includes('jump') || lowerText.includes('sneak') || lowerText.includes('punch')) { |
| 119 | + this.lastTitleTime = Date.now(); |
| 120 | + if (!this.isActive) this.setActive(true); |
| 121 | + } |
| 122 | + |
| 123 | + // Logging for debug |
| 124 | + // Chat.log('§7Title: ' + text); |
| 125 | + |
| 126 | + const player = Player.getPlayer(); |
| 127 | + if (!player) return; |
| 128 | + |
| 129 | + if (lowerText.includes('look left')) { |
| 130 | + Chat.log('§aAntiAFK: §7Looking LEFT'); |
| 131 | + const yaw = player.getYaw(); |
| 132 | + player.lookAt(yaw - 90, player.getPitch()); |
| 133 | + } else if (lowerText.includes('look right')) { |
| 134 | + Chat.log('§aAntiAFK: §7Looking RIGHT'); |
| 135 | + const yaw = player.getYaw(); |
| 136 | + player.lookAt(yaw + 90, player.getPitch()); |
| 137 | + } else if (lowerText.includes('look down')) { |
| 138 | + Chat.log('§aAntiAFK: §7Looking DOWN'); |
| 139 | + player.lookAt(player.getYaw(), 90); |
| 140 | + } else if (lowerText.includes('look up')) { |
| 141 | + Chat.log('§aAntiAFK: §7Looking UP'); |
| 142 | + player.lookAt(player.getYaw(), -90); |
| 143 | + } else if (lowerText.includes('jump')) { |
| 144 | + Chat.log('§aAntiAFK: §7Jumping'); |
| 145 | + this.keys.jump.click(); |
| 146 | + } else if (lowerText.includes('sneak')) { |
| 147 | + Chat.log('§aAntiAFK: §7Sneaking'); |
| 148 | + this.keys.sneak.set(true); |
| 149 | + Client.waitTick(10); |
| 150 | + this.keys.sneak.set(false); |
| 151 | + } else if (lowerText.includes('punch') || lowerText.includes('attack')) { |
| 152 | + Chat.log('§aAntiAFK: §7Punching'); |
| 153 | + this.keys.attack.click(); |
| 154 | + } |
| 155 | + } |
| 156 | + |
| 157 | + private registerCommands() { |
| 158 | + const cmd = CommandManager.create('antiafk'); |
| 159 | + |
| 160 | + cmd.literal('toggle') |
| 161 | + .executes(() => { |
| 162 | + this.config.enabled = !this.config.enabled; |
| 163 | + this.saveConfig(); |
| 164 | + Chat.log(`§7AntiAFK is now ${this.config.enabled ? '§aENABLED' : '§cDISABLED'}`); |
| 165 | + }); |
| 166 | + |
| 167 | + cmd.register(); |
| 168 | + } |
| 169 | +} |
0 commit comments