package bin; import lib.turtle.Helper; import kernel.turtle.TurtleMutex; import kernel.turtle.Turtle; import lib.turtle.InvManager; import lib.CLIAppBase; using tink.CoreApi; @:build(macros.Binstore.includeBin("Turtle", ["turtle", "t"])) class TurtleCtl extends CLIAppBase { public function new() { registerAsyncSubcommand("f", (args) -> { return asynPerform(Turtle.forward, args.getInt("times") ?? 1); }, [Optional(Int("times"))]); registerAsyncSubcommand("b", (args) -> { return asynPerform(Turtle.back, args.getInt("times") ?? 1); }, [Optional(Int("times"))]); registerAsyncSubcommand("l", (args) -> { return asynPerform(Turtle.turnLeft, args.getInt("times") ?? 1); }, [Optional(Int("times"))]); registerAsyncSubcommand("r", (args) -> { return asynPerform(Turtle.turnRight, args.getInt("times") ?? 1); }, [Optional(Int("times"))]); registerAsyncSubcommand("u", (args) -> { return asynPerform(Turtle.up, args.getInt("times") ?? 1); }, [Optional(Int("times"))]); registerAsyncSubcommand("d", (args) -> { return asynPerform(Turtle.down, args.getInt("times") ?? 1); }, [Optional(Int("times"))]); registerAsyncSubcommand("defrag", (args) -> { return asynPerform(() -> { // TODO: when defrag can fail return that error InvManager.defrag(); return Success(null); }, 1); }); registerSyncSubcommand("fuel", (args) -> { var lvl = Turtle.getFuelLevel(); var limit = Turtle.getFuelLimit(); handle.writeLine('${lvl}/${limit} (${(lvl / limit) * 100}%)'); return true; }); registerAsyncSubcommand("fuel-sources", (args) -> { return asynPerform(() -> { var items = InvManager.getCombustableItems(); for (i in items) { handle.writeLine(i); } return Success(null); }, 1); }); registerAsyncSubcommand("refuel", (args) -> { var refuelTo = Turtle.getFuelLimit(); var arg = args.getString("to"); if (arg != null) { var split = arg.split("%"); if (split.length > 1) { // Is percentage var parsed = Std.parseFloat(split[0]); if (parsed == null) { handle.writeLine("Failed to parse ammount"); return Future.sync(false); } refuelTo = Math.round(refuelTo * (parsed / 100)); } else { // Is absolute var parsed = Std.parseInt(arg); if (parsed == null) { handle.writeLine("Failed to parse ammount"); return Future.sync(false); } refuelTo = parsed; } } return asynPerform(() -> { InvManager.refuel(refuelTo, []); return Success(null); }, 1); }, [Optional(String("to"))]); registerAsyncSubcommand("dig", (args) -> { var direction = args.getString("direction"); switch (direction) { case "front" | "f": return asynPerform(() -> Turtle.dig(Front), 1); case "top" | "t" | "up" | "u": return asynPerform(() -> Turtle.dig(Up), 1); case "bot" | "bottom" | "b" | "down" | "d": return asynPerform(() -> Turtle.dig(Down), 1); default: return Future.sync(false); } }, [String("direction")]); registerAsyncSubcommand("tunnel", (args) -> { var len = args.getInt("length"); return asynPerform(Helper.combine.bind([Turtle.digEmpty.bind(Front), Turtle.forward, Turtle.digEmpty.bind(Up)]), len); }, [Int("length")]); } private function asynPerform(op:Void->Outcome, times:Int):Future { return new Future((wakeup) -> { if (times == 0) { wakeup(false); return null; } if (!Turtle.isTurtle()) { handle.write("This is not a turtle!"); wakeup(false); return null; } if (!handle.claimTurtleMutex()) { handle.writeLine("Failed to claim mutex"); wakeup(false); return null; } TurtleMutex.runInTThread(() -> { for (i in 0...times) { switch op() { case Success(_): case Failure(failure): handle.writeLine('Failed: $failure'); wakeup(false); return; } } wakeup(true); }); return null; }); } }