2438 lines
83 KiB
C
2438 lines
83 KiB
C
#ifndef NEONUCLEUS_H
|
|
#define NEONUCLEUS_H
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
// Platform checking support, to help out users.
|
|
// Used internally as well.
|
|
// Based off https://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor
|
|
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
|
#ifndef NN_WINDOWS
|
|
#define NN_WINDOWS
|
|
#endif
|
|
#elif __APPLE__
|
|
#ifndef NN_MACOS
|
|
#define NN_MACOS
|
|
#endif
|
|
#elif __linux__
|
|
#ifndef NN_LINUX
|
|
#define NN_LINUX
|
|
#endif
|
|
#endif
|
|
|
|
#if __unix__
|
|
#ifndef NN_UNIX
|
|
#define NN_UNIX
|
|
#endif
|
|
#ifndef NN_POSIX
|
|
#define NN_POSIX
|
|
#endif
|
|
#elif defined(_POSIX_VERSION)
|
|
#ifndef NN_POSIX
|
|
#define NN_POSIX
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if defined(_MSC_VER) && !defined(__cplusplus)
|
|
#ifndef NN_ATOMIC_MSVC
|
|
#define NN_ATOMIC_MSVC
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef _MSC_VER
|
|
#define NN_INIT(type)
|
|
#else
|
|
#define NN_INIT(type) (type)
|
|
#endif
|
|
|
|
// every C standard header we depend on, conveniently put here
|
|
#include <stddef.h> // for NULL,
|
|
#include <stdint.h> // for intptr_t
|
|
#include <stdbool.h> // for true, false and bool
|
|
|
|
/* MSVC can't use VLA;
|
|
* What we see : NN_VLA(const char *, comps, len);
|
|
* What compiler see after preproccessor : const char * comps[len];
|
|
* What actaully was : const char *comps[len];
|
|
*/
|
|
// Test: gcc -E -DNN_VLA\(type,name,count\)="type name[count]" -x c - <<< 'NN_VLA(const char *, comps, len);'
|
|
#ifdef _MSC_VER
|
|
// avoid #include <malloc.h>, for it can pollute the namespace
|
|
// with symbols to functions which are not linked with in baremetal.
|
|
void *_alloca(size_t);
|
|
#define NN_VLA(type, name, count) type *name = (type *)_alloca(sizeof(type) * (count))
|
|
#else
|
|
#define NN_VLA(type, name, count) type name[count]
|
|
#endif
|
|
|
|
// Internally we need stdatomic.h and, if NN_BAREMETAL is not defined, stdlib.h and time.h
|
|
|
|
// The entire NeoNucleus API, in one header file
|
|
|
|
// Internal limits or constants
|
|
|
|
#define NN_KiB (1024)
|
|
#define NN_MiB (1024 * NN_KiB)
|
|
#define NN_GiB (1024 * NN_MiB)
|
|
#define NN_TiB ((size_t)1024 * NN_GiB)
|
|
|
|
// the alignment an allocation should have
|
|
#define NN_ALLOC_ALIGN 16
|
|
// the maximum amount of items the callstack can have.
|
|
#define NN_MAX_STACK 256
|
|
// the maximum size a path is allowed to have, including the NULL terminator!
|
|
#define NN_MAX_PATH 256
|
|
// the maximum size of a label
|
|
#define NN_MAX_LABEL 256
|
|
// maximum size of a wakeup message
|
|
#define NN_MAX_WAKEUPMSG 2048
|
|
// the maximum amount of file descriptors that can be open simultaneously
|
|
#define NN_MAX_OPENFILES 16
|
|
// the maximum amount of userdata that can be sent simultaneously.
|
|
#define NN_MAX_USERDATA 64
|
|
// maximum size of a signal, computed the same as modem packet costs.
|
|
#define NN_MAX_SIGNALSIZE 8192
|
|
// maximum amount of signals.
|
|
#define NN_MAX_SIGNALS 128
|
|
// the maximum value of a port. Ports start at 1.
|
|
#define NN_MAX_PORT 65535
|
|
// the magic port number to close all ports
|
|
#define NN_CLOSEPORTS 0
|
|
// maximum amount of architectures one machine can support.
|
|
#define NN_MAX_ARCHITECTURES 32
|
|
// maximum size of the architecture name EEPROMs can store
|
|
#define NN_MAX_ARCHNAME 64
|
|
// maximum size of an address.
|
|
// This only matters in places where an address is returned through a component, as it is the amount of space to allocate for the response.
|
|
// Past this there would be a truncation which would invalidate the address.
|
|
// However, 64 is unrealistically long, as UUIDv4 only needs 36.
|
|
// Please, do not go above this.
|
|
#define NN_MAX_ADDRESS 64
|
|
// the port used by tunnel cards. This port is invalid for modems.
|
|
#define NN_TUNNEL_PORT 0
|
|
// maximum amount of users a computer can have
|
|
#define NN_MAX_USERS 64
|
|
// maximum length of a username
|
|
#define NN_MAX_USERNAME 128
|
|
|
|
// the maximum size of a UTF-8 character
|
|
#define NN_MAX_UNICODE_BUFFER 4
|
|
|
|
// the maximum size of a component error message. If the error is bigger than this,
|
|
// it is truncated.
|
|
#define NN_MAX_ERROR_SIZE 1024
|
|
|
|
// unicode (UTF-8) support library
|
|
|
|
typedef unsigned int nn_codepoint;
|
|
|
|
bool nn_unicode_validate(const char *s, size_t len);
|
|
// validates only the *first* codepoint in the NULL-terminated string.
|
|
// This returns the length in bytes of the codepoint, with 0 meaning
|
|
// invalid.
|
|
size_t nn_unicode_validateFirstChar(const char *s, size_t len);
|
|
|
|
// returns the amount of unicode codepoints in the UTF-8 string.
|
|
// Undefined behavior for invalid UTF-8, make sure to validate it if needed.
|
|
size_t nn_unicode_len(const char *s, size_t len);
|
|
// returns the amount of unicode codepoints in the UTF-8 string.
|
|
// If s is invalid UTF-8, all invalid bytes are considered a 1-byte codepoint.
|
|
size_t nn_unicode_lenPermissive(const char *s, size_t len);
|
|
|
|
// Writes the codepoints of s into codepoints.
|
|
// Undefined behavior for invalid UTF-8, make sure to validate it if needed.
|
|
// The codepoints buffer must be big enough to store the string, use nn_unicode_len()
|
|
// to get the required buffer length.
|
|
void nn_unicode_codepoints(const char *s, size_t len, nn_codepoint *codepoints);
|
|
// Writes the codepoints of s into codepoints.
|
|
// If s is invalid UTF-8, all invalid bytes are considered a 1-byte codepoint.
|
|
// The codepoints buffer must be big enough to store the string, use nn_unicode_lenPermissive()
|
|
// to get the required buffer length.
|
|
void nn_unicode_codepointsPermissive(const char *s, size_t len, nn_codepoint *codepoints);
|
|
|
|
// Returns the first codepoint from a UTF-8 string.
|
|
// If s is invalid UTF-8, the behavior is undefined.
|
|
nn_codepoint nn_unicode_firstCodepoint(const char *s);
|
|
// Returns the size, in bytes, required by UTF-8 for a codepoint.
|
|
size_t nn_unicode_codepointSize(nn_codepoint codepoint);
|
|
// Writes the UTF-8 bytes for a given codepoint into buffer.
|
|
// It does NOT write a NULL terminator, but it does return the length.
|
|
size_t nn_unicode_codepointToChar(char buffer[NN_MAX_UNICODE_BUFFER], nn_codepoint codepoint);
|
|
// the width, on a screen, for a codepoint.
|
|
// This matters for emojies.
|
|
size_t nn_unicode_charWidth(nn_codepoint codepoint);
|
|
// The width, on a screen, for an entire string.
|
|
// The behavior is undefined for
|
|
size_t nn_unicode_wlen(const char *s, size_t len);
|
|
size_t nn_unicode_wlenPermissive(const char *s, size_t len);
|
|
|
|
// Returns the amount of bytes needed to store the UTF-8 encoded text.
|
|
// The behavior on invalid codepoints is undefined.
|
|
size_t nn_unicode_countBytes(nn_codepoint *codepoints, size_t len);
|
|
// Writes the UTF-8 encoded text.
|
|
// DOES NOT WRITE A NULL TERMINATOR.
|
|
// s must be big enough to store the string, use nn_unicode_bytelen()
|
|
// to allocate the correct amount of space.
|
|
// The behavior on invalid codepoints is undefined.
|
|
void nn_unicode_writeBytes(char *s, nn_codepoint *codepoints, size_t len);
|
|
|
|
// Returns the uppercase version of the codepoint
|
|
nn_codepoint nn_unicode_upper(nn_codepoint codepoint);
|
|
// Returns the lowercase version of the codepoint
|
|
nn_codepoint nn_unicode_lower(nn_codepoint codepoint);
|
|
|
|
// The type of a the function used as the allocator.
|
|
// The expected behavior is as follows:
|
|
// alloc(state, NULL, 0, newSize) -> malloc(newSize)
|
|
// alloc(state, memory, oldSize, 0) -> free(memory)
|
|
// alloc(state, memory, oldSize, newSize) -> realloc(memory, newSize)
|
|
//
|
|
// NeoNucleus will ensure oldSize is what the application requested on the last allocation.
|
|
// This is useful for allocators which may not do extensive bookkeeping.
|
|
// In the case of Out Of Memory, you are expected to return NULL.
|
|
typedef void *nn_AllocProc(void *state, void *memory, size_t oldSize, size_t newSize);
|
|
|
|
// Meant to return the time, in seconds, since some epoch.
|
|
typedef double nn_TimeProc(void *state);
|
|
|
|
typedef size_t nn_RngProc(void *state);
|
|
|
|
typedef enum nn_LockAction {
|
|
// create the mutex
|
|
NN_LOCK_CREATE,
|
|
// destroy the mutex
|
|
NN_LOCK_DESTROY,
|
|
// lock the mutex
|
|
NN_LOCK_LOCK,
|
|
// unlock the mutex
|
|
NN_LOCK_UNLOCK,
|
|
} nn_LockAction;
|
|
|
|
typedef struct nn_LockRequest {
|
|
// mutate it for NN_LOCK_INIT
|
|
void *lock;
|
|
nn_LockAction action;
|
|
} nn_LockRequest;
|
|
|
|
// Intended for a plain mutex.
|
|
// This is used for synchronization. OpenComputers achieves synchronization
|
|
// between the worker threads by sending them as requests to a central thread (indirect methods).
|
|
// In NeoNucleus, it is the same stuff, but direct ones may still be used across threads.
|
|
// Do note that locks are only used in "full" component implementations, such as the volatile storage devices.
|
|
// The interfaces do not do any automatic synchronization via locks, all synchronization is assumed
|
|
// to be handled in the implementer of the interface, because only you know how to best synchronize
|
|
// it with the outside world.
|
|
typedef void nn_LockProc(void *state, nn_LockRequest *req);
|
|
|
|
// The *context* NeoNucleus is operating in.
|
|
// This determines:
|
|
// - How memory is allocated
|
|
// - How random numbers are generated and what the range is
|
|
// - What the current time is
|
|
// - How locks work
|
|
typedef struct nn_Context {
|
|
void *state;
|
|
nn_AllocProc *alloc;
|
|
nn_TimeProc *time;
|
|
// the maximum value the RNG can produce.
|
|
// The RNG is assumed to generate [0, rngMaximum]. INCLUSIVE.
|
|
// When a [0, 1) range is needed, the value is divided by (rngMaximum+1),
|
|
// so rngMaximum+1 MUST NOT OVERFLOW.
|
|
size_t rngMaximum;
|
|
nn_RngProc *rng;
|
|
nn_LockProc *lock;
|
|
} nn_Context;
|
|
|
|
// if NN_BAREMETAL is defined when NeoNucleus is compiled,
|
|
// this function will fill in a bogus context that does nothing.
|
|
// Otherwise, it fills in a context which uses the C standard library.
|
|
// This function is only meant to be called once, to get the initial context.
|
|
// It does seed the RNG when using the C standard library, so do not
|
|
// call it in loops.
|
|
void nn_initContext(nn_Context *ctx);
|
|
|
|
// Memory allocation!!!
|
|
|
|
void *nn_alloc(nn_Context *ctx, size_t size);
|
|
void nn_free(nn_Context *ctx, void *memory, size_t size);
|
|
void *nn_realloc(nn_Context *ctx, void *memory, size_t oldSize, size_t newSize);
|
|
|
|
char *nn_strdup(nn_Context *ctx, const char *s);
|
|
void nn_strfree(nn_Context *ctx, char *s);
|
|
|
|
typedef struct nn_Lock nn_Lock;
|
|
|
|
nn_Lock *nn_createLock(nn_Context *ctx);
|
|
void nn_destroyLock(nn_Context *ctx, nn_Lock *lock);
|
|
void nn_lock(nn_Context *ctx, nn_Lock *lock);
|
|
void nn_unlock(nn_Context *ctx, nn_Lock *lock);
|
|
|
|
double nn_currentTime(nn_Context *ctx);
|
|
|
|
// generate a random RNG from 0 to the maximum
|
|
size_t nn_rand(nn_Context *ctx);
|
|
// generate a random float [0, 1)
|
|
double nn_randf(nn_Context *ctx);
|
|
// generate a random float [0, 1]
|
|
double nn_randfi(nn_Context *ctx);
|
|
|
|
typedef char nn_uuid[37];
|
|
void nn_randomUUID(nn_Context *ctx, nn_uuid uuid);
|
|
|
|
// Basic utils
|
|
|
|
// Does canonical path handling. Is used for sandboxing paths.
|
|
// It will turn \ to /, will turn invalid characters into spaces,
|
|
// and will resolve ...
|
|
// it also gets rid of / prefixes, / suffixes and //
|
|
void nn_simplifyPath(const char original[NN_MAX_PATH], char simplified[NN_MAX_PATH]);
|
|
|
|
typedef enum nn_Exit {
|
|
// no error
|
|
NN_OK = 0,
|
|
// out of memory.
|
|
NN_ENOMEM,
|
|
// over the limit. For example, adding too many architectures to a machine.
|
|
NN_ELIMIT,
|
|
// internal stack underflow when managing the stack.
|
|
NN_EBELOWSTACK,
|
|
// internal stack overflow when carrying values.
|
|
NN_ENOSTACK,
|
|
// bad invocation, error message stored in computer state
|
|
NN_EBADCALL,
|
|
// bad state, the function was called at the wrong time
|
|
NN_EBADSTATE,
|
|
} nn_Exit;
|
|
|
|
// This stores necessary data between computers
|
|
typedef struct nn_Universe nn_Universe;
|
|
|
|
nn_Universe *nn_createUniverse(nn_Context *ctx, void *userdata);
|
|
void nn_destroyUniverse(nn_Universe *universe);
|
|
void *nn_getUniverseData(nn_Universe *universe);
|
|
size_t nn_getUniverseMemoryLimit(nn_Universe *universe);
|
|
size_t nn_limitMemory(nn_Universe *universe, size_t memory);
|
|
void nn_setUniverseMemoryLimit(nn_Universe *universe, size_t limit);
|
|
size_t nn_getUniverseStorageLimit(nn_Universe *universe);
|
|
void nn_setUniverseStorageLimit(nn_Universe *universe, size_t limit);
|
|
size_t nn_limitStorage(nn_Universe *universe, size_t storage);
|
|
|
|
// The actual computer
|
|
typedef struct nn_Computer nn_Computer;
|
|
|
|
typedef enum nn_ComputerState {
|
|
// the machine is running just fine
|
|
NN_RUNNING = 0,
|
|
// machine is initializing. This is the state after createComputer but before the first nn_tick.
|
|
// It is a required state of various initialization functions.
|
|
NN_BOOTUP,
|
|
// the machine has powered off.
|
|
NN_POWEROFF,
|
|
// the machine demands being restarted.
|
|
NN_RESTART,
|
|
// the machine has crashed. RIP
|
|
NN_CRASHED,
|
|
// the machine ran out of energy.
|
|
NN_BLACKOUT,
|
|
// change architecture.
|
|
NN_CHARCH,
|
|
} nn_ComputerState;
|
|
|
|
typedef enum nn_ArchitectureAction {
|
|
// create the local state
|
|
NN_ARCH_INIT,
|
|
// destroy the local state
|
|
NN_ARCH_DEINIT,
|
|
// run 1 tick or synchronized task
|
|
NN_ARCH_TICK,
|
|
// get the free memory
|
|
NN_ARCH_FREEMEM,
|
|
// deserialize from an encoded state, passed into request.
|
|
NN_ARCH_DESERIALIZE,
|
|
// serialize to an encoded state, pushed it as a string
|
|
NN_ARCH_SERIALIZE,
|
|
} nn_ArchitectureAction;
|
|
|
|
typedef struct nn_ArchitectureRequest {
|
|
// the state pointer passed through
|
|
void *globalState;
|
|
// the computer which made the request
|
|
nn_Computer *computer;
|
|
// the local state bound to this computer.
|
|
// In NN_ARCH_INIT, this is NULL, and must be set to the new state, or an appropriate exit code returned.
|
|
void *localState;
|
|
// the action requested
|
|
nn_ArchitectureAction action;
|
|
union {
|
|
// in the case of NN_ARCH_TICK, where the tick is synchronized
|
|
bool synchronized;
|
|
// in the case of NN_ARCH_FREEMEM, the free memory
|
|
size_t freeMemory;
|
|
// in the case of NN_ARCH_DESERIALIZE, the buffer.
|
|
struct {
|
|
const char *memIn;
|
|
size_t memLen;
|
|
};
|
|
};
|
|
} nn_ArchitectureRequest;
|
|
|
|
typedef nn_Exit nn_ArchitectureHandler(nn_ArchitectureRequest *req);
|
|
|
|
typedef struct nn_Architecture {
|
|
const char *name;
|
|
void *state;
|
|
nn_ArchitectureHandler *handler;
|
|
} nn_Architecture;
|
|
|
|
// Standard RAM sizes.
|
|
// Standard OC goes from tier 1 to tier 6,
|
|
// NN adds 2 more tiers.
|
|
extern size_t nn_ramSizes[8];
|
|
|
|
typedef struct nn_Beep {
|
|
// frequenc, in Hz
|
|
double frequency;
|
|
// duration, in seconds
|
|
double duration;
|
|
// 0 is mute, 1 is 100%
|
|
double volume;
|
|
} nn_Beep;
|
|
|
|
// Morse beep, like a normal beep except it follows a morse code pattern.
|
|
// . is a short sound
|
|
// - is a long sound, 2x in length
|
|
// a space is a pause, 2x in length and dead silent.
|
|
// Every sound, including actual pauses, have a 50ms pause between them.
|
|
typedef struct nn_MorseBeep {
|
|
const char *pattern;
|
|
// frequency, in Hz
|
|
double frequency;
|
|
// duration of a ., in seconds
|
|
double beepDuration;
|
|
// 0 is mute, 1 is 100%
|
|
double volume;
|
|
} nn_MorseBeep;
|
|
|
|
typedef enum nn_EnvironmentAction {
|
|
NN_ENV_DRAWENERGY,
|
|
NN_ENV_POWERON,
|
|
NN_ENV_POWEROFF,
|
|
NN_ENV_CRASHED,
|
|
NN_ENV_BEEP,
|
|
NN_ENV_BEEPMORSE,
|
|
} nn_EnvironmentAction;
|
|
|
|
typedef struct nn_EnvironmentRequest {
|
|
nn_Computer *computer;
|
|
void *userdata;
|
|
nn_EnvironmentAction action;
|
|
union {
|
|
// for DRAWENERGY, is the amount to remove, and must be set to the amount remaining
|
|
double energy;
|
|
// for BEEP, information about the beep
|
|
nn_Beep beep;
|
|
// for BEEPMORSE, information about the beep
|
|
nn_MorseBeep morseBeep;
|
|
};
|
|
} nn_EnvironmentRequest;
|
|
|
|
typedef void nn_EnvironmentHandler(nn_EnvironmentRequest *req);
|
|
|
|
typedef struct nn_Environment {
|
|
void *userdata;
|
|
nn_EnvironmentHandler *handler;
|
|
} nn_Environment;
|
|
|
|
// The state of a *RUNNING* computer.
|
|
// Powered off computers shall not have a state, and as far as NeoNucleus is aware,
|
|
// not exist.
|
|
// The computer API *is not thread-safe*, so it is recommended that you use an external lock to manage it if you are running
|
|
// it in a multi-threaded environment.
|
|
// The userdata pointer is meant to store external data required by the environment.
|
|
// totalMemory is a hint to the architecture as to how much memory to allow the runner to use. It is in bytes.
|
|
// maxComponents and maxDevices determine how many components can be connected simultaneously to this computer, and how much device info can be
|
|
// registered on this computer.
|
|
nn_Computer *nn_createComputer(nn_Universe *universe, void *userdata, const char *address, size_t totalMemory, size_t maxComponents, size_t maxDevices);
|
|
void nn_retainComputer(nn_Computer *computer);
|
|
void nn_retainComputerN(nn_Computer *computer, size_t n);
|
|
// Destroys the state, effectively shutting down the computer.
|
|
void nn_destroyComputer(nn_Computer *computer);
|
|
void nn_destroyComputerN(nn_Computer *computer, size_t n);
|
|
void nn_lockComputer(nn_Computer *computer);
|
|
void nn_unlockComputer(nn_Computer *computer);
|
|
// stops the computer if an architecture state is already present,
|
|
// will also clear the signal buffer and set the state to NN_BOOTUP.
|
|
nn_Exit nn_startComputer(nn_Computer *computer);
|
|
// destroys the architecture state if present.
|
|
// Will also do other shutdown routines, such as unmounting every
|
|
void nn_stopComputer(nn_Computer *computer);
|
|
void nn_forceCrashComputer(nn_Computer *computer, const char *s);
|
|
// returns whether an architecture state is present
|
|
bool nn_isComputerOn(nn_Computer *computer);
|
|
void nn_setComputerEnvironment(nn_Computer *computer, nn_Environment env);
|
|
|
|
void nn_setDirectCost(nn_Computer *computer, double directCost);
|
|
double nn_getDirectCost(nn_Computer *computer);
|
|
|
|
// Device information
|
|
|
|
// Standard device attribute fields
|
|
|
|
#define NN_DEVICEATTR_CLASS "class"
|
|
#define NN_DEVICEATTR_DESC "description"
|
|
#define NN_DEVICEATTR_VENDOR "vendor"
|
|
#define NN_DEVICEATTR_PRODUCT "product"
|
|
#define NN_DEVICEATTR_VERSION "version"
|
|
#define NN_DEVICEATTR_SERIAL "serial"
|
|
#define NN_DEVICEATTR_CAPACITY "capacity"
|
|
#define NN_DEVICEATTR_SIZE "size"
|
|
#define NN_DEVICEATTR_CLOCK "clock"
|
|
#define NN_DEVICEATTR_WIDTH "width"
|
|
|
|
// Standard device classes
|
|
|
|
#define NN_DEVICECLASS_SYSTEM "system"
|
|
#define NN_DEVICECLASS_BRIDGE "bridge"
|
|
#define NN_DEVICECLASS_MEMORY "memory"
|
|
#define NN_DEVICECLASS_PROCESSOR "processor"
|
|
#define NN_DEVICECLASS_ADDRESS "address"
|
|
#define NN_DEVICECLASS_STORAGE "storage"
|
|
#define NN_DEVICECLASS_DISK "disk"
|
|
#define NN_DEVICECLASS_TAPE "tape"
|
|
#define NN_DEVICECLASS_BUS "bus"
|
|
#define NN_DEVICECLASS_NETWORK "network"
|
|
#define NN_DEVICECLASS_DISPLAY "display"
|
|
#define NN_DEVICECLASS_INPUT "input"
|
|
#define NN_DEVICECLASS_PRINTER "printer"
|
|
#define NN_DEVICECLASS_MULTIMEDIA "multimedia"
|
|
#define NN_DEVICECLASS_COMMUNICATION "communication"
|
|
#define NN_DEVICECLASS_POWER "power"
|
|
#define NN_DEVICECLASS_VOLUME "volume"
|
|
#define NN_DEVICECLASS_GENERIC "generic"
|
|
|
|
typedef struct nn_DeviceField {
|
|
const char *name;
|
|
const char *value;
|
|
} nn_DeviceField;
|
|
|
|
typedef struct nn_CommonDeviceInfo {
|
|
const char *CLASS;
|
|
const char *DESC;
|
|
const char *VENDOR;
|
|
const char *PRODUCT;
|
|
const char *VERSION;
|
|
const char *SERIAL;
|
|
const char *CAPACITY;
|
|
const char *SIZE;
|
|
const char *CLOCK;
|
|
const char *WIDTH;
|
|
} nn_CommonDeviceInfo;
|
|
|
|
const char *nn_deviceInfoAt(nn_Computer *computer, size_t idx);
|
|
const nn_DeviceField *nn_getDeviceInfo(nn_Computer *computer, size_t idx, size_t *fieldCount);
|
|
nn_Exit nn_addDeviceInfo(nn_Computer *computer, const char *addr, const nn_DeviceField *fields);
|
|
nn_Exit nn_addDeviceInfoL(nn_Computer *computer, const char *addr, const nn_DeviceField *fields, size_t fieldCount);
|
|
nn_Exit nn_addCommonDeviceInfo(nn_Computer *computer, const char *addr, nn_CommonDeviceInfo info);
|
|
// Sets every field to NULL.
|
|
void nn_clearCommonDeviceInfo(nn_CommonDeviceInfo *info);
|
|
bool nn_removeDeviceInfo(nn_Computer *computer, const char *addr);
|
|
|
|
void nn_beepComputer(nn_Computer *computer, nn_Beep beep);
|
|
void nn_beepComputerMorse(nn_Computer *computer, nn_MorseBeep beep);
|
|
|
|
// get the userdata pointer
|
|
void *nn_getComputerUserdata(nn_Computer *computer);
|
|
const char *nn_getComputerAddress(nn_Computer *computer);
|
|
nn_Universe *nn_getComputerUniverse(nn_Computer *computer);
|
|
nn_Context *nn_getUniverseContext(nn_Universe *universe);
|
|
nn_Context *nn_getComputerContext(nn_Computer *computer);
|
|
|
|
// Returns the memory usage limit of the computer.
|
|
size_t nn_getTotalMemory(nn_Computer *computer);
|
|
// Gets the total amount of free memory the computer has available. The total memory - this is the amount of memory used.
|
|
size_t nn_getFreeMemory(nn_Computer *computer);
|
|
// Gets the total amount of used memory the computer has allocated.
|
|
// This is just the total minus the free, and does not take into
|
|
// account the overhead of storing the computer instance.
|
|
size_t nn_getUsedMemory(nn_Computer *computer);
|
|
// gets the current uptime of a computer. When the computer is not running, this value can be anything and loses all meaning.
|
|
double nn_getUptime(nn_Computer *computer);
|
|
|
|
// Deserialize an encoded computer state.
|
|
// Encoding depends on architecture.
|
|
// Will push it as a string and then call the architecture, which will decode it and pop it.
|
|
nn_Exit nn_deserializeComputer(nn_Computer *computer, const char *buf, size_t buflen);
|
|
|
|
// Serialize the computer state.
|
|
// Encoding depends on architecture.
|
|
// Pushes the output, if successful, as a string on the stack.
|
|
nn_Exit nn_serializeComputer(nn_Computer *computer);
|
|
|
|
// address is copied.
|
|
// It can be NULL if you wish to have no tmp address.
|
|
// It can fail due to out-of-memory errors.
|
|
nn_Exit nn_setTmpAddress(nn_Computer *computer, const char *address);
|
|
// can return NULL if none was set
|
|
const char *nn_getTmpAddress(nn_Computer *computer);
|
|
|
|
// Registers a user to the computer.
|
|
nn_Exit nn_addUser(nn_Computer *computer, const char *user);
|
|
// Unregisters a user from the computer.
|
|
// If they were never there, nothing is removed and all is fine.
|
|
// It returns if the user was originally there.
|
|
bool nn_removeUser(nn_Computer *computer, const char *user);
|
|
// NULL for out-of-bound users
|
|
// Can be used to iterate all users.
|
|
const char *nn_getUser(nn_Computer *computer, size_t idx);
|
|
// Helper function.
|
|
// Always returns true if 0 users are registered.
|
|
// If users are registered, it will only return true if the specified
|
|
// user is registered.
|
|
// This can be used for checking signals.
|
|
bool nn_hasUser(nn_Computer *computer, const char *user);
|
|
|
|
// Sets the computer's architecture.
|
|
// The architecture determines everything from how the computer runs, to how it turns off.
|
|
// Everything is limited by the architecture.
|
|
// The architecture is copied, it can be freed after this is called.
|
|
void nn_setArchitecture(nn_Computer *computer, const nn_Architecture *arch);
|
|
// Gets the current architecture.
|
|
nn_Architecture nn_getArchitecture(nn_Computer *computer);
|
|
// Sets the computer's desired architecture.
|
|
// The desired architecture indicates, when the computer state is CHARCH, what the new architecture should be.
|
|
// This is set even if it is not in the supported architecture list, *you must check if it is in that list first.*
|
|
// The architecture is copied, it can be freed after this is called.
|
|
void nn_setDesiredArchitecture(nn_Computer *computer, const nn_Architecture *arch);
|
|
// Gets the desired architecture. This is the architecture the computer should use after changing architectures.
|
|
nn_Architecture nn_getDesiredArchitecture(nn_Computer *computer);
|
|
// Adds a new supported architecture, which indicates to the code running on this computer that it is possible to switch to that architecture.
|
|
// The architecture is copied, it can be freed after this is called.
|
|
nn_Exit nn_addSupportedArchitecture(nn_Computer *computer, const nn_Architecture *arch);
|
|
// Returns the array of supported architectures, as well as the length.
|
|
const nn_Architecture *nn_getSupportedArchitectures(nn_Computer *computer, size_t *len);
|
|
// Helper function for searching for an architecture using a computer which supports it and the architecture name.
|
|
// If the architecture is not found, it returns one with a NULL name.
|
|
nn_Architecture nn_findSupportedArchitecture(nn_Computer *computer, const char *name);
|
|
|
|
// sets the energy capacity of the computer.
|
|
void nn_setTotalEnergy(nn_Computer *computer, double maxEnergy);
|
|
// gets the energy capacity of the computer
|
|
double nn_getTotalEnergy(nn_Computer *computer);
|
|
// gets the current amount of energy
|
|
double nn_getEnergy(nn_Computer *computer);
|
|
// Returns true if there is no more energy left, and a blackout has occured.
|
|
bool nn_removeEnergy(nn_Computer *computer, double energy);
|
|
|
|
// copies the string into the local error buffer. The error is NULL terminated, but also capped by NN_MAX_ERROR_SIZE
|
|
void nn_setError(nn_Computer *computer, const char *s);
|
|
// set a default error message from an exit.
|
|
// Does nothing for EBADCALL.
|
|
void nn_setErrorFromExit(nn_Computer *computer, nn_Exit exit);
|
|
// copies the string into the local error buffer. The error is capped by NN_MAX_ERROR_SIZE-1. The -1 is there because the NULL terminator is still inserted at the end.
|
|
// Do note that nn_getError() still returns a NULL-terminated string, thus NULL terminators in this error will lead to a shortened error.
|
|
void nn_setLError(nn_Computer *computer, const char *s, size_t len);
|
|
// Gets a pointer to the local error buffer. This is only meaningful when NN_EBADCALL is returned.
|
|
const char *nn_getError(nn_Computer *computer);
|
|
// clears the computer's error buffer, making nn_getError return a simple empty string.
|
|
void nn_clearError(nn_Computer *computer);
|
|
|
|
// sets the computer state to the desired state. This is meant for architectures to report things like reboots or shutdowns, DO NOT ABUSE THIS.
|
|
void nn_setComputerState(nn_Computer *computer, nn_ComputerState state);
|
|
// gets the current computer state
|
|
nn_ComputerState nn_getComputerState(nn_Computer *computer);
|
|
|
|
// Checks if the uptime is below the idle timestamp.
|
|
bool nn_isComputerIdle(nn_Computer *computer);
|
|
// Shifts over the idle timestamp.
|
|
void nn_addIdleTime(nn_Computer *computer, double time);
|
|
void nn_resetIdleTime(nn_Computer *computer);
|
|
// runs a tick of the computer. Make sure to check the state as well!
|
|
// Does not do anything if we're currently waiting on a synced call
|
|
// This automatically resets the component budgets and call budget.
|
|
// It also sets the idle timestamp to the current uptime.
|
|
nn_Exit nn_tick(nn_Computer *computer);
|
|
|
|
// runs a synchronized tick of the computer. How this differs depends on architecture.
|
|
// Generally, this is meant to be in the same thread for all computers, and is if the external world is fundamentally not thread-safe,
|
|
// however components must interact with it.
|
|
// In this case, those component methods would be marked as NN_INDIRECT, or more accurately will not be marked as NN_DIRECT, and the architecture would queue them as synchronized tasks.
|
|
// Architectures should generally NOT ignore this if they can.
|
|
nn_Exit nn_tickSynchronized(nn_Computer *computer);
|
|
|
|
// raw component and methods
|
|
|
|
typedef struct nn_Component nn_Component;
|
|
|
|
typedef enum nn_MethodFlags {
|
|
// calling will consume the entire call budget
|
|
NN_INDIRECT = 0,
|
|
// calling will only consume 1 call from the call budget
|
|
NN_DIRECT = (1<<0),
|
|
// this indicates this method wraps a *field*
|
|
// getter means calling it with no arguments will return the current value,
|
|
NN_GETTER = (1<<1),
|
|
// this indicates this method wraps a *field*
|
|
// setter means calling it with 1 argument will try to set the value.
|
|
NN_SETTER = (1<<2),
|
|
} nn_MethodFlags;
|
|
|
|
#define NN_FIELD_MASK (NN_GETTER | NN_SETTER)
|
|
|
|
typedef struct nn_Method {
|
|
const char *name;
|
|
const char *doc;
|
|
nn_MethodFlags flags;
|
|
} nn_Method;
|
|
|
|
typedef enum nn_ComponentAction {
|
|
// component dropped
|
|
NN_COMP_DROP,
|
|
// component method invoked
|
|
NN_COMP_INVOKE,
|
|
// checking if component method is enabled
|
|
// (may be locked by tier)
|
|
NN_COMP_CHECKMETHOD,
|
|
// userdata request
|
|
NN_COMP_USERDATA,
|
|
} nn_ComponentAction;
|
|
|
|
typedef enum nn_UserdataAction {
|
|
NN_USER_DROP,
|
|
NN_USER_SERIALIZE,
|
|
NN_USER_DESERIALIZE,
|
|
NN_USER_GETMETHOD,
|
|
NN_USER_INVOKE,
|
|
} nn_UserdataAction;
|
|
|
|
typedef struct nn_UserdataRequest {
|
|
void *state;
|
|
nn_UserdataAction action;
|
|
union {
|
|
struct {
|
|
const char *data;
|
|
size_t len;
|
|
} deserialize;
|
|
struct {
|
|
size_t idx;
|
|
// set to NULL if idx is out of bounds
|
|
nn_Method *method;
|
|
} getmethod;
|
|
struct {
|
|
const char *method;
|
|
size_t returnCount;
|
|
} invoke;
|
|
};
|
|
} nn_UserdataRequest;
|
|
|
|
typedef struct nn_ComponentRequest {
|
|
nn_Context *ctx;
|
|
nn_Computer *computer;
|
|
void *state;
|
|
void *classState;
|
|
const char *compAddress;
|
|
nn_ComponentAction action;
|
|
// method index
|
|
unsigned int methodIdx;
|
|
union {
|
|
// return count
|
|
size_t returnCount;
|
|
// method enabled
|
|
bool methodEnabled;
|
|
nn_UserdataRequest *user;
|
|
};
|
|
} nn_ComponentRequest;
|
|
|
|
typedef nn_Exit (nn_ComponentHandler)(nn_ComponentRequest *request);
|
|
|
|
// creates a blank component.
|
|
// It has no methods,
|
|
nn_Component *nn_createComponent(nn_Universe *universe, const char *address, const char *type);
|
|
void nn_retainComponent(nn_Component *c);
|
|
void nn_retainComponentN(nn_Component *c, size_t n);
|
|
void nn_dropComponent(nn_Component *c);
|
|
void nn_dropComponentN(nn_Component *c, size_t n);
|
|
|
|
// configure the state
|
|
void nn_setComponentHandler(nn_Component *c, nn_ComponentHandler *handler);
|
|
void nn_setComponentState(nn_Component *c, void *state);
|
|
void nn_setComponentClassState(nn_Component *c, void *state);
|
|
// sets the methods, same implications as setComponentMethodsArray.
|
|
// methods is NULL-terminated, as in, it is terminated by a method with a NULL name.
|
|
nn_Exit nn_setComponentMethods(nn_Component *c, const nn_Method *methods);
|
|
// sets the methods.
|
|
// The memory of the strings is copied, so they can be freed after this returns.
|
|
// This operation is NOT atomic, if it fails, it will clear out the previous methods.
|
|
nn_Exit nn_setComponentMethodsArray(nn_Component *c, const nn_Method *methods, size_t count);
|
|
// Sets an internal type ID, which is meant to be a more precise typename.
|
|
// For example, ncomplib would set ncl-screen for the screen component,
|
|
// so the GPU can confirm it is being bound to a screen it knows how to use.
|
|
nn_Exit nn_setComponentTypeID(nn_Component *c, const char *internalTypeID);
|
|
|
|
// Sets the method flags
|
|
void nn_setComponentMethodFlags(nn_Component *c, const char *method, nn_MethodFlags flags);
|
|
// combines method flags
|
|
void nn_addComponentMethodFlags(nn_Component *c, const char *method, nn_MethodFlags flags);
|
|
// removes method flags
|
|
void nn_removeComponentMethodFlags(nn_Component *c, const char *method, nn_MethodFlags flags);
|
|
|
|
// get component state
|
|
void *nn_getComponentState(nn_Component *c);
|
|
// get component class state
|
|
void *nn_getComponentClassState(nn_Component *c);
|
|
// counts how many methods are registered. May return too many if some of them are not enabled.
|
|
size_t nn_countComponentMethods(nn_Component *c);
|
|
// will fill the methodnames array with the names of the *enabled* methods.
|
|
// Will set *len to the amount of methods.
|
|
void nn_getComponentMethods(nn_Component *c, const char **methodnames, size_t *len);
|
|
// whether a method is defined and enabled
|
|
bool nn_hasComponentMethod(nn_Component *c, const char *method);
|
|
const char *nn_getComponentDoc(nn_Component *c, const char *method);
|
|
nn_MethodFlags nn_getComponentMethodFlags(nn_Component *c, const char *method);
|
|
const char *nn_getComponentType(nn_Component *c);
|
|
const char *nn_getComponentTypeID(nn_Component *c);
|
|
const char *nn_getComponentAddress(nn_Component *c);
|
|
|
|
// Adds a component to the computer on a given slot.
|
|
// This will also queue a component_added signal if the computer is in a running state, unless silent is true.
|
|
// If the component already is mounted, an error is returned.
|
|
nn_Exit nn_mountComponent(nn_Computer *c, nn_Component *comp, int slot, bool silent);
|
|
// Removes a component from the computer.
|
|
// This will also queue a component_removed signal if the computer is in a running state, unless silent is true.
|
|
// If the component is not mounted, no error is returned.
|
|
nn_Exit nn_unmountComponent(nn_Computer *c, const char *address, bool silent);
|
|
nn_Exit nn_swapComponents(nn_Computer *c, nn_Component *previous, nn_Component *next, int slot);
|
|
// gets a component by address. Will return NULL if there is none.
|
|
nn_Component *nn_getComponent(nn_Computer *c, const char *address);
|
|
int nn_getComponentSlot(nn_Computer *c, const char *address);
|
|
size_t nn_countComponents(nn_Computer *c);
|
|
void nn_getComponents(nn_Computer *c, const char **components);
|
|
|
|
// invoke the component method.
|
|
// Everything on-stack is taken as an argument.
|
|
// Will pop off trailing nulls.
|
|
// Every remaining stack value is what the component returned.
|
|
// In the case of errors, the contents of the stack is undefined
|
|
nn_Exit nn_invokeComponent(nn_Computer *computer, const char *compAddress, const char *method);
|
|
|
|
// send a signal to a component.
|
|
// Computer actually can be NULL, but the component may crash if the signal
|
|
// assumes one is specified.
|
|
nn_Exit nn_signalComponent(nn_Component *component, nn_Computer *computer, const char *signal);
|
|
|
|
// Userdata!!!!
|
|
|
|
// Allocates a userdata index. Returns -1 on failure or if there are too many.
|
|
int nn_allocUserdata(nn_Computer *computer, void *state, const char *compAddress);
|
|
|
|
// Frees a userdata index.
|
|
void nn_freeUserdata(nn_Computer *computer, size_t userdata);
|
|
|
|
// Returns whether the userdata index is valid
|
|
bool nn_isUserdataValid(nn_Computer *computer, size_t userdata);
|
|
|
|
// If compAddress is correct and userdata is valid, returns the state pointer.
|
|
// If not, returns NULL, to prevent UB.
|
|
void *nn_unwrapUserdata(nn_Computer *computer, size_t userdata, const char *compAddress);
|
|
|
|
// gets the component address which manages this userdata
|
|
const char *nn_getUserdataComponent(nn_Computer *computer, size_t userdata);
|
|
|
|
// Gets information about a method of this userdata, by index.
|
|
// If idx is out of bounds, this returns true, which means to stop iteration.
|
|
// If method->name is NULL, the method should be skipped.
|
|
bool nn_getUserdataMethod(nn_Computer *computer, size_t userdata, size_t idx, nn_Method *method);
|
|
|
|
// Invokes a method on some userdata, same semantics as nn_invokeComponent
|
|
nn_Exit nn_invokeUserdata(nn_Computer *computer, size_t userdata, const char *method);
|
|
|
|
// Serializes the userdata into a buffer and pushes it as a string.
|
|
// Make sure to keep track of its index and component address!
|
|
nn_Exit nn_serializeUserdata(nn_Computer *computer, size_t userdata);
|
|
|
|
// Deserializes userdata at a particular index.
|
|
// NOTE: if the component does not exist, or the userdata index is already taken, this errors.
|
|
nn_Exit nn_deserializeUserdata(nn_Computer *computer, size_t userdata, const char *compAddress, const char *buf, size_t len);
|
|
|
|
// default call budgets for 4 tiers of CPUs
|
|
extern double nn_defaultCallBudgets[4];
|
|
// the call budget of a creative CPU
|
|
extern double nn_unlimitedCallBudget;
|
|
// default component limits for 4 tiers of component buses / CPUs
|
|
extern size_t nn_defaultComponentLimits[4];
|
|
// the component limit of a creative component bus
|
|
extern size_t nn_creativeComponentLimit;
|
|
|
|
// Sets the call budget.
|
|
// The default is 1.
|
|
void nn_setCallBudget(nn_Computer *computer, double budget);
|
|
|
|
// gets the total call budget
|
|
double nn_getCallBudget(nn_Computer *computer);
|
|
|
|
// returns the remaining call budget
|
|
double nn_callBudgetRemaining(nn_Computer *computer);
|
|
|
|
// automatically called by nn_tick()
|
|
void nn_resetCallBudget(nn_Computer *computer);
|
|
|
|
// returns whether there is no more call budget left.
|
|
// At this point, the architecture should exit with a yield.
|
|
bool nn_componentsOverused(nn_Computer *computer);
|
|
|
|
void nn_resetComponentBudgets(nn_Computer *computer);
|
|
|
|
// Uses 1/perTick to the component budget.
|
|
// Upon a full component budget being used for that component, it returns true.
|
|
// nn_componentsOverused() will also return true.
|
|
// This indicates the architecture should yield, to throttle the computer for overuse.
|
|
bool nn_costComponent(nn_Computer *computer, double perTick);
|
|
// Uses amount/perTick to the component budget.
|
|
// Upon a full component budget being used for that component, it returns true.
|
|
// nn_componentsOverused() will also return true.
|
|
// This indicates the architecture should yield, to throttle the computer for overuse.
|
|
bool nn_costComponentN(nn_Computer *computer, double amount, double perTick);
|
|
|
|
// call stack operations.
|
|
// The type system and API are inspired by Lua, as Lua remains the most popular architecture for OpenComputers.
|
|
// This does support other languages, however it may make some APIs clunky due to the usage of tables and 1-based indexing.
|
|
// Internally, reference counting is used to manage the memory automatically. The API is designed such that strong reference cycles
|
|
// cannot occur.
|
|
|
|
// returns if there is enough space for [amount] values
|
|
bool nn_checkstack(nn_Computer *computer, size_t amount);
|
|
|
|
// pushes a null on the call stack
|
|
nn_Exit nn_pushnull(nn_Computer *computer);
|
|
// pushes a boolean on the call stack
|
|
nn_Exit nn_pushbool(nn_Computer *computer, bool truthy);
|
|
// pushes a number on the call stack
|
|
nn_Exit nn_pushnumber(nn_Computer *computer, double num);
|
|
// casts [num] to a double and pushes it on the call stack
|
|
nn_Exit nn_pushinteger(nn_Computer *computer, intptr_t num);
|
|
// pushes a NULL-terminated string on the call stack. The string is copied, so you can free it afterwards without worry.
|
|
nn_Exit nn_pushstring(nn_Computer *computer, const char *str);
|
|
// pushes a string on the call stack. The string is copied, so you can free it afterwards without worry. The copy will have a NULL terminator inserted
|
|
// at the end for APIs which need it, but the length is also stored.
|
|
nn_Exit nn_pushlstring(nn_Computer *computer, const char *str, size_t len);
|
|
// pushes a computer userdata to the stack. This is indicative of a resource, such as an HTTP request.
|
|
nn_Exit nn_pushuserdata(nn_Computer *computer, size_t userdataIdx);
|
|
// pushes a table meant to be an array. [len] is the length of the array. The keys are numbers and 1-indexed, just like in Lua.
|
|
// The values are popped, then the array is pushed.
|
|
nn_Exit nn_pusharraytable(nn_Computer *computer, size_t len);
|
|
// pushes a table. [len] is the amount of pairs. Keys should not be duplicated, as they are not de-duplicated.
|
|
// The stack should have a sequence of K1,V1,K2,V2,etc., len pairs long.
|
|
// The pairs are popped, then the array is pushed.
|
|
nn_Exit nn_pushtable(nn_Computer *computer, size_t len);
|
|
|
|
// stack management
|
|
|
|
// pops the top value off the stack
|
|
nn_Exit nn_pop(nn_Computer *computer);
|
|
// pops the top N values off the stack
|
|
nn_Exit nn_popn(nn_Computer *computer, size_t n);
|
|
// pushes the top value onto the stack, effectively duplicating the top value.
|
|
nn_Exit nn_dupe(nn_Computer *computer);
|
|
// pushes the top N values onto the stack, effectively duplicating the top N values.
|
|
nn_Exit nn_dupen(nn_Computer *computer, size_t n);
|
|
|
|
// pushes the value at idx.
|
|
nn_Exit nn_dupeat(nn_Computer *computer, size_t idx);
|
|
|
|
// get the current amount of values on the call stack.
|
|
// For component calls, calling this at the start effectively gives you the argument count.
|
|
size_t nn_getstacksize(nn_Computer *computer);
|
|
// Removes all values from the stack.
|
|
// It is recommended to do this when initiating a component call or
|
|
// after returning from errors, as the call stack may have
|
|
// random junk on it.
|
|
void nn_clearstack(nn_Computer *computer);
|
|
|
|
// type check! The API may misbehave if types do not match, so always type-check!
|
|
|
|
// Returns whether the value at [idx] is a null.
|
|
// [idx] starts at 0.
|
|
bool nn_isnull(nn_Computer *computer, size_t idx);
|
|
// Returns whether the value at [idx] is a boolean.
|
|
// [idx] starts at 0.
|
|
bool nn_isboolean(nn_Computer *computer, size_t idx);
|
|
// Returns whether the value at [idx] is a number.
|
|
// [idx] starts at 0.
|
|
bool nn_isnumber(nn_Computer *computer, size_t idx);
|
|
// Returns whether the value at [idx] is a number AND
|
|
// the number can safely be cast to an intptr_t.
|
|
bool nn_isinteger(nn_Computer *computer, size_t idx);
|
|
// Returns whether the value at [idx] is a string.
|
|
// [idx] starts at 0.
|
|
bool nn_isstring(nn_Computer *computer, size_t idx);
|
|
// Returns whether the value at [idx] is a userdata.
|
|
// [idx] starts at 0.
|
|
bool nn_isuserdata(nn_Computer *computer, size_t idx);
|
|
// Returns whether the value at [idx] is a table.
|
|
// [idx] starts at 0.
|
|
bool nn_istable(nn_Computer *computer, size_t idx);
|
|
// Returns the name of the type of the value at that index.
|
|
// For out of bounds indexes, "none" is returned.
|
|
const char *nn_typenameof(nn_Computer *computer, size_t idx);
|
|
|
|
// Argument helpers
|
|
|
|
// Returns true if the argument at that index is not null.
|
|
bool nn_checknull(nn_Computer *computer, size_t idx, const char *errMsg);
|
|
// Returns true if the argument at that index is not a boolean.
|
|
bool nn_checkboolean(nn_Computer *computer, size_t idx, const char *errMsg);
|
|
// Returns true if the argument at that index is not a number.
|
|
bool nn_checknumber(nn_Computer *computer, size_t idx, const char *errMsg);
|
|
// Returns true if the argument at that index is not an integer.
|
|
bool nn_checkinteger(nn_Computer *computer, size_t idx, const char *errMsg);
|
|
// Returns true if the argument at that index is not a string.
|
|
bool nn_checkstring(nn_Computer *computer, size_t idx, const char *errMsg);
|
|
// Returns true if the argument at that index is not userdata.
|
|
bool nn_checkuserdata(nn_Computer *computer, size_t idx, const char *errMsg);
|
|
// Returns true if the argument at that index is a table.
|
|
bool nn_checktable(nn_Computer *computer, size_t idx, const char *errMsg);
|
|
|
|
// Checks if idx is equal to the stack size.
|
|
// If it is, it will push a null.
|
|
nn_Exit nn_defaultnull(nn_Computer *computer, size_t idx);
|
|
// Checks if idx is equal to the stack size.
|
|
// If it is, it will push a boolean [value].
|
|
nn_Exit nn_defaultboolean(nn_Computer *computer, size_t idx, bool value);
|
|
// Checks if idx is equal to the stack size.
|
|
// If it is, it will push a number [num].
|
|
nn_Exit nn_defaultnumber(nn_Computer *computer, size_t idx, double num);
|
|
// Checks if idx is equal to the stack size.
|
|
// If it is, it will push an integer [num].
|
|
nn_Exit nn_defaultinteger(nn_Computer *computer, size_t idx, intptr_t num);
|
|
// Checks if idx is equal to the stack size.
|
|
// If it is, it will push a string [str].
|
|
nn_Exit nn_defaultstring(nn_Computer *computer, size_t idx, const char *str);
|
|
// Checks if idx is equal to the stack size.
|
|
// If it is, it will push a string [str].
|
|
nn_Exit nn_defaultlstring(nn_Computer *computer, size_t idx, const char *str, size_t len);
|
|
// Checks if idx is equal to the stack size.
|
|
// If it is, it will push the userdata [userdataIdx].
|
|
nn_Exit nn_defaultuserdata(nn_Computer *computer, size_t idx, size_t userdataIdx);
|
|
// Checks if idx is equal to the stack size.
|
|
// If it is, it will push an empty table.
|
|
nn_Exit nn_defaulttable(nn_Computer *computer, size_t idx);
|
|
|
|
// NOTE: behavior of the nn_to*() functions and nn_dumptable() when the values have the wrong types or at out of bounds indexes is undefined.
|
|
|
|
// Returns the boolean value at [idx].
|
|
bool nn_toboolean(nn_Computer *computer, size_t idx);
|
|
// Returns the number value at [idx].
|
|
double nn_tonumber(nn_Computer *computer, size_t idx);
|
|
// Returns the number value at [idx] cast to an intptr_t.
|
|
// NOTE: for numbers where nn_isinteger() returns false,
|
|
// the cast is undefined.
|
|
// This includes values such as infinity and NaN, where
|
|
// the behavior is platform, ABI and compiler-specific.
|
|
intptr_t nn_tointeger(nn_Computer *computer, size_t idx);
|
|
// Returns the string value at [idx].
|
|
const char *nn_tostring(nn_Computer *computer, size_t idx);
|
|
// Returns the string value and its length at [idx].
|
|
const char *nn_tolstring(nn_Computer *computer, size_t idx, size_t *len);
|
|
// Returns the userdata index at [idx].
|
|
size_t nn_touserdata(nn_Computer *computer, size_t idx);
|
|
// Takes a table value and pushes onto the stack the key-value pairs, as well as writes how many there were in [len].
|
|
// It pushes them as K1,V1,K2,V2,K3,V3,etc., just like went in to pushtable. And yes, the keys are not de-duplicated.
|
|
nn_Exit nn_dumptable(nn_Computer *computer, size_t idx, size_t *len);
|
|
|
|
// computes the cost of the top [values] values using the same algorithm as
|
|
// the modem.
|
|
// It will return -1 if the values are invalid.
|
|
// The algorithm is as mentioned in https://ocdoc.cil.li/component:modem, with 1 small change to match OC's code.
|
|
// and is as follows:
|
|
// - Every value adds a 2 byte overhead
|
|
// - Numbers add another 8 bytes, true/false/null another 1 byte, strings as
|
|
// many bytes as they contain, except empty strings count as 1 byte.
|
|
int nn_countValueCost(nn_Computer *computer, size_t values);
|
|
|
|
// computes the signal cost.
|
|
// This is a slightly modified version of value cost, except it allows
|
|
// tables and userdata.
|
|
// All values are always valid.
|
|
// For userdata and tables:
|
|
// - Userdata adds another 8 bytes overhead like numbers do.
|
|
// - Tables add yet another 2 byte overhead for their terminator, and the sum of all of the size of the keys and values they contain as per this algorithm.
|
|
size_t nn_countSignalCost(nn_Computer *computer, size_t values);
|
|
|
|
// Returns the amount of signals stored
|
|
size_t nn_countSignals(nn_Computer *computer);
|
|
// Pops [valueCount] values from the call stack and pushes them as a signal.
|
|
nn_Exit nn_pushSignal(nn_Computer *computer, size_t valueCount);
|
|
// Removes the first signal and pushes the values onto the call stack, while setting valueCount to the amount of values in the signal.
|
|
// If there is no signal, it returns EBADSTATE
|
|
nn_Exit nn_popSignal(nn_Computer *computer, size_t *valueCount);
|
|
|
|
nn_Exit nn_transferErrorFrom(nn_Exit exit, nn_Computer *from, nn_Computer *to);
|
|
|
|
// Signal helpers
|
|
|
|
// common mouse buttons, not an exhaustive list
|
|
#define NN_BUTTON_LEFT 0
|
|
#define NN_BUTTON_RIGHT 1
|
|
#define NN_BUTTON_MIDDLE 2
|
|
|
|
// OC keycodes
|
|
// taken from https://github.com/MightyPirates/OpenComputers/blob/52da41b5e171b43fea80342dc75d808f97a0f797/src/main/resources/assets/opencomputers/loot/openos/lib/core/full_keyboard.lua
|
|
#define NN_KEY_UNKNOWN 0
|
|
#define NN_KEY_1 0x02
|
|
#define NN_KEY_2 0x03
|
|
#define NN_KEY_3 0x04
|
|
#define NN_KEY_4 0x05
|
|
#define NN_KEY_5 0x06
|
|
#define NN_KEY_6 0x07
|
|
#define NN_KEY_7 0x08
|
|
#define NN_KEY_8 0x09
|
|
#define NN_KEY_9 0x0A
|
|
#define NN_KEY_0 0x0B
|
|
#define NN_KEY_A 0x1E
|
|
#define NN_KEY_B 0x30
|
|
#define NN_KEY_C 0x2E
|
|
#define NN_KEY_D 0x20
|
|
#define NN_KEY_E 0x12
|
|
#define NN_KEY_F 0x21
|
|
#define NN_KEY_G 0x22
|
|
#define NN_KEY_H 0x23
|
|
#define NN_KEY_I 0x17
|
|
#define NN_KEY_J 0x24
|
|
#define NN_KEY_K 0x25
|
|
#define NN_KEY_L 0x26
|
|
#define NN_KEY_M 0x32
|
|
#define NN_KEY_N 0x31
|
|
#define NN_KEY_O 0x18
|
|
#define NN_KEY_P 0x19
|
|
#define NN_KEY_Q 0x10
|
|
#define NN_KEY_R 0x13
|
|
#define NN_KEY_S 0x1F
|
|
#define NN_KEY_T 0x14
|
|
#define NN_KEY_U 0x16
|
|
#define NN_KEY_V 0x2F
|
|
#define NN_KEY_W 0x11
|
|
#define NN_KEY_X 0x2D
|
|
#define NN_KEY_Y 0x15
|
|
#define NN_KEY_Z 0x2C
|
|
|
|
#define NN_KEY_APOSTROPHE 0x28
|
|
#define NN_KEY_AT 0x91
|
|
#define NN_KEY_BACK 0x0E
|
|
#define NN_KEY_BACKSLASH 0x2B
|
|
// caps-lock
|
|
#define NN_KEY_CAPITAL 0x3A
|
|
#define NN_KEY_COLON 0x92
|
|
#define NN_KEY_COMMA 0x33
|
|
#define NN_KEY_ENTER 0x1C
|
|
#define NN_KEY_EQUALS 0x0D
|
|
// accent grave
|
|
#define NN_KEY_GRAVE 0x29
|
|
#define NN_KEY_LBRACKET 0x1A
|
|
#define NN_KEY_LCONTROL 0x1D
|
|
// left alt
|
|
#define NN_KEY_LMENU 0x38
|
|
#define NN_KEY_LSHIFT 0x2A
|
|
#define NN_KEY_MINUS 0x0C
|
|
#define NN_KEY_NUMLOCK 0x45
|
|
#define NN_KEY_PAUSE 0xC5
|
|
#define NN_KEY_PERIOD 0x34
|
|
#define NN_KEY_RBRACKET 0x1B
|
|
#define NN_KEY_RCONTROL 0x9D
|
|
// right alt
|
|
#define NN_KEY_RMENU 0xB8
|
|
#define NN_KEY_RSHIFT 0x36
|
|
// scroll lock
|
|
#define NN_KEY_SCROLL 0x46
|
|
#define NN_KEY_SEMICOLON 0x27
|
|
#define NN_KEY_SLASH 0x35
|
|
#define NN_KEY_SPACE 0x39
|
|
#define NN_KEY_STOP 0x95
|
|
#define NN_KEY_TAB 0x0F
|
|
#define NN_KEY_UNDERLINE 0x93
|
|
|
|
#define NN_KEY_UP 0xC8
|
|
#define NN_KEY_DOWN 0xD0
|
|
#define NN_KEY_LEFT 0xCB
|
|
#define NN_KEY_RIGHT 0xCD
|
|
#define NN_KEY_HOME 0xC7
|
|
#define NN_KEY_END 0xCF
|
|
#define NN_KEY_PAGEUP 0xC9
|
|
#define NN_KEY_PAGEDOWN 0xD1
|
|
#define NN_KEY_INSERT 0xD2
|
|
#define NN_KEY_DELETE 0xD3
|
|
|
|
#define NN_KEY_F1 0x3B
|
|
#define NN_KEY_F2 0x3C
|
|
#define NN_KEY_F3 0x3D
|
|
#define NN_KEY_F4 0x3E
|
|
#define NN_KEY_F5 0x3F
|
|
#define NN_KEY_F6 0x40
|
|
#define NN_KEY_F7 0x41
|
|
#define NN_KEY_F8 0x42
|
|
#define NN_KEY_F9 0x43
|
|
#define NN_KEY_F10 0x44
|
|
#define NN_KEY_F11 0x57
|
|
#define NN_KEY_F12 0x58
|
|
#define NN_KEY_F13 0x64
|
|
#define NN_KEY_F14 0x65
|
|
#define NN_KEY_F15 0x66
|
|
#define NN_KEY_F16 0x67
|
|
#define NN_KEY_F17 0x68
|
|
#define NN_KEY_F18 0x69
|
|
#define NN_KEY_F19 0x71
|
|
|
|
#define NN_KEY_KANA 0x70
|
|
#define NN_KEY_KANJI 0x94
|
|
#define NN_KEY_CONVERT 0x79
|
|
#define NN_KEY_NOCONVERT 0x7B
|
|
#define NN_KEY_YEN 0x7D
|
|
#define NN_KEY_CIRCUMFLEX 0x90
|
|
#define NN_KEY_AX 0x96
|
|
|
|
#define NN_KEY_NUMPAD0 0x52
|
|
#define NN_KEY_NUMPAD1 0x4F
|
|
#define NN_KEY_NUMPAD2 0x50
|
|
#define NN_KEY_NUMPAD3 0x51
|
|
#define NN_KEY_NUMPAD4 0x4B
|
|
#define NN_KEY_NUMPAD5 0x4C
|
|
#define NN_KEY_NUMPAD6 0x4D
|
|
#define NN_KEY_NUMPAD7 0x47
|
|
#define NN_KEY_NUMPAD8 0x48
|
|
#define NN_KEY_NUMPAD9 0x49
|
|
#define NN_KEY_NUMPADMUL 0x37
|
|
#define NN_KEY_NUMPADDIV 0xB5
|
|
#define NN_KEY_NUMPADSUB 0x4A
|
|
#define NN_KEY_NUMPADADD 0x4E
|
|
#define NN_KEY_NUMPADDECIMAL 0x53
|
|
#define NN_KEY_NUMPADCOMMA 0xB3
|
|
#define NN_KEY_NUMPADENTER 0x9C
|
|
#define NN_KEY_NUMPADEQUALS 0x8D
|
|
|
|
// the bottom side, can also be downwards / negative y
|
|
#define NN_SIDE_BOTTOM 0
|
|
// the top side, can also be upwards / positive y
|
|
#define NN_SIDE_TOP 1
|
|
// backwards, can also be north / negative z
|
|
#define NN_SIDE_BACK 2
|
|
// forwards, can also be south / positive z
|
|
#define NN_SIDE_FRONT 3
|
|
// to the right, can also be west / negative x
|
|
#define NN_SIDE_RIGHT 4
|
|
// to the left, can also be east / positive x
|
|
#define NN_SIDE_LEFT 5
|
|
// absolutely no clue
|
|
#define NN_SIDE_UNKNOWN 6
|
|
|
|
// pushes a screen_resized signal
|
|
nn_Exit nn_pushScreenResized(nn_Computer *computer, const char *screenAddress, int newWidth, int newHeight);
|
|
// pushes a touch signal
|
|
// The signal is checked, as in, the player must be a user of the computer if users are defined.
|
|
nn_Exit nn_pushTouch(nn_Computer *computer, const char *screenAddress, double x, double y, int button, const char *player);
|
|
// pushes a drag signal
|
|
// The signal is checked, as in, the player must be a user of the computer if users are defined.
|
|
nn_Exit nn_pushDrag(nn_Computer *computer, const char *screenAddress, double x, double y, int button, const char *player);
|
|
// pushes a drop signal
|
|
// The signal is checked, as in, the player must be a user of the computer if users are defined.
|
|
nn_Exit nn_pushDrop(nn_Computer *computer, const char *screenAddress, double x, double y, int button, const char *player);
|
|
// pushes a scroll signal
|
|
// A positive direction usually means up, a negative one usually means down.
|
|
// The signal is checked, as in, the player must be a user of the computer if users are defined.
|
|
nn_Exit nn_pushScroll(nn_Computer *computer, const char *screenAddress, double x, double y, double direction, const char *player);
|
|
// pushes a walk signal
|
|
// The signal is checked, as in, the player must be a user of the computer if users are defined.
|
|
nn_Exit nn_pushWalk(nn_Computer *computer, const char *screenAddress, double x, double y, const char *player);
|
|
|
|
// pushes a key_down event
|
|
// charcode is the unicode code-point of the typed character. It should be uppercase/lowercase depending on shift or capslock.
|
|
// keycode is an OC-specific keycode, and should be from the NN_KEY_* constants.
|
|
// player is the name of the player which used the keyboard. Some programs use it for splitscreen games.
|
|
// The signal is checked, as in, the player must be a user of the computer if users are defined.
|
|
nn_Exit nn_pushKeyDown(nn_Computer *computer, const char *keyboardAddress, nn_codepoint charcode, int keycode, const char *player);
|
|
// pushes a key_up event
|
|
// charcode is the unicode code-point of the typed character. It should be uppercase/lowercase depending on shift or capslock.
|
|
// keycode is an OC-specific keycode, and should be from the NN_KEY_* constants.
|
|
// player is the name of the player which used the keyboard. Some programs use it for splitscreen games.
|
|
// The signal is checked, as in, the player must be a user of the computer if users are defined.
|
|
nn_Exit nn_pushKeyUp(nn_Computer *computer, const char *keyboardAddress, nn_codepoint charcode, int keycode, const char *player);
|
|
// pushes a clipboard event
|
|
// clipboard should be a NULL-terminated string.
|
|
// NN does no truncation of the contents, but it is best to limit it.
|
|
// The signal is checked, as in, the player must be a user of the computer if users are defined.
|
|
nn_Exit nn_pushClipboard(nn_Computer *computer, const char *keyboardAddress, const char *clipboard, const char *player);
|
|
// pushes a clipboard event
|
|
// len is the length of the clipboard.
|
|
// NN does no truncation of the contents, but it is best to limit it.
|
|
// The signal is checked, as in, the player must be a user of the computer if users are defined.
|
|
nn_Exit nn_pushLClipboard(nn_Computer *computer, const char *keyboardAddress, const char *clipboard, size_t len, const char *player);
|
|
|
|
// pushes a redstone_changed signal.
|
|
// side is the side of the device the redstone changed on
|
|
// oldValue is the old value
|
|
// newValue is the new value, must not be equal to oldValue
|
|
// color is the color of the redstone signal
|
|
// if color < 0, it is set to null
|
|
nn_Exit nn_pushRedstoneChanged(nn_Computer *computer, const char *redstoneAddress, int side, int oldValue, int newValue, int color);
|
|
|
|
// pushes a motion signal.
|
|
// Do note that it is meant to only be sent if the entity has a direct line of sight and if |(relX, relY, relZ)| >= sensitivity.
|
|
// This signal does *not* check if the motion sensor actually is sensitive enough to detect it, so make sure to check it yourself.
|
|
// relX, relY and relZ are the relative postion in 3D Cartesian space.
|
|
// entityName can be NULL if the entity has no name.
|
|
nn_Exit nn_pushMotion(nn_Computer *computer, double relX, double relY, double relZ, const char *entityName);
|
|
|
|
// Pushes an internet_ready signal.
|
|
// This signal is queued when an internet socket is ready for commmunication.
|
|
nn_Exit nn_pushInternetReady(nn_Computer *computer, const char *id, size_t idlen);
|
|
|
|
// A buffer with encoded values
|
|
typedef struct nn_EncodedNetworkContents {
|
|
nn_Context *ctx;
|
|
char *buf;
|
|
size_t buflen;
|
|
size_t valueCount;
|
|
} nn_EncodedNetworkContents;
|
|
|
|
// applies basic encoding to a network message. This encoding has a header, and thus should remain backwards-compatible.
|
|
// The encoding serves 2 purposes:
|
|
// 1. Prevent shared memory between computers. Values do not use atomic reference counting, and thus this could lead to UAF or memory leaks.
|
|
// 2. Simplify implementing packet queues, which should be used in relays. The lack of access to raw values would force implementers to use
|
|
// an encoding anyways.
|
|
// This only encodes the contents, not the sender, hops, or other metadata which may be needed in the queue.
|
|
// This does not pop the values, in case you need them afterwards. If you don't just call nn_popn().
|
|
// The encoding is architecture-dependent, so be careful with storing it on-disk.
|
|
// Do note that the architecture-dependent parts are sizeof(double), sizeof(size_t) and endianness.
|
|
// The encoding is simple:
|
|
// - 0x00 for null
|
|
// - 0x01 for true
|
|
// - 0x02 for false
|
|
// - 0x03 + <bytes of double> for a number
|
|
// - 0x04 + <bytes of size_t length> + <bytes> for a string
|
|
// - 0x05 + <bytes of size_t id> for resource
|
|
// - 0x06 + <bytes of size_t length> + <values> for a table
|
|
nn_Exit nn_encodeNetworkContents(nn_Computer *computer, nn_EncodedNetworkContents *contents, size_t valueCount);
|
|
// Allocates a copy of [buf] and stores it in contents.
|
|
// This is useful for copying network contents, either from storage or from another buffer.
|
|
nn_Exit nn_copyNetworkContents(nn_Context *ctx, nn_EncodedNetworkContents *contents, const char *buf, size_t buflen, size_t valueCount);
|
|
void nn_dropNetworkContents(nn_EncodedNetworkContents *contents);
|
|
// Pushes the encoded contents onto the stack.
|
|
// This does not drop the network contents.
|
|
nn_Exit nn_pushNetworkContents(nn_Computer *computer, const nn_EncodedNetworkContents *contents);
|
|
|
|
// push a modem_message, can be queued by both modems and tunnels.
|
|
// This does not check if the modem has that port open, so make sure to check it yourself.
|
|
// It does not check if the distance is within the modem's range, if it is wireless, and thus does not send it.
|
|
// Note that relays should change the sender.
|
|
nn_Exit nn_pushModemMessage(nn_Computer *computer, const char *modemAddress, const char *sender, int port, double distance, const nn_EncodedNetworkContents *contents);
|
|
|
|
// EEPROM class
|
|
|
|
// reads and writes are always 1/1
|
|
typedef struct nn_EEPROM {
|
|
// the maximum capacity of the EEPROM
|
|
size_t size;
|
|
// the maximum capacity of the EEPROM's associated data
|
|
size_t dataSize;
|
|
// the energy cost of reading an EEPROM
|
|
double readEnergyCost;
|
|
// the energy cost of reading an EEPROM's associated data
|
|
double readDataEnergyCost;
|
|
// the energy cost of writing to an EEPROM
|
|
double writeEnergyCost;
|
|
// the energy cost of writing to an EEPROM's associated data
|
|
double writeDataEnergyCost;
|
|
// idle time added when writing code
|
|
double writeDelay;
|
|
// idle time added when writing data
|
|
double writeDataDelay;
|
|
} nn_EEPROM;
|
|
|
|
typedef enum nn_EEPROMAction {
|
|
// component is dropped
|
|
NN_EEPROM_DROP,
|
|
// check if readonly. If so, buflen should be 1, else it should be 0.
|
|
NN_EEPROM_ISRO,
|
|
// make the EEPROM readonly. Checksum already verified.
|
|
NN_EEPROM_MKRO,
|
|
// write the contents of the code into buf.
|
|
// Set buflen to the length.
|
|
NN_EEPROM_GET,
|
|
// store the contents in buf into the EEPROM as code.
|
|
// the length of buf is in buflen.
|
|
NN_EEPROM_SET,
|
|
NN_EEPROM_GETDATA,
|
|
NN_EEPROM_SETDATA,
|
|
NN_EEPROM_GETARCH,
|
|
NN_EEPROM_SETARCH,
|
|
NN_EEPROM_GETLABEL,
|
|
NN_EEPROM_SETLABEL,
|
|
} nn_EEPROMAction;
|
|
|
|
typedef struct nn_EEPROMRequest {
|
|
nn_Context *ctx;
|
|
nn_Computer *computer;
|
|
void *state;
|
|
const nn_EEPROM *eeprom;
|
|
nn_EEPROMAction action;
|
|
union {
|
|
char *buf;
|
|
const char *robuf;
|
|
bool readonly;
|
|
};
|
|
size_t buflen;
|
|
} nn_EEPROMRequest;
|
|
|
|
typedef nn_Exit (nn_EEPROMHandler)(nn_EEPROMRequest *request);
|
|
|
|
// Tier 1 - The normal EEPROM equivalent
|
|
// Tier 2 - A better EEPROM
|
|
// Tier 3 - An even better EEPROM
|
|
// Tier 4- The best EEPROM
|
|
extern const nn_EEPROM nn_defaultEEPROMs[4];
|
|
|
|
nn_Component *nn_createEEPROM(nn_Universe *universe, const char *address, const nn_EEPROM *eeprom, void *state, nn_EEPROMHandler *handler);
|
|
|
|
// Filesystem class
|
|
|
|
typedef struct nn_Filesystem {
|
|
// the maximum capacity of the filesystem
|
|
size_t spaceTotal;
|
|
// how many read calls can be done per tick
|
|
// seek also count as reads.
|
|
double readsPerTick;
|
|
// how many write calls can be done per tick
|
|
double writesPerTick;
|
|
// how many open calls can be done per tick
|
|
double opensPerTick;
|
|
// The energy cost of an actual read/write.
|
|
// It is per-byte, so if a read returns 4096 bytes, then this cost is multiplied by 4096.
|
|
double dataEnergyCost;
|
|
// maximum size of a read.
|
|
// Do note that this entire buffer is allocated, and thus if you
|
|
// set it to a high number, you may get weird high allocations.
|
|
// This also determines read performance.
|
|
size_t maxReadSize;
|
|
} nn_Filesystem;
|
|
|
|
typedef enum nn_FSAction {
|
|
NN_FS_DROP,
|
|
|
|
// drive metadata
|
|
NN_FS_SPACEUSED,
|
|
NN_FS_GETLABEL,
|
|
NN_FS_SETLABEL,
|
|
NN_FS_ISRO,
|
|
|
|
// for file I/O
|
|
NN_FS_OPEN,
|
|
NN_FS_CLOSE,
|
|
NN_FS_READ,
|
|
NN_FS_WRITE,
|
|
NN_FS_SEEK,
|
|
|
|
// for list
|
|
NN_FS_OPENDIR,
|
|
NN_FS_READDIR,
|
|
NN_FS_CLOSEDIR,
|
|
|
|
// checking metadata
|
|
NN_FS_STAT,
|
|
// make directory, recursively
|
|
NN_FS_MKDIR,
|
|
|
|
// rename, if renamed to NULL then remove
|
|
NN_FS_RENAME,
|
|
} nn_FSAction;
|
|
|
|
typedef enum nn_FSWhence {
|
|
NN_SEEK_SET,
|
|
NN_SEEK_CUR,
|
|
NN_SEEK_END,
|
|
} nn_FSWhence;
|
|
|
|
typedef struct nn_FSRequest {
|
|
nn_Context *ctx;
|
|
nn_Computer *computer;
|
|
void *state;
|
|
const nn_Filesystem *fs;
|
|
nn_FSAction action;
|
|
int fd;
|
|
union {
|
|
struct {
|
|
const char *path;
|
|
const char *mode;
|
|
} open;
|
|
struct {
|
|
char *buf;
|
|
size_t len;
|
|
} read;
|
|
struct {
|
|
const char *buf;
|
|
size_t len;
|
|
} write;
|
|
struct {
|
|
nn_FSWhence whence;
|
|
// set to new offset
|
|
int off;
|
|
} seek;
|
|
const char *opendir;
|
|
struct {
|
|
// directory path, as a reminder if need be
|
|
const char *dirpath;
|
|
char *buf;
|
|
// set to length of entry name
|
|
size_t len;
|
|
} readdir;
|
|
struct {
|
|
// set to NULL if missing
|
|
const char *path;
|
|
// whether it is a directory
|
|
bool isDirectory;
|
|
// in seconds. Result will be multiplied by 1000.
|
|
// This is because OpenOS code is garbage.
|
|
intptr_t lastModified;
|
|
// size. 0 for directories.
|
|
size_t size;
|
|
} stat;
|
|
struct {
|
|
const char *from;
|
|
// if NULL, delete from, recursively.
|
|
const char *to;
|
|
} rename;
|
|
const char *mkdir;
|
|
struct {
|
|
const char *buf;
|
|
size_t len;
|
|
} setlabel;
|
|
struct {
|
|
char *buf;
|
|
size_t len;
|
|
} getlabel;
|
|
bool isReadonly;
|
|
size_t spaceUsed;
|
|
};
|
|
} nn_FSRequest;
|
|
|
|
typedef nn_Exit (nn_FSHandler)(nn_FSRequest *request);
|
|
|
|
// 4 Tiers.
|
|
// 0 - Tier 1 equivalent
|
|
// 1 - Tier 2 equivalent
|
|
// 2 - Tier 3 equivalent
|
|
// 3 - Tier 4, a better version of Tier 3.
|
|
extern const nn_Filesystem nn_defaultFilesystems[4];
|
|
// a basic floppy
|
|
extern const nn_Filesystem nn_defaultFloppy;
|
|
// a generic tmpfs
|
|
extern const nn_Filesystem nn_defaultTmpFS;
|
|
|
|
nn_Component *nn_createFilesystem(nn_Universe *universe, const char *address, const nn_Filesystem *fs, void *state, nn_FSHandler *handler);
|
|
|
|
bool nn_mergeFilesystems(nn_Filesystem *merged, const nn_Filesystem *fs, size_t len);
|
|
|
|
// Drive class
|
|
|
|
typedef struct nn_Drive {
|
|
// The capacity of the drive.
|
|
// It is in bytes, but it MUST be a multiple of the sector size.
|
|
// The total amount of sectors, as in capacity / sectorSize, must also be divisible by the platter count.
|
|
// If it is not, it is UB.
|
|
size_t capacity;
|
|
// the sector size, typically 512
|
|
size_t sectorSize;
|
|
// the amount of platters the drive has. This contributes to how many "rotations" are needed.
|
|
// A drive with 8 sectors but 1 platter, when seeking from sector 1 to 8, would mean 7 rotations.
|
|
// However, if it has 2 platters, it'd be seen as 1 to 4 being at the same angle as 5 to 8, which
|
|
// would mean only 3 rotations.
|
|
size_t platterCount;
|
|
// how many reads can be issued per tick.
|
|
// Anything that kicks out the current cacheline counts as a read.
|
|
size_t readsPerTick;
|
|
// how many writes can be issued per tick.
|
|
// Writing a sector counts as 1 write.
|
|
// Writing a byte counts as 1 read (may be eaten by cache) and 1 write,
|
|
// you can imagine it as reading the sector, editing the byte,
|
|
// then writing the sector back.
|
|
size_t writesPerTick;
|
|
// Set to 0 for *infinite*, effectively an SSD with infinite lifespan.
|
|
// This would mean there is 0 penalty for seeking (technically unreliastic even for an SSD).
|
|
// This is simply used to compute idle time. It is in literal full rotations per minute.
|
|
// It is aligned to the cache lines.
|
|
size_t rpm;
|
|
// If false, it behaves like a normal OC drive, where the drive can spin backwards to seek.
|
|
// However, this is unrealistic, as doing so may crack the sensitive platter and make the
|
|
// reader lose lift.
|
|
// For fans of physics, this option only allows the seeks to go forwards.
|
|
// This is super punishing at a slow RPM, so it is recommended to bump up
|
|
// the RPM to something like 7200 RPM.
|
|
bool onlySpinForwards;
|
|
// The energy cost of an actual read/write.
|
|
// It is per-byte, so if a read returns 4096 bytes, then this cost is multiplied by 4096.
|
|
double dataEnergyCost;
|
|
} nn_Drive;
|
|
|
|
extern const nn_Drive nn_defaultDrives[4];
|
|
extern const nn_Drive nn_floppyDrive;
|
|
|
|
|
|
typedef enum nn_DriveAction {
|
|
// drive gone
|
|
NN_DRIVE_DROP,
|
|
// get current label
|
|
NN_DRIVE_GETLABEL,
|
|
// set or remove current label
|
|
NN_DRIVE_SETLABEL,
|
|
// get the current head position, as a sector
|
|
NN_DRIVE_CURPOS,
|
|
// read a sector
|
|
NN_DRIVE_READSECTOR,
|
|
// write a sector
|
|
NN_DRIVE_WRITESECTOR,
|
|
// write a byte
|
|
NN_DRIVE_WRITEBYTE,
|
|
// is drive read-only
|
|
NN_DRIVE_ISRO,
|
|
} nn_DriveAction;
|
|
|
|
typedef struct nn_DriveRequest {
|
|
nn_Context *ctx;
|
|
nn_Computer *computer;
|
|
void *state;
|
|
const nn_Drive *drv;
|
|
nn_DriveAction action;
|
|
union {
|
|
struct {
|
|
char *buf;
|
|
size_t len;
|
|
} getlabel;
|
|
struct {
|
|
const char *label;
|
|
size_t len;
|
|
} setlabel;
|
|
size_t curpos;
|
|
struct {
|
|
// 1-indexed
|
|
size_t sector;
|
|
char *buf;
|
|
} readSector;
|
|
struct {
|
|
// 1-indexed
|
|
size_t sector;
|
|
const char *buf;
|
|
} writeSector;
|
|
struct {
|
|
// 1-indexed
|
|
size_t byte;
|
|
unsigned char value;
|
|
} writeByte;
|
|
bool readonly;
|
|
};
|
|
} nn_DriveRequest;
|
|
|
|
typedef nn_Exit (nn_DriveHandler)(nn_DriveRequest *request);
|
|
|
|
nn_Component *nn_createDrive(nn_Universe *universe, const char *address, const nn_Drive *drive, void *state, nn_DriveHandler *handler);
|
|
|
|
bool nn_mergeDrives(nn_Drive *merged, const nn_Drive *drives, size_t len);
|
|
|
|
typedef struct nn_NandFlash {
|
|
// capacity of flash
|
|
size_t capacity;
|
|
// sector size
|
|
size_t sectorSize;
|
|
// reads per tick
|
|
size_t readsPerTick;
|
|
// writes per tick
|
|
size_t writesPerTick;
|
|
// The layering, in bits.
|
|
// 1 is SLC, 2 is MLC, 3 is TLC, etc.
|
|
// This number may amplify how quickly the total write count increases.
|
|
size_t cellLevel;
|
|
// the maximum amount of write amplification.
|
|
// Set to 0 to disable amplification RNG.
|
|
// The game will generate, using Context RNG, a real number from [0, 1]
|
|
// then raise it to writeAmplificationExponent,
|
|
// then multiply it by this number, and by the cell level.
|
|
// then clamp it to be at least 1 and at most this maximum.
|
|
unsigned int maxWriteAmplification;
|
|
int writeAmplificationExponent;
|
|
// the maximum amount of writes *per sector.*
|
|
// Set to 0 to make the nandflash eternal.
|
|
size_t maxWriteCount;
|
|
// how much per byte
|
|
double dataEnergyCost;
|
|
} nn_NandFlash;
|
|
|
|
typedef enum nn_FlashAction {
|
|
NN_FLASH_DROP,
|
|
NN_FLASH_GETLABEL,
|
|
NN_FLASH_SETLABEL,
|
|
NN_FLASH_ISRO,
|
|
// read a sector
|
|
NN_FLASH_READSECTOR,
|
|
// write a sector
|
|
// also adds an amount of writes
|
|
NN_FLASH_WRITESECTOR,
|
|
// write a sector
|
|
// also adds an amount of writes
|
|
NN_FLASH_WRITEBYTE,
|
|
// get the amount of writes
|
|
NN_FLASH_GETWRITES,
|
|
} nn_FlashAction;
|
|
|
|
typedef struct nn_FlashRequest {
|
|
nn_Context *ctx;
|
|
nn_Computer *computer;
|
|
void *state;
|
|
const nn_NandFlash *flash;
|
|
nn_FlashAction action;
|
|
union {
|
|
struct {
|
|
char *buf;
|
|
size_t len;
|
|
} getlabel;
|
|
struct {
|
|
const char *buf;
|
|
size_t len;
|
|
} setlabel;
|
|
struct {
|
|
char *buf;
|
|
// 1-indexed
|
|
size_t sec;
|
|
} readsector;
|
|
struct {
|
|
const char *buf;
|
|
// 1-indexed
|
|
size_t sec;
|
|
// how many writes to add
|
|
size_t writesAdded;
|
|
} writesector;
|
|
struct {
|
|
size_t byte;
|
|
char val;
|
|
// how many writes to add
|
|
size_t writesAdded;
|
|
} writebyte;
|
|
// for GETWRITES
|
|
size_t writeCount;
|
|
bool readonly;
|
|
};
|
|
} nn_FlashRequest;
|
|
|
|
typedef nn_Exit (nn_FlashHandler)(nn_FlashRequest *request);
|
|
|
|
extern const nn_NandFlash nn_defaultSSDs[4];
|
|
extern const nn_NandFlash nn_floppySSD;
|
|
|
|
nn_Component *nn_createFlash(nn_Universe *universe, const char *address, const nn_NandFlash *drive, void *state, nn_FlashHandler *handler);
|
|
|
|
bool nn_mergeFlash(nn_NandFlash *merged, const nn_NandFlash *flash, size_t len);
|
|
|
|
// Screen class
|
|
|
|
typedef enum nn_ScreenFeatures {
|
|
NN_SCRF_NONE = 0,
|
|
// whether it supports mouse input.
|
|
// If it doesn't, it should not emit
|
|
// touch, drag or other mouse events.
|
|
// Walk events should also not be emitted.
|
|
NN_SCRF_MOUSE = 1<<0,
|
|
// Whether precise mode is supported.
|
|
NN_SCRF_PRECISE = 1<<1,
|
|
// Whether touch inverted is supported.
|
|
NN_SCRF_TOUCHINVERTED = 1<<2,
|
|
// it indicates that the palette can be edited.
|
|
NN_SCRF_EDITABLECOLORS = 1<<3,
|
|
} nn_ScreenFeatures;
|
|
|
|
// A struct for the reference screen configurations
|
|
// This does not influence the interface at all,
|
|
// however it exists as a runtime reference of what
|
|
// the conventional screen tiers are.
|
|
typedef struct nn_ScreenConfig {
|
|
// maximum width
|
|
int maxWidth;
|
|
// maximum height
|
|
int maxHeight;
|
|
// screen features
|
|
nn_ScreenFeatures features;
|
|
// default palette, if applicable.
|
|
// Can be NULL if there is none,
|
|
// in which case consider memsetting
|
|
// them to #000000.
|
|
int *defaultPalette;
|
|
// the amount of editable palette colors
|
|
int paletteColors;
|
|
// how many editable palette colors there are.
|
|
// It'd always be the first N ones.
|
|
int editableColors;
|
|
// the maximum depth of the screen
|
|
char maxDepth;
|
|
// energy per fully white pixel.
|
|
// Scaled to mathc luminance of each pixel.
|
|
// This is meant to be per Minecraft tick, so 20 times per second.
|
|
double energyPerPixel;
|
|
// minimum brightness. Default brightness is always 100%
|
|
// The value here is meant to be scaled such that 1 means 100% brightness
|
|
double minBrightness;
|
|
// maximum brightness. Note that brightness rendering is emulator-specific
|
|
// The value here is meant to be scaled such that 1 means 100% brightness
|
|
double maxBrightness;
|
|
} nn_ScreenConfig;
|
|
|
|
// OC has 3 tiers, NN adds a 4th one as well.
|
|
extern const nn_ScreenConfig nn_defaultScreens[4];
|
|
|
|
|
|
// GPU class
|
|
typedef struct nn_GPU {
|
|
// the minimum between these and the screen's
|
|
// are the maximum width/height/depth supported.
|
|
int maxWidth;
|
|
int maxHeight;
|
|
char maxDepth;
|
|
// this is in pixels.
|
|
size_t totalVRAM;
|
|
// amount of times copy can be called before running out of budget.
|
|
int copyPerTick;
|
|
// amount of times fill can be called before running out of budget.
|
|
int fillPerTick;
|
|
// amount of times set can be called before running out of budget.
|
|
int setPerTick;
|
|
// amount of times setForeground can be called before running out of budget.
|
|
int setForegroundPerTick;
|
|
// amount of times setBackground can be called before running out of budget.
|
|
int setBackgroundPerTick;
|
|
// energy per pixel set.
|
|
double energyPerWrite;
|
|
// energy per pixel filled
|
|
double energyPerFill;
|
|
// energy per pixel copied
|
|
double energyPerCopy;
|
|
// energy per space set.
|
|
double energyPerClear;
|
|
} nn_GPU;
|
|
|
|
// 1 GPU tier for every screen.
|
|
extern const nn_GPU nn_defaultGPUs[4];
|
|
|
|
typedef enum nn_GPUAction {
|
|
NN_GPU_DROP,
|
|
NN_GPU_BIND,
|
|
NN_GPU_GETSCREEN,
|
|
NN_GPU_GETBG,
|
|
NN_GPU_SETBG,
|
|
NN_GPU_GETFG,
|
|
NN_GPU_SETFG,
|
|
NN_GPU_GETPALETTE,
|
|
NN_GPU_SETPALETTE,
|
|
NN_GPU_MAXDEPTH,
|
|
NN_GPU_GETDEPTH,
|
|
NN_GPU_SETDEPTH,
|
|
NN_GPU_MAXRES,
|
|
NN_GPU_GETRES,
|
|
NN_GPU_SETRES,
|
|
NN_GPU_GETVIEWPORT,
|
|
NN_GPU_SETVIEWPORT,
|
|
NN_GPU_GET,
|
|
NN_GPU_SET,
|
|
NN_GPU_COPY,
|
|
NN_GPU_FILL,
|
|
NN_GPU_GETACTIVEBUF,
|
|
NN_GPU_SETACTIVEBUF,
|
|
NN_GPU_BUFFERS,
|
|
NN_GPU_ALLOCBUF,
|
|
NN_GPU_FREEBUF,
|
|
NN_GPU_FREEALLBUFS,
|
|
NN_GPU_FREEMEM,
|
|
NN_GPU_GETBUFSIZE,
|
|
NN_GPU_BITBLT,
|
|
} nn_GPUAction;
|
|
|
|
typedef struct nn_GPURequest {
|
|
nn_Context *ctx;
|
|
nn_Computer *computer;
|
|
void *state;
|
|
const nn_GPU *gpu;
|
|
nn_GPUAction action;
|
|
union {
|
|
struct {
|
|
const char *address;
|
|
bool reset;
|
|
} bind;
|
|
// GETSCREEN result
|
|
char screenAddr[NN_MAX_ADDRESS];
|
|
// GET/SET BG/FG
|
|
struct {
|
|
int color;
|
|
bool isPalette;
|
|
int oldColor;
|
|
bool wasPalette;
|
|
int oldPaletteIdx; // -1 if none
|
|
} color;
|
|
// GET/SET PALETTE
|
|
struct {
|
|
int index;
|
|
int color;
|
|
int oldColor;
|
|
} palette;
|
|
// MAXDEPTH / GETDEPTH / SETDEPTH
|
|
struct {
|
|
char depth;
|
|
char oldDepth;
|
|
} depth;
|
|
// MAXRES/GETRES/SETRES/GETVIEWPORT/SETVIEWPORT
|
|
struct {
|
|
int width;
|
|
int height;
|
|
} resolution;
|
|
// GET pixel
|
|
struct {
|
|
int x, y;
|
|
nn_codepoint codepoint;
|
|
int fg, bg;
|
|
int fgIdx, bgIdx; // -1 if not palette
|
|
} get;
|
|
// SET string
|
|
struct {
|
|
int x, y;
|
|
const char *value;
|
|
size_t len;
|
|
bool vertical;
|
|
} set;
|
|
// COPY
|
|
struct {
|
|
int x, y, w, h, tx, ty;
|
|
} copy;
|
|
// FILL
|
|
struct {
|
|
int x, y, w, h;
|
|
nn_codepoint codepoint;
|
|
} fill;
|
|
// GET/SET ACTIVE BUFFER, FREE BUFFER
|
|
struct {
|
|
int index;
|
|
} buffer;
|
|
// ALLOCATE BUFFER
|
|
struct {
|
|
int w, h, index;
|
|
} allocBuf;
|
|
// TOTALMEM / FREEMEM
|
|
size_t memory;
|
|
// GETBUFSIZE
|
|
struct {
|
|
int index, w, h;
|
|
} bufSize;
|
|
// BITBLT
|
|
struct {
|
|
int dst, col, row, w, h;
|
|
int src, fromCol, fromRow;
|
|
} bitblt;
|
|
// BUFFERS / count returned here, indices
|
|
// pushed on stack by handler
|
|
size_t bufCount;
|
|
};
|
|
} nn_GPURequest;
|
|
|
|
typedef nn_Exit (nn_GPUHandler)(nn_GPURequest *req);
|
|
|
|
nn_Component *nn_createGPU(
|
|
nn_Universe *universe, const char *address,
|
|
const nn_GPU *gpu, void *state,
|
|
nn_GPUHandler *handler);
|
|
|
|
typedef enum nn_ScreenAction {
|
|
NN_SCREEN_DROP,
|
|
NN_SCREEN_ISON,
|
|
NN_SCREEN_TURNON,
|
|
NN_SCREEN_TURNOFF,
|
|
NN_SCREEN_GETASPECTRATIO,
|
|
NN_SCREEN_GETKEYBOARDS,
|
|
NN_SCREEN_SETPRECISE,
|
|
NN_SCREEN_ISPRECISE,
|
|
NN_SCREEN_SETTOUCHINVERTED,
|
|
NN_SCREEN_ISTOUCHINVERTED,
|
|
// sets the brightness (from 0 to 1)
|
|
NN_SCREEN_SETBRIGHT,
|
|
// get the brightness (from 0 to 1)
|
|
NN_SCREEN_GETBRIGHT,
|
|
} nn_ScreenAction;
|
|
|
|
typedef struct nn_ScreenRequest {
|
|
nn_Context *ctx;
|
|
nn_Computer *computer;
|
|
void *state;
|
|
const nn_ScreenConfig *screen;
|
|
nn_ScreenAction action;
|
|
union {
|
|
// turnOn / turnOff / isOn
|
|
struct {
|
|
bool wasOn;
|
|
bool isOn;
|
|
} power;
|
|
// getAspectRatio
|
|
struct {
|
|
int w, h;
|
|
} aspect;
|
|
// getKeyboards — addresses pushed on stack by
|
|
// handler; count returned here
|
|
size_t kbCount;
|
|
// setPrecise / isPrecise /
|
|
// setTouchModeInverted / isTouchModeInverted
|
|
bool flag;
|
|
double brightness;
|
|
};
|
|
} nn_ScreenRequest;
|
|
|
|
typedef nn_Exit (nn_ScreenHandler)(nn_ScreenRequest *req);
|
|
|
|
nn_Component *nn_createScreen(
|
|
nn_Universe *universe, const char *address,
|
|
const nn_ScreenConfig *scrconf, void *state,
|
|
nn_ScreenHandler *handler
|
|
);
|
|
|
|
// Computes a CRC32 checksum
|
|
unsigned int nn_computeCRC32(const char *data, size_t datalen);
|
|
|
|
typedef struct nn_DataCard {
|
|
// The buffer size of the data card, limit in both input and output.
|
|
// In OC, this value is 1MiB regardless of tier.
|
|
// As there is no out buffer and you are expected to push strings,
|
|
// the buffer is not pre-allocated. This is intentional, as memory
|
|
// would be wasted and it could be a potential attack vector otherwise.
|
|
size_t limit;
|
|
|
|
// The maximum amount of secure random bytes that can be generated.
|
|
// In OC, this was hardcoded to 1024. Here, its configurable.
|
|
// Unlike the normal limit, this does not preallocate the maximum capacity,
|
|
// as the amount of bytes needed is known perfectly.
|
|
size_t maxRandom;
|
|
|
|
// for encoding/decoding. OC defaulted to 32
|
|
size_t base64PerTick;
|
|
// for deflate/inflate. OC defaulted to 4
|
|
size_t deflatingPerTick;
|
|
// OC defaulted to 32
|
|
size_t crc32PerTick;
|
|
// OC defaulted to 8
|
|
size_t md5PerTick;
|
|
// OC defaulted to 4
|
|
size_t sha256PerTick;
|
|
// for encrypt/decrypt. OC defaulted to 4
|
|
size_t encryptPerTick;
|
|
// for generateKeyPair. OC defaulted to 1
|
|
size_t genPerTick;
|
|
// for deserializeKey. OC defaulted to 8
|
|
size_t deserializePerTick;
|
|
// OC defaulted to 1
|
|
size_t ecdhPerTick;
|
|
// OC defaulted to 1
|
|
size_t ecdsaPerTick;
|
|
// OC defaults to 4
|
|
size_t randomPerTick;
|
|
|
|
// Capabilities
|
|
bool canHash;
|
|
bool canEncrypt;
|
|
bool canECDH;
|
|
bool canCompress;
|
|
|
|
// Trivial operation cost (CRC32 and base64 encoding/decoding)
|
|
double trivialCost;
|
|
double trivialCostByte;
|
|
|
|
// Simple operation cost (MD5 and encryption/decryption)
|
|
double simpleCost;
|
|
double simpleCostByte;
|
|
|
|
double complexCost;
|
|
double complexCostByte;
|
|
|
|
// Assymetric operation cost (ECDH, ECDSA). ECDH has no per-byte cost, and ECDSA uses complexCostByte as it relies on SHA256.
|
|
double assymetricCost;
|
|
} nn_DataCard;
|
|
|
|
typedef enum nn_DataCardAction {
|
|
// Data card destroyed
|
|
NN_DATA_DROP,
|
|
|
|
// If you want to match the behavior of OC, which you should if you want
|
|
// data compressed or encrypted in OC to work in your emulators, you should
|
|
// aim to match what the JVM, com.google.common.hash.Hashing and javax.crypto do.
|
|
// For more details, see https://github.com/MightyPirates/OpenComputers/blob/master-MC1.7.10/src/main/scala/li/cil/oc/server/component/DataCard.scala
|
|
|
|
// encoding base64
|
|
NN_DATA_ENCODE64,
|
|
|
|
NN_DATA_DECODE64,
|
|
// hashing
|
|
|
|
// CRC32, little endian
|
|
NN_DATA_CRC32,
|
|
|
|
// SHA2-256 hash, optional HMAC key (javax.crypto HmacSHA256)
|
|
NN_DATA_SHA256,
|
|
|
|
// MD5 hash, optional HMAC key (javax.crypto HmacMD5)
|
|
NN_DATA_MD5,
|
|
|
|
// Deflate. To match OC, make it follow the ZLIB format, which has a 2 byte header.
|
|
NN_DATA_DEFLATE,
|
|
|
|
// Inflate. Should support the ZLIB format, as thats what OC uses, and GZIP support is optional.
|
|
NN_DATA_INFLATE,
|
|
|
|
// Encrypt data with AES-128. The full algorithm is AES/CBC/PKCS5, as is use PKCS5 for padding, CBC for block sequences, and AES-128 for encrypting blocks.
|
|
// It does also receive a 128-bit AES Initialization Vector, for better security.
|
|
NN_DATA_ENCRYPT,
|
|
|
|
// Decrypt data, also using AES/CBC/PKCS5.
|
|
NN_DATA_DECRYPT,
|
|
|
|
// Meant to be *secure RNG*, and can generate anywhere between 1 and the data card's maxRandom.
|
|
NN_DATA_RANDOM,
|
|
|
|
// Generate an ECDH public/private pair of either 256 or 384 bits each.
|
|
NN_DATA_GENKEYS,
|
|
|
|
// validate key, cuz we feel like it
|
|
NN_DATA_VALIDATEKEY,
|
|
|
|
// Does an ECDH pass, matching javax.crypto.KeyAgreement.
|
|
// This generates a shared secret as binary data.
|
|
// This is not an AES key as output, the AES key is often computed by either MD5 hashing
|
|
// the shared secret, or SHA256 hashing it and chopping the hash in half.
|
|
NN_DATA_ECDH,
|
|
|
|
// ECDSA algorithm, sign data using an ECDH (private) key.
|
|
NN_DATA_ECDSA_SIGN,
|
|
// ECDSA algorithm, verify data using an ECDH (public) key and signature.
|
|
NN_DATA_ECDSA_VERIFY,
|
|
} nn_DataCardAction;
|
|
|
|
// The representation of datacard key userdata
|
|
typedef struct nn_DataKey {
|
|
bool isPublic;
|
|
unsigned short bytelen;
|
|
char bytes[];
|
|
} nn_DataKey;
|
|
|
|
typedef struct nn_DataCardRequest {
|
|
nn_Context *ctx;
|
|
nn_Computer *computer;
|
|
void *state;
|
|
const nn_DataCard *dataCard;
|
|
nn_DataCardAction action;
|
|
// TODO: the fields
|
|
union {
|
|
struct {
|
|
const char *data;
|
|
size_t datalen;
|
|
char checksum[4];
|
|
} crc32;
|
|
struct {
|
|
const char *data;
|
|
size_t datalen;
|
|
char checksum[16];
|
|
} md5;
|
|
struct {
|
|
const char *data;
|
|
size_t datalen;
|
|
char checksum[32];
|
|
} sha256;
|
|
// for encrypt/decrypt
|
|
struct {
|
|
const char *data;
|
|
size_t datalen;
|
|
const char *key;
|
|
const char *iv;
|
|
} encrypt;
|
|
struct {
|
|
char *buf;
|
|
size_t buflen;
|
|
} randbuf;
|
|
// for deflate, inflate, encode64 and decode64
|
|
struct {
|
|
const char *data;
|
|
size_t datalen;
|
|
};
|
|
struct {
|
|
const char *buf;
|
|
size_t len;
|
|
bool isPublic;
|
|
} validatekey;
|
|
struct {
|
|
const nn_DataKey *publicKey;
|
|
const nn_DataKey *privateKey;
|
|
} ecdh;
|
|
struct {
|
|
const char *data;
|
|
size_t len;
|
|
const nn_DataKey *privateKey;
|
|
} sign;
|
|
struct {
|
|
const char *data;
|
|
size_t datalen;
|
|
const nn_DataKey *publicKey;
|
|
const char *signature;
|
|
size_t siglen;
|
|
// returns whether the signature actually passed
|
|
bool sigpassed;
|
|
} checksig;
|
|
int genkeybitsize;
|
|
};
|
|
} nn_DataCardRequest;
|
|
|
|
typedef nn_Exit (nn_DataCardHandler)(nn_DataCardRequest *req);
|
|
|
|
extern nn_DataCard nn_defaultDataCards[3];
|
|
|
|
nn_Component *nn_createDataCard(nn_Universe *universe, const char *address, const nn_DataCard *dataCard, void *state, nn_DataCardHandler *handler);
|
|
|
|
typedef struct nn_Modem {
|
|
// maximum range. Set to 0 for non-wireless modems
|
|
size_t maxRange;
|
|
// maximum values in a packet
|
|
size_t maxValues;
|
|
// maximum logical packet size. Note that the encoding is more efficient than the packet size algorithm estimates
|
|
size_t maxPacketSize;
|
|
// the maximum amount of open ports
|
|
size_t maxOpenPorts;
|
|
// whether the modem supports wired connectivity.
|
|
// Support for wireless checks if maxRange > 0.
|
|
bool isWired;
|
|
// base energy cost of 1 network message
|
|
double basePacketCost;
|
|
// energy cost of a full packet, at the maximum logical size
|
|
double fullPacketCost;
|
|
// energy cost per wireless packet strength level
|
|
double costPerStrength;
|
|
} nn_Modem;
|
|
|
|
extern nn_Modem nn_defaultWiredModem;
|
|
extern nn_Modem nn_defaultWirelessModems[2];
|
|
|
|
typedef enum nn_ModemAction {
|
|
// modem dropped
|
|
NN_MODEM_DROP,
|
|
// check whether a port is open
|
|
NN_MODEM_ISOPEN,
|
|
// open a port
|
|
NN_MODEM_OPEN,
|
|
// close a port
|
|
NN_MODEM_CLOSE,
|
|
// get open ports
|
|
NN_MODEM_GETPORTS,
|
|
// send/broadcast a message
|
|
NN_MODEM_SEND,
|
|
// get current modem strength
|
|
NN_MODEM_GETSTRENGTH,
|
|
// set current modem strength
|
|
NN_MODEM_SETSTRENGTH,
|
|
// returns the wake message
|
|
NN_MODEM_GETWAKEMESSAGE,
|
|
// set the wake message
|
|
NN_MODEM_SETWAKEMESSAGE,
|
|
} nn_ModemAction;
|
|
|
|
typedef struct nn_ModemRequest {
|
|
nn_Context *ctx;
|
|
nn_Computer *computer;
|
|
void *state;
|
|
const nn_Modem *modem;
|
|
const char *localAddress;
|
|
nn_ModemAction action;
|
|
union {
|
|
struct {
|
|
size_t port;
|
|
bool opened;
|
|
} isOpen;
|
|
size_t openPort;
|
|
// NN_CLOSEPORTS means close all
|
|
size_t closePort;
|
|
struct {
|
|
// store the port numbers in this buffer
|
|
unsigned short *activePorts;
|
|
// the amount of active ports.
|
|
// the initial value is the capacity of activePorts
|
|
size_t len;
|
|
} getPorts;
|
|
struct {
|
|
const nn_EncodedNetworkContents *contents;
|
|
// NULL for broadcast
|
|
const char *address;
|
|
size_t port;
|
|
// The signal strength it was sent at
|
|
// This is an *OUT* field, it is assumed the handler keeps track of the correct strength
|
|
size_t strengthSent;
|
|
} send;
|
|
// for getStrength, setStrength.
|
|
size_t strength;
|
|
struct {
|
|
char *buf;
|
|
size_t len;
|
|
bool isFuzzy;
|
|
} getWake;
|
|
struct {
|
|
const char *buf;
|
|
size_t len;
|
|
bool isFuzzy;
|
|
} setWake;
|
|
};
|
|
} nn_ModemRequest;
|
|
|
|
typedef nn_Exit (nn_ModemHandler)(nn_ModemRequest *req);
|
|
|
|
nn_Component *nn_createModem(nn_Universe *universe, const char *address, const nn_Modem *modem, void *state, nn_ModemHandler *handler);
|
|
|
|
typedef struct nn_Tunnel {
|
|
// maximum values in a packet
|
|
size_t maxValues;
|
|
// maximum logical packet size. Note that the encoding is more efficient than the packet size algorithm estimates
|
|
size_t maxPacketSize;
|
|
// minimum energy cost of 1 transmission
|
|
double basePacketCost;
|
|
// extra energy cost of 1 full transmission
|
|
double fullPacketCost;
|
|
} nn_Tunnel;
|
|
|
|
extern nn_Tunnel nn_defaultTunnel;
|
|
|
|
typedef enum nn_TunnelAction {
|
|
// tunnel dropped
|
|
NN_TUNNEL_DROP,
|
|
// gets the channel, result should be pushed to the top of the stack
|
|
NN_TUNNEL_GETCHANNEL,
|
|
// send/broadcast a message
|
|
NN_TUNNEL_SEND,
|
|
// returns the wake message
|
|
NN_TUNNEL_GETWAKEMESSAGE,
|
|
// set the wake message
|
|
NN_TUNNEL_SETWAKEMESSAGE,
|
|
} nn_TunnelAction;
|
|
|
|
typedef struct nn_TunnelRequest {
|
|
nn_Context *ctx;
|
|
nn_Computer *computer;
|
|
void *state;
|
|
const nn_Tunnel *tunnel;
|
|
const char *localAddress;
|
|
nn_TunnelAction action;
|
|
union {
|
|
// for send
|
|
const nn_EncodedNetworkContents *toSend;
|
|
struct {
|
|
char *buf;
|
|
size_t len;
|
|
bool isFuzzy;
|
|
} getWake;
|
|
struct {
|
|
const char *buf;
|
|
size_t len;
|
|
bool isFuzzy;
|
|
} setWake;
|
|
};
|
|
} nn_TunnelRequest;
|
|
|
|
typedef nn_Exit (nn_TunnelHandler)(nn_TunnelRequest *req);
|
|
|
|
nn_Component *nn_createTunnel(nn_Universe *universe, const char *address, const nn_Tunnel *modem, void *state, nn_TunnelHandler *handler);
|
|
|
|
typedef enum nn_InternetProtocol {
|
|
NN_INET_NONE = 0,
|
|
NN_INET_HTTP = 1<<0,
|
|
NN_INET_TCP = 1<<1,
|
|
NN_INET_UDP = 1<<2,
|
|
NN_INET_WEBSOCKET = 1<<3,
|
|
NN_INET_TLS = 1<<4,
|
|
|
|
NN_INET_ALL = NN_INET_HTTP | NN_INET_TCP | NN_INET_UDP | NN_INET_WEBSOCKET | NN_INET_TLS,
|
|
} nn_InternetProtocol;
|
|
|
|
typedef struct nn_InternetCard {
|
|
// bitwise OR multiple of them
|
|
unsigned char protocolsSupported;
|
|
// per-byte cost of a write
|
|
double transmissionEnergyCost;
|
|
} nn_InternetCard;
|
|
|
|
extern nn_InternetCard nn_defaultInternetCard;
|
|
|
|
typedef struct nn_InternetConnection {
|
|
nn_InternetProtocol protocol;
|
|
void *state;
|
|
} nn_InternetConnection;
|
|
|
|
typedef struct nn_HTTPHeader {
|
|
const char *name;
|
|
const char *value;
|
|
} nn_HTTPHeader;
|
|
|
|
typedef struct nn_InternetRequest {
|
|
nn_Context *ctx;
|
|
nn_Computer *computer;
|
|
void *state;
|
|
const nn_Tunnel *tunnel;
|
|
const char *localAddress;
|
|
nn_InternetConnection *connection;
|
|
union {
|
|
// does a socket connection, for any of the supported protocols
|
|
struct {
|
|
// URL of connection
|
|
const char *url;
|
|
// port. Useless for HTTP connections, as they should use 80 for HTTP and 443 for HTTPS
|
|
unsigned short port;
|
|
// HTTP specific
|
|
size_t postdatalen;
|
|
const char *postdata;
|
|
const nn_HTTPHeader *headers;
|
|
size_t headerlen;
|
|
} connect;
|
|
};
|
|
} nn_InternetRequest;
|
|
|
|
// Colors and palettes.
|
|
// Do note that the
|
|
|
|
// The NeoNucleus 2-bit palette
|
|
extern int nn_palette2[4];
|
|
|
|
// The NeoNucleus 3-bit palette
|
|
extern int nn_palette3[8];
|
|
|
|
// The OC 4-bit palette.
|
|
extern int nn_ocpalette4[16];
|
|
|
|
// The Minecraft 4-bit palette, using dye colors.
|
|
extern int nn_mcpalette4[16];
|
|
|
|
// The OC 8-bit palette.
|
|
extern int nn_ocpalette8[256];
|
|
|
|
// initializes the contents of the palettes.
|
|
void nn_initPalettes();
|
|
|
|
// Returns a number from 0 to 1 representing the perceived luminance.
|
|
double nn_colorLuminance(int color);
|
|
// Expensive.
|
|
// Maps a color to the closest match in a palette.
|
|
int nn_mapColor(int color, int *palette, size_t len);
|
|
// Expensive.
|
|
// Maps a color within a given depth.
|
|
// Invalid depths behave identically to 24-bit, in which case the color is left unchanged.
|
|
int nn_mapDepth(int color, int depth);
|
|
|
|
// the name of a depth, if valid.
|
|
// If invalid, NULL is returned, thus this can be used to check
|
|
// if a depth is valid as well.
|
|
// Valid depths are 1, 2, 3, 4, 8, 16 and 24.
|
|
const char *nn_depthName(int depth);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|