merge: promote next to master

This commit is contained in:
Guillaume ARM 2026-06-07 22:42:52 +02:00
commit 877764a177
17 changed files with 408 additions and 1388 deletions

View File

@ -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.

View File

@ -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
View 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
View 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.

View 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.

View 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.

View 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.

View 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/)

View 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)

View File

@ -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()

View File

@ -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
View 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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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();

View File

@ -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()