This commit is contained in:
2026-05-09 16:31:19 +03:00
parent f832369ce0
commit e7a166f85c
7 changed files with 501 additions and 288 deletions

View File

@@ -6,6 +6,7 @@ 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
@@ -20,6 +21,9 @@ SANITIZE=undefined,address
DEBUG=-ggdb DEBUG=-ggdb
endif endif
NN_STD=gnu99
EMU_STD=c23
NNFLAGS= NNFLAGS=
SANITIZE_FLAGS= SANITIZE_FLAGS=
@@ -28,7 +32,7 @@ ifdef SANITIZE
SANITIZE_FLAGS += -fsanitize=$(SANITIZE) SANITIZE_FLAGS += -fsanitize=$(SANITIZE)
endif endif
CFLAGS=-fPIC $(OPT) $(SANITIZE_FLAGS) $(DEBUG) $(NNFLAGS) CFLAGS=-fPIC $(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)

View File

@@ -751,7 +751,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 = {}
@@ -87,6 +105,7 @@ local function sandboxValue(val)
__gc = function() __gc = function()
userdata.free(val) userdata.free(val)
end, end,
__userdata = val,
} }
local wrapped = {type = "userdata", userdata = val} local wrapped = {type = "userdata", userdata = val}
@@ -108,7 +127,9 @@ 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
@@ -231,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
@@ -465,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,
@@ -516,9 +549,6 @@ sandbox = {
}, },
utf8 = utf8, utf8 = utf8,
-- unsafe, don't care
userdata = userdata,
} }
sandbox._G = sandbox sandbox._G = sandbox

View File

