Files
2025-11-09 22:15:21 +01:00
..
2025-11-09 22:15:21 +01:00
2025-11-09 22:15:21 +01:00

opencomputers

Typed wrappers for the OC2R high-level API based on oc2r-core. Each module exposes a safe, idiomatic Rust interface for a specific device class.

Usage Overview

Every wrapper sits on top of Device::call. Typical imports look like:

use oc2r_core::{DeviceBus, Result, DEFAULT_DEVICE_PATH};
use opencomputers::*;

Attach the device before use:

let mut bus = DeviceBus::connect(DEFAULT_DEVICE_PATH)?;
let mut redstone = RedstoneInterface::attach(&mut bus)?
    .expect("no redstone interface attached");
redstone.subscribe()?; // unsubscribe() once you are done

Robot

use opencomputers::{Robot, RobotDirection};

let mut robot = Robot::attach(&mut bus)?.expect("no robot available");
println!("energy {}/{}", robot.energy()?, robot.capacity()?);

let selected = robot.slot(None)?;
println!("selected slot {selected}");
if let Some(stack) = robot.stack(None)? {
    println!("holding: {stack:?}");
}

if robot.move_blocking(RobotDirection::Forward)? {
    println!("stepped forward");
}
robot.turn(RobotDirection::Left)?;

Redstone Interface

use opencomputers::{RedstoneInterface, RedstoneSignal, Side};

redstone.set_output_state(Side::East, true)?;
let input = redstone.input(Side::East)?;
let output = redstone.output(Side::East)?;
redstone.set_output_level(Side::East, 7)?;

if let Some(signal) = redstone.try_event()? {
    println!("{} -> {}", signal.side, signal.level);
}

Side implements FromStr so strings like "north" parse safely. Incoming events surface as RedstoneSignal { side, level }; see examples/redstone-events.rs for a full event loop.

Energy Storage

use opencomputers::EnergyStorage;

let mut energy = EnergyStorage::attach(&mut bus)?.expect("no energy storage");
println!("{}/{}", energy.energy_stored()?, energy.max_energy_stored()?);
println!("can_extract: {}", energy.can_extract()?);
println!("can_receive: {}", energy.can_receive()?);

Fluid Handler

use opencomputers::FluidHandler;

let mut fluids = FluidHandler::attach(&mut bus)?.expect("no fluid handler");
let tanks = fluids.tank_count()? as usize;
for tank in 0..tanks {
    let capacity = fluids.tank_capacity(tank)?;
    let content = fluids.fluid_in_tank(tank)?;
    println!("tank {tank}: {content:?}/{capacity}");
}

Item Handler

use opencomputers::ItemHandler;

let mut items = ItemHandler::attach(&mut bus)?.expect("no item handler");
let slots = items.slot_count()? as usize;
for slot in 0..slots {
    let stack = items.stack_in_slot(slot)?;
    let limit = items.slot_limit(slot)?;
    println!("slot {slot}: {stack:?} (limit {limit})");
}

CPU

use opencomputers::Cpu;

let mut cpu = Cpu::attach(&mut bus)?.expect("no cpu card");
println!("frequency {} MHz", cpu.frequency()?);

Sound Card

use opencomputers::SoundCard;

let mut sound = SoundCard::attach(&mut bus)?.expect("no sound card");
sound.play_with_volume_and_pitch("minecraft:block.note_block.harp", 0.8, 1.2)?;
let matches = sound.find("note_block")?;
println!("found {} sound(s)", matches.len());

Block Operations Module

use opencomputers::{BlockOperations, RobotSide};

let mut ops = BlockOperations::attach(&mut bus)?.expect("no block module");
ops.excavate_on(RobotSide::Front)?;
ops.place_on(RobotSide::Down)?;
println!("durability {}", ops.durability()?);
if ops.repair()? {
    println!("tool repaired");
}

Inventory Operations Module

use opencomputers::{InventoryOperations, RobotSide};

let mut inv = InventoryOperations::attach(&mut bus)?.expect("no inventory module");
inv.move_items(0, 1, 32)?;
inv.drop_on(16, RobotSide::Front)?;
let taken = inv.take_from_slot_on(0, 8, RobotSide::Up)?;
println!("taken {taken}");

File Import/Export Card

use opencomputers::FileImportExport;

let mut fie = FileImportExport::attach(&mut bus)?.expect("no file card");
fie.reset()?;
fie.begin_export("test.txt")?;
fie.write_export_chunk(b"hello world")?;
fie.finish_export()?;

if fie.request_import()? {
    if let Some(info) = fie.begin_import()? {
        println!(
            "importing {} ({} bytes)",
            info.name.unwrap_or_default(),
            info.size
        );
        while let Some(bytes) = fie.read_import_chunk()? {
            // write bytes to disk
            println!("chunk {} bytes", bytes.len());
        }
    }
}

Device-specific events remain accessible through Device::next_event or DeviceBus::next_event_for when you need raw payloads.

Examples