mirror of
https://github.com/SikongJueluo/cc-utils.git
synced 2025-11-05 03:37:50 +08:00
finish basic autocraft for create store
This commit is contained in:
120
src/autocraft/main.ts
Normal file
120
src/autocraft/main.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import { CraftManager } from "@/lib/CraftManager";
|
||||
import * as peripheralManager from "../lib/PeripheralManager";
|
||||
import { CCLog } from "@/lib/ccLog";
|
||||
|
||||
const log = new CCLog("autocraft.log");
|
||||
|
||||
const peripheralsRelativeSides = {
|
||||
packagesContainer: "minecraft:chest_10",
|
||||
itemsContainer: "minecraft:chest_9",
|
||||
packageExtractor: "create:packager_1",
|
||||
blockReader: "front",
|
||||
wiredModem: "back",
|
||||
};
|
||||
|
||||
function main() {
|
||||
const packagesContainer = peripheralManager.findByNameRequired(
|
||||
"inventory",
|
||||
peripheralsRelativeSides.packagesContainer,
|
||||
);
|
||||
|
||||
const itemsContainer = peripheralManager.findByNameRequired(
|
||||
"inventory",
|
||||
peripheralsRelativeSides.itemsContainer,
|
||||
);
|
||||
|
||||
const packageExtractor = peripheralManager.findByNameRequired(
|
||||
"inventory",
|
||||
peripheralsRelativeSides.packageExtractor,
|
||||
);
|
||||
|
||||
const blockReader = peripheralManager.findByNameRequired(
|
||||
"blockReader",
|
||||
peripheralsRelativeSides.blockReader,
|
||||
);
|
||||
|
||||
const wiredModem = peripheralManager.findByNameRequired(
|
||||
"wiredModem",
|
||||
peripheralsRelativeSides.wiredModem,
|
||||
);
|
||||
const turtleLocalName = wiredModem.getNameLocal();
|
||||
|
||||
const craftManager = new CraftManager(turtleLocalName);
|
||||
|
||||
let hasPackage = redstone.getInput("front");
|
||||
while (true) {
|
||||
if (!hasPackage) os.pullEvent("redstone");
|
||||
hasPackage = redstone.getInput("front");
|
||||
if (!hasPackage) {
|
||||
continue;
|
||||
}
|
||||
log.info(`Package detected`);
|
||||
|
||||
const itemsInfo = packagesContainer.list();
|
||||
for (const key in itemsInfo) {
|
||||
const slot = parseInt(key);
|
||||
const item = itemsInfo[slot];
|
||||
log.info(`${item.count}x ${item.name} in slot ${key}`);
|
||||
|
||||
// Get package NBT
|
||||
packagesContainer.pushItems(turtleLocalName, slot);
|
||||
const packageInfo = blockReader.getBlockData().Items[1];
|
||||
// log.info(textutils.serialise(packageInfo));
|
||||
|
||||
// Get recipe
|
||||
const packageRecipes = CraftManager.getPackageRecipe(packageInfo);
|
||||
|
||||
// No recipe, just extract package
|
||||
if (packageRecipes == undefined) {
|
||||
packageExtractor.pullItems(turtleLocalName, 1);
|
||||
log.info(`No recipe, just pass`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Extract package
|
||||
// log.info(`Get recipe ${textutils.serialise(recipe)}`);
|
||||
packageExtractor.pullItems(turtleLocalName, 1);
|
||||
|
||||
// Pull and craft multi recipe
|
||||
for (const recipe of packageRecipes) {
|
||||
let craftOutputItem: BlockItemDetailData | undefined = undefined;
|
||||
let restCraftCnt = recipe.Count;
|
||||
|
||||
do {
|
||||
// Clear workbench
|
||||
craftManager.pushAll(itemsContainer);
|
||||
|
||||
log.info(`Pull items according to a recipe`);
|
||||
const craftCnt = craftManager.pullItems(
|
||||
recipe,
|
||||
itemsContainer,
|
||||
restCraftCnt,
|
||||
);
|
||||
if (craftCnt == 0) break;
|
||||
craftManager.craft();
|
||||
log.info(`Craft ${craftCnt} times`);
|
||||
restCraftCnt -= craftCnt;
|
||||
|
||||
// Get output item
|
||||
craftOutputItem ??= blockReader.getBlockData().Items[1];
|
||||
} while (restCraftCnt > 0);
|
||||
|
||||
// Finally output
|
||||
if (restCraftCnt > 0) {
|
||||
log.warn(`Only craft ${recipe.Count - restCraftCnt} times`);
|
||||
} else {
|
||||
log.info(`Finish craft ${recipe.Count}x ${craftOutputItem?.id}`);
|
||||
}
|
||||
craftManager.pushAll(itemsContainer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
main();
|
||||
} catch (error: unknown) {
|
||||
log.error(textutils.serialise(error as object));
|
||||
} finally {
|
||||
log.close();
|
||||
}
|
||||
203
src/lib/CraftManager.ts
Normal file
203
src/lib/CraftManager.ts
Normal file
@@ -0,0 +1,203 @@
|
||||
import { CCLog } from "./ccLog";
|
||||
|
||||
const log = new CCLog("CraftManager.log");
|
||||
|
||||
// ComputerCraft Turtle inventory layout:
|
||||
// 1, 2, 3, 4
|
||||
// 5, 6, 7, 8
|
||||
// 9, 10, 11, 12
|
||||
// 13, 14, 15, 16
|
||||
|
||||
const TURTLE_SIZE = 16;
|
||||
// const CRAFT_SLOT_CNT = 9;
|
||||
const CRAFT_SLOT_TABLE: number[] = [1, 2, 3, 5, 6, 7, 9, 10, 11];
|
||||
// const REST_SLOT_CNT = 7;
|
||||
// const REST_SLOT_TABLE: number[] = [4, 8, 12, 13, 14, 15, 16];
|
||||
|
||||
interface CreatePackageTag {
|
||||
Items: {
|
||||
Items: {
|
||||
id: string;
|
||||
Count: number;
|
||||
Slot: number;
|
||||
}[];
|
||||
Size: number;
|
||||
};
|
||||
Fragment: {
|
||||
Index: number;
|
||||
OrderContext: {
|
||||
OrderedCrafts: {
|
||||
Pattern: {
|
||||
Entries: {
|
||||
Item: {
|
||||
id: string;
|
||||
Count: number;
|
||||
tag?: object;
|
||||
};
|
||||
Amount: number;
|
||||
}[];
|
||||
};
|
||||
Count: number;
|
||||
}[];
|
||||
OrderedStacks: {
|
||||
Entries: {
|
||||
Item: {
|
||||
id: string;
|
||||
Count: number;
|
||||
};
|
||||
Amount: number;
|
||||
}[];
|
||||
};
|
||||
};
|
||||
IsFinal: number;
|
||||
OrderId: number;
|
||||
LinkIndex: number;
|
||||
IsFinalLink: number;
|
||||
};
|
||||
Address: string;
|
||||
}
|
||||
|
||||
interface CraftRecipeItem {
|
||||
Item: {
|
||||
id: string;
|
||||
Count: number;
|
||||
};
|
||||
Amount: number;
|
||||
}
|
||||
|
||||
interface CraftRecipe {
|
||||
PatternEntries: Record<number, CraftRecipeItem>;
|
||||
Count: number;
|
||||
}
|
||||
|
||||
type CraftMode = "keep" | "keepProduct" | "keepIngredient";
|
||||
|
||||
class CraftManager {
|
||||
private localName: string;
|
||||
|
||||
constructor(modem: WiredModemPeripheral | string) {
|
||||
if (turtle == undefined) {
|
||||
throw new Error("Script must be run in a turtle computer");
|
||||
}
|
||||
|
||||
if (modem == undefined) {
|
||||
throw new Error("Please provide a valid modem");
|
||||
}
|
||||
|
||||
let name = "";
|
||||
if (typeof modem === "string") {
|
||||
name = modem;
|
||||
} else {
|
||||
if (peripheral.getType(modem) !== "modem") {
|
||||
throw new Error("Please provide a valid modem");
|
||||
}
|
||||
|
||||
name = modem.getNameLocal();
|
||||
if (name === null) {
|
||||
throw new Error("Please provide a valid modem");
|
||||
}
|
||||
}
|
||||
this.localName = name;
|
||||
// log.info(`Get turtle name : ${name}`);
|
||||
}
|
||||
|
||||
public pushAll(outputInventory: InventoryPeripheral): void {
|
||||
for (let i = 1; i <= TURTLE_SIZE; i++) {
|
||||
outputInventory.pullItems(this.localName, i);
|
||||
}
|
||||
}
|
||||
|
||||
public craft(dstInventory?: InventoryPeripheral, limit?: number): void {
|
||||
turtle.craft(limit);
|
||||
|
||||
if (dstInventory != undefined) {
|
||||
dstInventory.pullItems(this.localName, 1, limit);
|
||||
}
|
||||
}
|
||||
|
||||
public static getPackageRecipe(
|
||||
item: BlockItemDetailData,
|
||||
): CraftRecipe[] | undefined {
|
||||
if (
|
||||
!item.id.includes("create:cardboard_package") ||
|
||||
(item.tag as CreatePackageTag)?.Fragment?.OrderContext
|
||||
?.OrderedCrafts?.[0] == undefined
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const orderedCraft = (item.tag as CreatePackageTag).Fragment.OrderContext
|
||||
.OrderedCrafts;
|
||||
return orderedCraft.map((value, _) => ({
|
||||
PatternEntries: value.Pattern.Entries,
|
||||
Count: value.Count,
|
||||
}));
|
||||
}
|
||||
|
||||
public pullItems(
|
||||
recipe: CraftRecipe,
|
||||
inventory: InventoryPeripheral,
|
||||
limit: number,
|
||||
): number {
|
||||
let maxCraftCount = limit;
|
||||
|
||||
for (const index in recipe.PatternEntries) {
|
||||
const entry = recipe.PatternEntries[index];
|
||||
if (entry.Item.Count == 0 || entry.Item.id == "minecraft:air") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const ingredientList = inventory.list();
|
||||
let restCount = maxCraftCount;
|
||||
for (const key in ingredientList) {
|
||||
// Get item detail and check max count
|
||||
const slot = parseInt(key);
|
||||
const ingredient = inventory.getItemDetail(slot)!;
|
||||
if (entry.Item.id != ingredient.name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const ingredientMaxCount = ingredient.maxCount;
|
||||
if (maxCraftCount > ingredientMaxCount) {
|
||||
maxCraftCount = ingredientMaxCount;
|
||||
restCount = maxCraftCount;
|
||||
}
|
||||
log.info(
|
||||
`Slot ${slot} ${ingredient.name} max count: ${ingredientMaxCount}`,
|
||||
);
|
||||
|
||||
// TODO: Process multi count entry item
|
||||
if (ingredient.count >= restCount) {
|
||||
inventory.pushItems(
|
||||
this.localName,
|
||||
slot,
|
||||
restCount,
|
||||
CRAFT_SLOT_TABLE[parseInt(index) - 1],
|
||||
);
|
||||
restCount = 0;
|
||||
break;
|
||||
} else {
|
||||
inventory.pushItems(
|
||||
this.localName,
|
||||
slot,
|
||||
ingredient.count,
|
||||
CRAFT_SLOT_TABLE[parseInt(index) - 1],
|
||||
);
|
||||
restCount -= ingredient.count;
|
||||
}
|
||||
}
|
||||
|
||||
if (restCount > 0) return 0;
|
||||
}
|
||||
|
||||
return maxCraftCount;
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
CraftManager,
|
||||
CraftRecipe,
|
||||
CraftMode,
|
||||
CraftRecipeItem,
|
||||
CreatePackageTag,
|
||||
};
|
||||
97
src/lib/PeripheralManager.ts
Normal file
97
src/lib/PeripheralManager.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
type PeripheralType = "inventory" | "modem" | "wiredModem" | "blockReader";
|
||||
type BlockSide = "top" | "bottom" | "left" | "right" | "front" | "back";
|
||||
|
||||
// Declare the function signature for findBySide
|
||||
function findByName(
|
||||
devType: "inventory",
|
||||
devName: string,
|
||||
): InventoryPeripheral | undefined;
|
||||
function findByName(
|
||||
devType: "modem",
|
||||
devName: string,
|
||||
): ModemPeripheral | undefined;
|
||||
function findByName(
|
||||
devType: "wiredModem",
|
||||
devName: string,
|
||||
): WiredModemPeripheral | undefined;
|
||||
function findByName(
|
||||
devType: "blockReader",
|
||||
devName: string,
|
||||
): BlockReaderPeripheral | undefined;
|
||||
function findByName(
|
||||
devType: PeripheralType,
|
||||
side: BlockSide,
|
||||
): IPeripheral | undefined;
|
||||
function findByName(
|
||||
devType: PeripheralType,
|
||||
devName: string,
|
||||
): IPeripheral | undefined;
|
||||
|
||||
// Implement the function signature for findBySide
|
||||
function findByName(
|
||||
devType: PeripheralType,
|
||||
devName: string,
|
||||
): IPeripheral | undefined {
|
||||
const dev = peripheral.find(
|
||||
devType == "wiredModem" ? "modem" : devType,
|
||||
(name: string, _) => {
|
||||
return name == devName;
|
||||
},
|
||||
)[0];
|
||||
|
||||
// Seperate Modem and wiredModem
|
||||
if (
|
||||
devType == "modem" &&
|
||||
((dev as ModemPeripheral).isWireless == undefined ||
|
||||
(dev as ModemPeripheral).isWireless() == false)
|
||||
)
|
||||
return undefined;
|
||||
|
||||
if (
|
||||
devType == "wiredModem" &&
|
||||
(dev as ModemPeripheral).isWireless != undefined &&
|
||||
(dev as ModemPeripheral).isWireless() == true
|
||||
)
|
||||
return undefined;
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
// Declare the function signature for findBySideRequired
|
||||
function findByNameRequired(
|
||||
devType: "inventory",
|
||||
devName: string,
|
||||
): InventoryPeripheral;
|
||||
function findByNameRequired(devType: "modem", devName: string): ModemPeripheral;
|
||||
function findByNameRequired(
|
||||
devType: "wiredModem",
|
||||
devName: string,
|
||||
): WiredModemPeripheral;
|
||||
function findByNameRequired(
|
||||
devType: "blockReader",
|
||||
devName: string,
|
||||
): BlockReaderPeripheral;
|
||||
function findByNameRequired<T extends IPeripheral>(
|
||||
devType: PeripheralType,
|
||||
side: BlockSide,
|
||||
): T;
|
||||
function findByNameRequired<T extends IPeripheral>(
|
||||
devType: PeripheralType,
|
||||
devName: string,
|
||||
): T;
|
||||
|
||||
// Implement the function signature for findBySideRequired
|
||||
function findByNameRequired<T extends IPeripheral>(
|
||||
devType: PeripheralType,
|
||||
side: string,
|
||||
): T {
|
||||
const dev = findByName(devType, side);
|
||||
if (!dev) {
|
||||
throw new Error(
|
||||
`Required peripheral of type '${devType}' not found on side '${side}'`,
|
||||
);
|
||||
}
|
||||
return dev as T;
|
||||
}
|
||||
|
||||
export { PeripheralType, BlockSide, findByName, findByNameRequired };
|
||||
67
src/lib/ccLog.ts
Normal file
67
src/lib/ccLog.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
enum LogLevel {
|
||||
Info = 0,
|
||||
Warn = 1,
|
||||
Error = 2,
|
||||
}
|
||||
|
||||
export class CCLog {
|
||||
private fp: LuaFile | undefined;
|
||||
constructor(filename?: string) {
|
||||
term.clear();
|
||||
term.setCursorPos(1, 1);
|
||||
if (filename != undefined && filename.length != 0) {
|
||||
const filepath = shell.dir() + "/" + filename;
|
||||
const [file, error] = io.open(filepath, fs.exists(filepath) ? "a" : "w+");
|
||||
if (file != undefined) {
|
||||
this.fp = file;
|
||||
} else {
|
||||
throw Error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getFormatMsg(msg: string, level: LogLevel): string {
|
||||
const date = os.date("*t");
|
||||
return `[ ${date.year}/${date.month}/${date.day} -- ${date.hour}:${date.min}:${date.sec} ${LogLevel[level]} ] : ${msg}\r\n`;
|
||||
}
|
||||
|
||||
public writeLine(msg: string, color?: Color) {
|
||||
let originalColor: Color = 0;
|
||||
if (color != undefined) {
|
||||
originalColor = term.getTextColor();
|
||||
term.setTextColor(color);
|
||||
}
|
||||
|
||||
// Log
|
||||
term.write(msg);
|
||||
if (this.fp != undefined) {
|
||||
this.fp.write(msg);
|
||||
}
|
||||
|
||||
if (color != undefined) {
|
||||
term.setTextColor(originalColor);
|
||||
}
|
||||
|
||||
// Next line
|
||||
term.setCursorPos(1, term.getCursorPos()[1] + 1);
|
||||
}
|
||||
|
||||
public info(msg: string) {
|
||||
this.writeLine(this.getFormatMsg(msg, LogLevel.Info), colors.green);
|
||||
}
|
||||
|
||||
public warn(msg: string) {
|
||||
this.writeLine(this.getFormatMsg(msg, LogLevel.Warn), colors.orange);
|
||||
}
|
||||
|
||||
public error(msg: string) {
|
||||
this.writeLine(this.getFormatMsg(msg, LogLevel.Error), colors.red);
|
||||
}
|
||||
|
||||
public close() {
|
||||
if (this.fp !== undefined) {
|
||||
this.fp.close();
|
||||
this.fp = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
374
src/lib/event.ts
Normal file
374
src/lib/event.ts
Normal file
@@ -0,0 +1,374 @@
|
||||
// You may comment out any events you don't need to save space. Make sure to
|
||||
// delete them from eventInitializers as well.
|
||||
|
||||
export interface IEvent {
|
||||
get_name(): string;
|
||||
get_args(): any[];
|
||||
}
|
||||
|
||||
export class CharEvent implements IEvent {
|
||||
public character: string = "";
|
||||
public get_name() {return "char";}
|
||||
public get_args() {return [this.character];}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string") || (args[0] as string) != "char") return null;
|
||||
let ev = new CharEvent();
|
||||
ev.character = (args[1] as string);
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
export class KeyEvent implements IEvent {
|
||||
public key: Key = 0;
|
||||
public isHeld: boolean = false;
|
||||
public isUp: boolean = false;
|
||||
public get_name() {return this.isUp ? "key_up" : "key";}
|
||||
public get_args() {return [this.key, (this.isUp ? null : this.isHeld)];}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string") || ((args[0] as string) != "key" && (args[0] as string) != "key_up")) return null;
|
||||
let ev = new KeyEvent();
|
||||
ev.key = (args[1] as number);
|
||||
ev.isUp = (args[0] as string) == "key_up";
|
||||
ev.isHeld = ev.isUp ? false : (args[2] as boolean);
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
export class PasteEvent implements IEvent {
|
||||
public text: string = "";
|
||||
public get_name() {return "paste";}
|
||||
public get_args() {return [(this.text as any)];}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string") || (args[0] as string) != "paste") return null;
|
||||
let ev = new PasteEvent();
|
||||
ev.text = (args[1] as string);
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
export class TimerEvent implements IEvent {
|
||||
public id: number = 0;
|
||||
public isAlarm: boolean = false;
|
||||
public get_name() {return this.isAlarm ? "alarm" : "timer";}
|
||||
public get_args() {return [this.id];}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string") || ((args[0] as string) != "timer" && (args[0] as string) != "alarm")) return null;
|
||||
let ev = new TimerEvent();
|
||||
ev.id = (args[1] as number);
|
||||
ev.isAlarm = (args[0] as string) == "alarm";
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
export class TaskCompleteEvent implements IEvent {
|
||||
public id: number = 0;
|
||||
public success: boolean = false;
|
||||
public error: string | null = null;
|
||||
public params: any[] = [];
|
||||
public get_name() {return "task_complete";}
|
||||
public get_args() {
|
||||
if (this.success) return [this.id, this.success].concat(this.params);
|
||||
else return [this.id, this.success, this.error];
|
||||
}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string") || (args[0] as string) != "task_complete") return null;
|
||||
let ev = new TaskCompleteEvent();
|
||||
ev.id = (args[1] as number);
|
||||
ev.success = (args[2] as boolean);
|
||||
if (ev.success) {
|
||||
ev.error = null;
|
||||
ev.params = args.slice(3);
|
||||
} else {
|
||||
ev.error = (args[3] as string);
|
||||
ev.params = [];
|
||||
}
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
export class RedstoneEvent implements IEvent {
|
||||
public get_name() {return "redstone";}
|
||||
public get_args() {return [];}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string") || (args[0] as string) != "redstone") return null;
|
||||
let ev = new RedstoneEvent();
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
export class TerminateEvent implements IEvent {
|
||||
public get_name() {return "terminate";}
|
||||
public get_args() {return [];}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string") || (args[0] as string) != "terminate") return null;
|
||||
let ev = new TerminateEvent();
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
export class DiskEvent implements IEvent {
|
||||
public side: string = "";
|
||||
public eject: boolean = false;
|
||||
public get_name() {return this.eject ? "disk_eject" : "disk";}
|
||||
public get_args() {return [this.side];}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string") || ((args[0] as string) != "disk" && (args[0] as string) != "disk_eject")) return null;
|
||||
let ev = new DiskEvent();
|
||||
ev.side = (args[1] as string);
|
||||
ev.eject = (args[0] as string) == "disk_eject";
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
export class PeripheralEvent implements IEvent {
|
||||
public side: string = "";
|
||||
public detach: boolean = false;
|
||||
public get_name() {return this.detach ? "peripheral_detach" : "peripheral";}
|
||||
public get_args() {return [this.side];}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string") || ((args[0] as string) != "peripheral" && (args[0] as string) != "peripheral_detach")) return null;
|
||||
let ev = new PeripheralEvent();
|
||||
ev.side = (args[1] as string);
|
||||
ev.detach = (args[0] as string) == "peripheral_detach";
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
export class RednetMessageEvent implements IEvent {
|
||||
public sender: number = 0;
|
||||
public message: any;
|
||||
public protocol: string | null = null;
|
||||
public get_name() {return "rednet_message";}
|
||||
public get_args() {return [this.sender, this.message, this.protocol];}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string") || (args[0] as string) != "rednet_message") return null;
|
||||
let ev = new RednetMessageEvent();
|
||||
ev.sender = (args[1] as number);
|
||||
ev.message = args[2];
|
||||
ev.protocol = (args[3] as string);
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
export class ModemMessageEvent implements IEvent {
|
||||
public side: string = "";
|
||||
public channel: number = 0;
|
||||
public replyChannel: number = 0;
|
||||
public message: any;
|
||||
public distance: number = 0;
|
||||
public get_name() {return "modem_message";}
|
||||
public get_args() {return [this.side, this.channel, this.replyChannel, this.message, this.distance];}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string") || (args[0] as string) != "modem_message") return null;
|
||||
let ev = new ModemMessageEvent();
|
||||
ev.side = (args[1] as string);
|
||||
ev.channel = (args[2] as number);
|
||||
ev.replyChannel = (args[3] as number);
|
||||
ev.message = args[4];
|
||||
ev.distance = (args[5] as number);
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
export class HTTPEvent implements IEvent {
|
||||
public url: string = "";
|
||||
public handle: HTTPResponse | null = null;
|
||||
public error: string | null = null;
|
||||
public get_name() {return this.error == null ? "http_success" : "http_failure";}
|
||||
public get_args() {return [this.url, (this.error == null ? this.handle : this.error), (this.error != null ? this.handle : null)];}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string") || ((args[0] as string) != "http_success" && (args[0] as string) != "http_failure")) return null;
|
||||
let ev = new HTTPEvent();
|
||||
ev.url = (args[1] as string);
|
||||
if ((args[0] as string) == "http_success") {
|
||||
ev.error = null;
|
||||
ev.handle = (args[2] as HTTPResponse);
|
||||
} else {
|
||||
ev.error = (args[2] as string);
|
||||
if (ev.error == null) ev.error = "";
|
||||
ev.handle = (args[3] as HTTPResponse);
|
||||
}
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
export class WebSocketEvent implements IEvent {
|
||||
public handle: WebSocket | null = null;
|
||||
public error: string | null = null;
|
||||
public get_name() {return this.error == null ? "websocket_success" : "websocket_failure";}
|
||||
public get_args() {return [this.handle == null ? this.error : this.handle];}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string") || ((args[0] as string) != "websocket_success" && (args[0] as string) != "websocket_failure")) return null;
|
||||
let ev = new WebSocketEvent();
|
||||
if ((args[0] as string) == "websocket_success") {
|
||||
ev.handle = (args[1] as WebSocket);
|
||||
ev.error = null;
|
||||
} else {
|
||||
ev.error = (args[1] as string);
|
||||
ev.handle = null;
|
||||
}
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
export enum MouseEventType {
|
||||
Click,
|
||||
Up,
|
||||
Scroll,
|
||||
Drag,
|
||||
Touch,
|
||||
Move,
|
||||
}
|
||||
|
||||
export class MouseEvent implements IEvent {
|
||||
public button: number = 0;
|
||||
public x: number = 0;
|
||||
public y: number = 0;
|
||||
public side: string | null = null;
|
||||
public type: MouseEventType = MouseEventType.Click;
|
||||
public get_name() {
|
||||
return {
|
||||
[MouseEventType.Click]: "mouse_click",
|
||||
[MouseEventType.Up]: "mouse_up",
|
||||
[MouseEventType.Scroll]: "mouse_scroll",
|
||||
[MouseEventType.Drag]: "mouse_drag",
|
||||
[MouseEventType.Touch]: "monitor_touch",
|
||||
[MouseEventType.Move]: "mouse_move"
|
||||
}[this.type];
|
||||
}
|
||||
public get_args() {return [(this.type == MouseEventType.Touch ? this.side : this.button), this.x, this.y];}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string")) return null;
|
||||
let ev = new MouseEvent();
|
||||
const type = args[0] as string;
|
||||
if (type == "mouse_click") {ev.type = MouseEventType.Click; ev.button = (args[1] as number); ev.side = null;}
|
||||
else if (type == "mouse_up") {ev.type = MouseEventType.Up; ev.button = (args[1] as number); ev.side = null;}
|
||||
else if (type == "mouse_scroll") {ev.type = MouseEventType.Scroll; ev.button = (args[1] as number); ev.side = null;}
|
||||
else if (type == "mouse_drag") {ev.type = MouseEventType.Drag; ev.button = (args[1] as number); ev.side = null;}
|
||||
else if (type == "monitor_touch") {ev.type = MouseEventType.Touch; ev.button = 0; ev.side = (args[1] as string);}
|
||||
else if (type == "mouse_move") {ev.type = MouseEventType.Move; ev.button = (args[1] as number); ev.side = null;}
|
||||
else return null;
|
||||
ev.x = (args[2] as number);
|
||||
ev.y = (args[3] as number);
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
export class ResizeEvent implements IEvent {
|
||||
public side: string | null = null;
|
||||
public get_name() {return this.side == null ? "term_resize" : "monitor_resize";}
|
||||
public get_args() {return [this.side];}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string") || ((args[0] as string) != "term_resize" && (args[0] as string) != "monitor_resize")) return null;
|
||||
let ev = new ResizeEvent();
|
||||
if ((args[0] as string) == "monitor_resize") ev.side = (args[1] as string);
|
||||
else ev.side = null;
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
export class TurtleInventoryEvent implements IEvent {
|
||||
public get_name() {return "turtle_inventory";}
|
||||
public get_args() {return [];}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string") || (args[0] as string) != "turtle_inventory") return null;
|
||||
let ev = new TurtleInventoryEvent();
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
class SpeakerAudioEmptyEvent implements IEvent {
|
||||
public side: string = "";
|
||||
public get_name() {return "speaker_audio_empty";}
|
||||
public get_args() {return [this.side];}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string") || (args[0] as string) != "speaker_audio_empty") return null;
|
||||
let ev: SpeakerAudioEmptyEvent;
|
||||
ev.side = args[1] as string;
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
class ComputerCommandEvent implements IEvent {
|
||||
public args: string[] = [];
|
||||
public get_name() {return "computer_command";}
|
||||
public get_args() {return this.args;}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string") || (args[0] as string) != "computer_command") return null;
|
||||
let ev: ComputerCommandEvent;
|
||||
ev.args = args.slice(1);
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
class Event implements IEvent {
|
||||
|
||||
public get_name() {return "";}
|
||||
public get_args() {return [(: any)];}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
if (!(typeof args[0] === "string") || (args[0] as string) != "") return null;
|
||||
let ev: Event;
|
||||
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
export class GenericEvent implements IEvent {
|
||||
public args: any[] = [];
|
||||
public get_name() {return (this.args[0] as string);}
|
||||
public get_args() {return this.args.slice(1);}
|
||||
public static init(args: any[]): IEvent | null {
|
||||
let ev = new GenericEvent();
|
||||
ev.args = args;
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
let eventInitializers: ((args: any[]) => IEvent | null)[] = [
|
||||
CharEvent.init,
|
||||
KeyEvent.init,
|
||||
PasteEvent.init,
|
||||
TimerEvent.init,
|
||||
TaskCompleteEvent.init,
|
||||
RedstoneEvent.init,
|
||||
TerminateEvent.init,
|
||||
DiskEvent.init,
|
||||
PeripheralEvent.init,
|
||||
RednetMessageEvent.init,
|
||||
ModemMessageEvent.init,
|
||||
HTTPEvent.init,
|
||||
WebSocketEvent.init,
|
||||
MouseEvent.init,
|
||||
ResizeEvent.init,
|
||||
TurtleInventoryEvent.init,
|
||||
SpeakerAudioEmptyEvent.init,
|
||||
ComputerCommandEvent.init,
|
||||
GenericEvent.init
|
||||
];
|
||||
|
||||
type Constructor<T extends {} = {}> = new (...args: any[]) => T;
|
||||
export function pullEventRaw(filter: string | null = null): IEvent | null {
|
||||
let args = table.pack(...coroutine.yield(filter));
|
||||
for (let init of eventInitializers) {
|
||||
let ev = init(args);
|
||||
if (ev != null) return ev;
|
||||
}
|
||||
return GenericEvent.init(args);
|
||||
}
|
||||
export function pullEvent(filter: string | null = null): IEvent | null {
|
||||
let ev = pullEventRaw(filter);
|
||||
if (ev instanceof TerminateEvent) throw "Terminated";
|
||||
return ev;
|
||||
}
|
||||
export function pullEventRawAs<T extends IEvent>(type: Constructor<T>, filter: string | null = null): T | null {
|
||||
let ev = pullEventRaw(filter);
|
||||
if ((ev instanceof type)) return ev as T;
|
||||
else return null;
|
||||
}
|
||||
export function pullEventAs<T extends IEvent>(type: Constructor<T>, filter: string | null = null): T | null {
|
||||
let ev = pullEvent(filter);
|
||||
if ((ev instanceof type)) return ev as T;
|
||||
else return null;
|
||||
}
|
||||
Reference in New Issue
Block a user