bevy-remote-protocol
Version:
Bevy Remote Protocol Client
439 lines (433 loc) • 15.9 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
BevyRemoteProtocol: () => BevyRemoteProtocol,
BrpStructure: () => BrpStructure,
ServerVersion: () => ServerVersion,
short: () => short
});
module.exports = __toCommonJS(index_exports);
// src/protocol.ts
var import_url = require("url");
// src/types.ts
var BrpStructure = class _BrpStructure {
constructor(tree) {
this.tree = tree;
}
has(path = []) {
return _BrpStructure.hasBrpValue(this.tree, path);
}
get(path = []) {
return _BrpStructure.getBrpValue(this.tree, path);
}
set(path = [], value) {
if (path.length === 0) {
this.tree = value;
return;
}
_BrpStructure.setBrpValue(this.tree, path, value);
}
keys(path = []) {
const iterable = this.get(path);
if (typeof iterable !== "object") return [];
if (iterable === void 0 || iterable === null) return [];
if (iterable instanceof Array) return [...iterable.keys()];
return Object.keys(iterable);
}
values(path = []) {
const iterable = this.get(path);
if (typeof iterable !== "object") return [];
if (iterable === void 0 || iterable === null) return [];
return Object.values(iterable);
}
static hasBrpValue(value, path = []) {
if (value === void 0) return false;
if (path.length === 0) return true;
if (typeof value !== "object" || value === null) return false;
const key = path[0];
if (value instanceof Array) {
if (typeof key !== "number") return false;
return this.hasBrpValue(value[key], path.slice(1));
}
if (typeof key !== "string") return false;
return this.hasBrpValue(value[key], path.slice(1));
}
static getBrpValue(value, path = []) {
if (value === void 0) return void 0;
if (path.length === 0) return value;
if (typeof value !== "object" || value === null) return void 0;
const key = path[0];
if (value instanceof Array) {
if (typeof key !== "number") return null;
return _BrpStructure.getBrpValue(value[key], path.slice(1));
}
if (typeof key !== "string") return null;
return _BrpStructure.getBrpValue(value[key], path.slice(1));
}
static setBrpValue(value, path = [], setter) {
if (path.length === 0) return;
if (typeof value !== "object" || value === null) return;
const key = path[0];
if (value instanceof Array) {
if (typeof key !== "number") return;
if (path.length === 1) {
value[key] = setter;
return;
}
_BrpStructure.setBrpValue(value[key], path.slice(1), setter);
return;
}
if (typeof key !== "string") return;
if (path.length === 1) {
value[key] = setter;
return;
}
_BrpStructure.setBrpValue(value[key], path.slice(1), setter);
}
};
var ServerVersion = /* @__PURE__ */ ((ServerVersion2) => {
ServerVersion2["IGNORE"] = "IGNORE";
ServerVersion2["V0_15"] = "0.15";
ServerVersion2["V0_16"] = "0.16";
return ServerVersion2;
})(ServerVersion || {});
// src/protocol.ts
var import_util = require("util");
function reverseMap(map) {
const result = {};
for (const key in map) {
const value = map[key];
result[value] = key;
}
return result;
}
function collectMaps(maps) {
const collection = {};
for (const map of maps) {
for (const key in map) {
collection[key] = map[key];
}
}
return collection;
}
var _BevyRemoteProtocol = class _BevyRemoteProtocol {
constructor(url, version) {
this.id = 0;
this.url = url;
this.serverVersion = version;
}
nextId() {
return this.id++;
}
translateToInternal(message) {
const table = (() => {
if (this.serverVersion === "IGNORE" /* IGNORE */) return {};
return _BevyRemoteProtocol.ANY_TO_INTERNAL;
})();
for (const search in table) {
message = message.replace(new RegExp(search, "g"), table[search]);
}
return message;
}
translateToSpecificVersion(message) {
const table = (() => {
switch (this.serverVersion) {
case "0.15" /* V0_15 */:
return _BevyRemoteProtocol.INTERNAL_TO_V0_15;
case "0.16" /* V0_16 */:
return _BevyRemoteProtocol.INTERNAL_TO_V0_16;
default:
return {};
}
})();
for (const search in table) {
message = message.replace(new RegExp(search, "g"), table[search]);
}
return message;
}
requestWrapper(rpcMethod, rpcParams, signal) {
return {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json"
},
body: this.translateToSpecificVersion(
JSON.stringify({
jsonrpc: "2.0",
id: this.nextId(),
method: rpcMethod,
params: rpcParams
})
),
signal
};
}
async request(method, params) {
return await JSON.parse(
this.translateToInternal(await (await fetch(this.url, this.requestWrapper(method, params))).text())
);
}
async requestStream(method, params, signal, observer) {
const response = await fetch(this.url, this.requestWrapper(method, params, signal));
if (!response.body) return null;
try {
for await (const chunk of response.body) {
const decoded = _BevyRemoteProtocol.decoder.decode(chunk);
const translated = this.translateToInternal(decoded);
const parsed = JSON.parse(translated.slice(decoded.indexOf("{")));
if (parsed.result) observer(parsed.result);
}
} catch (error) {
}
return null;
}
/**
* Retrieve the values of one or more components from an entity.
*
* This function passes a flag `strict` as `false` by default.
*
* `params`:
* - `entity`: The ID of the entity whose components will be fetched.
* - `components`: An array of [fully-qualified type names] of components to fetch.
* - `strict` (optional): A flag to enable strict mode which will fail if any one of the
* components is not present or can not be reflected.
*
* `result`:
* - `components`: A map associating each type name to its value on the requested entity.
* - `errors`: A map associating each type name with an error if it was not on the entity
* or could not be reflected.
*/
async get(entity, components) {
return this.request("bevy/get", { entity, components, strict: false });
}
/**
* Retrieve the values of one or more components from an entity.
*
* This function passes a flag `strict` as `true` by default.
*
* `params`:
* - `entity`: The ID of the entity whose components will be fetched.
* - `components`: An array of [fully-qualified type names] of components to fetch.
* - `strict` (optional): A flag to enable strict mode which will fail if any one of the
* components is not present or can not be reflected.
*
* `result`: A map associating each type name to its value on the requested entity.
*/
async get_strict(entity, components) {
return this.request("bevy/get", { entity, components, strict: true });
}
/**
* Perform a query over components in the ECS, returning all matching entities and their associated
* component values.
*
* All of the arrays that comprise this request are optional, and when they are not provided, they
* will be treated as if they were empty.
*
* `params`:
* - `components` (optional): An array of [fully-qualified type names] of components to fetch.
* - `option` (optional): An array of fully-qualified type names of components to fetch optionally.
* - `has` (optional): An array of fully-qualified type names of components whose presence will be
* reported as boolean values.
* - `with` (optional): An array of fully-qualified type names of components that must be present
* on entities in order for them to be included in results.
* - `without` (optional): An array of fully-qualified type names of components that must *not* be
* present on entities in order for them to be included in results.
*
* `result`: An array, each of which is an object containing:
* - `entity`: The ID of a query-matching entity.
* - `components`: A map associating each type name from `components`/`option` to its value on the matching
* entity if the component is present.
* - `has`: A map associating each type name from `has` to a boolean value indicating whether or not the
* entity has that component. If `has` was empty or omitted, this key will be omitted in the response.
*/
async query({
components,
option,
has,
filterWith,
filterWithout
}) {
return this.request("bevy/query", {
data: { components, option, has },
filter: { with: filterWith, without: filterWithout }
});
}
/**
* Create a new entity with the provided components and return the resulting entity ID.
*
* `params`:
* - `components`: A map associating each component's [fully-qualified type name] with its value.
*
* `result`:
* - `entity`: The ID of the newly spawned entity.
*/
async spawn(components) {
return this.request("bevy/spawn", { components });
}
/**
* Despawn the entity with the given ID.
*
* `params`:
* - `entity`: The ID of the entity to be despawned.
*
* `result`: null.
*/
async destroy(entity) {
return this.request("bevy/destroy", { entity });
}
/**
* Delete one or more components from an entity.
*
* `params`:
* - `entity`: The ID of the entity whose components should be removed.
* - `components`: An array of [fully-qualified type names] of components to be removed.
*
* `result`: null.
*/
async remove(entity, components) {
return this.request("bevy/remove", { entity, components });
}
/**
* Insert one or more components into an entity.
*
* `params`:
* - `entity`: The ID of the entity to insert components into.
* - `components`: A map associating each component's fully-qualified type name with its value.
*
* `result`: null.
*/
async insert(entity, components) {
return this.request("bevy/insert", { entity, components });
}
/**
* Assign a new parent to one or more entities.
*
* `params`:
* - `entities`: An array of entity IDs of entities that will be made children of the `parent`.
* - `parent` (optional): The entity ID of the parent to which the child entities will be assigned.
* If excluded, the given entities will be removed from their parents.
*
* `result`: null.
*/
async reparent(entities, parent) {
return this.request("bevy/reparent", { entities, parent });
}
/**
* List all registered components or all components present on an entity.
*
* When `params` is not provided, this lists all registered components. If `params` is provided,
* this lists only those components present on the provided entity.
*
* `params` (optional):
* - `entity`: The ID of the entity whose components will be listed.
*
* `result`: An array of fully-qualified type names of components.
*/
async list(entity) {
if (entity) return this.request("bevy/list", { entity });
return this.request("bevy/list", null);
}
/**
* Watch the values of one or more components from an entity.
*
* This function passes a flag `strict` as `false` by default.
*
* `params`:
* - `entity`: The ID of the entity whose components will be fetched.
* - `components`: An array of [fully-qualified type names] of components to fetch.
* - `signal`: A signal object that allows you to abort it if required via an {@link AbortController} object.
* - `observer`: A handler of chunks of Response.
*
* `result`:
* - `components`: A map of components added or changed in the last tick associating each type
* name to its value on the requested entity.
* - `removed`: An array of fully-qualified type names of components removed from the entity
* in the last tick.
* - `errors`: A map associating each type name with an error if it was not on the entity
* or could not be reflected.
*/
async get_watch(entity, components, signal, observer) {
return this.requestStream("bevy/get+watch", { entity, components, strict: false }, signal, observer);
}
/**
* Watch the values of one or more components from an entity.
*
* This function passes a flag `strict` as `true` by default.
* Response will fail if any one of the components is not present or can not be refleceted.
*
* `params`:
* - `entity`: The ID of the entity whose components will be fetched.
* - `components`: An array of [fully-qualified type names] of components to fetch.
* - `signal`: A signal object that allows you to abort it if required via an {@link AbortController} object.
* - `observer`: A handler of chunks of Response.
*
* `result`:
* - `components`: A map of components added or changed in the last tick associating each type
* name to its value on the requested entity.
* - `removed`: An array of fully-qualified type names of components removed from the entity
* in the last tick.
*/
async get_watch_strict(entity, components, signal, observer) {
return this.requestStream("bevy/get+watch", { entity, components, strict: true }, signal, observer);
}
/**
* Watch all components present on an entity.
*
* When `entity` is not provided, this lists all registered components. If `entity` is provided,
* this lists only those components present on the provided entity.
*
* `params`:
* - `signal`: A signal object that allows you to abort it if required via an {@link AbortController} object.
* - `observer`: A handler of chunks of Response.
* - `entity`: (optional) The ID of the entity whose components will be listed.
*
* `result`:
* - `added`: An array of fully-qualified type names of components added to the entity in the
* last tick.
* - `removed`: An array of fully-qualified type names of components removed from the entity
* in the last tick.
*/
async list_watch(signal, observer, entity) {
if (entity) return this.requestStream("bevy/list+watch", { entity }, signal, observer);
return this.requestStream("bevy/list+watch", null, signal, observer);
}
};
_BevyRemoteProtocol.DEFAULT_URL = new import_url.URL("http://127.0.0.1:15702");
_BevyRemoteProtocol.INTERNAL_TO_V0_15 = {
"bevy_ecs::hierarchy::Children": "bevy_hierarchy::components::children::Children",
"bevy_ecs::name::Name": "bevy_core::name::Name"
};
_BevyRemoteProtocol.INTERNAL_TO_V0_16 = {};
_BevyRemoteProtocol.ANY_TO_INTERNAL = collectMaps([reverseMap(_BevyRemoteProtocol.INTERNAL_TO_V0_15), reverseMap(_BevyRemoteProtocol.INTERNAL_TO_V0_16)]);
_BevyRemoteProtocol.decoder = new import_util.TextDecoder();
var BevyRemoteProtocol = _BevyRemoteProtocol;
// src/index.ts
function short(typePath) {
return (/[^::]*$/.exec(typePath.split("<")[0]) ?? "???")[0];
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
BevyRemoteProtocol,
BrpStructure,
ServerVersion,
short
});