finish basic autocraft for create store

This commit is contained in:
2025-10-07 22:15:41 +08:00
parent c8eeb4f354
commit d3cbc15450
26 changed files with 3386 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
node_modules
*.lua
.DS_Store
event/
build/

9
.justfile Normal file
View File

@@ -0,0 +1,9 @@
set windows-shell := ["powershell.exe", "-NoLogo", "-Command"]
build: build-autocraft sync
build-autocraft:
pnpm build-autocraft
sync:
cp -r "./build/*" "C:\\Users\\sikongjueluo\\AppData\\Roaming\\CraftOS-PC\\computer\\0\\user\\"

38
eslint.config.mjs Normal file
View File

@@ -0,0 +1,38 @@
// @ts-check
import eslint from "@eslint/js";
import { defineConfig } from "eslint/config";
import tseslint from "typescript-eslint";
export default defineConfig(
eslint.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.stylisticTypeChecked,
{
languageOptions: {
parserOptions: {
project: ["./tsconfig.json", "./tsconfig.autocraft.json"],
},
},
rules: {
"@typescript-eslint/strict-boolean-expressions": "error",
"@typescript-eslint/prefer-nullish-coalescing": "error",
"@typescript-eslint/no-unused-vars": [
"error",
{
args: "all",
argsIgnorePattern: "^_",
caughtErrors: "all",
caughtErrorsIgnorePattern: "^_",
destructuredArrayIgnorePattern: "^_",
varsIgnorePattern: "^_",
ignoreRestSiblings: true,
},
],
},
},
{
files: ["**/*.js", "**/*.mjs"],
...tseslint.configs.disableTypeChecked,
},
);

25
package.json Normal file
View File

@@ -0,0 +1,25 @@
{
"name": "cc-utils",
"version": "1.0.0",
"description": "Template project for ComputerCraft programs written in TypeScript.",
"main": "main.ts",
"scripts": {
"build": "tstl",
"build-autocraft": "tstl -p ./tsconfig.autocraft.json",
"sync": "cp -r \"./build/*\" \"C:\\Users\\sikongjueluo\\AppData\\Roaming\\CraftOS-PC\\computer\\0\\user\""
},
"devDependencies": {
"@eslint/js": "^9.36.0",
"@sikongjueluo/advanced-peripherals-types": "file:types/advanced-peripherals",
"@jackmacwindows/cc-types": "file:types/cc",
"@jackmacwindows/craftos-types": "file:types/craftos",
"@jackmacwindows/lua-types": "^2.13.2",
"@jackmacwindows/typescript-to-lua": "^1.28.1",
"@typescript-to-lua/language-extensions": "^1.19.0",
"eslint": "^9.36.0",
"typescript": "^5.7.2",
"typescript-eslint": "^8.45.0"
},
"author": "sikongjueluo",
"license": "MIT"
}

1147
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

120
src/autocraft/main.ts Normal file
View 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
View 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,
};

View 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
View 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
View 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;
}

9
tsconfig.autocraft.json Normal file
View File

@@ -0,0 +1,9 @@
{
"$schema": "https://raw.githubusercontent.com/MCJack123/TypeScriptToLua/master/tsconfig-schema.json",
"extends": "./tsconfig.json",
"tstl": {
"luaBundle": "build/autocraft.lua",
"luaBundleEntry": "src/autocraft/main.ts"
},
"include": ["src/autocraft/*.ts"]
}

32
tsconfig.json Normal file
View File

@@ -0,0 +1,32 @@
{
"$schema": "https://raw.githubusercontent.com/MCJack123/TypeScriptToLua/master/tsconfig-schema.json",
"compilerOptions": {
"target": "ESNext",
"lib": ["ESNext"],
"baseUrl": ".",
"moduleResolution": "node",
"strict": true,
"types": [
"@sikongjueluo/advanced-peripherals-types",
"@jackmacwindows/lua-types/cc",
"@jackmacwindows/craftos-types",
"@jackmacwindows/cc-types",
"@typescript-to-lua/language-extensions"
],
"paths": {
"@/*": ["./src/*"],
"@jackmacwindows/craftos-types": ["./types/craftos"],
"@jackmacwindows/lua-types/cc": ["./types/cc"],
"@sikongjueluo/advanced-peripherals-types": [
"./types/advanced-peripherals"
]
}
},
"tstl": {
"luaTarget": "CC",
"luaLibImport": "require-minimal",
"tstlVerbose": true,
"noImplicitSelf": true
},
"include": ["./*.ts", "./src/**/*.ts", "./types/**/*.ts"]
}

14
types/advanced-peripherals/index.d.ts vendored Normal file
View File

@@ -0,0 +1,14 @@
declare interface BlockItemDetailData {
id: string;
tag: object;
Count: number;
Slot: number;
}
declare interface BlockDetailData {
Items: Record<number, BlockItemDetailData>;
}
declare class BlockReaderPeripheral {
getBlockData(): BlockDetailData;
}

View File

@@ -0,0 +1,11 @@
{
"name": "@sikongjueluo/advanced-peripherals-types",
"version": "1.0.0",
"description": "TypeScript type definitions for base Advanced Peripherals APIs.",
"types": "./index.d.ts",
"files": [
"./index.d.ts"
],
"author": "SikongJueluo",
"license": "MIT"
}

8
types/cc/audio/dfpwm.d.ts vendored Normal file
View File

@@ -0,0 +1,8 @@
/** @noSelfInFile **/
/** @noResolution **/
declare module "cc.audio.dfpwm" {
export function make_encoder(): (pcm: number[]) => string;
export function encode(pcm: number[]): string;
export function make_decoder(): (dfpwm: string) => number[];
export function decode(dfpwm: string): number[];
}

