diff --git a/src/luaarch.c b/src/luaarch.c index 68cc3c8..172e270 100644 --- a/src/luaarch.c +++ b/src/luaarch.c @@ -116,6 +116,27 @@ static void luaArch_nnToLua(luaArch *arch, lua_State *L, size_t nnIdx) { luaL_error(L, "bad NN value: %s", nn_typenameof(C, nnIdx)); } +static int luaArch_computer_beep(lua_State *L) { + nn_Beep beep = {.frequency = 1000, .duration = 1, .volume = 1}; + if(lua_isnumber(L, 1)) { + beep.frequency = lua_tonumber(L, 1); + } + if(lua_isnumber(L, 2)) { + beep.duration = lua_tonumber(L, 2); + } + if(lua_isnumber(L, 3)) { + beep.volume = lua_tonumber(L, 3); + } + if(beep.frequency < 20) beep.frequency = 20; + if(beep.duration < 0) beep.duration = 0; + if(beep.volume < 0) beep.volume = 0; + if(beep.frequency > 20000) beep.frequency = 20000; + if(beep.duration > 5) beep.duration = 5; + if(beep.volume > 1) beep.volume = 1; + nn_setComputerBeep(luaArch_from(L)->computer, beep); + return 0; +} + static int luaArch_computer_freeMemory(lua_State *L) { lua_pushinteger(L, nn_getFreeMemory(luaArch_from(L)->computer)); return 1; @@ -531,6 +552,8 @@ static int luaArch_unicode_wtrunc(lua_State *L) { static void luaArch_loadEnv(lua_State *L) { lua_createtable(L, 0, 10); int computer = lua_gettop(L); + lua_pushcfunction(L, luaArch_computer_beep); + lua_setfield(L, computer, "beep"); lua_pushcfunction(L, luaArch_computer_freeMemory); lua_setfield(L, computer, "freeMemory"); lua_pushcfunction(L, luaArch_computer_totalMemory); diff --git a/src/main.c b/src/main.c index 5752cfc..d22fa85 100644 --- a/src/main.c +++ b/src/main.c @@ -457,7 +457,6 @@ int main(int argc, char **argv) { } } -restart:; nn_Computer *c = nn_createComputer(u, NULL, "computer0", ramTotal, 256, 256); if(showStats) { // collects stats @@ -549,6 +548,11 @@ restart:; if(t != NULL) nn_pushClipboard(c, "mainKB", t, player); } + if(IsKeyPressed(KEY_TAB)) { + printf("force crashing\n"); + nn_forceCrashComputer(c, "get crashed lol"); + } + while(1) { int keycode = GetKeyPressed(); nn_codepoint unicode = GetCharPressed(); @@ -574,6 +578,11 @@ restart:; keybuf[i].key = 0; nn_pushKeyUp(c, "mainKB", keybuf[i].unicode, key, player); } + // unicode keys handled by raylib + if(IsKeyPressedRepeat(keybuf[i].key) && keybuf[i].unicode == 0) { + int key = keycode_to_oc(keybuf[i].key); + nn_pushKeyDown(c, "mainKB", keybuf[i].unicode, key, player); + } } } @@ -594,7 +603,6 @@ restart:; if(getenv("NN_NOIDLE") != NULL) nn_resetIdleTime(c); nn_Exit e = nn_tick(c); if(e != NN_OK) { - nn_setErrorFromExit(c, e); printf("error: %s\n", nn_getError(c)); goto cleanup; } @@ -616,10 +624,18 @@ restart:; } if(state == NN_RESTART) { printf("restart requested\n"); - nn_destroyComputer(c); - goto restart; + nn_stopComputer(c); + ncl_resetScreen(nn_getComponentState(screen)); + nn_addIdleTime(c, 1); + 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:; diff --git a/src/neonucleus.c b/src/neonucleus.c index fb28588..b571d72 100644 --- a/src/neonucleus.c +++ b/src/neonucleus.c @@ -784,6 +784,15 @@ void nn_hashDeinit(nn_HashMap *map) { nn_free(map->ctx, map->buf, map->hash->entSize * map->bufsize); } +void nn_hashClear(nn_HashMap *map) { + for(size_t i = 0; i < map->bufsize; i++) { + void *ent = NN_PTROFF(map->buf, i, map->hash->entSize); + if(map->hash->handler(NN_HASH_CMP, ent, NULL) == NN_HASH_DIFFERENT) { + map->hash->handler(NN_HASH_REMOVE, ent, NULL); + } + } +} + size_t nn_hashGetHash(nn_HashMap *map, void *entry) { return map->hash->handler(NN_HASH_HASH, entry, NULL); } @@ -1044,6 +1053,7 @@ typedef struct nn_Computer { size_t userCount; double idleTimestamp; double memoryScale; + nn_Beep beep; nn_Value callstack[NN_MAX_STACK]; char errorBuffer[NN_MAX_ERROR_SIZE]; nn_Architecture archs[NN_MAX_ARCHITECTURES]; @@ -1169,6 +1179,7 @@ nn_Computer *nn_createComputer(nn_Universe *universe, void *userdata, const char c->memoryScale = 1; // set to empty string c->errorBuffer[0] = '\0'; + nn_clearComputerBeep(c); return c; } @@ -1196,34 +1207,86 @@ static const nn_MethodEntry *nn_getInternalMethod(nn_Component *c, const char *m return nn_hashGet(&c->methodsMap, &lookingFor); } -void nn_destroyComputer(nn_Computer *computer) { - nn_Context *ctx = &computer->universe->ctx; +nn_Exit nn_startComputer(nn_Computer *computer) { + if(nn_isComputerOn(computer)) { + nn_stopComputer(computer); + } + nn_ArchitectureRequest req; + req.computer = computer; + req.globalState = computer->arch.state; + req.localState = NULL; + req.action = NN_ARCH_INIT; + nn_Exit err = computer->arch.handler(&req); + if(err) { + computer->state = NN_CRASHED; + nn_setErrorFromExit(computer, err); + return err; + } + computer->archState = req.localState; + return NN_OK; +} - if(computer->arch.name != NULL && computer->archState != NULL) { +void nn_stopComputer(nn_Computer *computer) { + nn_Context *ctx = &computer->universe->ctx; + if(nn_isComputerOn(computer)) { nn_ArchitectureRequest req; req.computer = computer; req.globalState = computer->arch.state; req.localState = computer->archState; req.action = NN_ARCH_DEINIT; computer->arch.handler(&req); + computer->archState = NULL; } - - for(size_t i = 0; i < computer->stackSize; i++) { - nn_dropValue(computer->callstack[i]); - } - for(nn_ComponentEntry *c = nn_hashIterate(&computer->components, NULL); c != NULL; c = nn_hashIterate(&computer->components, c)) { - nn_signalComponent(c->comp, computer, NN_CSIGUNMOUNTED); - nn_dropComponent(c->comp); - } + computer->state = NN_BOOTUP; for(size_t i = 0; i < computer->signalCount; i++) { nn_Signal s = computer->signals[i]; for(size_t j = 0; j < s.len; j++) nn_dropValue(s.values[j]); nn_free(ctx, s.values, sizeof(nn_Value) * s.len); } + computer->signalCount = 0; +} + +void nn_forceCrashComputer(nn_Computer *computer, const char *s) { + nn_stopComputer(computer); + computer->state = NN_CRASHED; + nn_setError(computer, s); +} + +bool nn_isComputerOn(nn_Computer *computer) { + return computer->archState != NULL; +} + +void nn_setComputerBeep(nn_Computer *computer, nn_Beep beep) { + if(beep.duration < 0) beep.duration = 0; + computer->beep = beep; + nn_addIdleTime(computer, beep.duration); +} + +bool nn_getComputerBeep(nn_Computer *computer, nn_Beep *beep) { + *beep = computer->beep; + return computer->beep.volume > 0; +} + +void nn_clearComputerBeep(nn_Computer *computer) { + computer->beep.volume = 0; +} + +void nn_destroyComputer(nn_Computer *computer) { + nn_Context *ctx = &computer->universe->ctx; + nn_stopComputer(computer); + + for(size_t i = 0; i < computer->stackSize; i++) { + nn_dropValue(computer->callstack[i]); + } for(size_t i = 0; i < computer->userCount; i++) { nn_strfree(ctx, computer->users[i]); } + for(nn_ComponentEntry *c = nn_hashIterate(&computer->components, NULL); c != NULL; c = nn_hashIterate(&computer->components, c)) { + nn_signalComponent(c->comp, computer, NN_CSIGUNMOUNTED); + nn_dropComponent(c->comp); + } + nn_destroyLock(ctx, computer->lock); nn_hashDeinit(&computer->components); if(computer->tmpaddress != NULL) nn_strfree(ctx, computer->tmpaddress); nn_strfree(ctx, computer->address); @@ -1522,6 +1585,9 @@ void nn_resetIdleTime(nn_Computer *computer) { } nn_Exit nn_tick(nn_Computer *computer) { + if(computer->state == NN_CRASHED) { + return NN_EBADSTATE; + } nn_resetCallBudget(computer); nn_resetComponentBudgets(computer); nn_clearstack(computer); @@ -1531,20 +1597,10 @@ nn_Exit nn_tick(nn_Computer *computer) { computer->idleTimestamp = nn_getUptime(computer); if(computer->state == NN_BOOTUP) { // init state - nn_ArchitectureRequest req; - req.computer = computer; - req.globalState = computer->arch.state; - req.localState = NULL; - req.action = NN_ARCH_INIT; - err = computer->arch.handler(&req); - if(err) { - computer->state = NN_CRASHED; - nn_setErrorFromExit(computer, err); - return err; - } - computer->archState = req.localState; + err = nn_startComputer(computer); + if(err) return err; } else if(computer->state != NN_RUNNING) { - nn_setErrorFromExit(computer, NN_EBADSTATE); + if(computer->state != NN_CRASHED) nn_setErrorFromExit(computer, NN_EBADSTATE); return NN_EBADSTATE; } computer->state = NN_RUNNING; @@ -1562,8 +1618,6 @@ nn_Exit nn_tick(nn_Computer *computer) { return NN_OK; } -// TODO: every component method src/neonucleus.h:530 - static nn_Exit nn_defaultComponent(nn_ComponentRequest *request) { return NN_OK; } diff --git a/src/neonucleus.h b/src/neonucleus.h index 8e9ba50..cde15db 100644 --- a/src/neonucleus.h +++ b/src/neonucleus.h @@ -410,6 +410,26 @@ nn_Computer *nn_createComputer(nn_Universe *universe, void *userdata, const char void nn_destroyComputer(nn_Computer *computer); 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); + +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 void *nn_getComputerUserdata(nn_Computer *computer); const char *nn_getComputerAddress(nn_Computer *computer);