@@ -191,8 +191,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) {
@@ -209,6 +210,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;
@@ -556,6 +587,7 @@ 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);
char *eepromCode = (char *)minBIOS; char *eepromCode = (char *)minBIOS;
size_t eepromSize = strlen(minBIOS); size_t eepromSize = strlen(minBIOS);
@@ -709,6 +741,7 @@ 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);
int ltx = 0, lty = 0; int ltx = 0, lty = 0;
double scrollBuf = 0; double scrollBuf = 0;
double tickTime = 0; double tickTime = 0;
@@ -887,7 +920,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) {
@@ -947,6 +979,7 @@ cleanup:;
nn_dropComponent(keyboard); nn_dropComponent(keyboard);
nn_dropComponent(dataCard); nn_dropComponent(dataCard);
nn_dropComponent(modem); nn_dropComponent(modem);
nn_dropComponent(tunnel);
// rip the universe // rip the universe
nn_destroyUniverse(u); nn_destroyUniverse(u);
ncl_destroyGlyphCache(gc); ncl_destroyGlyphCache(gc);

View File

@@ -518,7 +518,7 @@ typedef struct ncl_ScreenPixel {
int realBg; int realBg;
} ncl_ScreenPixel; } ncl_ScreenPixel;
typedef struct ncl_ScreenState { struct ncl_ScreenState {
nn_Context *ctx; nn_Context *ctx;
nn_Lock *lock; nn_Lock *lock;
nn_ScreenConfig conf; nn_ScreenConfig conf;
@@ -534,7 +534,7 @@ typedef struct ncl_ScreenState {
size_t keyboardCount; size_t keyboardCount;
double brightness; double brightness;
char *keyboards[NCL_MAX_KEYBOARD]; char *keyboards[NCL_MAX_KEYBOARD];
} ncl_ScreenState; };
typedef struct nn_VRAMBuf { typedef struct nn_VRAMBuf {
int width; int width;

View File

@@ -70,10 +70,9 @@ bool nn_decRef(nn_refc_t *refc, size_t n) {
} }
#endif #endif
typedef struct nn_Lock nn_Lock;
// the special includes // the special includes
#ifndef NN_BAREMETAL #ifndef NN_BAREMETAL
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#include <stdio.h> #include <stdio.h>
@@ -91,6 +90,7 @@ typedef struct nn_Lock nn_Lock;
#endif #endif
#ifdef NN_POSIX #ifdef NN_POSIX
#include <unistd.h>
#include <sys/time.h> #include <sys/time.h>
#include <pthread.h> #include <pthread.h>
#endif #endif
@@ -894,7 +894,7 @@ typedef struct nn_MethodEntry {
unsigned int idx; unsigned int idx;
} nn_MethodEntry; } nn_MethodEntry;
typedef struct nn_Component { struct nn_Component {
nn_refc_t refc; nn_refc_t refc;
nn_Universe *universe; nn_Universe *universe;
char *address; char *address;
@@ -906,7 +906,7 @@ typedef struct nn_Component {
nn_Arena methodArena; nn_Arena methodArena;
nn_HashMap methodsMap; nn_HashMap methodsMap;
size_t methodCount; size_t methodCount;
} nn_Component; };
static size_t nn_methodHash(nn_HashAction act, void *_slot, void *_ent) { static size_t nn_methodHash(nn_HashAction act, void *_slot, void *_ent) {
nn_MethodEntry *slot = _slot; nn_MethodEntry *slot = _slot;
@@ -937,14 +937,14 @@ static const nn_HashContext nn_methodHasher = {
.handler = (nn_HashHandler *)nn_methodHash, .handler = (nn_HashHandler *)nn_methodHash,
}; };
typedef struct nn_Universe { struct nn_Universe {
nn_Context ctx; nn_Context ctx;
void *userdata; void *userdata;
// 0 for unbounded // 0 for unbounded
size_t memoryLimit; size_t memoryLimit;
// 0 for unbounded // 0 for unbounded
size_t storageLimit; size_t storageLimit;
} nn_Universe; };
typedef struct nn_ComponentEntry { typedef struct nn_ComponentEntry {
const char *address; const char *address;
@@ -1069,7 +1069,7 @@ typedef struct nn_Userdata {
char *compAddress; char *compAddress;
} nn_Userdata; } nn_Userdata;
typedef struct nn_Computer { struct nn_Computer {
nn_ComputerState state; nn_ComputerState state;
nn_Universe *universe; nn_Universe *universe;
nn_Environment env; nn_Environment env;
@@ -1098,7 +1098,7 @@ typedef struct nn_Computer {
nn_Signal signals[NN_MAX_SIGNALS]; nn_Signal signals[NN_MAX_SIGNALS];
char *users[NN_MAX_USERS]; char *users[NN_MAX_USERS];
nn_Userdata uservals[NN_MAX_USERDATA]; nn_Userdata uservals[NN_MAX_USERDATA];
} nn_Computer; };
nn_Universe *nn_createUniverse(nn_Context *ctx, void *userdata) { nn_Universe *nn_createUniverse(nn_Context *ctx, void *userdata) {
nn_Universe *u = nn_alloc(ctx, sizeof(nn_Universe)); nn_Universe *u = nn_alloc(ctx, sizeof(nn_Universe));
@@ -1240,13 +1240,6 @@ void nn_unlockComputer(nn_Computer *computer) {
static void nn_dropValue(nn_Value val); static void nn_dropValue(nn_Value val);
static nn_ComponentEntry *nn_getInternalComponent(nn_Computer *computer, const char *address) {
nn_ComponentEntry lookingFor = {
.address = address,
};
return nn_hashGet(&computer->components, &lookingFor);
}
nn_Exit nn_startComputer(nn_Computer *computer) { nn_Exit nn_startComputer(nn_Computer *computer) {
if(nn_isComputerOn(computer)) { if(nn_isComputerOn(computer)) {
nn_stopComputer(computer); nn_stopComputer(computer);
@@ -7052,7 +7045,7 @@ static nn_Exit nn_modemHandler(nn_ComponentRequest *req) {
nn_setError(C, "invalid port"); nn_setError(C, "invalid port");
return NN_EBADCALL; return NN_EBADCALL;
} }
size_t valcount = nn_getstacksize(C) - 1; size_t valcount = nn_getstacksize(C) - 2;
if(valcount > state->modem.maxValues) return NN_EBADCALL; if(valcount > state->modem.maxValues) return NN_EBADCALL;
int cost = nn_countValueCost(C, valcount); int cost = nn_countValueCost(C, valcount);
if(cost < 0) { if(cost < 0) {
@@ -7201,3 +7194,156 @@ nn_Tunnel nn_defaultTunnel = {
.basePacketCost = 100, .basePacketCost = 100,
.fullPacketCost = 256, .fullPacketCost = 256,
}; };
typedef enum nn_TunnelNum {
NN_TUNNELNUM_MAXPACKETSIZE,
NN_TUNNELNUM_MAXVALUES,
NN_TUNNELNUM_GETCHANNEL,
NN_TUNNELNUM_SEND,
NN_TUNNELNUM_GETWAKE,
NN_TUNNELNUM_SETWAKE,
NN_TUNNELNUM_COUNT,
} nn_TunnelNum;
typedef struct nn_TunnelState {
nn_Context *ctx;
nn_Tunnel tunnel;
nn_TunnelHandler *handler;
} nn_TunnelState;
static nn_Exit nn_tunnelHandler(nn_ComponentRequest *req) {
if(req->action == NN_COMP_USERDATA) return NN_OK;
nn_Context *ctx = req->ctx;
nn_TunnelState *state = req->classState;
nn_Computer *C = req->computer;
nn_TunnelNum method = req->methodIdx;
if(req->action == NN_COMP_CHECKMETHOD) return NN_OK;
nn_TunnelRequest treq;
treq.ctx = ctx;
treq.computer = C;
treq.state = req->state;
treq.tunnel = &state->tunnel;
treq.localAddress = req->compAddress;
nn_Exit e;
if(req->action == NN_COMP_DROP) {
treq.action = NN_TUNNEL_DROP;
state->handler(&treq);
nn_free(ctx, state, sizeof(*state));
return NN_OK;
}
if(method == NN_TUNNELNUM_MAXPACKETSIZE) {
req->returnCount = 1;
return nn_pushinteger(C, state->tunnel.maxPacketSize);
}
if(method == NN_TUNNELNUM_MAXVALUES) {
req->returnCount = 1;
return nn_pushinteger(C, state->tunnel.maxValues);
}
if(method == NN_TUNNELNUM_GETCHANNEL) {
treq.action = NN_TUNNEL_GETCHANNEL;
req->returnCount = 1;
return state->handler(&treq);
}
if(method == NN_TUNNELNUM_SEND) {
size_t valcount = nn_getstacksize(C);
if(valcount > state->tunnel.maxValues) return NN_EBADCALL;
int cost = nn_countValueCost(C, valcount);
if(cost < 0) {
nn_setError(C, "invalid contents");
return NN_EBADCALL;
}
if(cost > state->tunnel.maxPacketSize) return NN_ELIMIT;
nn_EncodedNetworkContents data;
e = nn_encodeNetworkContents(C, &data, valcount);
if(e) return e;
treq.action = NN_TUNNEL_SEND;
treq.toSend = &data;
e = state->handler(&treq);
nn_dropNetworkContents(&data);
if(!e) {
nn_removeEnergy(C, state->tunnel.basePacketCost + state->tunnel.fullPacketCost * cost / state->tunnel.maxPacketSize);
req->returnCount = 1;
e = nn_pushbool(C, true);
}
return e;
}
if(method == NN_TUNNELNUM_GETWAKE) {
char buf[NN_MAX_WAKEUPMSG];
treq.action = NN_TUNNEL_GETWAKEMESSAGE;
treq.getWake.buf = buf;
treq.getWake.len = NN_MAX_WAKEUPMSG;
e = state->handler(&treq);
if(e) return e;
req->returnCount = 2;
e = treq.getWake.len == 0 ? nn_pushnull(C) : nn_pushlstring(C, buf, treq.getWake.len);
if(e) return e;
return nn_pushbool(C, treq.getWake.isFuzzy);
}
if(method == NN_TUNNELNUM_SETWAKE) {
e = nn_defaultstring(C, 0, "");
if(e) return e;
if(nn_checkstring(C, 0, "bad argument #1 (string expected)")) return NN_EBADCALL;
e = nn_defaultboolean(C, 1, false);
if(e) return e;
if(nn_checkboolean(C, 1, "bad argument #2 (boolean expected)")) return NN_EBADCALL;
treq.action = NN_TUNNEL_SETWAKEMESSAGE;
treq.setWake.buf = nn_tolstring(C, 0, &treq.setWake.len);
if(treq.setWake.len > NN_MAX_WAKEUPMSG) return NN_ELIMIT;
treq.setWake.isFuzzy = nn_toboolean(C, 1);
e = state->handler(&treq);
if(e) return e;
req->returnCount = 1;
return nn_pushbool(C, true);
}
if(C) nn_setError(C, "tunnel: not implemented yet");
return NN_EBADCALL;
}
nn_Component *nn_createTunnel(nn_Universe *universe, const char *address, const nn_Tunnel *tunnel, void *state, nn_TunnelHandler *handler) {
nn_Component *c = nn_createComponent(
universe, address, "tunnel");
if(c == NULL) return NULL;
const nn_Method methods[NN_TUNNELNUM_COUNT] = {
[NN_TUNNELNUM_MAXPACKETSIZE] = {"maxPacketSize", "function(): integer - Returns the maximum logical packet size", NN_DIRECT},
[NN_TUNNELNUM_MAXVALUES] = {"maxValues", "function(): integer - Returns the maximum amount of values", NN_DIRECT},
[NN_TUNNELNUM_GETCHANNEL] = {"getChannel", "function(): string - Get the ID of the channel", NN_DIRECT},
[NN_TUNNELNUM_SEND] = {"send", "function(...): boolean - Send a packet", NN_INDIRECT},
[NN_TUNNELNUM_GETWAKE] = {"getWakeMessage", "function(): string?, boolean - Returns the wake message, if any, and whether it is fuzzy", NN_DIRECT},
[NN_TUNNELNUM_SETWAKE] = {"setWakeMessage", "function(message: string?, fuzzy: boolean) - Changes the wake-up message of the modem", NN_INDIRECT},
};
nn_Exit e = nn_setComponentMethodsArray(
c, methods, NN_TUNNELNUM_COUNT);
if(e) { nn_dropComponent(c); return NULL; }
nn_Context *ctx = &universe->ctx;
nn_TunnelState *cls = nn_alloc(ctx, sizeof(*cls));
if(cls == NULL) {
nn_dropComponent(c);
return NULL;
}
cls->ctx = ctx;
cls->tunnel = *tunnel;
cls->handler = handler;
nn_setComponentState(c, state);
nn_setComponentClassState(c, cls);
nn_setComponentHandler(c, nn_tunnelHandler);
return c;
}

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
@@ -1042,6 +1042,258 @@ 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);
// 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
@@ -1923,14 +2175,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];
@@ -2039,7 +2283,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;
@@ -2097,250 +2341,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