Files
neonucleus/TODO.md
2026-05-23 16:27:47 +02:00

11 KiB

Vanilla components needed

Not everything OC has (as a few of them are really MC-centered) but most of it.

  • computer component
  • internet component (note: NN does not handle internet requests, those are up to the emulator)
  • relay component (note: OCDoc still refers to it as access_point)
  • geolyzer component
  • redstone component
  • motion_sensor component
  • printer3d component (note: maybe add signal for when printer completes?)
  • sign component
  • microcontroller component
  • hologram component
  • disk_drive component
  • note_block component

Custom components needed

  • oled component (OLED screen, a store of draw commands and resolution from NN's perspective)
  • ipu component, an Image Processing Unit. Can bind with oleds, and issues said draw commands
  • vt, a combination of a GPU, a screen and a keyboard with limited functionality. Offers direct operations on the video memory
  • (maybe) qpu component, a Quantum Processing Unit for quantum computing
  • radio_controller and radio_tower components, for radio telecommunications
  • (maybe) clock component for arbitrary precision time-keeping
  • led component for LED matrixes and/or LED lights
  • speaker component, allows playing audio by asking for binary samples and pushing a signal when it needs more
  • microphone component, allows reading audio from nearby sources
  • tape_drive component, compatible with Computronics
  • cd_drive to work with CDs (can be read-only, write-only or read-write)
  • serial component, for serial communications with other devices (see Serial)
  • iron_noteblock component
  • colorful_lamp component

To make it good

  • make more stuff const if it can be. Gotta help out the optimizer
  • put a bunch of internal-only functions as fastcall
  • write a bunch of unit tests to ensure the public API works correctly
  • ensure OOMs are recoverable
  • do a hude audit for bugs at some point

To make it fast

NOTE: we're mostly bottlenecked by the architecture (typically a Lua VM) and the intentional bottlenecking from call costs. breaking changes are allowed but like try to avoid them.

  • make signals use a circular buffer instead of a simple array
  • use more arenas if possible
  • reduce pointer nesting, not only for simplicity, but so we spend less time reading from main memory

Component extensions

filesystem

  • getMaxRead(): integer, returns the maximum size of a read; effectively the ideal buffer size

drive

  • readUByte(byte: integer): integer, reads an unsigned byte

Unique components

Subject to change, still being discussed with the other NeoFlock members.

Serial

The serial component would have the methods:

  • read(len: integer): string, to read data
  • write(data: string): boolean, to send data
  • isConnected(): boolean, to check if the port is currently connected
  • setProtocol(protocol: string): string, sets the protocol string of our port, which may be truncated.
  • getProtocol(): string, gets the currently registered protocol of our port. Default is raw.

It would also push the following signals:

  • serial_connected(portAddress: string, protocol: string), when connected
  • serial_protocol(portAddress: string, protocol: string), when other side changed protocol mid-connection.
  • serial_disconnected(portAddress: string), when the port is disconnected
  • serial_data(portAddress: string, amount: integer), when new data is available (and how much)

Radio

For very large-distance telecommunications. Frequency is in Hz.

The radio_controller component, which enables listening to connected radio towers

  • isOpen(): boolean, whether listening is enabled
  • open(): boolean, to open for listening
  • close(): boolean, to close the listener
  • setRange(minimum: number, maximum: number): boolean, sets the frequency range we listen for.
  • getRange(): number, number, gets the frequency range we listen for.

The radio_tower component, which actually receives and sends the waves

  • isEmitter(): boolean, whether this tower can, in fact, send radio waves
  • minFrequency: number, the minimum frequency it can detect and transmit (getter field)
  • maxFrequency: number, the maximum frequency it can detect and transmit (getter field)
  • resolution: integer, how many frequencies can be listened for in that range. The frequencies sent to the controller are rounded to one of these (getter field)
  • getRangeOf(frequency: number): number, to get the maximum range for a given frequency
  • maxPacketSize(): integer, to get the maximum size that can be sent at once, typically 32KiB.
  • baseFrequency: number, gets the base frequency of radio communications, typically 100 kHz. (getter field)
  • emit(frequency: number, data: string): boolean, to emit a radio packet on a given frequency. The frequency must be in range, and will be rounded to one within resolution

Radio waves travel at a (likely configurable) speed and have extremely large range on lower frequencies. They can also have bit flips.

The range and speed are based off the frequency range. Given base frequency f0, base energy cost e0, base range r0, we can compute energy cost e, range r of a given frequency f using:

  • r = r0 / (f / f0)
  • e = e0 * (f / f0)

When one is received, it will push:

  • radio_message(localControllerAddress: string, localTowerAddress: string, distance: number, frequency: number, data: string), where frequency is rounded to within the resolution of the tower. It does ensure the frequency is within the controller range and the controller is open. Data may be corrupted by bit flips. Distance is in meters. As you can notice, there is no sender address. It is the responsibility of the protocol to identify and verify senders.

VT

A generic virtual terminal. Like a GPU + screen, but with no VRAM. Has a 256-color palette representing ANSI 256 colors. Subsequently, colors 0-15 represent ANSI escape colors. The entire palette is editable.

The vt component has:

  • getResolution(): integer, integer, to get the resolution. Cannot be changed
  • getDepth(): integer, to get the color depth. Cannot be changed
  • getColor(index: integer): integer, to get a color
  • setColor(index: integer, color: integer): integer, sets a color and returns the old one. Characters who's colors were table indexes would be updated
  • setForeground(color: integer, fromTable?: boolean), sets a foreground color, optionally as a table index
  • getForeground(): integer, integer?, returns what the foreground color was, and the table index if applicable
  • setBackground(color: integer, fromTable?: boolean), sets a background color, optionally as a table index
  • getBackground(): integer, integer?, returns what the background color was, and the table index if applicable
  • set(idx: integer, data: string): boolean, to write to the screen's unicode buffer. While data is UTF-8, the buffer stores codepoints. Pretend the terminal does an internal conversion from UTF-8 to UTF-32
  • getColorOf(idx: integer): integer, integer, integer?, integer?, to get the foreground color, background color, and palette indexes of a tile
  • get(idx: integer, len: integer): string, to get the contents of part of the VT's unicode buffer, encoded as UTF-8

It also pushes the signals of keyboards and screens (no precise) for using input.

The unicode buffer is a 0-indexed buffer of codepoints alongside the color data. When writing to the unicode buffer, it also writes to the color buffer. If x and y are 0-indexed, then x + y * width is the index in the buffer

CD drives

The cd_drive component has:

  • hasDisk(): boolean, to check whether a disk is in the drive
  • isReadonly(): boolean, to check whether the drive is read-only (often is)
  • isDiskErasable(): boolean, to check whether the disk is erasable, which requires support from both the disk and the drive
  • getCapacity(): integer, gets the capacity of the disk
  • tell(): integer, current 0-indexed byte offset into the disk
  • seekTo(position: integer): boolean, seek to a 0-indexed byte offset in the disk
  • moveBy(delta: integer): boolean, move the current position by some amount of bytes (+/-), can wrap around
  • maxReadSize(): integer, to return the maximum size of a read
  • read(len: integer): string, to read some data. Does wrap around
  • write(data: string): boolean, to write some data. Does wrap around.

It also pushes the signals:

  • cd_added(driveAddress: string), for when a disk is added
  • cd_removed(driveAddress: string), for when a disk is removed

Writing to non-erasable drives

Instead of erroring out, it instead ORs the bits between what was there and what is written. This means you can still write the initial contents, as the CD starts out 0'd, but subsequent writes are likely to corrupt previous ones.

CDs vs tape

Tape is slow. CDs are fast. Tape is always fully writable. CDs may not always be erasable. Tape has high capacity, CDs do not.

CDs vs unmanaged floppies

CDs require special software support, while floppies appear as just smaller HDDs. Unmanaged floppies are always erasable, while CDs may not be. CDs are typically lower capacity.

LED

The led_matrix component has:

  • getResolution(): integer, integer, gets the resolution of the LED matrix.
  • getIntensity(x: integer, y: integer): number, gets the intensity of an LED.
  • setIntensity(x: integer, y: integer, intensity: number): number, sets the intensity of an LED and returns the old one.

Intensity is between 0 (off) and 1 (full brightness). An LED matrix has really high call budget, thus it is ideal for frequency updating status updates.

nandflash

Heavily inspired by ossm_flash

  • getWearLevel(): number, returns a number from 0 to 100, where 0 means full life and 100 means dead
  • getSectorSize(): integer, returns the logical sector size
  • getCapacity(): integer, the capacity, in bytes, of the flash storage
  • getLayers(): integer, returns the layering amount, for example 3 for TLC. Effectively an indication for lifetime, with higher being worse.
  • readSector(sec: integer): string, read a sector
  • writeSector(sec: integer, data: string): boolean, write a sector
  • readByte(byte: integer): integer, reads a signed byte
  • readUByte(byte: integer): integer, reads an unsigned byte
  • writeByte(byte: integer, val: integer): boolean, writes a byte
  • isReadonly(): boolean, check whether flash is read-only
  • getLabel(): string?, get drive label
  • setLabel(label: string?): string?, get drive label

Speaker

TODO: interface

Microphone

TODO: interface

OLED/IPU

TODO: interface

To re-evaluate

  • Make the hashmap growing/shrinking to save on memory.
  • Exposing the internal hashmap implementation.
  • Having a copy of the context stored directly in requests instead of having to use getComputerContext, as it simplifies the APIs and allows them to be made more portable.
  • Exposing more internal functions that may be useful to the user to prevent pointless rewriting and duplicate machine code.