|
| 1 | +import Config from '../libs/Config'; |
| 2 | +import { CommandManager } from '../libs/CommandBuilderWrapper'; |
| 3 | +import { BaritoneAPI } from '../libs/BaritoneAPIProvider'; |
| 4 | +import { Key } from '../libs/KeyManager'; |
| 5 | + |
| 6 | +enum SellState { |
| 7 | + IDLE, |
| 8 | + WAIT_FOR_SCREEN, |
| 9 | + CLICK_49, |
| 10 | + WAIT_AFTER_49, |
| 11 | + CLICK_12, |
| 12 | + WAIT_AFTER_12, |
| 13 | + CLOSE, |
| 14 | +} |
| 15 | + |
| 16 | +interface PrisonUtilsConfig { |
| 17 | + enabled: boolean; |
| 18 | + delaySeconds: number; |
| 19 | +} |
| 20 | + |
| 21 | +export class PrisonUtils { |
| 22 | + private readonly configPath = './config/jayc331-config.json'; |
| 23 | + private readonly scriptId = 'prisonUtils'; |
| 24 | + private readonly defaultConfig: PrisonUtilsConfig = { |
| 25 | + enabled: false, |
| 26 | + delaySeconds: 120, |
| 27 | + }; |
| 28 | + |
| 29 | + private config: PrisonUtilsConfig; |
| 30 | + private state: SellState = SellState.IDLE; |
| 31 | + private stateTickCounter = 0; |
| 32 | + private lastSellTime = 0; |
| 33 | + |
| 34 | + private readonly lmb = new Key('key.mouse.left'); |
| 35 | + private builderProcess: any; |
| 36 | + |
| 37 | + private isScreenOpen = false; |
| 38 | + private resumeAt = 0; |
| 39 | + private resumePending = false; |
| 40 | + |
| 41 | + constructor() { |
| 42 | + this.config = Config.readConfig(this.configPath, this.defaultConfig, this.scriptId); |
| 43 | + // Get the builder process safely |
| 44 | + try { |
| 45 | + const provider = BaritoneAPI.getProvider(); |
| 46 | + const primary = provider.getPrimaryBaritone(); |
| 47 | + this.builderProcess = primary.getBuilderProcess(); |
| 48 | + } catch (e) { |
| 49 | + Chat.log('§cPrisonUtils: Could not load Baritone BuilderProcess.'); |
| 50 | + } |
| 51 | + |
| 52 | + this.registerListeners(); |
| 53 | + this.registerCommands(); |
| 54 | + } |
| 55 | + |
| 56 | + private registerListeners() { |
| 57 | + JsMacros.on( |
| 58 | + 'Tick', |
| 59 | + JavaWrapper.methodToJava(() => this.onTick()) |
| 60 | + ); |
| 61 | + JsMacros.on( |
| 62 | + 'OpenScreen', |
| 63 | + JavaWrapper.methodToJava((event) => this.onOpenScreen(event)) |
| 64 | + ); |
| 65 | + } |
| 66 | + |
| 67 | + private onOpenScreen(event: any) { |
| 68 | + if (!this.config.enabled) return; |
| 69 | + |
| 70 | + // If a screen opens, pause baritone and release mouse |
| 71 | + if (this.builderProcess && this.builderProcess.isActive()) { |
| 72 | + this.builderProcess.pause(); |
| 73 | + this.lmb.set(false); |
| 74 | + } |
| 75 | + |
| 76 | + this.isScreenOpen = true; |
| 77 | + this.resumePending = false; // Cancel any pending resume |
| 78 | + } |
| 79 | + |
| 80 | + private onTick() { |
| 81 | + if (!this.config.enabled) { |
| 82 | + // Ensure key is released if disabled |
| 83 | + if (this.lmb.pressed) this.lmb.set(false); |
| 84 | + return; |
| 85 | + } |
| 86 | + |
| 87 | + // Allow input even if "paused" (reflection hack from original script) |
| 88 | + try { |
| 89 | + const mc = Client.getMinecraft(); |
| 90 | + const field = Reflection.getDeclaredField(mc.getClass(), 'field_1695'); |
| 91 | + field.setAccessible(true); |
| 92 | + field.set(mc, true); |
| 93 | + } catch (e) { |
| 94 | + // Ignore if field doesn't exist (version diff) |
| 95 | + } |
| 96 | + |
| 97 | + const currentScreen = Hud.getOpenScreen(); |
| 98 | + |
| 99 | + // Detect Screen Close |
| 100 | + if (this.isScreenOpen && !currentScreen) { |
| 101 | + this.isScreenOpen = false; |
| 102 | + // Screen just closed. Schedule resume. |
| 103 | + // Original script waits 20 ticks (approx 1000ms) |
| 104 | + this.resumeAt = Date.now() + 500; |
| 105 | + this.resumePending = true; |
| 106 | + } |
| 107 | + |
| 108 | + // Handle Resume |
| 109 | + if (this.resumePending && Date.now() > this.resumeAt) { |
| 110 | + this.resumePending = false; |
| 111 | + if (this.builderProcess) { |
| 112 | + this.builderProcess.resume(); |
| 113 | + if (this.builderProcess.isActive()) { |
| 114 | + this.lmb.set(true); |
| 115 | + } |
| 116 | + } |
| 117 | + } |
| 118 | + |
| 119 | + // Periodic Sell / Mining Logic |
| 120 | + if (this.builderProcess && this.builderProcess.isActive()) { |
| 121 | + // If not in a menu, hold LMB to mine (if active) |
| 122 | + if (!currentScreen && !this.resumePending) { |
| 123 | + this.lmb.set(true); |
| 124 | + } |
| 125 | + |
| 126 | + // Check for Auto Sell |
| 127 | + if (this.state === SellState.IDLE && !currentScreen) { |
| 128 | + const now = Date.now(); |
| 129 | + if (now - this.lastSellTime > this.config.delaySeconds * 1000) { |
| 130 | + this.startSellSequence(); |
| 131 | + } |
| 132 | + } |
| 133 | + } |
| 134 | + |
| 135 | + // Handle Sell State Machine |
| 136 | + if (this.state !== SellState.IDLE) { |
| 137 | + this.handleSellState(currentScreen); |
| 138 | + } |
| 139 | + } |
| 140 | + |
| 141 | + private startSellSequence() { |
| 142 | + Chat.log('§aPrisonUtils: §7Selling...'); |
| 143 | + Chat.say('/sell'); |
| 144 | + this.state = SellState.WAIT_FOR_SCREEN; |
| 145 | + this.stateTickCounter = 0; |
| 146 | + this.lastSellTime = Date.now(); |
| 147 | + } |
| 148 | + |
| 149 | + private handleSellState(currentScreen: any) { |
| 150 | + this.stateTickCounter++; |
| 151 | + const TICK_DELAY = 10; // Original used 10 ticks ~ 500ms |
| 152 | + |
| 153 | + switch (this.state) { |
| 154 | + case SellState.WAIT_FOR_SCREEN: |
| 155 | + if (currentScreen) { |
| 156 | + this.state = SellState.CLICK_49; |
| 157 | + this.stateTickCounter = 0; |
| 158 | + } else if (this.stateTickCounter > 40) { // 2 seconds timeout |
| 159 | + this.state = SellState.IDLE; // Failed to open |
| 160 | + } |
| 161 | + break; |
| 162 | + |
| 163 | + case SellState.CLICK_49: |
| 164 | + if (this.stateTickCounter >= TICK_DELAY) { |
| 165 | + this.clickSlot(49); |
| 166 | + this.state = SellState.WAIT_AFTER_49; |
| 167 | + this.stateTickCounter = 0; |
| 168 | + } |
| 169 | + break; |
| 170 | + |
| 171 | + case SellState.WAIT_AFTER_49: |
| 172 | + if (this.stateTickCounter >= TICK_DELAY) { |
| 173 | + this.state = SellState.CLICK_12; |
| 174 | + this.stateTickCounter = 0; |
| 175 | + } |
| 176 | + break; |
| 177 | + |
| 178 | + case SellState.CLICK_12: |
| 179 | + if (this.stateTickCounter >= 0) { // No extra delay needed? Original: wait 10 ticks BEFORE clicking 12 (handled by WAIT_AFTER_49) |
| 180 | + this.clickSlot(12); |
| 181 | + this.state = SellState.WAIT_AFTER_12; |
| 182 | + this.stateTickCounter = 0; |
| 183 | + } |
| 184 | + break; |
| 185 | + |
| 186 | + case SellState.WAIT_AFTER_12: |
| 187 | + if (this.stateTickCounter >= TICK_DELAY) { |
| 188 | + this.state = SellState.CLOSE; |
| 189 | + } |
| 190 | + break; |
| 191 | + |
| 192 | + case SellState.CLOSE: |
| 193 | + if (currentScreen) { |
| 194 | + const inv = Player.openInventory(); |
| 195 | + if (inv) inv.close(); |
| 196 | + } |
| 197 | + this.state = SellState.IDLE; |
| 198 | + break; |
| 199 | + } |
| 200 | + } |
| 201 | + |
| 202 | + private clickSlot(slot: number) { |
| 203 | + const inv = Player.openInventory(); |
| 204 | + if (inv) { |
| 205 | + inv.click(slot); |
| 206 | + } |
| 207 | + } |
| 208 | + |
| 209 | + private saveConfig() { |
| 210 | + Config.writeConfig(this.configPath, this.config, this.scriptId); |
| 211 | + } |
| 212 | + |
| 213 | + private registerCommands() { |
| 214 | + const cmd = CommandManager.create('prisonutils'); |
| 215 | + |
| 216 | + cmd.literal('toggle').executes(() => { |
| 217 | + this.config.enabled = !this.config.enabled; |
| 218 | + this.saveConfig(); |
| 219 | + Chat.log(`§7PrisonUtils is now ${this.config.enabled ? '§aENABLED' : '§cDISABLED'}`); |
| 220 | + if (!this.config.enabled) { |
| 221 | + this.lmb.set(false); |
| 222 | + this.state = SellState.IDLE; |
| 223 | + } |
| 224 | + }); |
| 225 | + |
| 226 | + cmd.literal('delay') |
| 227 | + .argument('seconds', 'int') |
| 228 | + .executes((ctx) => { |
| 229 | + const seconds = ctx.getArg('seconds'); |
| 230 | + this.config.delaySeconds = seconds; |
| 231 | + this.saveConfig(); |
| 232 | + Chat.log(`§7PrisonUtils sell delay set to §a${seconds}s`); |
| 233 | + }); |
| 234 | + |
| 235 | + cmd.register(); |
| 236 | + } |
| 237 | +} |
0 commit comments