merge: promote next to master
This commit is contained in:
commit
877764a177
87
CLAUDE.md
87
CLAUDE.md
@ -1,78 +1,41 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
Concise guidance for agents working in this repository.
|
||||
|
||||
## What this is
|
||||
## Project
|
||||
|
||||
A collection of [ComputerCraft](https://tweaked.cc/) (CC:Tweaked) Lua APIs, servers, and programs for in-game networked computers. Targets **CC:Tweaked for Minecraft 1.21** (latest). Runtime is the ComputerCraft Lua sandbox (`fs`, `peripheral`, `os.pullEvent`, `shell`, `parallel`, `modem.transmit`, etc.), not standard Lua.
|
||||
ComputerCraft / CC:Tweaked Lua APIs, servers, and programs for Minecraft 1.21. Code runs in the ComputerCraft sandbox, not standard Lua.
|
||||
|
||||
When more CC:Tweaked API details are needed, <https://tweaked.cc/module/turtle.html> is a useful documentation entrypoint. It is not mandatory to fetch every time, but its left-hand navigation includes the broader glossary and links to globals, modules (for example `cc.base64` and `cc.pretty`), peripherals, and events, even when the topic is not turtle-specific. A compact local index of these documentation pages is maintained in `docs/cc_glossary.md`.
|
||||
Use `docs/README.md` as the entrypoint for CC:Tweaked, Advanced Peripherals, and Create integration documentation links. Use `docs/adrs/README.md` for repository architecture decisions.
|
||||
|
||||
## Tooling constraints
|
||||
## Constraints
|
||||
|
||||
- **There is no way to run, build, or test this code yet.** It only executes inside ComputerCraft (in-game or under CraftOS-PC). Do not attempt to run Lua locally or add a test harness unless asked.
|
||||
- **Linting:** `just check` runs `luacheck` over all Lua source. **Always run `just check` after editing a Lua file, and fix any warnings before considering the change done.** Config lives in `.luacheckrc` (a custom `lua51+cc` std that knows the ComputerCraft sandbox globals and the `os`/`table` extensions). If a new genuine global is needed, add it there rather than suppressing the warning inline.
|
||||
- Match the existing style (2-space indent, semicolons, `local function`).
|
||||
- `require` paths are ComputerCraft-resolved and absolute from the computer root, e.g. `require('/apis/net')`. Most modules return a *factory* function — call it once to get the API: `local net = require('/apis/net')()`.
|
||||
- Do not run Lua locally or add a test harness unless asked; code executes in-game or CraftOS-PC.
|
||||
- After editing Lua, run `just check` and fix all `luacheck` warnings.
|
||||
- Use 2-space indent, semicolons, and `local function`.
|
||||
- `require` paths are absolute ComputerCraft paths, for example `require('/apis/net')()`.
|
||||
- Most API modules return factories; call the required module once before use.
|
||||
|
||||
## Architecture
|
||||
|
||||
Three layers, bottom-up:
|
||||
- `apis/eventloop.lua` is the single-threaded event loop around `os.pullEventRaw`; consider using it everywhere async behavior is needed. A handler that returns `api.STOP` auto-unregisters.
|
||||
- `apis/net.lua` builds modem packet messaging, routing, and request/response RPC on the event loop. `sendRequest` returns `ok, result, packet` and defaults to a 0.5s timeout.
|
||||
- A router (`/programs/router.lua`) must be running somewhere on the network; without it, packets lack `routerId`, `isPacketOk` rejects them, and cross-machine messaging silently fails.
|
||||
- `servers/` listen for requests and start loops; `programs/` are clients that send requests and exit.
|
||||
- Well-known channels: `9` ping, `10` router/default routing. Keep duplicated constants in sync.
|
||||
|
||||
1. **`apis/eventloop.lua`** — the foundation. A single-threaded event loop wrapping `os.pullEventRaw`. `register(eventName, handler)` returns a disposer; handlers returning `api.STOP` auto-unregister. Also provides `setTimeout`/clearTimeout, `onStart`/`onStop`, and `runLoop`. The loop auto-stops when no handlers/timeouts remain (unless `runLoop(true)`). Mutations during dispatch are queued (`unregisterQueue`, `removeTimeoutQueue`, `timeoutFactories`) and flushed after, so handlers can safely (un)register.
|
||||
## Boot And Install
|
||||
|
||||
2. **`apis/net.lua`** — messaging built on the event loop. Sends typed packets over modems. Key concepts:
|
||||
- **Packet** = `{ sourceId, sourceLabel, routerId, destId, message }`. `destId` may be a numeric computer ID, a string label, or `nil` (broadcast).
|
||||
- **Routing**: messages go out on `DEFAULT_ROUTING_CHANNEL` (10) to be picked up by a router, *unless* the sender is itself a router (`_G.isRouterEnabled`). **A router must be running somewhere on the network for net-based programs to reach other machines.**
|
||||
- **Request/response**: `sendRequest`/`listenRequest` implement RPC — the responder replies on `eventType .. "_response"`. `sendRequest` spins up a *private* event loop + net instance, waits up to `timeoutInSec` (default 0.5s), and returns `ok, result, packet`. `sendMultipleRequests` collects replies from many machines until timeout.
|
||||
- Higher-level helpers: `createRequest(channel, eventType)` and `createEvent(channel, eventType)`.
|
||||
|
||||
3. **`servers/`** and **`programs/`** — concrete uses of `net`. Servers `listenRequest` and call `net.startLoop()`; programs (clients) fire `sendRequest`/`sendMultipleRequests` and exit.
|
||||
|
||||
### Channels (well-known ports)
|
||||
|
||||
- `9` — ping
|
||||
- `10` — router / default routing channel
|
||||
- `64` — cube (deployment/control)
|
||||
|
||||
These are duplicated as local constants across files; keep them in sync when changing.
|
||||
|
||||
## The `cube` deployment system
|
||||
|
||||
`cube` (client `programs/cube.lua`, server `servers/cube-server.lua`) manages a cluster of "cube" machines over channel 64:
|
||||
|
||||
- `cube ls` — list reachable cubes (broadcast ping; each replies with its boot command). `*` marks the local machine.
|
||||
- `cube deploy` — walk the local filesystem (skipping `IGNORED_PATHS`: `/rom`, `/.cubeboot`, `/.git`, `/.gitignore`, `/startup.lua`), send every file to each remote cube via `deploy-file`, then reboot it.
|
||||
- `cube set-boot <machineId> [command]` — write/clear the remote's `/.cubeboot`, then reboot. Empty command deletes the boot hook.
|
||||
- `cube reboot <machineId>` — remote reboot.
|
||||
- `.cubeboot` holds a per-machine startup shell command, run by `servers/cube-boot.lua` at boot.
|
||||
|
||||
## Boot flow
|
||||
|
||||
`startup/servers.lua` is the entry point on each machine: it adds `/programs` to `shell.path`, then `parallel.waitForAll` runs an interactive shell alongside every server in `SERVERS`. When all stop, it reboots.
|
||||
|
||||
## CraftOS-PC emulation
|
||||
|
||||
`startup/servers.lua` detects the `periphemu` global and, when present, creates an emulated modem plus (on computer 0) a few emulated peer/router computers. Code guards CraftOS-PC quirks with `if periphemu then ... end` (e.g. `os.sleep(0.5)` after reboots in `cube.lua` to avoid crashes). Preserve these guards.
|
||||
|
||||
## Installation / distribution
|
||||
|
||||
`install.lua` is fetched and run on a machine via `wget run <raw-github-url>/install.lua`. It deletes old paths, re-downloads every file in `LIST_FILES` from the `master` branch raw GitHub URL by default, or from `next` when run with `--beta`, and runs `startup/servers.lua`. **When adding a new file that ships to machines, add it to `LIST_FILES` in `install.lua`** (and to `SERVERS` in `startup/servers.lua` if it's a server).
|
||||
- `startup/servers.lua` starts `/programs`, the shell, and configured servers via `parallel.waitForAll`.
|
||||
- Preserve `periphemu` guards used for CraftOS-PC emulation.
|
||||
- `install.lua` downloads files listed in `LIST_FILES` from `master`; add shipped files there.
|
||||
- Add new servers to `startup/servers.lua` as needed.
|
||||
|
||||
## Conventions
|
||||
|
||||
- Each module starts with `local _VERSION = '...'`; bump it when changing that module's behavior.
|
||||
- Programs accept `-version`/`--version` and `-help`/`--help` (and `-silent`/`--silent` for the router) via vararg `...`.
|
||||
- French comments appear throughout — fine to add either language, match the surrounding file.
|
||||
- Bump `local _VERSION = '...'` when changing module behavior.
|
||||
- Programs support `-version`/`--version` and `-help`/`--help`; router also supports `-silent`/`--silent`.
|
||||
- French or English comments are fine; match surrounding code.
|
||||
- Commit messages use lightweight conventional style: `topic(scope): description` or `topic: description`.
|
||||
|
||||
### Commit messages
|
||||
|
||||
Commit messages roughly follow Angular-style conventional commits, but the convention is intentionally lightweight. Use either `topic(scope): description` or `topic: description`.
|
||||
|
||||
- Common topics include `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`, `ci`, and `revert`.
|
||||
- Keep the description short, lowercase, imperative, and without a trailing period.
|
||||
- The exact topic/scope matters less than making the commit easy to scan.
|
||||
|
||||
## Development setup
|
||||
|
||||
See `DEVELOPMENT.md` for local development requirements and setup steps.
|
||||
See `DEVELOPMENT.md` for local setup.
|
||||
|
||||
12
README.md
12
README.md
@ -5,11 +5,6 @@
|
||||
wget run https://raw.githubusercontent.com/guillaumearm/cc-libs/master/install.lua
|
||||
```
|
||||
|
||||
Install the beta branch:
|
||||
```
|
||||
wget run https://raw.githubusercontent.com/guillaumearm/cc-libs/next/install.lua --beta
|
||||
```
|
||||
|
||||
## APIs
|
||||
- `/apis/eventloop`: a simple event loop API.
|
||||
- `/apis/net`: an API to simplify sending and receiving routed messages, based on the `eventloop` library.
|
||||
@ -18,15 +13,12 @@ wget run https://raw.githubusercontent.com/guillaumearm/cc-libs/next/install.lua
|
||||
All servers are automatically started at boot.
|
||||
|
||||
- `/servers/ping-server`: allows a machine to respond to a `ping` command.
|
||||
- `/servers/cube-server`: allows a machine to be controllable via `cube`.
|
||||
- `/servers/cube-boot.lua`: `cube` boot script.
|
||||
|
||||
## Programs
|
||||
- `router`: routes messages. You need to set up a router to use all `apis/net`-based programs and libraries.
|
||||
- `ping`: pings machines using `apis/net`.
|
||||
- `cube`: cube client for deployment. Use the `cube help` command for more details.
|
||||
- `goo`: turtle program for Just Dire Things goo block processing.
|
||||
- `upgrade`: upgrades the machine. Use `upgrade --beta` to install from the beta branch.
|
||||
- `events`: emits and logs computer events.
|
||||
- `upgrade`: upgrades the machine.
|
||||
|
||||
## Development
|
||||
See [DEVELOPMENT.md](./DEVELOPMENT.md) for development setup and workflow.
|
||||
|
||||
16
docs/README.md
Normal file
16
docs/README.md
Normal file
@ -0,0 +1,16 @@
|
||||
# Documentation
|
||||
|
||||
Start here when looking up ComputerCraft-related APIs, peripherals, or mod integrations used by this repository.
|
||||
|
||||
## Indexes
|
||||
|
||||
- [`cc_glossary.md`](cc_glossary.md) - CC:Tweaked globals, modules, peripherals, events, and guides.
|
||||
- [`advanced_peripherals_glossary.md`](advanced_peripherals_glossary.md) - Advanced Peripherals 0.7 guides, peripherals, turtles, integrations, and changelog pages.
|
||||
- [`create_cc_tweaked_glossary.md`](create_cc_tweaked_glossary.md) - Create CC:Tweaked integration pages.
|
||||
- [`adrs/`](adrs/) - Lightweight Architecture Decision Records for this repository.
|
||||
|
||||
## Notes
|
||||
|
||||
- These files are compact navigation indexes, not full documentation mirrors.
|
||||
- Prefer the local indexes first, then open the linked upstream docs for details.
|
||||
- Update the relevant `Last checked` line when refreshing an index.
|
||||
13
docs/adrs/README.md
Normal file
13
docs/adrs/README.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Architecture Decision Records
|
||||
|
||||
This directory contains lightweight Architecture Decision Records for this repository.
|
||||
|
||||
The goal is simple: keep a short memory of why we made repo-level choices while building ComputerCraft / CC:Tweaked code for Minecraft. This is not meant to be a heavy process.
|
||||
|
||||
Future ADRs can reuse the shape of the existing files when it is useful.
|
||||
|
||||
## Records
|
||||
|
||||
- [`adr-0001-target-computercraft.md`](adr-0001-target-computercraft.md) - Target ComputerCraft.
|
||||
- [`adr-0002-use-eventloop-for-async-code.md`](adr-0002-use-eventloop-for-async-code.md) - Use eventloop for async code.
|
||||
- [`adr-0003-current-net-api-state.md`](adr-0003-current-net-api-state.md) - Current net API state.
|
||||
28
docs/adrs/adr-0001-target-computercraft.md
Normal file
28
docs/adrs/adr-0001-target-computercraft.md
Normal file
@ -0,0 +1,28 @@
|
||||
# ADR 0001: Target ComputerCraft
|
||||
|
||||
## Status
|
||||
|
||||
Accepted
|
||||
|
||||
## Date
|
||||
|
||||
2026-06-07
|
||||
|
||||
## Context
|
||||
|
||||
This repository exists to build APIs, servers, and programs for ComputerCraft / CC:Tweaked inside Minecraft.
|
||||
|
||||
The code is Lua, but the runtime is not generic local Lua. The real environment provides ComputerCraft APIs such as `os.pullEvent`, `peripheral`, modems, timers, labels, computer IDs, and the CraftOS filesystem.
|
||||
|
||||
## Decision
|
||||
|
||||
This repo targets ComputerCraft / CC:Tweaked first.
|
||||
|
||||
Local Lua compatibility is not a goal by itself. Code can assume the ComputerCraft runtime and use ComputerCraft conventions when they make the in-game code clearer.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Prefer ComputerCraft-style absolute `require` paths, such as `require('/apis/net')()` (most API modules return factories — call the result once to get the API).
|
||||
- Local checks are useful, but runtime behavior should be validated in-game or with CraftOS-PC when needed.
|
||||
- Avoid adding a local Lua harness unless there is a clear reason.
|
||||
- Keep the repository practical: this is for playing Minecraft, not designing a general Lua framework.
|
||||
28
docs/adrs/adr-0002-use-eventloop-for-async-code.md
Normal file
28
docs/adrs/adr-0002-use-eventloop-for-async-code.md
Normal file
@ -0,0 +1,28 @@
|
||||
# ADR 0002: Use Eventloop For Async Code
|
||||
|
||||
## Status
|
||||
|
||||
Accepted
|
||||
|
||||
## Date
|
||||
|
||||
2026-06-07
|
||||
|
||||
## Context
|
||||
|
||||
ComputerCraft is event-driven. Direct `os.pullEvent` loops are easy to write, but they are hard to compose when multiple things need to happen at the same time.
|
||||
|
||||
This matters for servers, network listeners, timers, peripheral events, and future UI code. UI code especially will need to handle input, redraws, network replies, and timers together.
|
||||
|
||||
## Decision
|
||||
|
||||
New async code should use `/apis/eventloop`.
|
||||
|
||||
Event handlers, timers, server listeners, and future UI behavior should compose through the event loop instead of each feature owning its own blocking event loop.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Prefer `eventloop.register`, `setTimeout`, `onStart`, `onStop`, and `startLoop` for async behavior.
|
||||
- APIs that listen for events should accept an existing event loop as a constructor argument, the way `/apis/net` already takes one. Do not create a private loop inside a module.
|
||||
- Direct `os.pullEvent` loops should be rare and justified.
|
||||
- Existing code can stay as-is for now, but future async, server, and UI code should move toward eventloop composition.
|
||||
36
docs/adrs/adr-0003-current-net-api-state.md
Normal file
36
docs/adrs/adr-0003-current-net-api-state.md
Normal file
@ -0,0 +1,36 @@
|
||||
# ADR 0003: Current Net API State
|
||||
|
||||
## Status
|
||||
|
||||
Accepted
|
||||
|
||||
## Date
|
||||
|
||||
2026-06-07
|
||||
|
||||
## Context
|
||||
|
||||
`/apis/net` is the current networking abstraction in this repository.
|
||||
|
||||
It wraps modem messages with packet metadata and uses `/apis/eventloop` for listeners and request/response flows. It is useful for today's basic routed messages and RPC-like requests, but it is not a final protocol design.
|
||||
|
||||
## Decision
|
||||
|
||||
Keep using `/apis/net` for simple program and server messaging.
|
||||
|
||||
Document the current behavior as the baseline, without over-designing the future protocol before real needs appear.
|
||||
|
||||
## Current State
|
||||
|
||||
- Default routing channel is `10`.
|
||||
- Ping channel is `9`.
|
||||
- Packets include `sourceId`, `sourceLabel`, `routerId`, `destId`, and `message`.
|
||||
- Main convenience APIs include `send`, `listen`, `sendRequest`, `sendMultipleRequests`, `listenRequest`, `createEvent`, `createRequest`, and `openChannel` (alias `open`). Listening on a non-default channel requires `openChannel` first.
|
||||
- `sendRequest` and `sendMultipleRequests` run a private event loop, default to a `0.5s` timeout, and return `ok, result, packet` (or `ok, results, packets` for the multi variant).
|
||||
- Router behavior currently lives separately in `/programs/router.lua`. A router must be running on the network — otherwise non-router senders produce packets with `routerId = nil` and `isPacketOk` drops them on receive, so cross-machine messages silently fail.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Use `/apis/net` for current basic messaging needs.
|
||||
- Keep duplicated well-known channel constants in sync while they remain duplicated.
|
||||
- Future ADRs can replace or refine this one if the network protocol gains discovery, retries, schemas, versioning, auth, or a different routing model.
|
||||
129
docs/advanced_peripherals_glossary.md
Normal file
129
docs/advanced_peripherals_glossary.md
Normal file
@ -0,0 +1,129 @@
|
||||
# Advanced Peripherals Documentation Glossary
|
||||
|
||||
Compact index of Advanced Peripherals documentation pages for version 0.7 from <https://docs.advanced-peripherals.de/0.7/>. The first page in each navigation section, such as Chat Box, Chatty Turtle, AR Goggles, Mod Integrations, or Changelog 0.7.24r, exposes the broader section navigation.
|
||||
|
||||
Last checked: 2026-06-07.
|
||||
|
||||
ATM 10 note: [AR Goggles](https://docs.advanced-peripherals.de/0.7/items/ar_goggles/) are documented, but do not work in our current ATM 10 Advanced Peripherals 0.7 setup.
|
||||
|
||||
## Guides
|
||||
|
||||
- [Disabled Peripherals](https://docs.advanced-peripherals.de/0.7/guides/disabled_peripherals/)
|
||||
- [Lua Objects](https://docs.advanced-peripherals.de/0.7/guides/objects/)
|
||||
- [Item and Fluid Filters](https://docs.advanced-peripherals.de/0.7/guides/filters/)
|
||||
- [Cooldowns and Fuel consumption](https://docs.advanced-peripherals.de/0.7/guides/cooldowns_and_fuel_consumption/)
|
||||
- [Storage System Functions](https://docs.advanced-peripherals.de/0.7/guides/storage_system_functions/)
|
||||
- [How to: report a bug or request a feature](https://docs.advanced-peripherals.de/0.7/guides/how_to_report/)
|
||||
|
||||
## Peripherals
|
||||
|
||||
- [Chat Box](https://docs.advanced-peripherals.de/0.7/peripherals/chat_box/)
|
||||
- [Energy Detector](https://docs.advanced-peripherals.de/0.7/peripherals/energy_detector/)
|
||||
- [Environment Detector](https://docs.advanced-peripherals.de/0.7/peripherals/environment_detector/)
|
||||
- [Player Detector](https://docs.advanced-peripherals.de/0.7/peripherals/player_detector/)
|
||||
- [Inventory Manager](https://docs.advanced-peripherals.de/0.7/peripherals/inventory_manager/)
|
||||
- [NBT Storage](https://docs.advanced-peripherals.de/0.7/peripherals/nbt_storage/)
|
||||
- [Block Reader](https://docs.advanced-peripherals.de/0.7/peripherals/block_reader/)
|
||||
- [Geo Scanner](https://docs.advanced-peripherals.de/0.7/peripherals/geo_scanner/)
|
||||
- [Redstone Integrator](https://docs.advanced-peripherals.de/0.7/peripherals/redstone_integrator/)
|
||||
- [AR Controller](https://docs.advanced-peripherals.de/0.7/peripherals/ar_controller/)
|
||||
- [ME Bridge](https://docs.advanced-peripherals.de/0.7/peripherals/me_bridge/)
|
||||
- [RS Bridge](https://docs.advanced-peripherals.de/0.7/peripherals/rs_bridge/)
|
||||
- [Colony Integrator](https://docs.advanced-peripherals.de/0.7/peripherals/colony_integrator/)
|
||||
|
||||
## Turtles
|
||||
|
||||
- [Chatty Turtle](https://docs.advanced-peripherals.de/0.7/turtles/chatty_turtle/)
|
||||
- [Chunky Turtle](https://docs.advanced-peripherals.de/0.7/turtles/chunky_turtle/)
|
||||
- [Environment Turtle](https://docs.advanced-peripherals.de/0.7/turtles/environment_turtle/)
|
||||
- [Player Turtle](https://docs.advanced-peripherals.de/0.7/turtles/player_turtle/)
|
||||
- [Geoscanning Turtle](https://docs.advanced-peripherals.de/0.7/turtles/geo_scanner_turtle/)
|
||||
|
||||
## Metaphysics Turtles
|
||||
|
||||
- [Weak Automata](https://docs.advanced-peripherals.de/0.7/turtles/metaphysics/weak_automata/)
|
||||
- [Husbandry Automata](https://docs.advanced-peripherals.de/0.7/turtles/metaphysics/husbandry_automata/)
|
||||
- [End Automata](https://docs.advanced-peripherals.de/0.7/turtles/metaphysics/end_automata/)
|
||||
- [Overpowered Automata](https://docs.advanced-peripherals.de/0.7/turtles/metaphysics/overpowered_automata/)
|
||||
|
||||
## Items
|
||||
|
||||
- [AR Goggles](https://docs.advanced-peripherals.de/0.7/items/ar_goggles/) (documented, currently not working in our ATM 10/AP 0.7 setup)
|
||||
- [Chunk Controller](https://docs.advanced-peripherals.de/0.7/items/chunk_controller/)
|
||||
- [Computer Tool](https://docs.advanced-peripherals.de/0.7/items/computer_tool/)
|
||||
- [Memory Card](https://docs.advanced-peripherals.de/0.7/items/memory_card/)
|
||||
- [Pocket Computers](https://docs.advanced-peripherals.de/0.7/items/pocket_computer/)
|
||||
|
||||
## Mod Integrations
|
||||
|
||||
- [Mod Integrations overview](https://docs.advanced-peripherals.de/0.7/integrations/)
|
||||
|
||||
## Minecraft Integrations
|
||||
|
||||
- [Beacon](https://docs.advanced-peripherals.de/0.7/integrations/minecraft/beacon/)
|
||||
- [Note Block](https://docs.advanced-peripherals.de/0.7/integrations/minecraft/noteblock/)
|
||||
|
||||
## Botania Integrations
|
||||
|
||||
- [Flowers](https://docs.advanced-peripherals.de/0.7/integrations/botania/flowers/)
|
||||
- [Mana Pool](https://docs.advanced-peripherals.de/0.7/integrations/botania/pool/)
|
||||
- [Mana Spreader](https://docs.advanced-peripherals.de/0.7/integrations/botania/spreader/)
|
||||
|
||||
## Create Integrations
|
||||
|
||||
- [Basin](https://docs.advanced-peripherals.de/0.7/integrations/create/basin/)
|
||||
- [Blaze Burner](https://docs.advanced-peripherals.de/0.7/integrations/create/blazeburner/)
|
||||
- [Fluid Tank](https://docs.advanced-peripherals.de/0.7/integrations/create/fluidtank/)
|
||||
- [Mechanical Mixer](https://docs.advanced-peripherals.de/0.7/integrations/create/mechanicalmixer/)
|
||||
- [Blocks with Scroll Behaviour](https://docs.advanced-peripherals.de/0.7/integrations/create/scrollbehaviour/)
|
||||
|
||||
## Draconic Evolution Integrations
|
||||
|
||||
- [Draconic Evolution overview](https://docs.advanced-peripherals.de/0.7/integrations/draconic_evolution/)
|
||||
- [Energy Core](https://docs.advanced-peripherals.de/0.7/integrations/draconic_evolution/energy_core/)
|
||||
- [Reactor](https://docs.advanced-peripherals.de/0.7/integrations/draconic_evolution/reactor/)
|
||||
|
||||
## Immersive Engineering Integrations
|
||||
|
||||
- [Redstone Wire Connector](https://docs.advanced-peripherals.de/0.7/integrations/immersive_engineering/connector/)
|
||||
- [Redstone Probe](https://docs.advanced-peripherals.de/0.7/integrations/immersive_engineering/probe/)
|
||||
|
||||
## Integrated Dynamics Integrations
|
||||
|
||||
- [Variable Store](https://docs.advanced-peripherals.de/0.7/integrations/integrated_dynamics/variable_store/)
|
||||
|
||||
## Mekanism Integrations
|
||||
|
||||
- [Mekanism overview](https://docs.advanced-peripherals.de/0.7/integrations/mekanism/)
|
||||
- [Boiler Valve](https://docs.advanced-peripherals.de/0.7/integrations/mekanism/boiler/)
|
||||
- [Chemical Tank](https://docs.advanced-peripherals.de/0.7/integrations/mekanism/chemical/)
|
||||
- [Digital Miner](https://docs.advanced-peripherals.de/0.7/integrations/mekanism/digital_miner/)
|
||||
- [Dynamic Tank](https://docs.advanced-peripherals.de/0.7/integrations/mekanism/dynamic_tank/)
|
||||
- [Fission](https://docs.advanced-peripherals.de/0.7/integrations/mekanism/fission/)
|
||||
- [Fluid Tank](https://docs.advanced-peripherals.de/0.7/integrations/mekanism/fluid_tank/)
|
||||
- [Fusion](https://docs.advanced-peripherals.de/0.7/integrations/mekanism/fusion/)
|
||||
- [Generic Mekanism](https://docs.advanced-peripherals.de/0.7/integrations/mekanism/generic/)
|
||||
- [Induction Valve](https://docs.advanced-peripherals.de/0.7/integrations/mekanism/induction/)
|
||||
- [Solar Evaporation](https://docs.advanced-peripherals.de/0.7/integrations/mekanism/solar_evaporation/)
|
||||
- [Transmitter](https://docs.advanced-peripherals.de/0.7/integrations/mekanism/transmitter/)
|
||||
- [Turbine](https://docs.advanced-peripherals.de/0.7/integrations/mekanism/turbine/)
|
||||
- [Waste Barrel](https://docs.advanced-peripherals.de/0.7/integrations/mekanism/waste_barrel/)
|
||||
|
||||
## Powah Integrations
|
||||
|
||||
- [Ender Cell](https://docs.advanced-peripherals.de/0.7/integrations/powah/ender_cell/)
|
||||
- [Energy Cell](https://docs.advanced-peripherals.de/0.7/integrations/powah/energy_cell/)
|
||||
- [Furnator](https://docs.advanced-peripherals.de/0.7/integrations/powah/furnator/)
|
||||
- [Magmator](https://docs.advanced-peripherals.de/0.7/integrations/powah/magmator/)
|
||||
- [Reactor](https://docs.advanced-peripherals.de/0.7/integrations/powah/reactor/)
|
||||
- [Solar Panel](https://docs.advanced-peripherals.de/0.7/integrations/powah/solar_panel/)
|
||||
- [Thermo Generator](https://docs.advanced-peripherals.de/0.7/integrations/powah/thermo_generator/)
|
||||
|
||||
## Storage Drawers Integrations
|
||||
|
||||
- [Drawer](https://docs.advanced-peripherals.de/0.7/integrations/storage_drawers/drawer/)
|
||||
|
||||
## Changelogs
|
||||
|
||||
- [Changelog 0.7.24r](https://docs.advanced-peripherals.de/0.7/changelogs/0.7.24r/)
|
||||
- [Changelog 0.7r](https://docs.advanced-peripherals.de/0.7/changelogs/0.7r/)
|
||||
36
docs/create_cc_tweaked_glossary.md
Normal file
36
docs/create_cc_tweaked_glossary.md
Normal file
@ -0,0 +1,36 @@
|
||||
# Create CC:Tweaked Integration Documentation Glossary
|
||||
|
||||
Compact index of Create's CC:Tweaked integration documentation pages from <https://wiki.createmod.net/users/cc-tweaked-integration/logistics/packager>. The sidebar HTML on that page exposes the broader ComputerCraft integration navigation.
|
||||
|
||||
Last checked: 2026-06-07.
|
||||
|
||||
## Logistics
|
||||
|
||||
- [Packager](https://wiki.createmod.net/users/cc-tweaked-integration/logistics/packager)
|
||||
- [Re-Packager](https://wiki.createmod.net/users/cc-tweaked-integration/logistics/repackager)
|
||||
- [Stock Ticker](https://wiki.createmod.net/users/cc-tweaked-integration/logistics/stock-ticker)
|
||||
- [Redstone Requester](https://wiki.createmod.net/users/cc-tweaked-integration/logistics/redstone-requester)
|
||||
- [Table Cloth](https://wiki.createmod.net/users/cc-tweaked-integration/logistics/table-cloth)
|
||||
- [Package Frogport](https://wiki.createmod.net/users/cc-tweaked-integration/logistics/package-frogport)
|
||||
- [Postbox](https://wiki.createmod.net/users/cc-tweaked-integration/logistics/postbox)
|
||||
- [Package Object](https://wiki.createmod.net/users/cc-tweaked-integration/logistics/package-object)
|
||||
- [Order Data Object](https://wiki.createmod.net/users/cc-tweaked-integration/logistics/order-data-object)
|
||||
|
||||
## Trains
|
||||
|
||||
- [Train Station](https://wiki.createmod.net/users/cc-tweaked-integration/train/train-station)
|
||||
- [Train Signal](https://wiki.createmod.net/users/cc-tweaked-integration/train/train-signal)
|
||||
- [Train Observer](https://wiki.createmod.net/users/cc-tweaked-integration/train/train-observer)
|
||||
- [Train Schedule](https://wiki.createmod.net/users/cc-tweaked-integration/train/train-schedule)
|
||||
- [Libraries](https://wiki.createmod.net/users/cc-tweaked-integration/train/libraries)
|
||||
|
||||
## Peripherals
|
||||
|
||||
- [Nixie Tube](https://wiki.createmod.net/users/cc-tweaked-integration/nixie-tube)
|
||||
- [Display Link](https://wiki.createmod.net/users/cc-tweaked-integration/display-link)
|
||||
- [Sticker](https://wiki.createmod.net/users/cc-tweaked-integration/sticker)
|
||||
- [Sequenced Gearshift](https://wiki.createmod.net/users/cc-tweaked-integration/sequenced-gearshift)
|
||||
- [Rotational Speed Controller](https://wiki.createmod.net/users/cc-tweaked-integration/rotational-speed-controller)
|
||||
- [Creative Motor](https://wiki.createmod.net/users/cc-tweaked-integration/creative-motor)
|
||||
- [Speedometer](https://wiki.createmod.net/users/cc-tweaked-integration/speedometer)
|
||||
- [Stressometer](https://wiki.createmod.net/users/cc-tweaked-integration/stressometer)
|
||||
22
install.lua
22
install.lua
@ -1,19 +1,14 @@
|
||||
local _VERSION = '2.1.0'
|
||||
|
||||
local command = ...;
|
||||
local _VERSION = '2.2.0'
|
||||
|
||||
local LIST_FILES = {
|
||||
-- startup
|
||||
'startup/servers.lua',
|
||||
-- servers
|
||||
'servers/ping-server.lua',
|
||||
'servers/cube-server.lua',
|
||||
'servers/cube-boot.lua',
|
||||
-- programs
|
||||
'programs/router.lua', -- router is not in servers folder because he's not ran on every machines
|
||||
'programs/events.lua',
|
||||
'programs/ping.lua',
|
||||
'programs/cube.lua',
|
||||
'programs/goo.lua',
|
||||
'programs/upgrade.lua',
|
||||
-- apis
|
||||
'apis/net.lua',
|
||||
@ -24,14 +19,11 @@ local function printUsage()
|
||||
print('install usage:');
|
||||
print();
|
||||
print('\t\t\twget run <install-url>');
|
||||
print('\t\t\twget run <install-url> --beta');
|
||||
end
|
||||
|
||||
local branch = 'master';
|
||||
local command = ...;
|
||||
|
||||
if command == '--beta' or command == '-beta' then
|
||||
branch = 'next';
|
||||
elseif command ~= nil and command ~= '' then
|
||||
if command ~= nil and command ~= '' then
|
||||
printUsage();
|
||||
return;
|
||||
end
|
||||
@ -42,8 +34,12 @@ fs.delete('ping.lua') -- replaced by `programs/ping.lua`
|
||||
fs.delete('cube.lua') -- replaced by `programs/cube.lua`
|
||||
fs.delete('router.lua') -- replaced by `programs/router.lua`
|
||||
fs.delete('servers/cube-startup.lua'); -- replaced by `servers/cube-boot.lua`
|
||||
fs.delete('programs/cube.lua');
|
||||
fs.delete('programs/goo.lua');
|
||||
fs.delete('servers/cube-server.lua');
|
||||
fs.delete('servers/cube-boot.lua');
|
||||
|
||||
local REPO_PREFIX = 'https://raw.githubusercontent.com/guillaumearm/cc-libs/' .. branch .. '/'
|
||||
local REPO_PREFIX = 'https://raw.githubusercontent.com/guillaumearm/cc-libs/master/'
|
||||
|
||||
local previousDir = shell.dir()
|
||||
|
||||
|
||||
@ -1,342 +0,0 @@
|
||||
local _VERSION = '2.3.0';
|
||||
local CUBE_CHANNEL = 64;
|
||||
|
||||
local net = require('/apis/net')();
|
||||
|
||||
local args = table.pack(...);
|
||||
local cubeCommand = args[1];
|
||||
local firstArg = args[2];
|
||||
local secondArg = args[3];
|
||||
|
||||
local function getRemainingArgs(startIndex)
|
||||
local remainingArgs = {};
|
||||
|
||||
for i = startIndex, args.n do
|
||||
table.insert(remainingArgs, tostring(args[i]));
|
||||
end
|
||||
|
||||
return table.concat(remainingArgs, ' ');
|
||||
end
|
||||
|
||||
local IGNORED_PATHS = {
|
||||
['/rom'] = true,
|
||||
['/.cubeboot'] = true,
|
||||
['/.git'] = true,
|
||||
['/.gitignore'] = true,
|
||||
['/startup.lua'] = true,
|
||||
}
|
||||
|
||||
local function isValidPath(givenPath)
|
||||
return not IGNORED_PATHS[givenPath]
|
||||
end
|
||||
|
||||
local function getAllFiles(basePath, result)
|
||||
basePath = basePath or '/'
|
||||
result = result or {};
|
||||
|
||||
local fileNames = fs.list(basePath)
|
||||
|
||||
for i = 1, #fileNames do
|
||||
local filePath = basePath .. fileNames[i];
|
||||
local valid = isValidPath(filePath);
|
||||
|
||||
if valid and fs.isDir(filePath) then
|
||||
getAllFiles(filePath .. '/', result);
|
||||
elseif valid and not fs.isDir(filePath) then
|
||||
table.insert(result, filePath)
|
||||
end
|
||||
end
|
||||
|
||||
return result;
|
||||
end
|
||||
|
||||
local function readFile(path)
|
||||
local file = fs.open(path, "r");
|
||||
|
||||
if not file then
|
||||
return nil;
|
||||
end
|
||||
|
||||
local contents = file.readAll()
|
||||
file.close()
|
||||
|
||||
return contents
|
||||
end
|
||||
|
||||
--- Pads str to length len with char from right
|
||||
local leftPad = function(str, len, char)
|
||||
if char == nil then char = ' ' end
|
||||
local nbRepetition = len - #str;
|
||||
|
||||
if nbRepetition > 0 then
|
||||
return str .. string.rep(char, len - #str)
|
||||
end
|
||||
|
||||
return str;
|
||||
end
|
||||
|
||||
local function getRow(margin, str1, str2, str3)
|
||||
|
||||
margin = margin or '';
|
||||
|
||||
local row1 = leftPad(margin .. tostring(str1 or ''), 8, ' ')
|
||||
local row2 = leftPad(tostring(str2 or ''), 16, ' ')
|
||||
local row3 = leftPad(tostring(str3 or ''), 6, ' ')
|
||||
|
||||
return row1 .. row2 .. row3;
|
||||
end
|
||||
|
||||
local function isFlag(name)
|
||||
return function(arg)
|
||||
return arg == '-' .. name or arg == '--' .. name;
|
||||
end
|
||||
end
|
||||
|
||||
local isHelpFlag = isFlag('help');
|
||||
local isVersionFlag = isFlag('version');
|
||||
|
||||
local function printUsage()
|
||||
print('cube usage:')
|
||||
print();
|
||||
print('\t\t\tcube ls');
|
||||
print('\t\t\tcube configure');
|
||||
print('\t\t\tcube set-boot <machineId> [command]')
|
||||
print('\t\t\tcube reboot <machineId>')
|
||||
print('\t\t\tcube deploy')
|
||||
print('\t\t\tcube version')
|
||||
print('\t\t\tcube help <command>')
|
||||
end
|
||||
|
||||
local function printUsageCommand(commandName)
|
||||
local function setBootUsage()
|
||||
print('\t\t\tcube set-boot <machineId> [command]')
|
||||
print('Setup a startup shell command on a remote cube.')
|
||||
end
|
||||
|
||||
local USAGES = {
|
||||
ls = function()
|
||||
print('\t\t\tcube ls');
|
||||
print('Print all available cubes in the cluster.')
|
||||
end,
|
||||
configure = function()
|
||||
print('\t\t\tcube configure');
|
||||
print('Setup remote slave cubes.')
|
||||
end,
|
||||
["set-boot"] = setBootUsage,
|
||||
["setboot"] = setBootUsage,
|
||||
["set-start"] = setBootUsage,
|
||||
["setstart"] = setBootUsage,
|
||||
["set-startup"] = setBootUsage,
|
||||
["setstartup"] = setBootUsage,
|
||||
reboot = function()
|
||||
print('\t\t\tcube reboot <machineId>')
|
||||
print('Reboot a cube machine.');
|
||||
end,
|
||||
deploy = function()
|
||||
print('\t\t\tcube deploy')
|
||||
print('Transfer files on all slave cubes.')
|
||||
end,
|
||||
version = function()
|
||||
print('\t\t\tcube version')
|
||||
print('Print the program version.')
|
||||
end,
|
||||
help = function()
|
||||
print('\t\t\tcube help <command>')
|
||||
print('Print help on commands.')
|
||||
end,
|
||||
}
|
||||
|
||||
local usageFn = USAGES[commandName]
|
||||
|
||||
if not usageFn then
|
||||
return printUsage();
|
||||
end
|
||||
|
||||
return usageFn();
|
||||
end
|
||||
|
||||
if cubeCommand == nil or cubeCommand == '' or isHelpFlag(cubeCommand) then
|
||||
printUsage();
|
||||
return;
|
||||
end
|
||||
|
||||
------------
|
||||
-- reboot --
|
||||
------------
|
||||
local function rebootCommand(machineId, silentReboot)
|
||||
if not machineId or machineId == '' then
|
||||
printUsageCommand('reboot');
|
||||
return;
|
||||
end
|
||||
|
||||
local ok, results, packets = net.sendMultipleRequests(CUBE_CHANNEL, 'reboot', true, machineId);
|
||||
|
||||
if not ok then
|
||||
error(results);
|
||||
end
|
||||
|
||||
for k in ipairs(results) do
|
||||
local packet = packets[k];
|
||||
|
||||
if silentReboot ~= true then
|
||||
print('reboot machine \'' .. tostring(packet.sourceId) .. '\'');
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--------------
|
||||
-- set-boot --
|
||||
--------------
|
||||
local function setBootCommand(machineId, shellCommand)
|
||||
if not machineId then
|
||||
printUsageCommand('set-boot');
|
||||
return;
|
||||
end
|
||||
|
||||
local ok, results, packets = net.sendMultipleRequests(CUBE_CHANNEL, 'set-boot', shellCommand, machineId);
|
||||
|
||||
if not ok then
|
||||
error(results);
|
||||
end
|
||||
|
||||
for k in ipairs(results) do
|
||||
local packet = packets[k];
|
||||
|
||||
if shellCommand == nil or shellCommand == '' then
|
||||
print('boot DELETED');
|
||||
else
|
||||
print('boot UPDATED');
|
||||
end
|
||||
|
||||
rebootCommand(packet.sourceId, true);
|
||||
|
||||
-- prevent CraftOS-PC crashes
|
||||
if periphemu then
|
||||
os.sleep(0.5)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
------------
|
||||
-- deploy --
|
||||
------------
|
||||
local function deployCommand()
|
||||
local allFiles = getAllFiles()
|
||||
|
||||
-- 1. get all machine ids (except the current one)
|
||||
local ok, results, packets = net.sendMultipleRequests(CUBE_CHANNEL, 'ping', 'ping');
|
||||
|
||||
if not ok then
|
||||
error(results);
|
||||
end
|
||||
|
||||
local machineIds = {};
|
||||
|
||||
local localComputerId = os.getComputerID();
|
||||
|
||||
for k in ipairs(results) do
|
||||
local packet = packets[k];
|
||||
|
||||
if packet.sourceId ~= localComputerId then
|
||||
table.insert(machineIds, packet.sourceId);
|
||||
end
|
||||
end
|
||||
|
||||
-- 2. transfer files on all concerned machines
|
||||
for machineIndex = 1, #machineIds do
|
||||
local machineId = machineIds[machineIndex];
|
||||
|
||||
local fileTransfered = 0;
|
||||
|
||||
for i = 1, #allFiles do
|
||||
local filePath = allFiles[i];
|
||||
local fileContent = readFile(filePath)
|
||||
|
||||
local transferOk, res = net.sendRequest(CUBE_CHANNEL, 'deploy-file', { path = filePath, content = fileContent }, machineId);
|
||||
|
||||
if transferOk and res then
|
||||
fileTransfered = fileTransfered + 1;
|
||||
else
|
||||
print('Error transfering file \'' .. filePath .. '\'');
|
||||
end
|
||||
end
|
||||
|
||||
print(tostring(fileTransfered) .. ' file(s) transfered on machine ' .. tostring(machineId))
|
||||
|
||||
rebootCommand(machineId, true);
|
||||
|
||||
-- prevent CraftOS-PC crashes
|
||||
if periphemu then
|
||||
os.sleep(0.5)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local COMMANDS = {
|
||||
ls = function()
|
||||
local ok, results, packets = net.sendMultipleRequests(CUBE_CHANNEL, 'ping', 'ping');
|
||||
|
||||
if not ok then
|
||||
error(results);
|
||||
end
|
||||
|
||||
-- print('ID LABEL\t\t\t\tSTARTUP');
|
||||
print(getRow(' ', 'ID', 'LABEL', 'BOOT'))
|
||||
print('--------------------------------------------')
|
||||
|
||||
local localMachineId = os.getComputerID();
|
||||
|
||||
for k in ipairs(results) do
|
||||
local result = results[k];
|
||||
local packet = packets[k];
|
||||
|
||||
local prefix = ' ';
|
||||
|
||||
if packet.sourceId == localMachineId then
|
||||
prefix = '* '
|
||||
end
|
||||
|
||||
print(getRow(prefix, packet.sourceId, packet.sourceLabel, result.startup))
|
||||
end
|
||||
end,
|
||||
configure = function()
|
||||
print('not implemented yet.');
|
||||
end,
|
||||
["set-boot"] = setBootCommand,
|
||||
["setboot"] = setBootCommand,
|
||||
["set-start"] = setBootCommand,
|
||||
["setstart"] = setBootCommand,
|
||||
["set-startup"] = setBootCommand,
|
||||
["setstartup"] = setBootCommand,
|
||||
reboot = rebootCommand,
|
||||
deploy = deployCommand,
|
||||
version = function()
|
||||
print('cube client v' .. _VERSION);
|
||||
end,
|
||||
help = function(commandName)
|
||||
printUsageCommand(commandName);
|
||||
end
|
||||
}
|
||||
|
||||
local cmd;
|
||||
if isVersionFlag(cubeCommand) then
|
||||
cmd = COMMANDS.version;
|
||||
else
|
||||
cmd = COMMANDS[cubeCommand];
|
||||
end
|
||||
|
||||
if not cmd then
|
||||
printUsage();
|
||||
return;
|
||||
end
|
||||
|
||||
if (isHelpFlag(firstArg)) then
|
||||
printUsageCommand(cubeCommand);
|
||||
return;
|
||||
end
|
||||
|
||||
if cmd == setBootCommand then
|
||||
cmd(firstArg, getRemainingArgs(3));
|
||||
else
|
||||
cmd(firstArg, secondArg);
|
||||
end
|
||||
84
programs/events.lua
Normal file
84
programs/events.lua
Normal file
@ -0,0 +1,84 @@
|
||||
local _VERSION = '1.0.2';
|
||||
|
||||
local command = ...;
|
||||
|
||||
local function printUsage()
|
||||
print('events usage:');
|
||||
print();
|
||||
print('\t\t\tevents');
|
||||
print('\t\t\tevents version');
|
||||
print('\t\t\tevents help');
|
||||
end
|
||||
|
||||
local function sanitize(value, seen)
|
||||
local valueType = type(value);
|
||||
|
||||
if valueType == 'function' then
|
||||
return '<function>';
|
||||
end
|
||||
|
||||
if valueType ~= 'table' then
|
||||
return value;
|
||||
end
|
||||
|
||||
seen = seen or {};
|
||||
if seen[value] then
|
||||
return '<cycle>';
|
||||
end
|
||||
|
||||
seen[value] = true;
|
||||
|
||||
local result = {};
|
||||
for k, v in pairs(value) do
|
||||
result[sanitize(k, seen)] = sanitize(v, seen);
|
||||
end
|
||||
|
||||
seen[value] = nil;
|
||||
return result;
|
||||
end
|
||||
|
||||
local function valueToString(value)
|
||||
if type(value) == 'string' then
|
||||
return value;
|
||||
end
|
||||
|
||||
local ok, serialized = pcall(textutils.serialize, sanitize(value), { compact = true });
|
||||
if ok then
|
||||
return serialized;
|
||||
end
|
||||
|
||||
return '<' .. type(value) .. '>';
|
||||
end
|
||||
|
||||
if command == 'version' or command == '-version' or command == '--version' then
|
||||
print('events v' .. _VERSION);
|
||||
return;
|
||||
end
|
||||
|
||||
if command == 'help' or command == '-help' or command == '--help' then
|
||||
printUsage();
|
||||
return;
|
||||
end
|
||||
|
||||
if command ~= nil and command ~= '' then
|
||||
printUsage();
|
||||
return;
|
||||
end
|
||||
|
||||
print('Listening events... Press Ctrl+T to stop.');
|
||||
|
||||
while true do
|
||||
local event = table.pack(os.pullEventRaw());
|
||||
|
||||
if event[1] == 'terminate' then
|
||||
return;
|
||||
end
|
||||
|
||||
local parts = {};
|
||||
|
||||
for i = 1, event.n do
|
||||
parts[i] = valueToString(event[i]);
|
||||
end
|
||||
|
||||
print(table.concat(parts, ' '));
|
||||
end
|
||||
832
programs/goo.lua
832
programs/goo.lua
@ -1,832 +0,0 @@
|
||||
local _VERSION = "1.0.0"
|
||||
|
||||
local args = table.pack(...)
|
||||
local command = args[1]
|
||||
|
||||
local GOO_BLOCK_PREFIX = "justdirethings:gooblock_tier"
|
||||
local MIN_START_FUEL = 50
|
||||
local REFUEL_THRESHOLD = 1000
|
||||
local WAIT_SECONDS = 2
|
||||
local MIN_FEEDING_ITEMS = 4
|
||||
local MAX_SUCK_ATTEMPTS = 16
|
||||
|
||||
local FUEL_ITEMS = {
|
||||
"justdirethings:coal_t4",
|
||||
"justdirethings:coal_t3",
|
||||
"justdirethings:coal_t2",
|
||||
"justdirethings:coal_t1",
|
||||
"minecraft:coal",
|
||||
}
|
||||
|
||||
local PROCESS_ITEMS = {
|
||||
["minecraft:iron_block"] = { tier = 1 },
|
||||
["minecraft:coal_block"] = { tier = 1 },
|
||||
["mekanism:block_charcoal"] = { tier = 1 },
|
||||
["justdirethings:coalblock_t1"] = { tier = 1 },
|
||||
["justdirethings:coalblock_t2"] = { tier = 2 },
|
||||
["justdirethings:coalblock_t3"] = { tier = 3 },
|
||||
["justdirethings:coalblock_t4"] = { tier = 4 },
|
||||
["minecraft:gold_block"] = { tier = 2 },
|
||||
["minecraft:diamond_block"] = { tier = 3 },
|
||||
["minecraft:netherite_block"] = { tier = 4 },
|
||||
}
|
||||
|
||||
local FEEDING_ITEMS_BY_TIER = {
|
||||
[1] = { "minecraft:sugar", "minecraft:rotten_flesh" },
|
||||
[2] = { "minecraft:nether_wart" },
|
||||
[3] = { "minecraft:chorus_fruit" },
|
||||
[4] = { "minecraft:sculk" },
|
||||
}
|
||||
|
||||
local DIR_NORTH = 0
|
||||
local DIR_EAST = 1
|
||||
local DIR_SOUTH = 2
|
||||
local DIR_WEST = 3
|
||||
|
||||
local DIRECTION_DELTAS = {
|
||||
[DIR_NORTH] = { x = 0, z = -1 },
|
||||
[DIR_EAST] = { x = 1, z = 0 },
|
||||
[DIR_SOUTH] = { x = 0, z = 1 },
|
||||
[DIR_WEST] = { x = -1, z = 0 },
|
||||
}
|
||||
|
||||
local HOME = { x = -2, y = 0, z = 0, facing = DIR_EAST }
|
||||
local GOO_CHECK = { x = -1, y = 0, z = 0, facing = DIR_EAST }
|
||||
|
||||
local GOO_CHECKS = {
|
||||
{ name = "west goo check", x = -1, y = 0, z = 0, facing = DIR_EAST, action = "forward" },
|
||||
{ name = "east goo check", x = 1, y = 0, z = 0, facing = DIR_WEST, action = "forward" },
|
||||
{ name = "north goo check", x = 0, y = 0, z = -1, facing = DIR_SOUTH, action = "forward" },
|
||||
{ name = "south goo check", x = 0, y = 0, z = 1, facing = DIR_NORTH, action = "forward" },
|
||||
{ name = "top goo check", x = 0, y = 1, z = 0, facing = DIR_EAST, action = "down" },
|
||||
}
|
||||
|
||||
local TARGETS = {
|
||||
{ name = "west side", x = -2, y = 0, z = 0, facing = DIR_EAST, action = "forward" },
|
||||
{ name = "east side", x = 2, y = 0, z = 0, facing = DIR_WEST, action = "forward" },
|
||||
{ name = "north side", x = 0, y = 0, z = -2, facing = DIR_SOUTH, action = "forward" },
|
||||
{ name = "south side", x = 0, y = 0, z = 2, facing = DIR_NORTH, action = "forward" },
|
||||
{ name = "top", x = -1, y = 1, z = 0, facing = DIR_EAST, action = "forward" },
|
||||
}
|
||||
|
||||
local position = { x = HOME.x, y = HOME.y, z = HOME.z }
|
||||
local facing = HOME.facing
|
||||
local loggedBlockedItems = {}
|
||||
local placedTargets = {}
|
||||
local lastGooTier = nil
|
||||
|
||||
local function isFlag(name)
|
||||
return function(arg)
|
||||
return arg == "-" .. name or arg == "--" .. name
|
||||
end
|
||||
end
|
||||
|
||||
local isHelpFlag = isFlag("help")
|
||||
local isVersionFlag = isFlag("version")
|
||||
|
||||
local function printUsage()
|
||||
print("goo usage:")
|
||||
print()
|
||||
print("\t\t\tgoo start")
|
||||
print("\t\t\tgoo version")
|
||||
print("\t\t\tgoo help")
|
||||
end
|
||||
|
||||
if command == "version" or isVersionFlag(command) then
|
||||
print("goo v" .. _VERSION)
|
||||
return
|
||||
end
|
||||
|
||||
if command == nil or command == "" or command == "help" or isHelpFlag(command) then
|
||||
printUsage()
|
||||
return
|
||||
end
|
||||
|
||||
if command ~= "start" then
|
||||
printUsage()
|
||||
return
|
||||
end
|
||||
|
||||
if not turtle then
|
||||
error("goo must be run on a turtle")
|
||||
end
|
||||
|
||||
local function hasPickaxeEquipped()
|
||||
local left = turtle.getEquippedLeft()
|
||||
local right = turtle.getEquippedRight()
|
||||
|
||||
return (left and string.match(left.name or "", "_pickaxe$") ~= nil)
|
||||
or (right and string.match(right.name or "", "_pickaxe$") ~= nil)
|
||||
end
|
||||
|
||||
local function parseGooTier(blockName)
|
||||
local tier = string.match(blockName or "", "^" .. GOO_BLOCK_PREFIX .. "(%d+)$")
|
||||
|
||||
return tonumber(tier)
|
||||
end
|
||||
|
||||
local function isGooBlock(blockName)
|
||||
return parseGooTier(blockName) ~= nil
|
||||
end
|
||||
|
||||
local function isProcessBlock(blockName)
|
||||
return PROCESS_ITEMS[blockName] ~= nil
|
||||
end
|
||||
|
||||
local function isFuelItem(itemName)
|
||||
for i = 1, #FUEL_ITEMS do
|
||||
if FUEL_ITEMS[i] == itemName then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function isFeedingItemForTier(itemName, gooTier)
|
||||
local feedingItems = FEEDING_ITEMS_BY_TIER[gooTier] or {}
|
||||
|
||||
for i = 1, #feedingItems do
|
||||
if feedingItems[i] == itemName then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function countItem(itemName)
|
||||
local count = 0
|
||||
|
||||
for slot = 1, 16 do
|
||||
local item = turtle.getItemDetail(slot)
|
||||
|
||||
if item and item.name == itemName then
|
||||
count = count + item.count
|
||||
end
|
||||
end
|
||||
|
||||
return count
|
||||
end
|
||||
|
||||
local function countFeedingItems(gooTier)
|
||||
local count = 0
|
||||
local feedingItems = FEEDING_ITEMS_BY_TIER[gooTier] or {}
|
||||
|
||||
for i = 1, #feedingItems do
|
||||
count = count + countItem(feedingItems[i])
|
||||
end
|
||||
|
||||
return count
|
||||
end
|
||||
|
||||
local function findItemSlot(itemName)
|
||||
for slot = 1, 16 do
|
||||
local item = turtle.getItemDetail(slot)
|
||||
|
||||
if item and item.name == itemName then
|
||||
return slot, item
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local function hasFreeSlot()
|
||||
for slot = 1, 16 do
|
||||
if turtle.getItemCount(slot) == 0 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function getFuelLevel()
|
||||
local fuelLevel = turtle.getFuelLevel()
|
||||
|
||||
if fuelLevel == "unlimited" then
|
||||
return nil
|
||||
end
|
||||
|
||||
return fuelLevel
|
||||
end
|
||||
|
||||
local function getRefuelTarget()
|
||||
local fuelLimit = turtle.getFuelLimit()
|
||||
|
||||
if fuelLimit == "unlimited" or fuelLimit >= REFUEL_THRESHOLD then
|
||||
return REFUEL_THRESHOLD
|
||||
end
|
||||
|
||||
return fuelLimit
|
||||
end
|
||||
|
||||
local function findFuelSlot()
|
||||
for i = 1, #FUEL_ITEMS do
|
||||
local slot, item = findItemSlot(FUEL_ITEMS[i])
|
||||
|
||||
if slot then
|
||||
return slot, item
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local function turnRight()
|
||||
turtle.turnRight()
|
||||
facing = (facing + 1) % 4
|
||||
end
|
||||
|
||||
local function turnLeft()
|
||||
turtle.turnLeft()
|
||||
facing = (facing + 3) % 4
|
||||
end
|
||||
|
||||
local function turnTo(direction)
|
||||
while facing ~= direction do
|
||||
local rightTurns = (direction - facing) % 4
|
||||
|
||||
if rightTurns == 3 then
|
||||
turnLeft()
|
||||
else
|
||||
turnRight()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function moveForward()
|
||||
if not turtle.forward() then
|
||||
return false
|
||||
end
|
||||
|
||||
local delta = DIRECTION_DELTAS[facing]
|
||||
position.x = position.x + delta.x
|
||||
position.z = position.z + delta.z
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function moveUp()
|
||||
if not turtle.up() then
|
||||
return false
|
||||
end
|
||||
|
||||
position.y = position.y + 1
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function moveDown()
|
||||
if not turtle.down() then
|
||||
return false
|
||||
end
|
||||
|
||||
position.y = position.y - 1
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function moveAxis(target, positiveDirection, negativeDirection, axis)
|
||||
while position[axis] ~= target do
|
||||
if position[axis] < target then
|
||||
turnTo(positiveDirection)
|
||||
else
|
||||
turnTo(negativeDirection)
|
||||
end
|
||||
|
||||
if not moveForward() then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function goTo(target)
|
||||
while position.y < target.y do
|
||||
if not moveUp() then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
while position.y > target.y do
|
||||
if not moveDown() then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
if not moveAxis(target.x, DIR_EAST, DIR_WEST, "x") then
|
||||
return false
|
||||
end
|
||||
|
||||
if not moveAxis(target.z, DIR_SOUTH, DIR_NORTH, "z") then
|
||||
return false
|
||||
end
|
||||
|
||||
if target.facing then
|
||||
turnTo(target.facing)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function mustGoTo(target, description)
|
||||
while not goTo(target) do
|
||||
print("Cannot reach " .. description .. ". Clear the path and waiting...")
|
||||
os.sleep(WAIT_SECONDS)
|
||||
end
|
||||
end
|
||||
|
||||
local function goHome()
|
||||
mustGoTo(HOME, "home/provider")
|
||||
end
|
||||
|
||||
local function goToGooCheck()
|
||||
mustGoTo(GOO_CHECK, "goo check position")
|
||||
end
|
||||
|
||||
local function inspectDirection(action)
|
||||
if action == "forward" then
|
||||
return turtle.inspect()
|
||||
elseif action == "up" then
|
||||
return turtle.inspectUp()
|
||||
elseif action == "down" then
|
||||
return turtle.inspectDown()
|
||||
end
|
||||
|
||||
error("unknown inspect action " .. tostring(action))
|
||||
end
|
||||
|
||||
local function placeDirection(action)
|
||||
if action == "forward" then
|
||||
return turtle.place()
|
||||
elseif action == "up" then
|
||||
return turtle.placeUp()
|
||||
elseif action == "down" then
|
||||
return turtle.placeDown()
|
||||
end
|
||||
|
||||
error("unknown place action " .. tostring(action))
|
||||
end
|
||||
|
||||
local function refuelFromInventory()
|
||||
local fuelLevel = getFuelLevel()
|
||||
|
||||
if not fuelLevel or fuelLevel >= getRefuelTarget() then
|
||||
return false
|
||||
end
|
||||
|
||||
local previousSlot = turtle.getSelectedSlot()
|
||||
local consumedFuel = false
|
||||
|
||||
while fuelLevel < getRefuelTarget() do
|
||||
local slot, item = findFuelSlot()
|
||||
|
||||
if not slot then
|
||||
break
|
||||
end
|
||||
|
||||
turtle.select(slot)
|
||||
|
||||
if turtle.refuel(1) then
|
||||
consumedFuel = true
|
||||
print("Refueled with " .. item.name .. ". Fuel: " .. tostring(turtle.getFuelLevel()))
|
||||
fuelLevel = getFuelLevel()
|
||||
else
|
||||
print("Could not refuel with " .. item.name .. ".")
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
turtle.select(previousSlot)
|
||||
|
||||
return consumedFuel
|
||||
end
|
||||
|
||||
local function isProviderBelow()
|
||||
local ok = turtle.inspectDown()
|
||||
|
||||
return ok
|
||||
end
|
||||
|
||||
local function pullFromProvider()
|
||||
goHome()
|
||||
|
||||
local pulled = false
|
||||
|
||||
for _ = 1, MAX_SUCK_ATTEMPTS do
|
||||
if not hasFreeSlot() then
|
||||
break
|
||||
end
|
||||
|
||||
if turtle.suckDown() then
|
||||
pulled = true
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return pulled
|
||||
end
|
||||
|
||||
local function shouldKeepItem(item, gooTier)
|
||||
if isFuelItem(item.name) then
|
||||
return true
|
||||
end
|
||||
|
||||
local processItem = PROCESS_ITEMS[item.name]
|
||||
|
||||
if processItem and processItem.tier <= gooTier then
|
||||
return true
|
||||
end
|
||||
|
||||
if isFeedingItemForTier(item.name, gooTier) then
|
||||
return countFeedingItems(gooTier) <= MIN_FEEDING_ITEMS
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function depositOutputs(gooTier)
|
||||
goHome()
|
||||
|
||||
local previousSlot = turtle.getSelectedSlot()
|
||||
|
||||
for slot = 1, 16 do
|
||||
local item = turtle.getItemDetail(slot)
|
||||
|
||||
if item and not shouldKeepItem(item, gooTier) then
|
||||
turtle.select(slot)
|
||||
|
||||
if turtle.dropDown() then
|
||||
print("Deposited " .. item.name .. ".")
|
||||
else
|
||||
print("Could not deposit " .. item.name .. ". Provider may be full.")
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
turtle.select(previousSlot)
|
||||
end
|
||||
|
||||
local function waitForProvider(message)
|
||||
if message then
|
||||
print(message)
|
||||
end
|
||||
|
||||
repeat
|
||||
os.sleep(WAIT_SECONDS)
|
||||
until pullFromProvider()
|
||||
end
|
||||
|
||||
local function ensureStartFuel()
|
||||
while true do
|
||||
local fuelLevel = getFuelLevel()
|
||||
|
||||
if not fuelLevel or fuelLevel >= MIN_START_FUEL then
|
||||
return
|
||||
end
|
||||
|
||||
refuelFromInventory()
|
||||
fuelLevel = getFuelLevel()
|
||||
|
||||
if not fuelLevel or fuelLevel >= MIN_START_FUEL then
|
||||
return
|
||||
end
|
||||
|
||||
waitForProvider("Fuel is below " .. tostring(MIN_START_FUEL) .. ". Add fuel to the provider below home.")
|
||||
end
|
||||
end
|
||||
|
||||
local function ensureRuntimeFuel()
|
||||
local fuelLevel = getFuelLevel()
|
||||
|
||||
if not fuelLevel then
|
||||
return
|
||||
end
|
||||
|
||||
if fuelLevel < getRefuelTarget() then
|
||||
refuelFromInventory()
|
||||
end
|
||||
|
||||
fuelLevel = getFuelLevel()
|
||||
|
||||
while fuelLevel and fuelLevel < MIN_START_FUEL do
|
||||
waitForProvider("Fuel is below " .. tostring(MIN_START_FUEL) .. ". Add fuel to the provider below home.")
|
||||
refuelFromInventory()
|
||||
fuelLevel = getFuelLevel()
|
||||
end
|
||||
end
|
||||
|
||||
local function findFeedingSlot(gooTier)
|
||||
local feedingItems = FEEDING_ITEMS_BY_TIER[gooTier] or {}
|
||||
|
||||
for i = 1, #feedingItems do
|
||||
local slot, item = findItemSlot(feedingItems[i])
|
||||
|
||||
if slot then
|
||||
return slot, item
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local function findEligibleProcessSlot(gooTier)
|
||||
for slot = 1, 16 do
|
||||
local item = turtle.getItemDetail(slot)
|
||||
local processItem = item and PROCESS_ITEMS[item.name]
|
||||
|
||||
if processItem then
|
||||
if processItem.tier <= gooTier then
|
||||
return slot, item, processItem
|
||||
end
|
||||
|
||||
local logKey = item.name .. ":" .. tostring(gooTier)
|
||||
|
||||
if not loggedBlockedItems[logKey] then
|
||||
print(
|
||||
item.name
|
||||
.. " requires goo tier "
|
||||
.. tostring(processItem.tier)
|
||||
.. ", current tier is "
|
||||
.. tostring(gooTier)
|
||||
)
|
||||
loggedBlockedItems[logKey] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local function inspectGoo()
|
||||
for i = 1, #GOO_CHECKS do
|
||||
local check = GOO_CHECKS[i]
|
||||
|
||||
if goTo(check) then
|
||||
local ok, inspected = inspectDirection(check.action)
|
||||
|
||||
if ok then
|
||||
local tier = parseGooTier(inspected.name)
|
||||
|
||||
if tier then
|
||||
lastGooTier = tier
|
||||
|
||||
return tier, inspected, check
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if lastGooTier then
|
||||
print("Cannot reach the goo to inspect it. Using last known tier " .. tostring(lastGooTier) .. ".")
|
||||
|
||||
return lastGooTier, { state = { alive = true } }, nil
|
||||
end
|
||||
|
||||
error("expected a reachable Just Dire Things goo block around the turtle")
|
||||
end
|
||||
|
||||
local function ensureGooAlive()
|
||||
while true do
|
||||
local gooTier, inspected, check = inspectGoo()
|
||||
|
||||
if not check or inspected.state and inspected.state.alive == true then
|
||||
return gooTier
|
||||
end
|
||||
|
||||
local slot, item = findFeedingSlot(gooTier)
|
||||
|
||||
if not slot then
|
||||
waitForProvider("Goo tier " .. tostring(gooTier) .. " is not alive. Add feeding items to the provider.")
|
||||
else
|
||||
turtle.select(slot)
|
||||
print("Goo tier " .. tostring(gooTier) .. " is not alive. Feeding with " .. item.name .. "...")
|
||||
|
||||
if not placeDirection(check.action) then
|
||||
print("Could not feed the goo. Waiting before retry...")
|
||||
os.sleep(WAIT_SECONDS)
|
||||
else
|
||||
os.sleep(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function selectProcessItem(gooTier)
|
||||
local slot, item = findEligibleProcessSlot(gooTier)
|
||||
|
||||
if not slot then
|
||||
return nil
|
||||
end
|
||||
|
||||
turtle.select(slot)
|
||||
|
||||
return item
|
||||
end
|
||||
|
||||
local function inspectTarget(target)
|
||||
if target.action == "forward" then
|
||||
return turtle.inspect()
|
||||
elseif target.action == "up" then
|
||||
return turtle.inspectUp()
|
||||
elseif target.action == "down" then
|
||||
return turtle.inspectDown()
|
||||
end
|
||||
|
||||
error("unknown target action " .. tostring(target.action))
|
||||
end
|
||||
|
||||
local function digTarget(target)
|
||||
if target.action == "forward" then
|
||||
return turtle.dig()
|
||||
elseif target.action == "up" then
|
||||
return turtle.digUp()
|
||||
elseif target.action == "down" then
|
||||
return turtle.digDown()
|
||||
end
|
||||
|
||||
error("unknown target action " .. tostring(target.action))
|
||||
end
|
||||
|
||||
local function placeTarget(target)
|
||||
if target.action == "forward" then
|
||||
return turtle.place()
|
||||
elseif target.action == "up" then
|
||||
return turtle.placeUp()
|
||||
elseif target.action == "down" then
|
||||
return turtle.placeDown()
|
||||
end
|
||||
|
||||
error("unknown target action " .. tostring(target.action))
|
||||
end
|
||||
|
||||
local function ensureMiningSpace(gooTier)
|
||||
while not hasFreeSlot() do
|
||||
depositOutputs(gooTier)
|
||||
|
||||
if not hasFreeSlot() then
|
||||
print("Inventory is full and provider may be full. Waiting...")
|
||||
os.sleep(WAIT_SECONDS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function isTargetQueued(target)
|
||||
for i = 1, #placedTargets do
|
||||
if placedTargets[i] == target then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function removeQueuedTarget(index)
|
||||
table.remove(placedTargets, index)
|
||||
end
|
||||
|
||||
local function goToTarget(target)
|
||||
mustGoTo(target, target.name)
|
||||
end
|
||||
|
||||
local function mineQueuedTarget(gooTier)
|
||||
if #placedTargets == 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
local target = placedTargets[1]
|
||||
|
||||
goToTarget(target)
|
||||
ensureGooAlive()
|
||||
goToTarget(target)
|
||||
|
||||
local ok, inspected = inspectTarget(target)
|
||||
|
||||
if not ok then
|
||||
print("Queued " .. target.name .. " is empty.")
|
||||
removeQueuedTarget(1)
|
||||
return true
|
||||
end
|
||||
|
||||
if isProcessBlock(inspected.name) then
|
||||
return false
|
||||
end
|
||||
|
||||
if isGooBlock(inspected.name) then
|
||||
removeQueuedTarget(1)
|
||||
return true
|
||||
end
|
||||
|
||||
print("Mining processed " .. target.name .. " block: " .. tostring(inspected.name))
|
||||
ensureMiningSpace(gooTier)
|
||||
goToTarget(target)
|
||||
|
||||
if digTarget(target) then
|
||||
removeQueuedTarget(1)
|
||||
return true
|
||||
end
|
||||
|
||||
print("Could not mine " .. target.name .. ".")
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function placeAvailableTarget(gooTier)
|
||||
for i = 1, #TARGETS do
|
||||
local target = TARGETS[i]
|
||||
|
||||
if not isTargetQueued(target) then
|
||||
goToTarget(target)
|
||||
ensureGooAlive()
|
||||
goToTarget(target)
|
||||
|
||||
local ok, inspected = inspectTarget(target)
|
||||
|
||||
if ok then
|
||||
if not isProcessBlock(inspected.name) and not isGooBlock(inspected.name) then
|
||||
print("Mining existing " .. target.name .. " block: " .. tostring(inspected.name))
|
||||
ensureMiningSpace(gooTier)
|
||||
goToTarget(target)
|
||||
|
||||
if digTarget(target) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
else
|
||||
local item = selectProcessItem(gooTier)
|
||||
|
||||
if not item then
|
||||
return false
|
||||
end
|
||||
|
||||
print("Placing " .. item.name .. " on goo " .. target.name)
|
||||
|
||||
if placeTarget(target) then
|
||||
placedTargets[#placedTargets + 1] = target
|
||||
return true
|
||||
end
|
||||
|
||||
print("Could not place " .. target.name .. ".")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function waitAtOldestTarget()
|
||||
if #placedTargets == 0 then
|
||||
goToGooCheck()
|
||||
else
|
||||
goToTarget(placedTargets[1])
|
||||
end
|
||||
|
||||
print("Waiting for goo processing...")
|
||||
os.sleep(WAIT_SECONDS)
|
||||
end
|
||||
|
||||
local function startup()
|
||||
print("goo started. Layout: provider below turtle, goo two blocks ahead, turtle facing goo.")
|
||||
|
||||
if not hasPickaxeEquipped() then
|
||||
error("goo requires a turtle with a pickaxe equipped")
|
||||
end
|
||||
|
||||
if not isProviderBelow() then
|
||||
error("goo requires a provider/deposit barrel below the turtle")
|
||||
end
|
||||
|
||||
pullFromProvider()
|
||||
ensureStartFuel()
|
||||
end
|
||||
|
||||
startup()
|
||||
|
||||
while true do
|
||||
ensureRuntimeFuel()
|
||||
|
||||
local gooTier = ensureGooAlive()
|
||||
depositOutputs(gooTier)
|
||||
pullFromProvider()
|
||||
ensureRuntimeFuel()
|
||||
|
||||
gooTier = ensureGooAlive()
|
||||
local changed = mineQueuedTarget(gooTier)
|
||||
|
||||
if not changed then
|
||||
changed = placeAvailableTarget(gooTier)
|
||||
end
|
||||
|
||||
if not changed then
|
||||
if findEligibleProcessSlot(gooTier) then
|
||||
waitAtOldestTarget()
|
||||
else
|
||||
waitForProvider("No eligible process block found. Add inputs to the provider below home.")
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,7 +1,6 @@
|
||||
local _VERSION = '1.1.0';
|
||||
local _VERSION = '1.2.0';
|
||||
|
||||
local INSTALL_URL = 'https://raw.githubusercontent.com/guillaumearm/cc-libs/master/install.lua';
|
||||
local BETA_INSTALL_URL = 'https://raw.githubusercontent.com/guillaumearm/cc-libs/next/install.lua';
|
||||
|
||||
local command = ...;
|
||||
|
||||
@ -9,7 +8,6 @@ local function printUsage()
|
||||
print('upgrade usage:');
|
||||
print();
|
||||
print('\t\t\tupgrade');
|
||||
print('\t\t\tupgrade --beta');
|
||||
print('\t\t\tupgrade version');
|
||||
print('\t\t\tupgrade help');
|
||||
end
|
||||
@ -24,11 +22,6 @@ if command == 'help' or command == '-help' or command == '--help' then
|
||||
return;
|
||||
end
|
||||
|
||||
if command == '--beta' or command == '-beta' then
|
||||
shell.execute('wget', 'run', BETA_INSTALL_URL, '--beta');
|
||||
return;
|
||||
end
|
||||
|
||||
if command ~= nil and command ~= '' then
|
||||
printUsage();
|
||||
return;
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
local _VERSION = '2.0.0';
|
||||
|
||||
local function trim(s)
|
||||
return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
|
||||
local function readFile(path)
|
||||
local file = fs.open(path, "r");
|
||||
|
||||
if not file then
|
||||
return nil;
|
||||
end
|
||||
|
||||
local contents = file.readAll()
|
||||
file.close()
|
||||
|
||||
return contents
|
||||
end
|
||||
|
||||
local startupCommand = trim(readFile('.cubeboot') or "");
|
||||
|
||||
|
||||
if startupCommand ~= "" then
|
||||
print('cube-boot v' .. _VERSION .. ': execute \'' .. startupCommand .. '\'...');
|
||||
shell.run(startupCommand);
|
||||
else
|
||||
print('cube-startup v' .. _VERSION .. ' no startup command detected.')
|
||||
end
|
||||
@ -1,90 +0,0 @@
|
||||
local _VERSION = '2.1.0';
|
||||
|
||||
local net = require('/apis/net')();
|
||||
|
||||
local CUBE_CHANNEL = 64;
|
||||
|
||||
local function trim(s)
|
||||
return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
|
||||
local function readFile(path)
|
||||
local file = fs.open(path, "r");
|
||||
|
||||
if not file then
|
||||
return nil;
|
||||
end
|
||||
|
||||
local contents = file.readAll()
|
||||
file.close()
|
||||
|
||||
return contents
|
||||
end
|
||||
|
||||
local function writeFile(path, content)
|
||||
local file = fs.open(path, "w");
|
||||
|
||||
if not file then
|
||||
return false;
|
||||
end
|
||||
|
||||
file.write(content)
|
||||
file.close();
|
||||
|
||||
return true;
|
||||
end
|
||||
|
||||
local function ensureParentDir(path)
|
||||
local parentPath = string.match(path, '^(.+)/[^/]+$');
|
||||
|
||||
if parentPath and parentPath ~= '' and not fs.exists(parentPath) then
|
||||
fs.makeDir(parentPath);
|
||||
end
|
||||
end
|
||||
|
||||
local function getStartupCommand()
|
||||
return trim(readFile('.cubeboot') or "")
|
||||
end
|
||||
|
||||
-- ping event
|
||||
net.listenRequest(CUBE_CHANNEL, "ping", function(_, reply)
|
||||
local startupCommand = getStartupCommand();
|
||||
|
||||
reply({ startup = startupCommand });
|
||||
end)
|
||||
|
||||
-- reboot event
|
||||
net.listenRequest(CUBE_CHANNEL, "reboot", function(_, reply)
|
||||
reply(true);
|
||||
|
||||
os.sleep(0.2)
|
||||
os.reboot()
|
||||
end)
|
||||
|
||||
-- set-boot event
|
||||
net.listenRequest(CUBE_CHANNEL, "set-boot", function(startupCommand, reply)
|
||||
if startupCommand == nil or startupCommand == '' then
|
||||
fs.delete('/.cubeboot');
|
||||
reply(true);
|
||||
return;
|
||||
end
|
||||
|
||||
local res = writeFile('/.cubeboot', startupCommand);
|
||||
reply(res);
|
||||
end)
|
||||
|
||||
-- deploy-file event
|
||||
net.listenRequest(CUBE_CHANNEL, "deploy-file", function(payload, reply)
|
||||
if type(payload) ~= 'table' or type(payload.path) ~= 'string' or type(payload.content) ~= 'string' then
|
||||
reply(false);
|
||||
return;
|
||||
end
|
||||
|
||||
ensureParentDir(payload.path);
|
||||
reply(writeFile(payload.path, payload.content));
|
||||
end)
|
||||
|
||||
print('cube-server v' .. _VERSION .. ' started.')
|
||||
|
||||
-- start event loop
|
||||
net.startLoop();
|
||||
@ -1,9 +1,7 @@
|
||||
local _VERSION = '1.1.1'
|
||||
local _VERSION = '1.1.2'
|
||||
|
||||
local SERVERS = {
|
||||
"servers/ping-server",
|
||||
"servers/cube-server.lua",
|
||||
"servers/cube-boot.lua",
|
||||
};
|
||||
|
||||
local function init()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user