Compare commits

..

25 Commits

Author SHA1 Message Date
5f06a5659c Merge branch 'main' of https://gitea.codersquack.nl/NeoFlock/neonucleus 2026-06-06 03:51:15 +02:00
de13eeb85a removed a useless addition that caused pointless complications 2026-06-06 03:51:10 +02:00
7c086f6b8e update readme yayayay 2026-06-02 09:11:02 -03:00
c58e57b7c7 internet card progress 2026-05-24 18:40:53 +02:00
3b04fd45c7 internet progress 2026-05-23 20:30:31 +02:00
b88fd280ea I came, I saw, I conquered 2026-05-23 16:27:47 +02:00
b732f67b06 tmpfs works now 2026-05-23 16:23:44 +02:00
5c905e6f77 screen usage counter 2026-05-23 01:41:08 +02:00
2275cbf47d new tmpfs 2026-05-22 18:13:01 +02:00
79ea1c7f6f simplified the memory management 2026-05-19 23:44:54 +02:00
60b12ee507 support for morse code beeps 2026-05-18 23:57:50 +02:00
a6d7278735 beginnings of the internet (card) 2026-05-16 17:46:48 +03:00
810bf23942 we love accuracyslop 2026-05-14 18:11:18 +03:00
bcf0c06458 filesystem speeds were inaccurate 2026-05-14 18:04:43 +03:00
f0f6a21fef for debugging 2026-05-13 23:31:54 +03:00
a41e53f98f you didn't see that 2026-05-11 21:33:10 +03:00
172b7ce783 even more accuracyslop 2026-05-11 21:32:54 +03:00
37faa466f3 made it more accurateslop 2026-05-11 21:07:27 +03:00
fbd91be56d musl 'support'
musl suh ahh
2026-05-11 20:26:26 +03:00
461416362c more accuracy 2026-05-10 22:13:20 +03:00
e4d342a36f minor discrepancy 2026-05-09 17:57:54 +03:00
e7a166f85c C99 2026-05-09 16:31:19 +03:00
f832369ce0 fuck those invariants anyways 2026-05-09 13:29:47 +03:00
f9905d14fa data cards are so back 2026-05-09 02:24:01 +03:00
754a04de3c yipee data cards are done 2026-05-09 02:22:58 +03:00
10 changed files with 1836 additions and 779 deletions

View File

@@ -6,20 +6,23 @@ CC=cc
LD=$(CC) LD=$(CC)
AR=ar AR=ar
RANLIB=ranlib RANLIB=ranlib
WARN=-Wall -Werror -Wno-format-truncation
ifeq ($(MODE), release) ifeq ($(MODE), release)
OPT=-Oz OPT=-Oz
ifneq ($(CC), clang) DEBUG=
# clang emits LLVM bitcode in lto mode, which only clang and lld understand else ifeq ($(MODE), release-lto)
OPT += -flto OPT=-Oz -flto
endif
DEBUG= DEBUG=
else else
OPT=-O0 OPT=-O0
SANITIZE=undefined,address SANITIZE=undefined,address
DEBUG=-ggdb DEBUG=-g
endif endif
NN_STD=gnu99
EMU_STD=gnu23
NNFLAGS= NNFLAGS=
SANITIZE_FLAGS= SANITIZE_FLAGS=
@@ -28,7 +31,8 @@ ifdef SANITIZE
SANITIZE_FLAGS += -fsanitize=$(SANITIZE) SANITIZE_FLAGS += -fsanitize=$(SANITIZE)
endif endif
CFLAGS=-fPIC $(OPT) $(SANITIZE_FLAGS) $(DEBUG) $(NNFLAGS) # no-omit-frame-pointer so if a crash does happen we can trace it
CFLAGS=-fPIC -fno-omit-frame-pointer $(OPT) $(SANITIZE_FLAGS) $(DEBUG) $(NNFLAGS) $(WARN)
LDFLAGS=$(OPT) $(DEBUG) $(SANITIZE_FLAGS) LDFLAGS=$(OPT) $(DEBUG) $(SANITIZE_FLAGS)
@@ -44,21 +48,21 @@ SRC_DIR=src
all: bin lib dynlib all: bin lib dynlib
$(BUILD_DIR)/neonucleus.o: $(SRC_DIR)/neonucleus.c $(SRC_DIR)/neonucleus.h $(BUILD_DIR)/neonucleus.o: $(SRC_DIR)/neonucleus.c $(SRC_DIR)/neonucleus.h
$(CC) -o $(BUILD_DIR)/neonucleus.o -c $(SRC_DIR)/neonucleus.c $(CFLAGS) $(CC) -o $(BUILD_DIR)/neonucleus.o -c $(SRC_DIR)/neonucleus.c $(CFLAGS) -std=$(NN_STD)
$(BUILD_DIR)/ncomplib.o: $(SRC_DIR)/ncomplib.c $(SRC_DIR)/ncomplib.h $(BUILD_DIR)/ncomplib.o: $(SRC_DIR)/ncomplib.c $(SRC_DIR)/ncomplib.h
$(CC) -o $(BUILD_DIR)/ncomplib.o -c $(SRC_DIR)/ncomplib.c $(CFLAGS) $(CC) -o $(BUILD_DIR)/ncomplib.o -c $(SRC_DIR)/ncomplib.c $(CFLAGS) -std=$(NN_STD)
nn: $(BUILD_DIR)/neonucleus.o $(BUILD_DIR)/ncomplib.o nn: $(BUILD_DIR)/neonucleus.o $(BUILD_DIR)/ncomplib.o
$(BUILD_DIR)/luaarch.o: $(SRC_DIR)/luaarch.c $(SRC_DIR)/machine.lua $(BUILD_DIR)/luaarch.o: $(SRC_DIR)/luaarch.c $(SRC_DIR)/machine.lua
$(CC) -o $(BUILD_DIR)/luaarch.o -c $(SRC_DIR)/luaarch.c $(CFLAGS) $(INCLUA) $(CC) -o $(BUILD_DIR)/luaarch.o -c $(SRC_DIR)/luaarch.c $(CFLAGS) $(INCLUA) -std=$(EMU_STD)
$(BUILD_DIR)/glyphcache.o: $(SRC_DIR)/glyphcache.c $(SRC_DIR)/glyphcache.h $(BUILD_DIR)/glyphcache.o: $(SRC_DIR)/glyphcache.c $(SRC_DIR)/glyphcache.h
$(CC) -o $(BUILD_DIR)/glyphcache.o -c $(SRC_DIR)/glyphcache.c $(CFLAGS) $(CC) -o $(BUILD_DIR)/glyphcache.o -c $(SRC_DIR)/glyphcache.c $(CFLAGS) -std=$(EMU_STD)
$(BUILD_DIR)/main.o: $(SRC_DIR)/main.c $(SRC_DIR)/minBIOS.lua $(BUILD_DIR)/main.o: $(SRC_DIR)/main.c $(SRC_DIR)/minBIOS.lua
$(CC) -o $(BUILD_DIR)/main.o -c $(SRC_DIR)/main.c $(CFLAGS) $(INCLUA) $(CC) -o $(BUILD_DIR)/main.o -c $(SRC_DIR)/main.c $(CFLAGS) $(INCLUA) -std=$(EMU_STD)
bin: nn $(BUILD_DIR)/main.o $(BUILD_DIR)/luaarch.o $(BUILD_DIR)/glyphcache.o bin: nn $(BUILD_DIR)/main.o $(BUILD_DIR)/luaarch.o $(BUILD_DIR)/glyphcache.o
$(LD) $(LDFLAGS) -o $(BIN) $(BUILD_DIR)/neonucleus.o $(BUILD_DIR)/ncomplib.o $(BUILD_DIR)/main.o $(BUILD_DIR)/glyphcache.o $(BUILD_DIR)/luaarch.o $(LINKLIBC) $(LINKLIBM) $(LINKRAYLIB) $(LINKLUA) $(LD) $(LDFLAGS) -o $(BIN) $(BUILD_DIR)/neonucleus.o $(BUILD_DIR)/ncomplib.o $(BUILD_DIR)/main.o $(BUILD_DIR)/glyphcache.o $(BUILD_DIR)/luaarch.o $(LINKLIBC) $(LINKLIBM) $(LINKRAYLIB) $(LINKLUA)

