more balanced power usage and computer environments

This commit is contained in:
2026-05-03 15:55:11 +03:00
parent cd10093673
commit 571ccb3e3d
5 changed files with 122 additions and 117 deletions

View File

@@ -1,8 +1,6 @@
# For MVP functionality # For MVP functionality
- make `computer` component use callbacks - make `computer` component use callbacks
- make beeps, power, etc. be callbacks on one shared local state (computer environment)
- write a tester OS, basically a menu with tests to run
- finish tmpfs (rework the whole thing) - finish tmpfs (rework the whole thing)
- device info - device info
- userdata support - userdata support

View File

@@ -133,7 +133,8 @@ static int luaArch_computer_beep(lua_State *L) {
if(beep.frequency > 20000) beep.frequency = 20000; if(beep.frequency > 20000) beep.frequency = 20000;
if(beep.duration > 5) beep.duration = 5; if(beep.duration > 5) beep.duration = 5;
if(beep.volume > 1) beep.volume = 1; if(beep.volume > 1) beep.volume = 1;
nn_setComputerBeep(luaArch_from(L)->computer, beep); nn_beepComputer(luaArch_from(L)->computer, beep);
nn_addIdleTime(luaArch_from(L)->computer, beep.duration);
return 0; return 0;
} }

View File

@@ -329,11 +329,21 @@ void *ne_sandbox_alloc(void *state, void *memory, size_t oldSize, size_t newSize
double accumulatedEnergyCost = 0; double accumulatedEnergyCost = 0;
double totalEnergyLoss = 0; double totalEnergyLoss = 0;
double allEnergy = 10000;
double ne_energy_accumulator(void *state, nn_Computer *c, double n) { void ne_env(nn_EnvironmentRequest *req) {
accumulatedEnergyCost += n; if(req->action == NN_ENV_BEEP) {
totalEnergyLoss += n; printf("beep: %f Hz %fs %.02f%%\n", req->beep.frequency, req->beep.duration, req->beep.volume*100);
return nn_getTotalEnergy(c); return;
}
if(req->action == NN_ENV_DRAWENERGY) {
accumulatedEnergyCost += req->energy;
totalEnergyLoss += req->energy;
allEnergy -= req->energy;
req->energy = nn_getTotalEnergy(req->computer);
req->energy = allEnergy;
return;
}
} }
@@ -490,20 +500,16 @@ int main(int argc, char **argv) {
ncl_ScreenState *scrstate = nn_getComponentState(screen); ncl_ScreenState *scrstate = nn_getComponentState(screen);
ncl_mountKeyboard(scrstate, "mainKB"); ncl_mountKeyboard(scrstate, "mainKB");
nn_Computer *c = nn_createComputer(u, NULL, "computer0", ramTotal, 256, 256); nn_Computer *c = nn_createComputer(u, NULL, NULL, ramTotal, 256, 256);
nn_Component *wrappedC = nn_wrapComputer(c); nn_setComputerEnvironment(c, (nn_Environment) {.userdata = NULL, .handler = ne_env});
if(showStats) {
// collects stats
nn_setEnergyHandler(c, NULL, ne_energy_accumulator);
}
nn_setCallBudget(c, 0); nn_setCallBudget(c, 0);
nn_setTotalEnergy(c, allEnergy);
nn_setArchitecture(c, &arch); nn_setArchitecture(c, &arch);
nn_addSupportedArchitecture(c, &arch); nn_addSupportedArchitecture(c, &arch);
nn_setTmpAddress(c, nn_getComponentAddress(tmpfs)); nn_setTmpAddress(c, nn_getComponentAddress(tmpfs));
nn_mountComponent(c, wrappedC, 255, false);
nn_mountComponent(c, screen, -1, false); nn_mountComponent(c, screen, -1, false);
nn_mountComponent(c, ocelotCard, -1, false); nn_mountComponent(c, ocelotCard, -1, false);
nn_mountComponent(c, tmpfs, -1, false); nn_mountComponent(c, tmpfs, -1, false);
@@ -721,12 +727,6 @@ int main(int argc, char **argv) {
continue; continue;
} }
} }
nn_Beep beep;
if(nn_getComputerBeep(c, &beep)) {
nn_clearComputerBeep(c);
printf("beep: %f Hz, %fs, %f%% volume\n", beep.frequency, beep.duration, beep.volume * 100);
}
} }
cleanup:; cleanup:;
@@ -741,7 +741,6 @@ cleanup:;
nn_dropComponent(screen); nn_dropComponent(screen);
nn_dropComponent(gpuCard); nn_dropComponent(gpuCard);
nn_dropComponent(keyboard); nn_dropComponent(keyboard);
nn_dropComponent(wrappedC);
// rip the universe // rip the universe
nn_destroyUniverse(u); nn_destroyUniverse(u);
ncl_destroyGlyphCache(gc); ncl_destroyGlyphCache(gc);

