work on network encoding and documenting eventual component interfaces

This commit is contained in:
2026-04-05 01:04:24 +02:00
parent e3959a24da
commit dad8e34cca
6 changed files with 467 additions and 33 deletions

View File

@@ -356,7 +356,7 @@ int main(int argc, char **argv) {
InitWindow(800, 600, "NeoNucleus Test Emulator");
// create the universe
nn_Universe *u = nn_createUniverse(&ctx);
nn_Universe *u = nn_createUniverse(&ctx, NULL);
nn_Architecture arch = getLuaArch();
@@ -370,9 +370,17 @@ int main(int argc, char **argv) {
nn_Component *eepromCard = ncl_createEEPROM(u, NULL, &nn_defaultEEPROMs[3], minBIOS, strlen(minBIOS), false);
nn_Filesystem mainfsconf;
nn_Filesystem fsparts[] = {
nn_defaultFilesystems[3],
nn_defaultFilesystems[3],
nn_defaultFilesystems[3],
};
nn_mergeFilesystems(&mainfsconf, fsparts, sizeof(fsparts) / sizeof(fsparts[0]));
char mainfspath[NN_MAX_PATH];
snprintf(mainfspath, NN_MAX_PATH, "data/%s", mainDir);
nn_Component *managedfs = ncl_createFilesystem(u, NULL, mainfspath, &nn_defaultFilesystems[3], true);
nn_Component *managedfs = ncl_createFilesystem(u, NULL, mainfspath, &mainfsconf, true);
nn_Component *tmpfs = ncl_createTmpFS(u, NULL, &nn_defaultTmpFS, NCL_FILECOST_DEFAULT, false);
nn_Component *testingfs = ncl_createTmpFS(u, NULL, &nn_defaultFilesystems[3], NCL_FILECOST_DEFAULT, false);
@@ -400,7 +408,12 @@ int main(int argc, char **argv) {
"while computer.uptime() < now + 3 do computer.pullSignal(0.05) end\n"
"computer.shutdown(true)\n"
;
nn_Component *testDrive = ncl_createDrive(u, NULL, &nn_defaultSSDs[3], testDriveData, strlen(testDriveData), false);
nn_Drive driveconf;
nn_Drive driveparts[] = {
nn_floppySSD,
};
nn_mergeDrives(&driveconf, driveparts, sizeof(driveparts) / sizeof(driveparts[0]));
nn_Component *testDrive = ncl_createDrive(u, NULL, &driveconf, testDriveData, strlen(testDriveData), false);
ncl_setCLabel(managedfs, "Main Filesystem");
ncl_setCLabel(testingfs, "Secondary Filesystem");
@@ -452,6 +465,22 @@ restart:;
nn_setEnergyHandler(c, NULL, ne_energy_accumulator);
}
nn_setCallBudget(c, 0);
nn_EncodedNetworkContents contents;
nn_pushstring(c, "stuff");
nn_pushnull(c);
nn_pushnumber(c, 5.3);
nn_pushbool(c, false);
nn_encodeNetworkContents(c, &contents, 4);
nn_dropNetworkContents(&contents);
printf("size: %zu\n", contents.buflen);
for(size_t i = 0; i < contents.buflen; i++) {
unsigned char byte = contents.buf[i];
printf("%02X ", byte);
}
printf("\n");
// default for 64-bit
if(sizeof(void *) > 4) nn_setMemoryScale(c, 1.8);
@@ -468,7 +497,7 @@ restart:;
nn_mountComponent(c, eepromCard, 0);
nn_mountComponent(c, managedfs, 1);
nn_mountComponent(c, gpuCard, 2);
nn_mountComponent(c, testingfs, 3);
//nn_mountComponent(c, testingfs, 3);
nn_mountComponent(c, testDrive, 4);
while(true) {
if(WindowShouldClose()) break;
@@ -576,6 +605,8 @@ restart:;
nextTick = tickNow + tickDelay;
nn_clearstack(c);
nn_removeEnergy(c, ncl_getScreenEnergyUsage(nn_getComponentState(screen)));
if(getenv("NN_NOIDLE") != NULL) nn_resetIdleTime(c);
nn_Exit e = nn_tick(c);
if(e != NN_OK) {

View File

@@ -3186,6 +3186,20 @@ const char *ncl_getKeyboard(ncl_ScreenState *state,
return state->keyboards[idx];
}
double ncl_getScreenEnergyUsage(ncl_ScreenState *state) {
double sum = 0;
for(int y = 1; y <= state->viewportHeight; y++) {
for(int x = 1; x <= state->viewportWidth; x++) {
ncl_Pixel p = ncl_getScreenPixel(state, x, y);
sum += state->conf.energyPerPixel * nn_colorLuminance(p.bgColor);
if(p.codepoint != 0 && p.codepoint != ' ') {
sum += state->conf.energyPerPixel * nn_colorLuminance(p.fgColor);
}
}
}
return sum;
}
// general stuff
bool ncl_isNCLID(const char *type) {

View File

@@ -334,5 +334,6 @@ nn_Exit ncl_mountKeyboard(ncl_ScreenState *state, const char *keyboardAddress);
void ncl_unmountKeyboard(ncl_ScreenState *state, const char *keyboardAddress);
bool ncl_hasKeyboard(ncl_ScreenState *state, const char *keyboardAddress);
const char *ncl_getKeyboard(ncl_ScreenState *state, size_t idx);
double ncl_getScreenEnergyUsage(ncl_ScreenState *state);
#endif

View File

@@ -266,6 +266,23 @@ void nn_memset(void *dest, int x, size_t len) {
for(size_t i = 0; i < len; i++) out[i] = (char)x;
}
void nn_memreverse(void *dest, size_t len) {
size_t mid = len/2;
char *bytes = (char *)dest;
for(size_t i = 0; i < mid; i++) {
size_t j = len - i - 1;
char tmp = bytes[i];
bytes[i] = bytes[j];
bytes[j] = tmp;
}
}
bool nn_isLittleEndian() {
union {char c; size_t x;} test;
test.x = 1;
return test.c == 1;
}
// taken from https://wiki.osdev.org/CRC32
// OSDev wiki is really useful sometimes
// TODO: maybe allow one that uses compiler intrinsics
@@ -911,10 +928,13 @@ static const nn_HashContext nn_methodHasher = {
.handler = (nn_HashHandler *)nn_methodHash,
};
// currently just a wrapper around a context
// but will be way more in the future
typedef struct nn_Universe {
nn_Context ctx;
void *userdata;
// 0 for unbounded
size_t memoryLimit;
// 0 for unbounded
size_t storageLimit;
} nn_Universe;
typedef struct nn_ComponentEntry {
@@ -1030,10 +1050,13 @@ typedef struct nn_Computer {
char *users[NN_MAX_USERS];
} nn_Computer;
nn_Universe *nn_createUniverse(nn_Context *ctx) {
nn_Universe *nn_createUniverse(nn_Context *ctx, void *userdata) {
nn_Universe *u = nn_alloc(ctx, sizeof(nn_Universe));
if(u == NULL) return NULL;
u->ctx = *ctx;
u->userdata = userdata;
u->memoryLimit = 0;
u->storageLimit = 0;
return u;
}
@@ -1042,6 +1065,38 @@ void nn_destroyUniverse(nn_Universe *universe) {
nn_free(&ctx, universe, sizeof(nn_Universe));
}
void *nn_getUniverseData(nn_Universe *universe) {
return universe->userdata;
}
size_t nn_getUniverseMemoryLimit(nn_Universe *universe) {
return universe->memoryLimit;
}
void nn_setUniverseMemoryLimit(nn_Universe *universe, size_t limit) {
universe->memoryLimit = limit;
}
size_t nn_limitMemory(nn_Universe *universe, size_t memory) {
if(universe->memoryLimit == 0) return memory;
if(memory > universe->memoryLimit) memory = universe->memoryLimit;
return memory;
}
size_t nn_getUniverseStorageLimit(nn_Universe *universe) {
return universe->storageLimit;
}
void nn_setUniverseStorageLimit(nn_Universe *universe, size_t limit) {
universe->storageLimit = limit;
}
size_t nn_limitStorage(nn_Universe *universe, size_t storage) {
if(universe->memoryLimit == 0) return storage;
if(storage > universe->memoryLimit) storage = universe->storageLimit;
return storage;
}
double nn_default_energyHandler(void *state, nn_Computer *computer, double amount) {
(void)state;
(void)amount;
@@ -1062,6 +1117,8 @@ size_t nn_ramSizes[8] = {
nn_Computer *nn_createComputer(nn_Universe *universe, void *userdata, const char *address, size_t totalMemory, size_t maxComponents, size_t maxDevices) {
nn_Context *ctx = &universe->ctx;
totalMemory = nn_limitMemory(universe, totalMemory);
nn_Computer *c = nn_alloc(ctx, sizeof(nn_Computer));
if(c == NULL) return NULL;
@@ -2491,8 +2548,8 @@ const nn_Drive nn_defaultSSDs[4] = {
.sectorSize = 512,
.platterCount = 2,
.cacheLineSize = 2,
.readsPerTick = 20,
.writesPerTick = 10,
.readsPerTick = 10,
.writesPerTick = 5,
.rpm = 0,
.onlySpinForwards = false,
.dataEnergyCost = 64.0 / NN_MiB,
@@ -2502,8 +2559,8 @@ const nn_Drive nn_defaultSSDs[4] = {
.sectorSize = 512,
.platterCount = 4,
.cacheLineSize = 4,
.readsPerTick = 30,
.writesPerTick = 15,
.readsPerTick = 15,
.writesPerTick = 7,
.rpm = 0,
.onlySpinForwards = false,
.dataEnergyCost = 128.0 / NN_MiB,
@@ -2513,8 +2570,8 @@ const nn_Drive nn_defaultSSDs[4] = {
.sectorSize = 512,
.platterCount = 8,
.cacheLineSize = 8,
.readsPerTick = 40,
.writesPerTick = 20,
.readsPerTick = 20,
.writesPerTick = 10,
.rpm = 0,
.onlySpinForwards = false,
.dataEnergyCost = 256.0 / NN_MiB,
@@ -2524,8 +2581,8 @@ const nn_Drive nn_defaultSSDs[4] = {
.sectorSize = 512,
.platterCount = 16,
.cacheLineSize = 16,
.readsPerTick = 60,
.writesPerTick = 30,
.readsPerTick = 30,
.writesPerTick = 15,
.rpm = 0,
.onlySpinForwards = false,
.dataEnergyCost = 512.0 / NN_MiB,
@@ -2537,8 +2594,8 @@ const nn_Drive nn_floppySSD = {
.sectorSize = 512,
.platterCount = 1,
.cacheLineSize = 2,
.readsPerTick = 10,
.writesPerTick = 5,
.readsPerTick = 5,
.writesPerTick = 2,
.rpm = 0,
.onlySpinForwards = true,
.dataEnergyCost = 16.0 / NN_MiB,
@@ -2553,6 +2610,7 @@ const nn_ScreenConfig nn_defaultScreens[4] = {
.paletteColors = 0,
.editableColors = 0,
.features = NN_SCRF_NONE,
.energyPerPixel = 0.05,
},
NN_INIT(nn_ScreenConfig) {
.maxWidth = 80,
@@ -2562,6 +2620,7 @@ const nn_ScreenConfig nn_defaultScreens[4] = {
.paletteColors = 16,
.editableColors = 0,
.features = NN_SCRF_MOUSE | NN_SCRF_TOUCHINVERTED,
.energyPerPixel = 0.05,
},
NN_INIT(nn_ScreenConfig) {
.maxWidth = 160,
@@ -2571,6 +2630,7 @@ const nn_ScreenConfig nn_defaultScreens[4] = {
.paletteColors = 256,
.editableColors = 16,
.features = NN_SCRF_MOUSE | NN_SCRF_TOUCHINVERTED | NN_SCRF_PRECISE | NN_SCRF_EDITABLECOLORS,
.energyPerPixel = 0.05,
},
NN_INIT(nn_ScreenConfig) {
.maxWidth = 240,
@@ -2580,6 +2640,7 @@ const nn_ScreenConfig nn_defaultScreens[4] = {
.paletteColors = 256,
.editableColors = 256,
.features = NN_SCRF_NONE | NN_SCRF_EDITABLECOLORS,
.energyPerPixel = 0.05,
},
};
@@ -3280,6 +3341,117 @@ nn_Exit nn_pushLClipboard(nn_Computer *computer, const char *keyboardAddress, co
return nn_pushSignal(computer, 3);
}
nn_Exit nn_pushRedstoneChanged(nn_Computer *computer, const char *redstoneAddress, int side, int oldValue, int newValue, int color);
nn_Exit nn_pushMotion(nn_Computer *computer, double relX, double relY, double relZ, const char *entityName);
typedef enum nn_NetworkValueTag {
NN_NETVAL_NULL = 0x00,
NN_NETVAL_TRUE = 0x01,
NN_NETVAL_FALSE = 0x02,
NN_NETVAL_NUM = 0x03,
NN_NETVAL_STR = 0x04,
NN_NETVAL_RESOURCE = 0x05,
NN_NETVAL_TABLE = 0x06,
} nn_NetworkValueTag;
static size_t nn_sizeOfNetworkValue(nn_Value val);
static size_t nn_sizeOfNetworkContents(nn_Value *vals, size_t len) {
size_t s = 0;
for(size_t i = 0; i < len; i++) s += nn_sizeOfNetworkValue(vals[i]);
return s;
}
static size_t nn_sizeOfNetworkValue(nn_Value val) {
// 1-byte tag, + value-dependant encoding
size_t n = 1;
switch(val.type) {
case NN_VAL_NULL:
case NN_VAL_BOOL:
break;
case NN_VAL_NUM:
n += sizeof(double);
break;
case NN_VAL_STR:
n += sizeof(size_t) + val.string->len;
break;
case NN_VAL_USERDATA:
n += sizeof(size_t);
break;
case NN_VAL_TABLE:
n += sizeof(size_t) + nn_sizeOfNetworkContents(val.table->vals, val.table->len);
break;
}
return n;
}
static size_t nn_encodeNetworkValue(nn_Value val, char *buf) {
size_t n = 0;
switch(val.type) {
case NN_VAL_NULL:
*buf = NN_NETVAL_NULL;
return 1;
case NN_VAL_BOOL:
*buf = val.boolean ? NN_NETVAL_TRUE : NN_NETVAL_FALSE;
return 1;
case NN_VAL_NUM:
*buf = NN_NETVAL_NUM;
nn_memcpy(buf + 1, &val.number, sizeof(double));
return 1 + sizeof(double);
case NN_VAL_STR:
*buf = NN_NETVAL_STR;
nn_memcpy(buf + 1, &val.string->len, sizeof(size_t));
nn_memcpy(buf + 1 + sizeof(size_t), val.string->data, val.string->len);
return 1 + sizeof(size_t) + val.string->len;
case NN_VAL_USERDATA:
*buf = NN_NETVAL_RESOURCE;
nn_memcpy(buf + 1, &val.userdataIdx, sizeof(size_t));
return 1 + sizeof(size_t);
case NN_VAL_TABLE:
*buf = NN_NETVAL_TABLE;
n = 1;
nn_memcpy(buf + n, &val.table->len, sizeof(size_t));
n += sizeof(size_t);
for(size_t i = 0; i < val.table->len; i++) {
n += nn_encodeNetworkValue(val.table->vals[i], buf + n);
}
return n;
}
*buf = NN_NETVAL_NULL;
return 1;
}
nn_Exit nn_encodeNetworkContents(nn_Computer *computer, nn_EncodedNetworkContents *contents, size_t valueCount) {
if(computer->stackSize < valueCount) return NN_EBELOWSTACK;
nn_Value *vals = computer->callstack + computer->stackSize - valueCount;
size_t len = nn_sizeOfNetworkContents(vals, valueCount);
contents->ctx = &computer->universe->ctx;
contents->valueCount = valueCount;
contents->buflen = len;
contents->buf = nn_alloc(contents->ctx, len);
if(contents->buf == NULL) return NN_ENOMEM;
nn_memset(contents->buf, 0, len);
size_t n = 0;
for(size_t i = 0; i < valueCount; i++) {
n += nn_encodeNetworkValue(vals[i], contents->buf + n);
}
return NN_OK;
}
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) {
nn_free(contents->ctx, contents->buf, contents->buflen);
}
nn_Exit nn_pushNetworkContents(nn_Computer *computer, const nn_EncodedNetworkContents *contents);
nn_Exit nn_pushModemMessage(nn_Computer *computer, const char *modemAddress, const char *sender, int port, double distance, const nn_EncodedNetworkContents *contents);
typedef enum nn_EENum {
NN_EENUM_GETSIZE,
NN_EENUM_GETDATASIZE,
@@ -3860,6 +4032,22 @@ nn_Component *nn_createFilesystem(nn_Universe *universe, const char *address, co
return c;
}
bool nn_mergeFilesystems(nn_Filesystem *merged, const nn_Filesystem *fs, size_t len) {
if(len == 0) return false;
*merged = fs[0];
for(size_t i = 1; i < len; i++) {
merged->readsPerTick += fs[i].readsPerTick;
merged->writesPerTick += fs[i].writesPerTick;
if(merged->maxReadSize < fs[i].maxReadSize) merged->maxReadSize = fs[i].maxReadSize;
merged->dataEnergyCost += fs[i].dataEnergyCost;
merged->spaceTotal += fs[i].spaceTotal;
}
merged->readsPerTick /= len;
merged->writesPerTick /= len;
merged->dataEnergyCost /= len;
return true;
}
static void nn_drive_seekPenalty(nn_Computer *C, size_t lastSector, size_t newSector, const nn_Drive *drive) {
// Check if SSD
if(drive->rpm == 0) return;
@@ -4064,6 +4252,36 @@ nn_Component *nn_createDrive(nn_Universe *universe, const char *address, const n
return c;
}
bool nn_mergeDrives(nn_Drive *merged, const nn_Drive *drives, size_t len) {
if(len == 0) return false;
*merged = drives[0];
for(size_t i = 1; i < len; i++) {
nn_Drive d = drives[i];
// invalid SSD/HDD combo
if(d.rpm == 0 && merged->rpm != 0) return false;
if(d.rpm != 0 && merged->rpm == 0) return false;
// conflicting sector sizes
if(d.sectorSize != merged->sectorSize) return false;
if(d.rpm != 0) {
if(d.onlySpinForwards && !merged->onlySpinForwards) return false;
if(!d.onlySpinForwards && merged->onlySpinForwards) return false;
}
merged->readsPerTick += d.readsPerTick;
merged->writesPerTick += d.writesPerTick;
merged->dataEnergyCost += d.dataEnergyCost;
merged->rpm += d.rpm;
merged->capacity += d.capacity;
merged->cacheLineSize += d.cacheLineSize;
merged->platterCount += d.platterCount;
}
merged->readsPerTick /= len;
merged->writesPerTick /= len;
merged->dataEnergyCost /= len;
merged->rpm /= len;
return true;
}
typedef enum nn_ScreenNum {
NN_SCRNUM_ISON,
NN_SCRNUM_TURNON,
@@ -4656,14 +4874,16 @@ static nn_Exit nn_gpuHandler(nn_ComponentRequest *req) {
g.copy.h = nn_tointeger(C, 3);
g.copy.tx = nn_tointeger(C, 4);
g.copy.ty = nn_tointeger(C, 5);
// prevent issues
if(g.copy.w < 0) g.copy.w = 0;
if(g.copy.w > g.gpu->maxWidth) g.copy.w = g.gpu->maxWidth;
if(g.copy.h < 0) g.copy.h = 0;
if(g.copy.h > g.gpu->maxHeight) g.copy.h = g.gpu->maxHeight;
e = cls->handler(&g);
if(e) return e;
req->returnCount = 1;
nn_costComponent(C, req->compAddress, cls->gpu.copyPerTick);
// prevent issues
if(g.copy.tx < 1) g.copy.tx = 1;
if(g.copy.ty < 1) g.copy.ty = 1;
nn_removeEnergy(C, cls->gpu.energyPerWrite * g.copy.tx * g.copy.ty);
nn_removeEnergy(C, cls->gpu.energyPerWrite * g.copy.w * g.copy.h);
return nn_pushbool(C, true);
}
// fill
@@ -4681,15 +4901,17 @@ static nn_Exit nn_gpuHandler(nn_ComponentRequest *req) {
g.fill.y = nn_tointeger(C, 1);
g.fill.w = nn_tointeger(C, 2);
g.fill.h = nn_tointeger(C, 3);
// prevent issues
if(g.fill.w < 0) g.fill.w = 0;
if(g.fill.w > g.gpu->maxWidth) g.fill.w = g.gpu->maxWidth;
if(g.fill.h < 0) g.fill.h = 0;
if(g.fill.h > g.gpu->maxHeight) g.fill.h = g.gpu->maxHeight;
g.fill.codepoint = nn_unicode_firstCodepoint(
nn_tostring(C, 4));
e = cls->handler(&g);
if(e) return e;
req->returnCount = 1;
nn_costComponent(C, req->compAddress, cls->gpu.fillPerTick);
// prevent issues
if(g.fill.w < 1) g.fill.w = 1;
if(g.fill.h < 1) g.fill.h = 1;
nn_removeEnergy(C, (g.fill.codepoint == ' ' ? cls->gpu.energyPerClear : cls->gpu.energyPerWrite) * g.fill.w * g.fill.h);
return nn_pushbool(C, true);
}
@@ -4798,6 +5020,15 @@ static nn_Exit nn_gpuHandler(nn_ComponentRequest *req) {
g.bitblt.src = nn_tointeger(C, 5);
g.bitblt.fromCol = nn_tointeger(C, 6);
g.bitblt.fromRow = nn_tointeger(C, 7);
if(g.bitblt.w < 0) g.copy.w = 0;
if(g.bitblt.w > g.gpu->maxWidth) g.bitblt.w = g.gpu->maxWidth;
if(g.bitblt.h < 0) g.copy.h = 0;
if(g.bitblt.h > g.gpu->maxHeight) g.bitblt.h = g.gpu->maxHeight;
if(g.bitblt.dst == 0 || g.bitblt.src == 0) {
// taxed as a copy
nn_costComponent(C, req->compAddress, g.gpu->copyPerTick);
nn_removeEnergy(C, g.gpu->energyPerWrite * g.bitblt.w * g.bitblt.h);
}
e = cls->handler(&g);
if(e) return e;
req->returnCount = 1;

View File

@@ -77,7 +77,6 @@ void *_alloca(size_t);
#define NN_KiB (1024)
#define NN_MiB (1024 * NN_KiB)
#define NN_GiB (1024 * NN_MiB)
// probably recursive: #define NN_TiB (1024 * NN_TiB)
#define NN_TiB ((size_t)1024 * NN_GiB)
// the alignment an allocation should have
@@ -309,8 +308,15 @@ typedef enum nn_Exit {
// This stores necessary data between computers
typedef struct nn_Universe nn_Universe;
nn_Universe *nn_createUniverse(nn_Context *ctx);
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;
@@ -1071,6 +1077,8 @@ 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 {
@@ -1186,6 +1194,8 @@ 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);
// Screen class
typedef enum nn_ScreenFeatures {
@@ -1226,6 +1236,10 @@ typedef struct nn_ScreenConfig {
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;
} nn_ScreenConfig;
// OC has 3 tiers, NN adds a 4th one as well.
@@ -1694,12 +1708,21 @@ typedef struct nn_EncodedNetworkContents {
// 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 universal, so it is perfectly fine to store on-disk.
// 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_Computer *computer, nn_EncodedNetworkContents *contents, const char *buf, size_t buflen, size_t valueCount);
void nn_dropNetworkContents(nn_Computer *computer, nn_EncodedNetworkContents *contents);
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);
@@ -1707,7 +1730,7 @@ nn_Exit nn_pushNetworkContents(nn_Computer *computer, const nn_EncodedNetworkCon
// 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 if a relay with a card should change the sender.
// 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);
#ifdef __cplusplus