24
TODO.md
View File

@@ -1,22 +1,8 @@
# To improve the API
- finish tmpfs (rework the whole thing)
# To re-evaluate
- Make the hashmap growing/shrinking to save on memory.
- Exposing the internal hashmap implementation.
- Having a copy of the context stored directly in requests instead of having to use getComputerContext, as it simplifies the APIs and allows them
to be made more portable.
- Exposing more internal functions that may be useful to the user to prevent pointless rewriting and duplicate machine code.
# Vanilla components needed # Vanilla components needed
Not everything OC has (as a few of them are really MC-centered) but most of it. Not everything OC has (as a few of them are really MC-centered) but most of it.
- `computer` component - `computer` component
- `data` component (note: deflate, sha256 and aes impl are callbacks, to keep NN small and simple)
- `tunnel` component
- `internet` component (note: NN does not handle internet requests, those are up to the emulator) - `internet` component (note: NN does not handle internet requests, those are up to the emulator)
- `relay` component (note: OCDoc still refers to it as `access_point`) - `relay` component (note: OCDoc still refers to it as `access_point`)
- `geolyzer` component - `geolyzer` component
@@ -46,7 +32,7 @@ Not everything OC has (as a few of them are really MC-centered) but most of it.
- `iron_noteblock` component - `iron_noteblock` component
- `colorful_lamp` component - `colorful_lamp` component
# To make it good (after API is stable) # To make it good
- make more stuff const if it can be. Gotta help out the optimizer - make more stuff const if it can be. Gotta help out the optimizer
- put a bunch of internal-only functions as fastcall - put a bunch of internal-only functions as fastcall
@@ -228,3 +214,11 @@ TODO: interface
## OLED/IPU ## OLED/IPU
TODO: interface TODO: interface
# To re-evaluate
- Make the hashmap growing/shrinking to save on memory.
- Exposing the internal hashmap implementation.
- Having a copy of the context stored directly in requests instead of having to use getComputerContext, as it simplifies the APIs and allows them
to be made more portable.
- Exposing more internal functions that may be useful to the user to prevent pointless rewriting and duplicate machine code.

View File