View File

@@ -474,6 +474,7 @@ void nn_destroyLock(nn_Context *ctx, nn_Lock *lock) {
} }
void nn_lock(nn_Context *ctx, nn_Lock *lock) { void nn_lock(nn_Context *ctx, nn_Lock *lock) {
if(lock == NULL) return;
nn_LockRequest req; nn_LockRequest req;
req.lock = lock; req.lock = lock;
req.action = NN_LOCK_LOCK; req.action = NN_LOCK_LOCK;
@@ -481,6 +482,7 @@ void nn_lock(nn_Context *ctx, nn_Lock *lock) {
} }
void nn_unlock(nn_Context *ctx, nn_Lock *lock) { void nn_unlock(nn_Context *ctx, nn_Lock *lock) {
if(lock == NULL) return;
nn_LockRequest req; nn_LockRequest req;
req.lock = lock; req.lock = lock;
req.action = NN_LOCK_UNLOCK; req.action = NN_LOCK_UNLOCK;
@@ -1036,6 +1038,7 @@ typedef struct nn_Signal {
typedef struct nn_Computer { typedef struct nn_Computer {
nn_ComputerState state; nn_ComputerState state;
nn_Universe *universe; nn_Universe *universe;
nn_Environment env;
nn_Lock *lock; nn_Lock *lock;
void *userdata; void *userdata;
char *address; char *address;
@@ -1047,8 +1050,6 @@ typedef struct nn_Computer {
size_t totalCallBudget; size_t totalCallBudget;
nn_HashMap components; nn_HashMap components;
double totalEnergy; double totalEnergy;
void *energyState;
nn_EnergyHandler *energyHandler;
size_t totalMemory; size_t totalMemory;
double creationTimestamp; double creationTimestamp;
size_t stackSize; size_t stackSize;
@@ -1056,7 +1057,6 @@ typedef struct nn_Computer {
size_t signalCount; size_t signalCount;
size_t userCount; size_t userCount;
double idleTimestamp; double idleTimestamp;
nn_Beep beep;
nn_Value callstack[NN_MAX_STACK]; nn_Value callstack[NN_MAX_STACK];
char errorBuffer[NN_MAX_ERROR_SIZE]; char errorBuffer[NN_MAX_ERROR_SIZE];
nn_Architecture archs[NN_MAX_ARCHITECTURES]; nn_Architecture archs[NN_MAX_ARCHITECTURES];
@@ -1111,10 +1111,10 @@ size_t nn_limitStorage(nn_Universe *universe, size_t storage) {
return storage; return storage;
} }
double nn_default_energyHandler(void *state, nn_Computer *computer, double amount) { static void nn_default_envHandler(nn_EnvironmentRequest *req) {
(void)state; if(req->action == NN_ENV_DRAWENERGY) {
(void)amount; req->energy = req->computer->totalEnergy;
return nn_getTotalEnergy(computer); }
} }
size_t nn_ramSizes[8] = { size_t nn_ramSizes[8] = {
@@ -1146,7 +1146,12 @@ nn_Computer *nn_createComputer(nn_Universe *universe, void *userdata, const char
return NULL; return NULL;
} }
c->address = nn_strdup(ctx, address); if(address == NULL) {
c->address = nn_alloc(ctx, sizeof(nn_uuid));
if(c->address != NULL) nn_randomUUID(ctx, c->address);
} else {
c->address = nn_strdup(ctx, address);
}
if(c->address == NULL) { if(c->address == NULL) {
nn_destroyLock(ctx, c->lock); nn_destroyLock(ctx, c->lock);
nn_free(ctx, c, sizeof(nn_Computer)); nn_free(ctx, c, sizeof(nn_Computer));
@@ -1170,8 +1175,7 @@ nn_Computer *nn_createComputer(nn_Universe *universe, void *userdata, const char
} }
c->totalEnergy = 500; c->totalEnergy = 500;
c->energyState = NULL; c->env.handler = nn_default_envHandler;
c->energyHandler = nn_default_energyHandler;
c->totalMemory = totalMemory; c->totalMemory = totalMemory;
c->creationTimestamp = nn_currentTime(ctx); c->creationTimestamp = nn_currentTime(ctx);
c->stackSize = 0; c->stackSize = 0;
@@ -1181,7 +1185,6 @@ nn_Computer *nn_createComputer(nn_Universe *universe, void *userdata, const char
c->idleTimestamp = 0; c->idleTimestamp = 0;
// set to empty string // set to empty string
c->errorBuffer[0] = '\0'; c->errorBuffer[0] = '\0';
nn_clearComputerBeep(c);
return c; return c;
} }
@@ -1251,19 +1254,18 @@ bool nn_isComputerOn(nn_Computer *computer) {
return computer->archState != NULL; return computer->archState != NULL;
} }
void nn_setComputerBeep(nn_Computer *computer, nn_Beep beep) { void nn_setComputerEnvironment(nn_Computer *computer, nn_Environment env) {
computer->env = env;
}
void nn_beepComputer(nn_Computer *computer, nn_Beep beep) {
if(beep.duration < 0) beep.duration = 0; if(beep.duration < 0) beep.duration = 0;
computer->beep = beep; nn_EnvironmentRequest req;
nn_addIdleTime(computer, beep.duration); req.userdata = computer->env.userdata;
} req.computer = computer;
req.action = NN_ENV_BEEP;
bool nn_getComputerBeep(nn_Computer *computer, nn_Beep *beep) { req.beep = beep;
*beep = computer->beep; computer->env.handler(&req);
return computer->beep.volume > 0;
}
void nn_clearComputerBeep(nn_Computer *computer) {
computer->beep.volume = 0;
} }
void nn_destroyComputer(nn_Computer *computer) { void nn_destroyComputer(nn_Computer *computer) {
@@ -1422,29 +1424,34 @@ double nn_getTotalEnergy(nn_Computer *computer) {
} }
double nn_getEnergy(nn_Computer *computer) { double nn_getEnergy(nn_Computer *computer) {
double newEnergy = computer->energyHandler(computer->energyState, computer, 0); nn_EnvironmentRequest req;
if(newEnergy <= 0) { req.userdata = computer->env.userdata;
newEnergy = 0; req.computer = computer;
req.action = NN_ENV_DRAWENERGY;
req.energy = 0;
computer->env.handler(&req);
if(req.energy <= 0) {
req.energy = 0;
computer->state = NN_BLACKOUT; computer->state = NN_BLACKOUT;
} }
return newEnergy; return req.energy;
} }
bool nn_removeEnergy(nn_Computer *computer, double energy) { bool nn_removeEnergy(nn_Computer *computer, double energy) {
double newEnergy = computer->energyHandler(computer->energyState, computer, energy); nn_EnvironmentRequest req;
if(newEnergy <= 0) { req.userdata = computer->env.userdata;
newEnergy = 0; req.computer = computer;
req.action = NN_ENV_DRAWENERGY;
req.energy = energy;
computer->env.handler(&req);
if(req.energy <= 0) {
req.energy = 0;
computer->state = NN_BLACKOUT; computer->state = NN_BLACKOUT;
return true; return true;
} }
return false; return false;
} }
void nn_setEnergyHandler(nn_Computer *computer, void *energyState, nn_EnergyHandler *handler) {
computer->energyState = energyState;
computer->energyHandler = handler;
}
size_t nn_getTotalMemory(nn_Computer *computer) { size_t nn_getTotalMemory(nn_Computer *computer) {
return computer->totalMemory; return computer->totalMemory;
} }
@@ -2561,7 +2568,7 @@ const nn_Filesystem nn_defaultFilesystems[4] = {
.readsPerTick = 4, .readsPerTick = 4,
.writesPerTick = 2, .writesPerTick = 2,
.opensPerTick = 4, .opensPerTick = 4,
.dataEnergyCost = 256.0 / NN_MiB, .dataEnergyCost = 0.1 / NN_KiB,
.maxReadSize = 4096, .maxReadSize = 4096,
}, },
NN_INIT(nn_Filesystem) { NN_INIT(nn_Filesystem) {
@@ -2569,7 +2576,7 @@ const nn_Filesystem nn_defaultFilesystems[4] = {
.readsPerTick = 4, .readsPerTick = 4,
.writesPerTick = 2, .writesPerTick = 2,
.opensPerTick = 8, .opensPerTick = 8,
.dataEnergyCost = 512.0 / NN_MiB, .dataEnergyCost = 0.1 / NN_KiB,
.maxReadSize = 8192, .maxReadSize = 8192,
}, },
NN_INIT(nn_Filesystem) { NN_INIT(nn_Filesystem) {
@@ -2577,7 +2584,7 @@ const nn_Filesystem nn_defaultFilesystems[4] = {
.readsPerTick = 7, .readsPerTick = 7,
.writesPerTick = 3, .writesPerTick = 3,
.opensPerTick = 16, .opensPerTick = 16,
.dataEnergyCost = 1024.0 / NN_MiB, .dataEnergyCost = 0.1 / NN_KiB,
.maxReadSize = 16384, .maxReadSize = 16384,
}, },
NN_INIT(nn_Filesystem) { NN_INIT(nn_Filesystem) {
@@ -2585,7 +2592,7 @@ const nn_Filesystem nn_defaultFilesystems[4] = {
.readsPerTick = 13, .readsPerTick = 13,
.writesPerTick = 5, .writesPerTick = 5,
.opensPerTick = 32, .opensPerTick = 32,
.dataEnergyCost = 2048.0 / NN_MiB, .dataEnergyCost = 0.1 / NN_KiB,
.maxReadSize = 32768, .maxReadSize = 32768,
}, },
}; };
@@ -2595,7 +2602,7 @@ const nn_Filesystem nn_defaultFloppy = NN_INIT(nn_Filesystem) {
.spaceTotal = 512 * NN_KiB, .spaceTotal = 512 * NN_KiB,
.readsPerTick = 1, .readsPerTick = 1,
.writesPerTick = 1, .writesPerTick = 1,
.dataEnergyCost = 8.0 / NN_MiB, .dataEnergyCost = 0.1 / NN_KiB,
.maxReadSize = 2048, .maxReadSize = 2048,
}; };
@@ -2728,7 +2735,7 @@ const nn_ScreenConfig nn_defaultScreens[4] = {
.paletteColors = 0, .paletteColors = 0,
.editableColors = 0, .editableColors = 0,
.features = NN_SCRF_NONE, .features = NN_SCRF_NONE,
.energyPerPixel = 0.05, .energyPerPixel = 0.05 / (50*16),
.minBrightness = 0.5, .minBrightness = 0.5,
.maxBrightness = 1, .maxBrightness = 1,
}, },
@@ -2740,7 +2747,7 @@ const nn_ScreenConfig nn_defaultScreens[4] = {
.paletteColors = 16, .paletteColors = 16,
.editableColors = 0, .editableColors = 0,
.features = NN_SCRF_MOUSE | NN_SCRF_TOUCHINVERTED, .features = NN_SCRF_MOUSE | NN_SCRF_TOUCHINVERTED,
.energyPerPixel = 0.05, .energyPerPixel = 0.05 / (50*16),
.minBrightness = 0.25, .minBrightness = 0.25,
.maxBrightness = 1.2, .maxBrightness = 1.2,
}, },
@@ -2752,7 +2759,7 @@ const nn_ScreenConfig nn_defaultScreens[4] = {
.paletteColors = 256, .paletteColors = 256,
.editableColors = 16, .editableColors = 16,
.features = NN_SCRF_MOUSE | NN_SCRF_TOUCHINVERTED | NN_SCRF_PRECISE | NN_SCRF_EDITABLECOLORS, .features = NN_SCRF_MOUSE | NN_SCRF_TOUCHINVERTED | NN_SCRF_PRECISE | NN_SCRF_EDITABLECOLORS,
.energyPerPixel = 0.05, .energyPerPixel = 0.05 / (50*16),
.minBrightness = 0.1, .minBrightness = 0.1,
.maxBrightness = 1.5, .maxBrightness = 1.5,
}, },
@@ -2763,8 +2770,8 @@ const nn_ScreenConfig nn_defaultScreens[4] = {
.defaultPalette = nn_ocpalette8, .defaultPalette = nn_ocpalette8,
.paletteColors = 256, .paletteColors = 256,
.editableColors = 256, .editableColors = 256,
.features = NN_SCRF_NONE | NN_SCRF_EDITABLECOLORS, .features = NN_SCRF_MOUSE | NN_SCRF_TOUCHINVERTED | NN_SCRF_PRECISE | NN_SCRF_EDITABLECOLORS,
.energyPerPixel = 0.05, .energyPerPixel = 0.05 / (50*16),
.minBrightness = 0.1, .minBrightness = 0.1,
.maxBrightness = 2, .maxBrightness = 2,
}, },
@@ -2781,8 +2788,8 @@ const nn_GPU nn_defaultGPUs[4] = {
.setPerTick = 64, .setPerTick = 64,
.setForegroundPerTick = 32, .setForegroundPerTick = 32,
.setBackgroundPerTick = 32, .setBackgroundPerTick = 32,
.energyPerWrite = 0.0002, .energyPerWrite = 0.2 / (50*16),
.energyPerClear = 0.0001, .energyPerClear = 0.1 / (50*16),
}, },
NN_INIT(nn_GPU) { NN_INIT(nn_GPU) {
.maxWidth = 80, .maxWidth = 80,
@@ -2794,8 +2801,8 @@ const nn_GPU nn_defaultGPUs[4] = {
.setPerTick = 128, .setPerTick = 128,
.setForegroundPerTick = 64, .setForegroundPerTick = 64,
.setBackgroundPerTick = 64, .setBackgroundPerTick = 64,
.energyPerWrite = 0.001, .energyPerWrite = 0.2 / (50*16),
.energyPerClear = 0.0005, .energyPerClear = 0.1 / (50*16),
}, },
NN_INIT(nn_GPU) { NN_INIT(nn_GPU) {
.maxWidth = 160, .maxWidth = 160,
@@ -2807,8 +2814,8 @@ const nn_GPU nn_defaultGPUs[4] = {
.setPerTick = 256, .setPerTick = 256,
.setForegroundPerTick = 128, .setForegroundPerTick = 128,
.setBackgroundPerTick = 128, .setBackgroundPerTick = 128,
.energyPerWrite = 0.002, .energyPerWrite = 0.2 / (50*16),
.energyPerClear = 0.001, .energyPerClear = 0.1 / (50*16),
}, },
NN_INIT(nn_GPU) { NN_INIT(nn_GPU) {
.maxWidth = 240, .maxWidth = 240,
@@ -2820,8 +2827,8 @@ const nn_GPU nn_defaultGPUs[4] = {
.setPerTick = 512, .setPerTick = 512,
.setForegroundPerTick = 256, .setForegroundPerTick = 256,
.setBackgroundPerTick = 256, .setBackgroundPerTick = 256,
.energyPerWrite = 0.0025, .energyPerWrite = 0.2 / (50*16),
.energyPerClear = 0.0012, .energyPerClear = 0.1 / (50*16),
}, },
}; };
@@ -5977,8 +5984,8 @@ nn_Modem nn_defaultWiredModem = {
.maxPacketSize = 8192, .maxPacketSize = 8192,
.maxOpenPorts = 16, .maxOpenPorts = 16,
.isWired = true, .isWired = true,
.basePacketCost = 50, .basePacketCost = 0.5,
.fullPacketCost = 100, .fullPacketCost = 1,
.costPerStrength = 0, .costPerStrength = 0,
}; };
nn_Modem nn_defaultWirelessModems[2] = { nn_Modem nn_defaultWirelessModems[2] = {
@@ -5988,9 +5995,9 @@ nn_Modem nn_defaultWirelessModems[2] = {
.maxPacketSize = 8192, .maxPacketSize = 8192,
.maxOpenPorts = 16, .maxOpenPorts = 16,
.isWired = true, .isWired = true,
.basePacketCost = 100, .basePacketCost = 1,
.fullPacketCost = 500, .fullPacketCost = 5,
.costPerStrength = 30, .costPerStrength = 0.05,
}, },
NN_INIT(nn_Modem) { NN_INIT(nn_Modem) {
.maxRange = 400, .maxRange = 400,
@@ -5998,8 +6005,8 @@ nn_Modem nn_defaultWirelessModems[2] = {
.maxPacketSize = 8192, .maxPacketSize = 8192,
.maxOpenPorts = 16, .maxOpenPorts = 16,
.isWired = true, .isWired = true,
.basePacketCost = 200, .basePacketCost = 2,
.fullPacketCost = 1000, .fullPacketCost = 10,
.costPerStrength = 20, .costPerStrength = 0.05,
}, },
}; };

View File

@@ -397,6 +397,39 @@ typedef struct nn_Architecture {
// NN adds 2 more tiers. // NN adds 2 more tiers.
extern size_t nn_ramSizes[8]; extern size_t nn_ramSizes[8];
typedef struct nn_Beep {
double frequency;
double duration;
double volume;
} nn_Beep;
typedef enum nn_EnvironmentAction {
NN_ENV_DRAWENERGY,
NN_ENV_POWERON,
NN_ENV_POWEROFF,
NN_ENV_CRASHED,
NN_ENV_BEEP,
} 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;
};
} 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. // The state of a *RUNNING* computer.
// Powered off computers shall not have a state, and as far as NeoNucleus is aware, // Powered off computers shall not have a state, and as far as NeoNucleus is aware,
// not exist. // not exist.
@@ -420,30 +453,9 @@ void nn_stopComputer(nn_Computer *computer);
void nn_forceCrashComputer(nn_Computer *computer, const char *s); void nn_forceCrashComputer(nn_Computer *computer, const char *s);
// returns whether an architecture state is present // returns whether an architecture state is present
bool nn_isComputerOn(nn_Computer *computer); bool nn_isComputerOn(nn_Computer *computer);
void nn_setComputerEnvironment(nn_Computer *computer, nn_Environment env);
typedef enum nn_ComputerEvent { void nn_beepComputer(nn_Computer *computer, nn_Beep beep);
// when powered on
NN_COMPUTER_POWERON,
// when powered off
NN_COMPUTER_POWEROFF,
// when force-crashed
NN_COMPUTER_FORCECRASH,
// when crashed
NN_COMPUTER_CRASH,
} nn_ComputerEvent;
typedef void nn_ComputerListener(nn_Computer *computer, nn_ComputerEvent event);
void nn_setComputerListener(nn_Computer *computer, nn_ComputerListener *listener);
typedef struct nn_Beep {
double frequency;
double duration;
double volume;
} nn_Beep;
void nn_setComputerBeep(nn_Computer *computer, nn_Beep beep);
bool nn_getComputerBeep(nn_Computer *computer, nn_Beep *beep);
void nn_clearComputerBeep(nn_Computer *computer);
// get the userdata pointer // get the userdata pointer
void *nn_getComputerUserdata(nn_Computer *computer); void *nn_getComputerUserdata(nn_Computer *computer);
@@ -529,18 +541,6 @@ double nn_getEnergy(nn_Computer *computer);
// Returns true if there is no more energy left, and a blackout has occured. // Returns true if there is no more energy left, and a blackout has occured.
bool nn_removeEnergy(nn_Computer *computer, double energy); bool nn_removeEnergy(nn_Computer *computer, double energy);
// the handler of energy costs.
// The default handler just returns the total energy.
// Computers do not keep track of their current energy, they just call this function.
// getEnergy() calls this with amountToRemove set to 0. It is recommended to handle this as a fastpath.
// This should return the new amount of energy after the removal.
// A negative amount can be returned, it will be clamped to 0.
// If an error occurs, it is recommended to just return 0 and trigger a blackout.
// TODO: evaluate if API should be reworked to handle errors in energy handler.
typedef double nn_EnergyHandler(void *energyState, nn_Computer *computer, double amountToRemove);
void nn_setEnergyHandler(nn_Computer *computer, void *energyState, nn_EnergyHandler *handler);
// copies the string into the local error buffer. The error is NULL terminated, but also capped by NN_MAX_ERROR_SIZE // 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); void nn_setError(nn_Computer *computer, const char *s);
// set a default error message from an exit. // set a default error message from an exit.