9
types/cc/completion.d.ts vendored Normal file
View File

@@ -0,0 +1,9 @@
/** @noSelfInFile **/
/** @noResolution **/
declare module "cc.completion" {
export function choice(text: string, choices: string[], add_space?: boolean): string[];
export function peripheral(text: string, add_space?: boolean): string[];
export function side(text: string, add_space?: boolean): string[];
export function setting(text: string, add_space?: boolean): string[];
export function command(text: string, add_space?: boolean): string[];
}

11
types/cc/expect.d.ts vendored Normal file
View File

@@ -0,0 +1,11 @@
/** @noSelfInFile **/
/** @noResolution **/
declare module "cc/expect" {
namespace expect {
function expect(index: number, value: any, ...types: string[]): any;
function field(tbl: Object|LuaTable, index: string, ...types: string[]): any;
function range(num: number, min?: number, max?: number): number;
}
function expect(index: number, value: any, ...types: string[]): any;
export = expect;
}

8
types/cc/image/nft.d.ts vendored Normal file
View File

@@ -0,0 +1,8 @@
/** @noSelfInFile **/
/** @noResolution **/
declare module "cc.image.nft" {
type Image = {text: string, foreground: string, background: string}[];
export function parse(image: string): Image;
export function load(path: string): Image;
export function draw(image: Image, xPos: number, yPos: number, target?: ITerminal): void;
}

8
types/cc/index.d.ts vendored Normal file
View File

@@ -0,0 +1,8 @@
import "audio/dfpwm.d.ts";
import "completion.d.ts";
import "expect.d.ts";
import "image.nft.d.ts";
import "pretty.d.ts";
import "require.d.ts";
import "shell/completion.d.ts";
import "strings.d.ts";

9
types/cc/package.json Normal file
View File

@@ -0,0 +1,9 @@
{
"name": "@jackmacwindows/cc-types",
"version": "1.0.1",
"description": "TypeScript type definitions for CraftOS modules.",
"types": "index.d.ts",
"files": ["./*.d.ts", "./audio", "./image", "./shell"],
"author": "JackMacWindows",
"license": "MIT"
}

18
types/cc/pretty.d.ts vendored Normal file
View File

@@ -0,0 +1,18 @@
/** @noSelfInFile **/
/** @noResolution **/
declare module "cc.pretty" {
type Doc = {};
export const empty: Doc;
export const space: Doc;
export const line: Doc;
export const space_line: Doc;
export function text(text: string, color?: number): Doc;
export function concat(...args: (Doc|string)[]): Doc;
export function nest(depth: number, doc: Doc): Doc;
export function group(doc: Doc): Doc;
export function write(doc: Doc, ribbon_frac?: number): void;
export function print(doc: Doc, ribbon_frac?: number): void;
export function render(doc: Doc, width?: number, ribbon_frac?: number): string;
export function pretty(obj: any, options?: {function_args?: boolean, function_source: boolean}): Doc;
export function pretty_print(obj: any, options?: {function_args?: boolean, function_source: boolean}, ribbon_frac?: number): void;
}

5
types/cc/require.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
/** @noSelfInFile **/
/** @noResolution **/
declare module "cc.require" {
export function make(env: Object|LuaTable, dir: string): LuaMultiReturn<[(name: string) => any, Object|LuaTable]>;
}

16
types/cc/shell/completion.d.ts vendored Normal file
View File

@@ -0,0 +1,16 @@
/** @noSelfInFile **/
/** @noResolution **/
declare module "cc.shell.completion" {
export function file(shell: Object|LuaTable, text: string): string[];
export function dir(shell: Object|LuaTable, text: string): string[];
export function dirOrFile(shell: Object|LuaTable, text: string, previous: string[], add_space?: boolean): string[];
export function program(shell: Object|LuaTable, text: string): string[];
export function programWithArgs(shell: Object|LuaTable, text: string, previous: string[], starting: number): string[];
export function help(shell: Object|LuaTable, text: string, previous: string[]): string[];
export function choice(shell: Object|LuaTable, text: string, previous: string[], choices: string[], add_space?: boolean): string[];
export function peripheral(shell: Object|LuaTable, text: string, previous: string[], add_space?: boolean): string[];
export function side(shell: Object|LuaTable, text: string, previous: string[], add_space?: boolean): string[];
export function setting(shell: Object|LuaTable, text: string, previous: string[], add_space?: boolean): string[];
export function command(shell: Object|LuaTable, text: string, previous: string[], add_space?: boolean): string[];
export function build(...args: (null | ((text: string, previous: string[]) => string[]) | [(text: string, previous: string[], ...args: any[]) => string[], ...any[]])[]): (index: number, arg: string, previous: string[]) => string[];
}

7
types/cc/strings.d.ts vendored Normal file
View File

@@ -0,0 +1,7 @@
/** @noSelfInFile **/
/** @noResolution **/
declare module "cc.strings" {
export function wrap(text: string, width?: number): string[];
export function ensure_width(text: string, width?: number): string;
export function split(str: string, deliminator: string, plain?: boolean, limit?: number): string[];
}

1125
types/craftos/index.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
{
"name": "@jackmacwindows/craftos-types",
"version": "1.1.3",
"description": "TypeScript type definitions for base CraftOS APIs.",
"types": "./index.d.ts",
"files": [
"./index.d.ts"
],
"author": "JackMacWindows",
"license": "MIT"
}