@@ -17,10 +17,9 @@ fn addEngineSources(b: *std.Build, opts: LibBuildOpts) *std.Build.Module {
.strip = if (opts.optimize == .Debug) false else true, .strip = if (opts.optimize == .Debug) false else true,
.unwind_tables = if (opts.optimize == .Debug) null else .none, .unwind_tables = if (opts.optimize == .Debug) null else .none,
.pic = true, .pic = true,
.sanitize_c = if(strict) .full else null, .sanitize_c = if (strict) .full else null,
}); });
dataMod.addCSourceFiles(.{ dataMod.addCSourceFiles(.{
.files = &[_][]const u8{ .files = &[_][]const u8{
"src/neonucleus.c", "src/neonucleus.c",
@@ -62,7 +61,7 @@ fn compileRaylib(b: *std.Build, os: std.Target.Os.Tag, buildOpts: LibBuildOpts,
// passing it breaks it for some reason? // passing it breaks it for some reason?
// TODO: make it not break // TODO: make it not break
const raylib = b.addSystemCommand(&.{ "zig", "build"}); const raylib = b.addSystemCommand(&.{ "zig", "build" });
raylib.setCwd(b.path("foreign/raylib/")); raylib.setCwd(b.path("foreign/raylib/"));
raylib.stdio = .inherit; raylib.stdio = .inherit;
@@ -89,11 +88,7 @@ fn compileTheRightLua(b: *std.Build, target: std.Build.ResolvedTarget, version:
// its a static library because COFF is a pile of shit // its a static library because COFF is a pile of shit
const c = b.addLibrary(.{ const c = b.addLibrary(.{
.name = "lua", .name = "lua",
.root_module = b.addModule("luamod", .{ .root_module = b.addModule("luamod", .{ .link_libc = true, .optimize = .ReleaseFast, .target = target, .pic = true }),
.link_libc = true,
.optimize = .ReleaseFast,
.target = target,
}),
.linkage = .static, .linkage = .static,
}); });

View File

@@ -124,6 +124,27 @@ static void luaArch_nnToLua(luaArch *arch, lua_State *L, size_t nnIdx) {
} }
static int luaArch_computer_beep(lua_State *L) { static int luaArch_computer_beep(lua_State *L) {
if(lua_type(L, 1) == LUA_TSTRING) {
nn_MorseBeep beep = {.frequency = 1000, .beepDuration = 200, .volume = 1};
beep.pattern = lua_tostring(L, 1);
if(lua_isnumber(L, 2)) {
beep.frequency = lua_tonumber(L, 2);
}
if(lua_isnumber(L, 3)) {
beep.beepDuration = lua_tonumber(L, 3);
}
if(lua_isnumber(L, 4)) {
beep.volume = lua_tonumber(L, 4);
}
if(beep.frequency < 20) beep.frequency = 20;
if(beep.beepDuration < 0) beep.beepDuration = 0;
if(beep.volume < 0) beep.volume = 0;
if(beep.frequency > 20000) beep.frequency = 20000;
if(beep.beepDuration > 5) beep.beepDuration = 5;
if(beep.volume > 1) beep.volume = 1;
nn_beepComputerMorse(luaArch_from(L)->computer, beep);
return 0;
}
nn_Beep beep = {.frequency = 1000, .duration = 1, .volume = 1}; nn_Beep beep = {.frequency = 1000, .duration = 1, .volume = 1};
if(lua_isnumber(L, 1)) { if(lua_isnumber(L, 1)) {
beep.frequency = lua_tonumber(L, 1); beep.frequency = lua_tonumber(L, 1);
@@ -751,7 +772,7 @@ static void luaArch_loadEnv(lua_State *L) {
lua_setfield(L, unicode, "len"); lua_setfield(L, unicode, "len");
lua_pushcfunction(L, luaArch_unicode_sub); lua_pushcfunction(L, luaArch_unicode_sub);
lua_setfield(L, unicode, "sub"); lua_setfield(L, unicode, "sub");
lua_pushcfunction(L, luaArch_unicode_len); lua_pushcfunction(L, luaArch_unicode_wlen);
lua_setfield(L, unicode, "wlen"); lua_setfield(L, unicode, "wlen");
lua_pushcfunction(L, luaArch_unicode_wtrunc); lua_pushcfunction(L, luaArch_unicode_wtrunc);
lua_setfield(L, unicode, "wtrunc"); lua_setfield(L, unicode, "wtrunc");

View File

@@ -70,6 +70,24 @@ end
local syncedMethodStats local syncedMethodStats
local function unsandboxValue(val)
if type(val) == "table" then
local meta = getmetatable(val)
if meta then
if type(meta.__userdata) == "userdata" then
return meta.__userdata
end
end
local nt = {}
for sk, sv in pairs(val) do
local k, v = unsandboxValue(sk), unsandboxValue(sv)
if k ~= nil then nt[k] = v end
end
return nt
end
return val
end
local function sandboxValue(val) local function sandboxValue(val)
if type(val) == "table" then if type(val) == "table" then
local nt = {} local nt = {}
@@ -80,7 +98,6 @@ local function sandboxValue(val)
return nt return nt
end end
if type(val) == "userdata" then if type(val) == "userdata" then
-- Light userdata shall never escape our shi!
-- This matches how OC wraps it -- This matches how OC wraps it
-- TODO: just make our own shi with fields and stuff -- TODO: just make our own shi with fields and stuff
-- like a component proxy, because this sucks -- like a component proxy, because this sucks
@@ -88,9 +105,10 @@ local function sandboxValue(val)
__gc = function() __gc = function()
userdata.free(val) userdata.free(val)
end, end,
__userdata = val,
} }
local wrapped = {type = "userdata"} local wrapped = {type = "userdata", userdata = val}
for name, m in pairs(userdata.methods(val)) do for name, m in pairs(userdata.methods(val)) do
wrapped[name] = { wrapped[name] = {
name = name, name = name,
@@ -109,16 +127,18 @@ local function sandboxValue(val)
end end
local function realInvoke(address, method, ...) local function realInvoke(address, method, ...)
local t = {pcall(cinvoke, address, method, ...)} local args = {...}
for i=1,#args do args[i] = unsandboxValue(args[i]) end
local t = {pcall(cinvoke, address, method, table.unpack(args))}
if not _SYNCED and not os.getenv("NN_FAST") then if not _SYNCED and not os.getenv("NN_FAST") then
if computer.energy() <= 0 then sysyield() end -- out of power if computer.energy() <= 0 then sysyield() end -- out of power
if computer.isOverused() then sysyield() end -- overused if computer.isOverused() then sysyield() end -- overused
if computer.isIdle() then sysyield() end -- machine idle if computer.isIdle() then sysyield() end -- machine idle
end end
if os.getenv("NN_INVDBG") and component.type(address) == os.getenv("NN_INVDBG") then if component.type(address) == os.getenv("NN_INVDBG") or string.find(os.getenv("NN_METDBG") or "", method, nil, true) then
print("invoked", address, method, ...) print("invoked", address, method, ...)
print("got", table.unpack(t)) print(string.format("got %d values", #t), table.unpack(t))
end end
for i=1,#t do t[i] = sandboxValue(t[i]) end for i=1,#t do t[i] = sandboxValue(t[i]) end
@@ -232,6 +252,7 @@ function computer.pullSignal(timeout)
while true do while true do
if computer.uptime() >= deadline then return end if computer.uptime() >= deadline then return end
local t = {computer.popSignal()} local t = {computer.popSignal()}
for i=1,#t do t[i] = unsandboxValue(t[i]) end
if #t == 0 then if #t == 0 then
sysyield() sysyield()
else else
@@ -466,7 +487,18 @@ sandbox = {
isRobot = computer.isRobot, isRobot = computer.isRobot,
maxEnergy = computer.maxEnergy, maxEnergy = computer.maxEnergy,
pullSignal = computer.pullSignal, pullSignal = computer.pullSignal,
pushSignal = computer.pushSignal, pushSignal = function(name, ...)
checkArg(1, name, "string")
local t = {...}
for i=1,#t do
local v = unsandboxValue(t[i])
if type(v) == "userdata" then
return nil, "userdata is forbidden"
end
t[i] = v
end
return computer.pushSignal(name, table.unpack(t))
end,
removeUser = computer.removeUser, removeUser = computer.removeUser,
setArchitecture = computer.setArchitecture, setArchitecture = computer.setArchitecture,
shutdown = computer.shutdown, shutdown = computer.shutdown,
@@ -517,9 +549,6 @@ sandbox = {
}, },
utf8 = utf8, utf8 = utf8,
-- unsafe, don't care
userdata = userdata,
} }
sandbox._G = sandbox sandbox._G = sandbox

View File

@@ -104,10 +104,17 @@ static nn_Exit ne_dataBullshit(nn_DataCardRequest *req) {
return NN_OK; return NN_OK;
} }
if(action == NN_DATA_SHA256) { if(action == NN_DATA_SHA256) {
// does not match OC, dunno why
unsigned int *out = ComputeSHA256((unsigned char *)req->sha256.data, req->sha256.datalen); unsigned int *out = ComputeSHA256((unsigned char *)req->sha256.data, req->sha256.datalen);
if(out == NULL) return NN_ENOMEM; if(out == NULL) return NN_ENOMEM;
memcpy(req->sha256.checksum, out, 32); unsigned char buf[32];
for(size_t i = 0; i < 8; i++) {
// OC does BE
buf[i*4+3] = (out[i] >> 0) & 0xFF;
buf[i*4+2] = (out[i] >> 8) & 0xFF;
buf[i*4+1] = (out[i] >> 16) & 0xFF;
buf[i*4+0] = (out[i] >> 24) & 0xFF;
}
memcpy(req->sha256.checksum, buf, 32);
return NN_OK; return NN_OK;
} }
if(action == NN_DATA_RANDOM) { if(action == NN_DATA_RANDOM) {
@@ -123,6 +130,32 @@ static nn_Exit ne_dataBullshit(nn_DataCardRequest *req) {
return nn_pushlstring(C, req->data, req->datalen); return nn_pushlstring(C, req->data, req->datalen);
} }
if(action == NN_DATA_VALIDATEKEY) {
// its valid, trust
return NN_OK;
}
if(action == NN_DATA_GENKEYS) {
char a = 'A' + rand() % 26;
char b = 'A' + rand() % 26;
nn_pushlstring(C, &a, 1);
return nn_pushlstring(C, &b, 1);
}
if(action == NN_DATA_ECDH) {
char buf[32];
memset(buf, 'e', 32);
return nn_pushlstring(C, buf, 32);
}
if(action == NN_DATA_ECDSA_SIGN) {
return nn_pushstring(C, "epic signature bro");
}
if(action == NN_DATA_ECDSA_VERIFY) {
req->checksig.sigpassed = strcmp(req->checksig.signature, "epic signature bro");
return NN_OK;
}
if(C) nn_setError(C, "ne: data method not implemented"); if(C) nn_setError(C, "ne: data method not implemented");
return NN_EBADCALL; return NN_EBADCALL;
} }
@@ -165,8 +198,9 @@ static nn_Exit ne_modemBullshit(nn_ModemRequest *req) {
if(req->action == NN_MODEM_SEND) { if(req->action == NN_MODEM_SEND) {
req->send.strengthSent = req->modem->maxRange; req->send.strengthSent = req->modem->maxRange;
printf("Transmission from %s to %s (port %zu) of %zu bytes (%zu values)\n", req->localAddress, req->send.address == NULL ? "*" : req->send.address, req->send.port, req->send.contents->buflen, req->send.contents->valueCount); const char *dest = req->send.address == NULL ? "*" : req->send.address;
return nn_pushModemMessage(C, req->localAddress, nn_getComputerAddress(C), req->send.port, 0, req->send.contents); printf("Transmission from %s to %s (port %zu) of %zu bytes (%zu values)\n", req->localAddress, dest, req->send.port, req->send.contents->buflen, req->send.contents->valueCount);
return nn_pushModemMessage(C, req->localAddress, dest, req->send.port, 0, req->send.contents);
} }
if(req->action == NN_MODEM_GETWAKEMESSAGE) { if(req->action == NN_MODEM_GETWAKEMESSAGE) {
@@ -183,6 +217,36 @@ static nn_Exit ne_modemBullshit(nn_ModemRequest *req) {
return NN_EBADCALL; return NN_EBADCALL;
} }
static nn_Exit ne_tunnelBullshit(nn_TunnelRequest *req) {
nn_Computer *C = req->computer;
if(req->action == NN_TUNNEL_DROP) {
return NN_OK;
}
if(req->action == NN_TUNNEL_GETCHANNEL) {
return nn_pushstring(C, "creative");
}
if(req->action == NN_TUNNEL_SEND) {
printf("Transmission from tunnel %s of %zu bytes (%zu values)\n", req->localAddress, req->toSend->buflen, req->toSend->valueCount);
return nn_pushModemMessage(C, req->localAddress, nn_getComputerAddress(C), NN_TUNNEL_PORT, 0, req->toSend);
}
if(req->action == NN_TUNNEL_GETWAKEMESSAGE) {
req->getWake.len = 0;
req->getWake.isFuzzy = false;
return NN_OK;
}
if(req->action == NN_TUNNEL_SETWAKEMESSAGE) {
return NN_OK;
}
if(C) nn_setError(C, "ne: modem method not implemented");
return NN_EBADCALL;
}
static unsigned char ne_processColorPart(unsigned char channel, double brightness) { static unsigned char ne_processColorPart(unsigned char channel, double brightness) {
double n = (double)channel / 255; double n = (double)channel / 255;
n *= brightness; n *= brightness;
@@ -436,6 +500,7 @@ typedef struct ne_memSand {
char *buf; char *buf;
size_t used; size_t used;
size_t cap; size_t cap;
size_t active;
} ne_memSand; } ne_memSand;
void *ne_sandbox_alloc(void *state, void *memory, size_t oldSize, size_t newSize) { void *ne_sandbox_alloc(void *state, void *memory, size_t oldSize, size_t newSize) {
@@ -445,12 +510,16 @@ void *ne_sandbox_alloc(void *state, void *memory, size_t oldSize, size_t newSize
newSize = ne_alignAlloc(newSize, NN_ALLOC_ALIGN); newSize = ne_alignAlloc(newSize, NN_ALLOC_ALIGN);
// never free // never free
if(newSize == 0) return NULL; if(newSize == 0) {
sand->active -= oldSize;
return NULL;
}
if(memory == NULL) { if(memory == NULL) {
if(sand->cap - sand->used < newSize) return NULL; if(sand->cap - sand->used < newSize) return NULL;
// alloc new // alloc new
void *mem = sand->buf + sand->used; void *mem = sand->buf + sand->used;
sand->used += newSize; sand->used += newSize;
sand->active += newSize;
return mem; return mem;
} }
// realloc // realloc
@@ -458,6 +527,7 @@ void *ne_sandbox_alloc(void *state, void *memory, size_t oldSize, size_t newSize
if(sand->cap - sand->used < newSize) return NULL; if(sand->cap - sand->used < newSize) return NULL;
void *mem = sand->buf + sand->used; void *mem = sand->buf + sand->used;
sand->used += newSize; sand->used += newSize;
sand->active += newSize;
memcpy(mem, memory, oldSize); memcpy(mem, memory, oldSize);
return mem; return mem;
} }
@@ -472,6 +542,10 @@ void ne_env(nn_EnvironmentRequest *req) {
printf("beep: %f Hz %fs %.02f%%\n", req->beep.frequency, req->beep.duration, req->beep.volume*100); printf("beep: %f Hz %fs %.02f%%\n", req->beep.frequency, req->beep.duration, req->beep.volume*100);
return; return;
} }
if(req->action == NN_ENV_BEEPMORSE) {
printf("morse beep: %s, %f Hz %fs %.02f%%\n", req->morseBeep.pattern, req->morseBeep.frequency, req->morseBeep.beepDuration, req->morseBeep.volume*100);
return;
}
if(req->action == NN_ENV_DRAWENERGY) { if(req->action == NN_ENV_DRAWENERGY) {
accumulatedEnergyCost += req->energy; accumulatedEnergyCost += req->energy;
totalEnergyLoss += req->energy; totalEnergyLoss += req->energy;
@@ -482,6 +556,25 @@ void ne_env(nn_EnvironmentRequest *req) {
} }
} }
nn_Exit ne_inetBullshit(nn_InternetRequest *req) {
// welcome to hell
nn_Computer *C = req->computer;
// TODO: make this shi connect to the real internet
// preferrably use libcurl, openssl and a basic blocking socket layer
if(req->action == NN_INTERNET_CONNECT) {
req->connection->state = ne_inetBullshit;
return NN_OK;
}
if(req->action == NN_INTERNET_CLOSE) {
return NN_OK;
}
if(C) nn_setError(C, "inet bullshit: not supported");
return NN_EBADCALL;
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
const char *player = getenv("USER"); const char *player = getenv("USER");
@@ -502,6 +595,7 @@ int main(int argc, char **argv) {
ne_memSand sand; ne_memSand sand;
sand.buf = NULL; sand.buf = NULL;
sand.active = 0;
if(sandboxMem) { if(sandboxMem) {
// 1 MiB pre-allocated to prevent erasing the free-list // 1 MiB pre-allocated to prevent erasing the free-list
@@ -515,6 +609,10 @@ int main(int argc, char **argv) {
SetConfigFlags(FLAG_WINDOW_RESIZABLE); SetConfigFlags(FLAG_WINDOW_RESIZABLE);
InitWindow(800, 600, "NeoNucleus Test Emulator"); InitWindow(800, 600, "NeoNucleus Test Emulator");
const char *tierStr = getenv("NN_TIER");
if(tierStr == NULL) tierStr = "4";
int tier = atoi(tierStr);
// create the universe // create the universe
nn_Universe *u = nn_createUniverse(&ctx, NULL); nn_Universe *u = nn_createUniverse(&ctx, NULL);
@@ -530,6 +628,8 @@ int main(int argc, char **argv) {
nn_Component *dataCard = nn_createDataCard(u, NULL, &nn_defaultDataCards[2], NULL, ne_dataBullshit); nn_Component *dataCard = nn_createDataCard(u, NULL, &nn_defaultDataCards[2], NULL, ne_dataBullshit);
nn_Component *modem = nn_createModem(u, NULL, &nn_defaultWirelessModems[1], NULL, ne_modemBullshit); nn_Component *modem = nn_createModem(u, NULL, &nn_defaultWirelessModems[1], NULL, ne_modemBullshit);
nn_Component *tunnel = nn_createTunnel(u, NULL, &nn_defaultTunnel, NULL, ne_tunnelBullshit);
nn_Component *inet = nn_createInternet(u, NULL, &nn_defaultInternetCard, NULL, ne_inetBullshit);
char *eepromCode = (char *)minBIOS; char *eepromCode = (char *)minBIOS;
size_t eepromSize = strlen(minBIOS); size_t eepromSize = strlen(minBIOS);
@@ -554,20 +654,12 @@ int main(int argc, char **argv) {
nn_Component *eepromCard = ncl_createEEPROM(u, NULL, &nn_defaultEEPROMs[3], eepromCode, eepromSize, false); nn_Component *eepromCard = ncl_createEEPROM(u, NULL, &nn_defaultEEPROMs[3], eepromCode, eepromSize, 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]; char mainfspath[NN_MAX_PATH];
snprintf(mainfspath, NN_MAX_PATH, "data/%s", mainDir); snprintf(mainfspath, NN_MAX_PATH, "data/%s", mainDir);
nn_Component *managedfs = ncl_createFilesystem(u, NULL, mainfspath, &mainfsconf, true); nn_Component *managedfs = ncl_createFilesystem(u, NULL, mainfspath, &nn_defaultFilesystems[tier-1], true);
//nn_Component *tmpfs = ncl_createTmpFS(u, NULL, &nn_defaultTmpFS, NCL_FILECOST_DEFAULT, false); nn_Component *tmpfs = ncl_createTmpFS(u, NULL, &nn_defaultTmpFS, NCL_FILECOST_DEFAULT, false);
nn_Component *tmpfs = ncl_createFilesystem(u, NULL, "/tmp", &mainfsconf, false);
nn_Component *testingfs = ncl_createFilesystem(u, NULL, "aux", &nn_defaultFilesystems[3], false); nn_Component *testingfs = ncl_createFilesystem(u, NULL, "aux", &nn_defaultFilesystems[3], false);
nn_Component *debugfs = ncl_createTmpFS(u, NULL, &nn_defaultFilesystems[3], NCL_FILECOST_DEFAULT, false);
const char * const testDriveData = const char * const testDriveData =
"local g, s = component.list('gpu')(), component.list('screen')()\n" "local g, s = component.list('gpu')(), component.list('screen')()\n"
@@ -594,18 +686,18 @@ int main(int argc, char **argv) {
"while computer.uptime() < now + 3 do computer.pullSignal(0.05) end\n" "while computer.uptime() < now + 3 do computer.pullSignal(0.05) end\n"
"computer.shutdown(true)\n" "computer.shutdown(true)\n"
; ;
nn_Component *testDrive = ncl_createDrive(u, NULL, &nn_defaultDrives[3], testDriveData, strlen(testDriveData), false); nn_Component *testDrive = ncl_createDrive(u, NULL, &nn_defaultDrives[tier-1], testDriveData, strlen(testDriveData), false);
nn_Component *testFlash = ncl_createFlash(u, NULL, &nn_defaultSSDs[3], testDriveData, strlen(testDriveData), false); nn_Component *testFlash = ncl_createFlash(u, NULL, &nn_defaultSSDs[tier-1], testDriveData, strlen(testDriveData), false);
ncl_setCLabel(eepromCard, "EEPROM"); ncl_setCLabel(eepromCard, "EEPROM");
ncl_setCLabel(managedfs, "Main Filesystem"); ncl_setCLabel(managedfs, "Main Filesystem");
ncl_setCLabel(testingfs, "Secondary Filesystem"); ncl_setCLabel(testingfs, "Secondary Filesystem");
ncl_setCLabel(testDrive, "Unmanaged Storage"); ncl_setCLabel(testDrive, "Unmanaged Storage");
ncl_setCLabel(testFlash, "Flash Storage"); ncl_setCLabel(testFlash, "Flash Storage");
ncl_setCLabel(debugfs, "Debug Filesystem");
size_t ramTotal = 0; size_t ramTotal = 0;
ramTotal += 4 * nn_ramSizes[7]; ramTotal += 4 * nn_ramSizes[tier*2-1];
//ramTotal += nn_ramSizes[0];
SetExitKey(KEY_NULL); SetExitKey(KEY_NULL);
@@ -627,8 +719,9 @@ int main(int argc, char **argv) {
double nextSecond = 0; double nextSecond = 0;
double wattage = 0; double wattage = 0;
nn_Component *screen = ncl_createScreen(u, NULL, &nn_defaultScreens[3]); nn_Component *screen = ncl_createScreen(u, NULL, &nn_defaultScreens[tier-1]);
nn_Component *gpuCard = ncl_createGPU(u, NULL, &nn_defaultGPUs[3]); nn_GPU gpuConf = nn_defaultGPUs[tier-1];
nn_Component *gpuCard = ncl_createGPU(u, NULL, &gpuConf);
nn_Component *keyboard = nn_createComponent( nn_Component *keyboard = nn_createComponent(
u, "mainKB", "keyboard"); u, "mainKB", "keyboard");
@@ -636,13 +729,14 @@ int main(int argc, char **argv) {
ncl_mountKeyboard(scrstate, "mainKB"); ncl_mountKeyboard(scrstate, "mainKB");
// we assume server basically // we assume server basically
nn_Computer *c = nn_createComputer(u, NULL, NULL, ramTotal, nn_defaultComponentLimits[3] * 4, 256); nn_Computer * volatile c = nn_createComputer(u, NULL, NULL, ramTotal, nn_defaultComponentLimits[tier-1] * 4, 256);
nn_Environment cEnv = { nn_Environment cEnv = {
.userdata = NULL, .userdata = NULL,
.handler = ne_env, .handler = ne_env,
}; };
nn_setComputerEnvironment(c, cEnv); nn_setComputerEnvironment(c, cEnv);
nn_setCallBudget(c, nn_defaultCallBudgets[3]); // 5 cuz CPU + each RAM stick all have same tier call budgets
nn_setCallBudget(c, nn_defaultCallBudgets[tier-1] * 5);
nn_setTotalEnergy(c, allEnergy); nn_setTotalEnergy(c, allEnergy);
if(getenv("NN_FAST") != NULL) { if(getenv("NN_FAST") != NULL) {
tickDelay = 0; tickDelay = 0;
@@ -679,6 +773,9 @@ int main(int argc, char **argv) {
nn_mountComponent(c, testFlash, 5, false); nn_mountComponent(c, testFlash, 5, false);
nn_mountComponent(c, dataCard, 6, false); nn_mountComponent(c, dataCard, 6, false);
nn_mountComponent(c, modem, 7, false); nn_mountComponent(c, modem, 7, false);
nn_mountComponent(c, tunnel, 8, false);
nn_mountComponent(c, debugfs, 9, false);
nn_mountComponent(c, inet, 10, false);
int ltx = 0, lty = 0; int ltx = 0, lty = 0;
double scrollBuf = 0; double scrollBuf = 0;
double tickTime = 0; double tickTime = 0;
@@ -857,7 +954,6 @@ int main(int argc, char **argv) {
if(noIdle) nn_resetIdleTime(c); if(noIdle) nn_resetIdleTime(c);
// OC computers consume 0.5W when running, 0.05W when running but idle // OC computers consume 0.5W when running, 0.05W when running but idle
double normalPowerUsage = 0.5, idlePowerUsage = 0.05; double normalPowerUsage = 0.5, idlePowerUsage = 0.05;
bool isIdle = false;
nn_Exit e = nn_tick(c); nn_Exit e = nn_tick(c);
tickTime = GetTime() - tickNow; tickTime = GetTime() - tickNow;
if(tickTime < tickDelay) { if(tickTime < tickDelay) {
@@ -917,11 +1013,17 @@ cleanup:;
nn_dropComponent(keyboard); nn_dropComponent(keyboard);
nn_dropComponent(dataCard); nn_dropComponent(dataCard);
nn_dropComponent(modem); nn_dropComponent(modem);
nn_dropComponent(tunnel);
nn_dropComponent(debugfs);
nn_dropComponent(inet);
// rip the universe // rip the universe
nn_destroyUniverse(u); nn_destroyUniverse(u);
ncl_destroyGlyphCache(gc); ncl_destroyGlyphCache(gc);
if(eepromPath != NULL) free(eepromCode); if(eepromPath != NULL) free(eepromCode);
CloseWindow(); CloseWindow();
free(sand.buf); free(sand.buf);
if(sand.buf != NULL) {
printf("Leaked: %zu bytes\n", sand.active);
}
return 0; return 0;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -258,35 +258,29 @@ typedef struct ncl_ComponentStat {
// specific properties // specific properties
union { union {
struct { struct {
const nn_EEPROM *conf;
size_t codeUsed; size_t codeUsed;
size_t dataUsed; size_t dataUsed;
} eeprom; } eeprom;
struct { struct {
const nn_Filesystem *conf;
size_t spaceUsed; size_t spaceUsed;
size_t realDiskUsage; size_t realDiskUsage;
size_t filesOpen; size_t filesOpen;
const char *path; const char *path;
} fs; } fs;
struct { struct {
const nn_Drive *conf;
size_t lastSector; size_t lastSector;
} drive; } drive;
struct { struct {
const nn_NandFlash *conf;
size_t currentWriteCount; size_t currentWriteCount;
double wearlevel; double wearlevel;
} flash; } flash;
struct { struct {
const nn_GPU *conf;
size_t vramFree; size_t vramFree;
size_t bufferCount; size_t bufferCount;
// can be NULL if there is none // can be NULL if there is none
const char *boundScreen; const char *boundScreen;
} gpu; } gpu;
struct { struct {
const nn_ScreenConfig *conf;
ncl_ScreenState *state; ncl_ScreenState *state;
ncl_ScreenFlags flags; ncl_ScreenFlags flags;
int viewportWidth; int viewportWidth;
@@ -333,6 +327,8 @@ void ncl_unlockScreen(ncl_ScreenState *state);
void ncl_resetScreen(ncl_ScreenState *state); void ncl_resetScreen(ncl_ScreenState *state);
void ncl_getScreenResolution(const ncl_ScreenState *state, size_t *width, size_t *height); void ncl_getScreenResolution(const ncl_ScreenState *state, size_t *width, size_t *height);
void ncl_setScreenResolution(ncl_ScreenState *state, size_t width, size_t height); void ncl_setScreenResolution(ncl_ScreenState *state, size_t width, size_t height);
void ncl_getScreenMaxResolution(const ncl_ScreenState *state, size_t *width, size_t *height);
nn_Exit ncl_setScreenMaxResolution(ncl_ScreenState *state, size_t width, size_t height);
void ncl_getScreenViewport(const ncl_ScreenState *state, size_t *width, size_t *height); void ncl_getScreenViewport(const ncl_ScreenState *state, size_t *width, size_t *height);
void ncl_setScreenViewport(ncl_ScreenState *state, size_t width, size_t height); void ncl_setScreenViewport(ncl_ScreenState *state, size_t width, size_t height);
ncl_Pixel ncl_getScreenPixel(const ncl_ScreenState *state, int x, int y); ncl_Pixel ncl_getScreenPixel(const ncl_ScreenState *state, int x, int y);

File diff suppressed because it is too large Load Diff

View File

@@ -108,9 +108,9 @@ void *_alloca(size_t);
// maximum size of an address. // 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. // 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. // Past this there would be a truncation which would invalidate the address.
// However, 256 is unrealistically long, as UUIDv4 only needs 36. // However, 64 is unrealistically long, as UUIDv4 only needs 36.
// Please, do not go above this. // Please, do not go above this.
#define NN_MAX_ADDRESS 256 #define NN_MAX_ADDRESS 64
// the port used by tunnel cards. This port is invalid for modems. // the port used by tunnel cards. This port is invalid for modems.
#define NN_TUNNEL_PORT 0 #define NN_TUNNEL_PORT 0
// maximum amount of users a computer can have // maximum amount of users a computer can have
@@ -393,17 +393,36 @@ typedef struct nn_Architecture {
extern size_t nn_ramSizes[8]; extern size_t nn_ramSizes[8];
typedef struct nn_Beep { typedef struct nn_Beep {
// frequenc, in Hz
double frequency; double frequency;
// duration, in seconds
double duration; double duration;
// 0 is mute, 1 is 100%
double volume; double volume;
} nn_Beep; } 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 { typedef enum nn_EnvironmentAction {
NN_ENV_DRAWENERGY, NN_ENV_DRAWENERGY,
NN_ENV_POWERON, NN_ENV_POWERON,
NN_ENV_POWEROFF, NN_ENV_POWEROFF,
NN_ENV_CRASHED, NN_ENV_CRASHED,
NN_ENV_BEEP, NN_ENV_BEEP,
NN_ENV_BEEPMORSE,
} nn_EnvironmentAction; } nn_EnvironmentAction;
typedef struct nn_EnvironmentRequest { typedef struct nn_EnvironmentRequest {
@@ -415,6 +434,8 @@ typedef struct nn_EnvironmentRequest {
double energy; double energy;
// for BEEP, information about the beep // for BEEP, information about the beep
nn_Beep beep; nn_Beep beep;
// for BEEPMORSE, information about the beep
nn_MorseBeep morseBeep;
}; };
} nn_EnvironmentRequest; } nn_EnvironmentRequest;
@@ -435,8 +456,11 @@ typedef struct nn_Environment {
// maxComponents and maxDevices determine how many components can be connected simultaneously to this computer, and how much device info can be // 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. // 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); 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. // Destroys the state, effectively shutting down the computer.
void nn_destroyComputer(nn_Computer *computer); void nn_destroyComputer(nn_Computer *computer);
void nn_destroyComputerN(nn_Computer *computer, size_t n);
void nn_lockComputer(nn_Computer *computer); void nn_lockComputer(nn_Computer *computer);
void nn_unlockComputer(nn_Computer *computer); void nn_unlockComputer(nn_Computer *computer);
// stops the computer if an architecture state is already present, // stops the computer if an architecture state is already present,
@@ -450,6 +474,9 @@ void nn_forceCrashComputer(nn_Computer *computer, const char *s);
bool nn_isComputerOn(nn_Computer *computer); bool nn_isComputerOn(nn_Computer *computer);
void nn_setComputerEnvironment(nn_Computer *computer, nn_Environment env); 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 // Device information
// Standard device attribute fields // Standard device attribute fields
@@ -514,6 +541,7 @@ void nn_clearCommonDeviceInfo(nn_CommonDeviceInfo *info);
bool nn_removeDeviceInfo(nn_Computer *computer, const char *addr); bool nn_removeDeviceInfo(nn_Computer *computer, const char *addr);
void nn_beepComputer(nn_Computer *computer, nn_Beep beep); void nn_beepComputer(nn_Computer *computer, nn_Beep beep);
void nn_beepComputerMorse(nn_Computer *computer, nn_MorseBeep beep);
// get the userdata pointer // get the userdata pointer
void *nn_getComputerUserdata(nn_Computer *computer); void *nn_getComputerUserdata(nn_Computer *computer);
@@ -1042,6 +1070,262 @@ nn_Exit nn_popSignal(nn_Computer *computer, size_t *valueCount);
nn_Exit nn_transferErrorFrom(nn_Exit exit, nn_Computer *from, nn_Computer *to); 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 // EEPROM class
// reads and writes are always 1/1 // reads and writes are always 1/1
@@ -1520,8 +1804,12 @@ typedef struct nn_GPU {
int setForegroundPerTick; int setForegroundPerTick;
// amount of times setBackground can be called before running out of budget. // amount of times setBackground can be called before running out of budget.
int setBackgroundPerTick; int setBackgroundPerTick;
// energy per non-space set. // energy per pixel set.
double energyPerWrite; double energyPerWrite;
// energy per pixel filled
double energyPerFill;
// energy per pixel copied
double energyPerCopy;
// energy per space set. // energy per space set.
double energyPerClear; double energyPerClear;
} nn_GPU; } nn_GPU;
@@ -1809,6 +2097,9 @@ typedef enum nn_DataCardAction {
// Generate an ECDH public/private pair of either 256 or 384 bits each. // Generate an ECDH public/private pair of either 256 or 384 bits each.
NN_DATA_GENKEYS, NN_DATA_GENKEYS,
// validate key, cuz we feel like it
NN_DATA_VALIDATEKEY,
// Does an ECDH pass, matching javax.crypto.KeyAgreement. // Does an ECDH pass, matching javax.crypto.KeyAgreement.
// This generates a shared secret as binary data. // 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 // This is not an AES key as output, the AES key is often computed by either MD5 hashing
@@ -1821,6 +2112,13 @@ typedef enum nn_DataCardAction {
NN_DATA_ECDSA_VERIFY, NN_DATA_ECDSA_VERIFY,
} nn_DataCardAction; } 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 { typedef struct nn_DataCardRequest {
nn_Context *ctx; nn_Context *ctx;
nn_Computer *computer; nn_Computer *computer;
@@ -1860,6 +2158,30 @@ typedef struct nn_DataCardRequest {
const char *data; const char *data;
size_t datalen; 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; } nn_DataCardRequest;
@@ -1889,14 +2211,6 @@ typedef struct nn_Modem {
double costPerStrength; double costPerStrength;
} nn_Modem; } nn_Modem;
// A buffer with encoded values
typedef struct nn_EncodedNetworkContents {
nn_Context *ctx;
char *buf;
size_t buflen;
size_t valueCount;
} nn_EncodedNetworkContents;
extern nn_Modem nn_defaultWiredModem; extern nn_Modem nn_defaultWiredModem;
extern nn_Modem nn_defaultWirelessModems[2]; extern nn_Modem nn_defaultWirelessModems[2];
@@ -2005,7 +2319,7 @@ typedef struct nn_TunnelRequest {
void *state; void *state;
const nn_Tunnel *tunnel; const nn_Tunnel *tunnel;
const char *localAddress; const char *localAddress;
nn_ModemAction action; nn_TunnelAction action;
union { union {
// for send // for send
const nn_EncodedNetworkContents *toSend; const nn_EncodedNetworkContents *toSend;
@@ -2026,6 +2340,108 @@ 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); 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;
unsigned int maxReadSize;
// per-byte cost of a write
double transmissionEnergyCost;
} nn_InternetCard;
extern nn_InternetCard nn_defaultInternetCard;
typedef struct nn_InternetConnection {
nn_InternetProtocol protocol;
int port;
void *state;
nn_uuid id;
} nn_InternetConnection;
typedef struct nn_HTTPHeader {
const char *name;
const char *value;
} nn_HTTPHeader;
typedef enum nn_InternetAction {
NN_INTERNET_DROP,
// start a connection, remember to check connection->protocol to know which type of connection to establish
NN_INTERNET_CONNECT,
// Ensure a connection is established, error if not.
// It is assumed this operation will return whether it is currently connected,
// and should be called repeatedly until it works
NN_INTERNET_FINISHCONNECT,
// close a connection
NN_INTERNET_CLOSE,
// read from a connection. Set read.buf to NULL to mark EoF. read.len is the capacity, but also set how much was read in it.
NN_INTERNET_READ,
// write to a connection. HTTP connections do not have this method
NN_INTERNET_WRITE,
// get an HTTP response. Should push the response code, message (ie. OK for 200) and table
NN_INTERNET_RESPONSE,
} nn_INternetAction;
typedef struct nn_InternetRequest {
nn_Context *ctx;
nn_Computer *computer;
void *state;
const nn_InternetCard *inet;
const char *localAddress;
nn_InternetConnection *connection;
nn_INternetAction action;
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;
union {
struct {
// HTTP specific
size_t postdatalen;
const char *postdata;
const nn_HTTPHeader *headers;
size_t headerlen;
} http;
struct {
const char * const * subprotocols;
size_t subprotocolcount;
} websockets;
};
} connect;
struct {
const char *buf;
size_t len;
} write;
struct {
char *buf;
size_t len;
} read;
bool isConnected;
};
} nn_InternetRequest;
typedef nn_Exit (nn_InternetHandler)(nn_InternetRequest *req);
nn_Component *nn_createInternet(nn_Universe *universe, const char *address, const nn_InternetCard *inet, void *state, nn_InternetHandler *handler);
// Colors and palettes. // Colors and palettes.
// Do note that the // Do note that the
@@ -2063,250 +2479,6 @@ int nn_mapDepth(int color, int depth);
// Valid depths are 1, 2, 3, 4, 8, 16 and 24. // Valid depths are 1, 2, 3, 4, 8, 16 and 24.
const char *nn_depthName(int depth); const char *nn_depthName(int depth);
// 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);
// 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);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif