initial misty implementation
Some checks failed
Build and Deploy / build-linux (push) Failing after 1m41s
Build and Deploy / build-windows (CLANG64) (push) Failing after 10m50s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
Some checks failed
Build and Deploy / build-linux (push) Failing after 1m41s
Build and Deploy / build-windows (CLANG64) (push) Failing after 10m50s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
This commit is contained in:
@@ -519,6 +519,62 @@ var fnname = "doc"
|
||||
script = `(function ${fnname}() { ${script}; })`
|
||||
js.eval(DOCPATH, script)()
|
||||
|
||||
var enet = use('enet')
|
||||
|
||||
var $_ = {}
|
||||
|
||||
var host = enet.create_host()
|
||||
$_.host = host
|
||||
|
||||
console.log(`made a host with port ${host.port()}`)
|
||||
|
||||
globalThis.$_ = $_
|
||||
|
||||
var portal = undefined
|
||||
|
||||
var receive_fn = undefined;
|
||||
|
||||
$_.contact = function(callback, record)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
$_.connection = function(callback, actor, config)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
$_.portal = function(fn, port)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
$_.receiver = function(fn)
|
||||
{
|
||||
receive_fn = fn;
|
||||
}
|
||||
|
||||
$_.start = function(cb, prg, arg)
|
||||
{
|
||||
}
|
||||
|
||||
$_.stop = function(actor)
|
||||
{
|
||||
if (!actor)
|
||||
os.exit(0)
|
||||
}
|
||||
|
||||
$_.unneeded = function(fn, seconds)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
$_.delay = function(fn, seconds)
|
||||
{
|
||||
var id = os.addtimer(fn, seconds);
|
||||
return function() { os.removetimer(id); }
|
||||
}
|
||||
|
||||
use('cmd')(prosperon.argv)
|
||||
|
||||
})()
|
||||
|
||||
@@ -165,6 +165,47 @@ Cmdline.print_order = function (fn) {
|
||||
console.print(fn.doc + "\n");
|
||||
};
|
||||
|
||||
function parse_args(argv)
|
||||
{
|
||||
var args = {};
|
||||
for (var i = 0; i < argv.length; i++) {
|
||||
if (argv[i].startsWith("--")) {
|
||||
var key = argv[i].slice(2);
|
||||
if (i + 1 < argv.length && !argv[i + 1].startsWith("--")) {
|
||||
args[key] = argv[i + 1];
|
||||
i++; // Skip the value
|
||||
} else {
|
||||
args[key] = true; // Flag without value
|
||||
}
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
Cmdline.register_order(
|
||||
"spawn",
|
||||
function(argv) {
|
||||
var args = parse_args(argv)
|
||||
console.log(json.encode(args));
|
||||
if (!args.program)
|
||||
os.exit()
|
||||
|
||||
console.log(`going to connect to ${args.overling}`)
|
||||
if (args.overling) {
|
||||
// connect to the port
|
||||
$_.host.connect("localhost", args.overling);
|
||||
console.log("CONNECTING TO " + args.overling);
|
||||
while(1) {
|
||||
os.waitevent(_ => {}, 0.016)
|
||||
$_.host.service(e => { console.log(json.encode(e)) }, 0.016)
|
||||
}
|
||||
}
|
||||
spawn_root(args.program)
|
||||
},
|
||||
"Spawn a new prosperon actor.",
|
||||
"TOPIC"
|
||||
);
|
||||
|
||||
Cmdline.register_order(
|
||||
"help",
|
||||
function (order) {
|
||||
|
||||
107
source/jsffi.c
107
source/jsffi.c
@@ -28,6 +28,8 @@
|
||||
#include "cgltf.h"
|
||||
#include "physfs.h"
|
||||
|
||||
void gui_input(SDL_Event *e);
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
@@ -55,6 +57,7 @@ typedef struct rtree rtree;
|
||||
#include <SDL3/SDL_loadso.h>
|
||||
#include <SDL3/SDL_cpuinfo.h>
|
||||
|
||||
static Uint32 timer_cb_event;
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <Accelerate/Accelerate.h>
|
||||
@@ -7132,6 +7135,86 @@ JSValue js_os_version(JSContext *js, JSValue self, int argc, JSValue *argv) {
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
JSC_CCALL(os_createprocess,
|
||||
int ac = JS_ArrayLength(js,argv[0]);
|
||||
const char *args[ac+1];
|
||||
for (int i = 0; i < ac; i++) {
|
||||
JSValue astr = JS_GetPropertyUint32(js,argv[0],i);
|
||||
args[i] = JS_ToCString(js,astr);
|
||||
JS_FreeValue(js,astr);
|
||||
}
|
||||
|
||||
args[ac] = NULL;
|
||||
|
||||
SDL_Process *actor = SDL_CreateProcess(args, 0);
|
||||
|
||||
for (int i = 0; i < ac; i++)
|
||||
JS_FreeCString(js,args[i]);
|
||||
|
||||
if (!actor)
|
||||
return JS_ThrowReferenceError(js, "Unable to create process: %s\n", SDL_GetError());
|
||||
)
|
||||
|
||||
struct { SDL_TimerID key; JSValue *value; } *timer_hash = NULL;
|
||||
|
||||
Uint64 os_timer_cb(JSValue *fn, SDL_TimerID id, Uint64 delay)
|
||||
{
|
||||
SDL_UserEvent event;
|
||||
SDL_zero(event);
|
||||
event.type = timer_cb_event;
|
||||
event.data1 = fn;
|
||||
SDL_PushEvent(&event);
|
||||
hmdel(timer_hash, id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
JSC_CCALL(os_addtimer,
|
||||
JSValue *fn = malloc(sizeof(*fn));
|
||||
*fn = JS_DupValue(js,argv[0]);
|
||||
double secs;
|
||||
JS_ToFloat64(js, &secs, argv[1]);
|
||||
|
||||
SDL_TimerID id = SDL_AddTimerNS(secs*1000000000.0f, os_timer_cb, fn);
|
||||
|
||||
hmput(timer_hash, id, fn);
|
||||
|
||||
return JS_NewUint32(js,id);
|
||||
)
|
||||
|
||||
JSC_CCALL(os_removetimer,
|
||||
SDL_TimerID id;
|
||||
JS_ToUint32(js,&id, argv[0]);
|
||||
int rm = SDL_RemoveTimer(id);
|
||||
if (!rm) return JS_ThrowReferenceError(js,"Could not remove timer id %u: %s\n", id, SDL_GetError());
|
||||
JSValue *fn = hmget(timer_hash, id);
|
||||
if (fn != -1) {
|
||||
JS_FreeValue(js, *fn);
|
||||
free(fn);
|
||||
hmdel(timer_hash, id);
|
||||
}
|
||||
)
|
||||
|
||||
JSC_CCALL(os_waitevent,
|
||||
SDL_Event event;
|
||||
double secs;
|
||||
JS_ToFloat64(js, &secs, argv[1]);
|
||||
while (SDL_WaitEventTimeout(&event, secs*1000.0f)) {
|
||||
if (event.type == timer_cb_event) {
|
||||
JSValue *fn = event.user.data1;
|
||||
JSValue ret = JS_Call(js, *fn, JS_UNDEFINED, 0, NULL);
|
||||
JS_FreeValue(js,*fn);
|
||||
free(fn);
|
||||
uncaught_exception(js,ret);
|
||||
} else {
|
||||
gui_input(&event);
|
||||
JSValue e = event2js(js,event);
|
||||
JSValue ret = JS_Call(js,argv[0], JS_UNDEFINED, 1, &e);
|
||||
uncaught_exception(js,ret);
|
||||
}
|
||||
}
|
||||
return JS_UNDEFINED;
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_os_funcs[] = {
|
||||
MIST_FUNC_DEF(os, make_transform, 0),
|
||||
MIST_FUNC_DEF(os, clean_transforms, 0),
|
||||
@@ -7167,7 +7250,11 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
||||
|
||||
// dangerous ones that need disabled for shipping
|
||||
MIST_FUNC_DEF(os, env, 1),
|
||||
MIST_FUNC_DEF(os, system, 1),
|
||||
MIST_FUNC_DEF(os, system, 1),
|
||||
MIST_FUNC_DEF(os, createprocess, 0),
|
||||
MIST_FUNC_DEF(os, addtimer, 2),
|
||||
MIST_FUNC_DEF(os, removetimer, 1),
|
||||
MIST_FUNC_DEF(os, waitevent, 2),
|
||||
};
|
||||
|
||||
JSC_CCALL(js_dump_class, return js_get_object_class_distribution(js))
|
||||
@@ -7239,14 +7326,19 @@ static const JSCFunctionListEntry js_video_funcs[] = {
|
||||
MIST_FUNC_DEF(os, make_video, 1),
|
||||
};
|
||||
|
||||
void gui_input(SDL_Event *e);
|
||||
|
||||
// Polls and handles all input events
|
||||
JSValue js_os_engine_input(JSContext *js, JSValue self, int argc, JSValue *argv) {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
#ifndef NEDITOR
|
||||
if (event.type == timer_cb_event) {
|
||||
JSValue *fn = event.user.data1;
|
||||
JSValue ret = JS_Call(js, *fn, JS_UNDEFINED, 0, NULL);
|
||||
JS_FreeValue(js,*fn);
|
||||
uncaught_exception(js,ret);
|
||||
continue;
|
||||
}
|
||||
gui_input(&event);
|
||||
#endif
|
||||
JSValue e = event2js(js,event);
|
||||
JSValue ret = JS_Call(js,argv[0], JS_UNDEFINED, 1, &e);
|
||||
uncaught_exception(js,ret);
|
||||
@@ -7555,6 +7647,7 @@ static void signal_handler(int sig) {
|
||||
break;
|
||||
}
|
||||
if (!str) return;
|
||||
|
||||
script_evalf("prosperon.dispatch('%s')", str);
|
||||
}
|
||||
|
||||
@@ -7655,6 +7748,8 @@ void ffi_load(JSContext *js, int argc, char **argv) {
|
||||
QJSCLASSPREP_FUNCS(datastream);
|
||||
QJSCLASSPREP_FUNCS(timer);
|
||||
|
||||
timer_cb_event = SDL_RegisterEvents(1);
|
||||
|
||||
JS_SetPropertyStr(js, globalThis, "use_dyn", JS_NewCFunction(js,js_os_use_dyn,"use_dyn", 1));
|
||||
JS_SetPropertyStr(js, globalThis, "use_embed", JS_NewCFunction(js,js_os_use_embed,"use_embed", 1));
|
||||
|
||||
@@ -7793,5 +7888,7 @@ void ffi_load(JSContext *js, int argc, char **argv) {
|
||||
idx_buffer = JS_UNDEFINED;
|
||||
cycle_fn = JS_UNDEFINED;
|
||||
|
||||
JS_FreeValue(js,globalThis);
|
||||
JS_FreeValue(js,globalThis);
|
||||
|
||||
SDL_Init(SDL_INIT_EVENTS);
|
||||
}
|
||||
|
||||
@@ -40,25 +40,34 @@ static JSValue js_enet_deinitialize(JSContext *ctx, JSValueConst this_val,
|
||||
|
||||
/* Host creation */
|
||||
static JSValue js_enet_host_create(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv) {
|
||||
int argc, JSValueConst *argv) {
|
||||
ENetHost *host;
|
||||
ENetAddress address;
|
||||
JSValue obj;
|
||||
|
||||
// Default configuration matching the JavaScript object
|
||||
size_t peer_count = 32; // peer_count: 32
|
||||
size_t channel_limit = 0; // channel_limit: 0
|
||||
enet_uint32 incoming_bandwidth = 0; // incoming_bandwidth: 0
|
||||
enet_uint32 outgoing_bandwidth = 0; // outgoing_bandwidth: 0
|
||||
|
||||
if (argc < 1) {
|
||||
// Create client-like host, unbound
|
||||
host = enet_host_create(NULL, 32, 2, 0, 0);
|
||||
// Create client-like host with port 0 and "any" address
|
||||
address.host = ENET_HOST_ANY;
|
||||
address.port = 0;
|
||||
host = enet_host_create(&address, peer_count, channel_limit,
|
||||
incoming_bandwidth, outgoing_bandwidth);
|
||||
if (!host) {
|
||||
return JS_ThrowInternalError(ctx, "Failed to create ENet host (null address).");
|
||||
return JS_ThrowInternalError(ctx, "Failed to create ENet host (any address).");
|
||||
}
|
||||
goto RET;
|
||||
}
|
||||
|
||||
// If arg is provided, interpret as "ip:port" for server
|
||||
// If argument is provided, interpret as "ip:port" for server
|
||||
const char *address_str = JS_ToCString(ctx, argv[0]);
|
||||
if (!address_str) {
|
||||
if (!address_str)
|
||||
return JS_EXCEPTION; // memory or conversion error
|
||||
}
|
||||
|
||||
char ip[64];
|
||||
int port;
|
||||
|
||||
@@ -68,14 +77,20 @@ static JSValue js_enet_host_create(JSContext *ctx, JSValueConst this_val,
|
||||
}
|
||||
JS_FreeCString(ctx, address_str);
|
||||
|
||||
int err = enet_address_set_host_ip(&address, ip);
|
||||
if (err != 0) {
|
||||
return JS_ThrowInternalError(ctx, "Failed to set host IP from %s. Error %d.", ip, err);
|
||||
if (strcmp(ip, "any") == 0)
|
||||
address.host = ENET_HOST_ANY;
|
||||
else if (strcmp(ip, "broadcast"))
|
||||
address.host = ENET_HOST_BROADCAST;
|
||||
else {
|
||||
int err = enet_address_set_host_ip(&address, ip);
|
||||
if (err != 0) {
|
||||
return JS_ThrowInternalError(ctx, "Failed to set host IP from %s. Error %d.", ip, err);
|
||||
}
|
||||
}
|
||||
address.port = port;
|
||||
|
||||
// Create server host with max 32 clients, 2 channels
|
||||
host = enet_host_create(&address, 32, 2, 0, 0);
|
||||
// Create host with specified configuration
|
||||
host = enet_host_create(&address, peer_count, channel_limit, incoming_bandwidth, outgoing_bandwidth);
|
||||
if (!host) {
|
||||
return JS_ThrowInternalError(ctx, "Failed to create ENet host.");
|
||||
}
|
||||
@@ -93,6 +108,7 @@ RET:
|
||||
/* Host service: poll for events */
|
||||
static JSValue js_enet_host_service(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv) {
|
||||
|
||||
ENetHost *host = JS_GetOpaque(this_val, enet_host_id);
|
||||
if (!host) {
|
||||
return JS_EXCEPTION;
|
||||
@@ -105,14 +121,11 @@ static JSValue js_enet_host_service(JSContext *ctx, JSValueConst this_val,
|
||||
JSValue callback = argv[0];
|
||||
JS_DupValue(ctx, callback);
|
||||
|
||||
// Optional timeout
|
||||
int timeout = 0;
|
||||
if (argc > 1) {
|
||||
JS_ToInt32(ctx, &timeout, argv[1]);
|
||||
}
|
||||
double secs;
|
||||
JS_ToFloat64(ctx, &secs, argv[1]);
|
||||
|
||||
ENetEvent event;
|
||||
while (enet_host_service(host, &event, timeout) > 0) {
|
||||
while (enet_host_service(host, &event, secs*1000.0f) > 0) {
|
||||
JSValue event_obj = JS_NewObject(ctx);
|
||||
|
||||
switch (event.type) {
|
||||
@@ -273,6 +286,20 @@ static JSValue js_enet_host_broadcast(JSContext *ctx, JSValueConst this_val,
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_enet_host_get_port(JSContext *js, JSValueConst self, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetHost *host = JS_GetOpaque(self, enet_host_id);
|
||||
if (!host) return JS_EXCEPTION;
|
||||
return JS_NewInt32(js, host->address.port);
|
||||
}
|
||||
|
||||
static JSValue js_enet_host_get_address(JSContext *js, JSValueConst self, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetHost *host = JS_GetOpaque(self, enet_host_id);
|
||||
if (!host) return JS_EXCEPTION;
|
||||
return JS_NewInt32(js, host->address.host);
|
||||
}
|
||||
|
||||
/* Peer-level operations */
|
||||
static JSValue js_enet_peer_disconnect(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv) {
|
||||
@@ -429,6 +456,8 @@ static const JSCFunctionListEntry js_enet_host_funcs[] = {
|
||||
JS_CFUNC_DEF("connect", 2, js_enet_host_connect),
|
||||
JS_CFUNC_DEF("flush", 0, js_enet_host_flush),
|
||||
JS_CFUNC_DEF("broadcast", 1, js_enet_host_broadcast),
|
||||
JS_CFUNC_DEF("port", 0, js_enet_host_get_port),
|
||||
JS_CFUNC_DEF("address", 0, js_enet_host_get_address),
|
||||
};
|
||||
|
||||
static const JSCFunctionListEntry js_enet_peer_funcs[] = {
|
||||
|
||||
9
tests/overling.js
Normal file
9
tests/overling.js
Normal file
@@ -0,0 +1,9 @@
|
||||
var os = use('os')
|
||||
|
||||
var newguy = os.createprocess(["./prosperon", "spawn", "--program", "spawn2.js", "--overling", $_.host.port()])
|
||||
var hang = 0.016
|
||||
|
||||
while (1) {
|
||||
os.waitevent(_ => {}, hang)
|
||||
$_.host.service(e => {console.log(json.encode(e))}, hang)
|
||||
}
|
||||
5
tests/underling.js
Normal file
5
tests/underling.js
Normal file
@@ -0,0 +1,5 @@
|
||||
var os = use('os')
|
||||
|
||||
console.log("Created underling")
|
||||
|
||||
os.exit()
|
||||
Reference in New Issue
Block a user