@bedrock-oss/bedrock-boost
Version:
A utility package with helper functions for developing add-ons with Script API in Minecraft Bedrock Edition
1,670 lines (1,665 loc) • 92.7 kB
JavaScript
// src/Vec3.ts
import { Direction } from "@minecraft/server";
// src/Logging.ts
import { system, world } from "@minecraft/server";
// src/ChatColor.ts
var ChatColor = class _ChatColor {
/**
* Class ChatColor Constructor.
* @param code - The color code as a string.
* @param color - The color code as a hexadecimal number. Can be undefined.
*/
constructor(code, color) {
this.code = code;
this.color = color;
if (color) {
this.r = color >> 16 & 255;
this.g = color >> 8 & 255;
this.b = color & 255;
}
}
/**
* Black color code. (0)
*/
static BLACK = new _ChatColor("0", 0);
/**
* Dark blue color code. (1)
*/
static DARK_BLUE = new _ChatColor("1", 170);
/**
* Dark green color code. (2)
*/
static DARK_GREEN = new _ChatColor("2", 43520);
/**
* Dark aqua color code. (3)
*/
static DARK_AQUA = new _ChatColor("3", 43690);
/**
* Dark red color code. (4)
*/
static DARK_RED = new _ChatColor("4", 11141120);
/**
* Dark purple color code. (5)
*/
static DARK_PURPLE = new _ChatColor("5", 11141290);
/**
* Gold color code. (6)
*/
static GOLD = new _ChatColor("6", 16755200);
/**
* Gray color code. (7)
*/
static GRAY = new _ChatColor("7", 11184810);
/**
* Dark gray color code. (8)
*/
static DARK_GRAY = new _ChatColor("8", 5592405);
/**
* Blue color code. (9)
*/
static BLUE = new _ChatColor("9", 5592575);
/**
* Green color code. (a)
*/
static GREEN = new _ChatColor("a", 5635925);
/**
* Aqua color code. (b)
*/
static AQUA = new _ChatColor("b", 5636095);
/**
* Red color code. (c)
*/
static RED = new _ChatColor("c", 16733525);
/**
* Light purple color code. (d)
*/
static LIGHT_PURPLE = new _ChatColor("d", 16733695);
/**
* Yellow color code. (e)
*/
static YELLOW = new _ChatColor("e", 16777045);
/**
* White color code. (f)
*/
static WHITE = new _ChatColor("f", 16777215);
/**
* MineCoin gold color code. (g)
*/
static MINECOIN_GOLD = new _ChatColor("g", 14603781);
/**
* Material quartz color code. (h)
*/
static MATERIAL_QUARTZ = new _ChatColor("h", 14931153);
/**
* Material iron color code. (i)
*/
static MATERIAL_IRON = new _ChatColor("i", 13552330);
/**
* Material netherite color code. (j)
*/
static MATERIAL_NETHERITE = new _ChatColor("j", 4471355);
/**
* Material redstone color code. (m)
*/
static MATERIAL_REDSTONE = new _ChatColor("m", 9901575);
/**
* Material copper color code. (n)
*/
static MATERIAL_COPPER = new _ChatColor("n", 11823181);
/**
* Material gold color code. (p)
*/
static MATERIAL_GOLD = new _ChatColor("p", 14594349);
/**
* Material emerald color code. (q)
*/
static MATERIAL_EMERALD = new _ChatColor("q", 1155126);
/**
* Material diamond color code. (s)
*/
static MATERIAL_DIAMOND = new _ChatColor("s", 2931368);
/**
* Material lapis color code. (t)
*/
static MATERIAL_LAPIS = new _ChatColor("t", 2181499);
/**
* Material amethyst color code. (u)
*/
static MATERIAL_AMETHYST = new _ChatColor("u", 10116294);
/**
* Obfuscated color code. (k)
*/
static OBFUSCATED = new _ChatColor("k");
/**
* Bold color code. (l)
*/
static BOLD = new _ChatColor("l");
/**
* Italic color code. (o)
*/
static ITALIC = new _ChatColor("o");
/**
* Reset color code. (r)
*/
static RESET = new _ChatColor("r");
/**
* All available color codes.
*/
static VALUES = [
_ChatColor.BLACK,
_ChatColor.DARK_BLUE,
_ChatColor.DARK_GREEN,
_ChatColor.DARK_AQUA,
_ChatColor.DARK_RED,
_ChatColor.DARK_PURPLE,
_ChatColor.GOLD,
_ChatColor.GRAY,
_ChatColor.DARK_GRAY,
_ChatColor.BLUE,
_ChatColor.GREEN,
_ChatColor.AQUA,
_ChatColor.RED,
_ChatColor.LIGHT_PURPLE,
_ChatColor.YELLOW,
_ChatColor.WHITE,
_ChatColor.MINECOIN_GOLD,
_ChatColor.MATERIAL_QUARTZ,
_ChatColor.MATERIAL_IRON,
_ChatColor.MATERIAL_NETHERITE,
_ChatColor.MATERIAL_REDSTONE,
_ChatColor.MATERIAL_COPPER,
_ChatColor.MATERIAL_GOLD,
_ChatColor.MATERIAL_EMERALD,
_ChatColor.MATERIAL_DIAMOND,
_ChatColor.MATERIAL_LAPIS,
_ChatColor.MATERIAL_AMETHYST,
_ChatColor.OBFUSCATED,
_ChatColor.BOLD,
_ChatColor.ITALIC,
_ChatColor.RESET
];
/**
* All available color codes excluding the formatting codes.
*/
static ALL_COLORS = [
_ChatColor.BLACK,
_ChatColor.DARK_BLUE,
_ChatColor.DARK_GREEN,
_ChatColor.DARK_AQUA,
_ChatColor.DARK_RED,
_ChatColor.DARK_PURPLE,
_ChatColor.GOLD,
_ChatColor.GRAY,
_ChatColor.DARK_GRAY,
_ChatColor.BLUE,
_ChatColor.GREEN,
_ChatColor.AQUA,
_ChatColor.RED,
_ChatColor.LIGHT_PURPLE,
_ChatColor.YELLOW,
_ChatColor.WHITE,
_ChatColor.MINECOIN_GOLD,
_ChatColor.MATERIAL_QUARTZ,
_ChatColor.MATERIAL_IRON,
_ChatColor.MATERIAL_NETHERITE,
_ChatColor.MATERIAL_REDSTONE,
_ChatColor.MATERIAL_COPPER,
_ChatColor.MATERIAL_GOLD,
_ChatColor.MATERIAL_EMERALD,
_ChatColor.MATERIAL_DIAMOND,
_ChatColor.MATERIAL_LAPIS,
_ChatColor.MATERIAL_AMETHYST
];
r;
g;
b;
/**
* PREFIX is the section sign (§) used in Minecraft color codes.
*/
static PREFIX = "\xA7";
/**
* Returns the string representation of the ChatColor instance,
* which includes the PREFIX followed by the color code.
* @returns A string representing the ChatColor instance
*/
toString() {
return _ChatColor.PREFIX + this.code;
}
/**
* Returns the color code of the ChatColor instance.
* @returns The color code of this ChatColor instance.
*/
toRGB() {
return this.color;
}
/**
* Returns the hexadecimal string representation of the color code
* @returns {string | undefined} The hexadecimal representation of the color.
*/
toHex() {
return this.color?.toString(16);
}
/**
* Retrieve the value of the red component.
*
* @returns {number | undefined} The value of the red component, or undefined if it is not set.
*/
getRed() {
return this.r;
}
/**
* Retrieves the green value of the current color.
*
* @returns {number | undefined} The green value of the color, or undefined if it is not set.
*/
getGreen() {
return this.g;
}
/**
* Retrieves the blue value of a color.
*
* @returns The blue value of the color.
* @type {number | undefined}
*/
getBlue() {
return this.b;
}
/**
* Retrieves the format code associated with the chat color.
*
* @returns {string} The format code of the chat color.
*/
getCode() {
return this.code;
}
/**
* Removes color codes from the specified string
* @param str - The string from which color codes will be removed.
* @returns The string cleared from color codes.
*/
static stripColor(str) {
return str.replace(/§[0-9a-u]/g, "");
}
/**
* Finds the closest ChatColor code for the given RGB values
* @param r - Red part of the color.
* @param g - Green part of the color.
* @param b - Blue part of the color.
* @returns The closest ChatColor for the given RGB values.
*/
static findClosestColor(r, g, b) {
let minDistance = Number.MAX_VALUE;
let closestColor = _ChatColor.WHITE;
for (const color of _ChatColor.ALL_COLORS) {
if (color.r && color.g && color.b) {
const distance = Math.sqrt(Math.pow(color.r - r, 2) + Math.pow(color.g - g, 2) + Math.pow(color.b - b, 2));
if (distance < minDistance) {
minDistance = distance;
closestColor = color;
}
}
}
return closestColor;
}
};
// src/ColorJSON.ts
var ColorJSON = class _ColorJSON {
// Tokens
OpenObject = "{";
CloseObject = "}";
OpenArray = "[";
CloseArray = "]";
Comma = ",";
KeyValueSeparator = ":";
StringDelimiter = '"';
KeyDelimiter = "";
Indent = " ";
NewLine = "\n";
Space = " ";
// Threshold for inline representation
InlineThreshold = 60;
// Maximum depth to which objects will be traversed
MaxDepth = 1;
// Whether to include class names
IncludeClassNames = true;
// Values
FunctionValue = "\u0192";
NullValue = "null";
UndefinedValue = "undefined";
TrueValue = "true";
FalseValue = "false";
CycleValue = "[...cycle...]";
TruncatedObjectValue = "{...}";
// Colors
OpenCloseObjectColor = ChatColor.YELLOW;
OpenCloseArrayColor = ChatColor.AQUA;
NumberColor = ChatColor.DARK_AQUA;
StringColor = ChatColor.DARK_GREEN;
BooleanColor = ChatColor.GOLD;
NullColor = ChatColor.GOLD;
KeyColor = ChatColor.GRAY;
EscapeColor = ChatColor.GOLD;
FunctionColor = ChatColor.GRAY;
ClassColor = ChatColor.GRAY;
ClassStyle = ChatColor.BOLD;
CycleColor = ChatColor.DARK_RED;
/**
* The default ColorJSON instance
*/
static DEFAULT = new _ColorJSON();
static createPlain() {
const plain = new _ColorJSON();
plain.OpenCloseObjectColor = "";
plain.OpenCloseArrayColor = "";
plain.NumberColor = "";
plain.StringColor = "";
plain.BooleanColor = "";
plain.NullColor = "";
plain.KeyColor = "";
plain.EscapeColor = "";
plain.FunctionColor = "";
plain.ClassColor = "";
plain.ClassStyle = "";
plain.CycleColor = "";
return plain;
}
/**
* A ColorJSON instance that does not colorize anything.
*/
static PLAIN = this.createPlain();
/**
* Transforms a value into a chat-friendly, colored JSON representation.
* @param value - The value to transform.
*/
stringify(value) {
return this.stringifyValue(value, {
indentLevel: 0,
visited: /* @__PURE__ */ new WeakSet()
});
}
/**
* Transforms a string into a JSON representation.
* @param value - The string to transform.
*/
stringifyString(value) {
return this.StringColor + this.StringDelimiter + this.escapeString(value) + this.StringDelimiter + ChatColor.RESET;
}
/**
* Transforms a number into a JSON representation.
* @param value - The number to transform.
*/
stringifyNumber(value) {
return this.NumberColor + value.toString() + ChatColor.RESET;
}
/**
* Transforms a boolean into a JSON representation.
* @param value - The boolean to transform.
*/
stringifyBoolean(value) {
return this.BooleanColor + (value ? this.TrueValue : this.FalseValue) + ChatColor.RESET;
}
/**
* Transforms a function into a JSON representation.
* @param value - The function to transform.
*/
// eslint-disable-next-line @typescript-eslint/ban-types
stringifyFunction(value) {
return this.FunctionColor + this.FunctionValue + ChatColor.RESET;
}
/**
* Returns a null JSON representation.
*/
stringifyNull() {
return this.NullColor + this.NullValue + ChatColor.RESET;
}
/**
* Returns an undefined JSON representation.
*/
stringifyUndefined() {
return this.NullColor + this.UndefinedValue + ChatColor.RESET;
}
/**
* Returns a cycle JSON representation.
*/
stringifyCycle() {
return this.CycleColor + this.CycleValue + ChatColor.RESET;
}
/**
* Transforms an array into a JSON representation.
* @param value - The array to transform.
* @param indentLevel - The indentation level for pretty-printing.
*/
stringifyArray(value, ctx) {
const indentSpace = this.Indent.repeat(ctx.indentLevel);
if (value.length === 0) {
return this.OpenCloseArrayColor + this.OpenArray + this.CloseArray + ChatColor.RESET;
}
let result = this.OpenCloseArrayColor + this.OpenArray + ChatColor.RESET + this.NewLine;
let compactResult = this.OpenCloseArrayColor + this.OpenArray + ChatColor.RESET;
value.forEach((item, index) => {
result += indentSpace + this.Indent + this.stringifyValue(item, this.indent(ctx));
result += index < value.length - 1 ? this.Comma + this.NewLine : this.NewLine;
compactResult += this.stringifyValue(item, this.indent(ctx));
compactResult += index < value.length - 1 ? this.Comma + this.Space : "";
});
result += indentSpace + this.OpenCloseArrayColor + this.CloseArray + ChatColor.RESET;
compactResult += this.OpenCloseArrayColor + this.CloseArray + ChatColor.RESET;
if (compactResult.length < this.InlineThreshold) {
return compactResult;
}
return result;
}
/**
* Transforms an object into a truncated JSON representation.
* @param value - The object to transform.
* @param className - Class Name of the object.
* @param indentLevel - The indentation level for pretty-printing.
*/
stringifyTruncatedObject(value, className, ctx) {
return (this.IncludeClassNames ? this.ClassColor + "" + this.ClassStyle + className + ChatColor.RESET + this.Space : "") + this.TruncatedObjectValue;
}
/**
* Transforms an object into a JSON representation.
* @param value - The object to transform.
* @param className - Class Name of the object.
* @param entries - Entries of the object to transform.
* @param indentLevel - The indentation level for pretty-printing.
*/
stringifyObject(value, className, entries, ctx) {
const indentSpace = this.Indent.repeat(ctx.indentLevel);
const prefix = this.IncludeClassNames && className !== "Object" ? this.ClassColor + "" + this.ClassStyle + className + ChatColor.RESET + this.Space : "";
if (entries.length === 0) {
return prefix + this.OpenCloseObjectColor + this.OpenObject + this.CloseObject + ChatColor.RESET;
}
let result = prefix + this.OpenCloseObjectColor + this.OpenObject + ChatColor.RESET + this.NewLine;
let compactResult = prefix + this.OpenCloseObjectColor + this.OpenObject + ChatColor.RESET;
entries.forEach(([key, val], index) => {
const compactVal = this.stringifyValue(val, this.indent(ctx));
result += indentSpace + this.Indent + this.KeyColor + this.KeyDelimiter + key + this.KeyDelimiter + ChatColor.RESET + this.KeyValueSeparator + this.Space + compactVal;
result += index < entries.length - 1 ? this.Comma + this.NewLine : this.NewLine;
compactResult += this.KeyColor + key + ChatColor.RESET + this.KeyValueSeparator + this.Space + compactVal;
compactResult += index < entries.length - 1 ? this.Comma + this.Space : "";
});
result += indentSpace + this.OpenCloseObjectColor + this.CloseObject + ChatColor.RESET;
compactResult += this.OpenCloseObjectColor + this.CloseObject + ChatColor.RESET;
if (compactResult.length < this.InlineThreshold) {
return compactResult;
}
return result;
}
shouldTruncateObject(value, className, ctx) {
return !(className === "Object" || ctx.indentLevel <= this.MaxDepth || this.MaxDepth <= 0);
}
/**
* Transforms a value of any type into a JSON representation. This function is not meant to be overridden.
* @param value - The value to transform.
* @param indentLevel - The indentation level for pretty-printing.
*/
stringifyValue(value, ctx) {
if (value === null)
return this.stringifyNull();
if (value === void 0)
return this.stringifyUndefined();
if (typeof value === "number")
return this.stringifyNumber(value);
if (typeof value === "string")
return this.stringifyString(value);
if (typeof value === "boolean")
return this.stringifyBoolean(value);
if (typeof value === "function")
return this.stringifyFunction(value);
if (this.isCycle(value, ctx)) {
return this.stringifyCycle();
}
this.markCycle(value, ctx);
if (Array.isArray(value)) {
const result = this.stringifyArray(value, ctx.indentLevel ? this.indent(ctx) : ctx);
this.clearCycle(value, ctx);
return result;
}
if (typeof value === "object") {
const name = value.constructor.name;
if (!this.shouldTruncateObject(value, name, ctx)) {
const keySet = /* @__PURE__ */ new Set();
let prototype = Object.getPrototypeOf(value);
let keys = Object.keys(prototype);
while (keys.length > 0) {
keys.forEach((key) => keySet.add(key));
prototype = Object.getPrototypeOf(prototype);
keys = Object.keys(prototype);
}
Object.keys(value).forEach((key) => keySet.add(key));
keySet.delete("__cycleDetection__");
const allKeys = [...keySet].sort();
const entries = allKeys.map((key) => {
try {
return [key, value[key] ?? void 0];
} catch (e) {
return [key, void 0];
}
}).filter(([, val]) => typeof val !== "function" && val !== void 0);
const result = this.stringifyObject(value, name, entries, ctx);
this.clearCycle(value, ctx);
return result;
} else {
const result = this.stringifyTruncatedObject(value, name, ctx);
this.clearCycle(value, ctx);
return result;
}
}
this.clearCycle(value, ctx);
return ChatColor.RESET + value.toString();
}
/**
* Escapes a string for JSON.
* @param str - The string to escape.
*/
escapeString(str) {
return str.replace(/\\/g, this.EscapeColor + "\\\\" + this.StringColor).replace(/"/g, this.EscapeColor + '\\"' + this.StringColor).replace(/\n/g, this.EscapeColor + "\\n" + this.StringColor).replace(/\r/g, this.EscapeColor + "\\r" + this.StringColor).replace(/\t/g, this.EscapeColor + "\\t" + this.StringColor);
}
markCycle(value, ctx) {
ctx.visited.add(value);
}
isCycle(value, ctx) {
return ctx.visited.has(value);
}
clearCycle(value, ctx) {
ctx.visited.delete(value);
}
indent(ctx) {
return { ...ctx, indentLevel: ctx.indentLevel + 1 };
}
};
// src/Logging.ts
var sourceMapping = void 0;
try {
sourceMapping = globalSourceMapping;
} catch (e) {
}
var OutputType = /* @__PURE__ */ ((OutputType2) => {
OutputType2[OutputType2["Chat"] = 0] = "Chat";
OutputType2[OutputType2["ConsoleInfo"] = 1] = "ConsoleInfo";
OutputType2[OutputType2["ConsoleWarn"] = 2] = "ConsoleWarn";
OutputType2[OutputType2["ConsoleError"] = 3] = "ConsoleError";
return OutputType2;
})(OutputType || {});
var LogLevel = class _LogLevel {
/**
* The constructor for each log level.
*
* @param {number} level - The numerical level for this logger.
* @param {string} name - The string name for this logger.
* @param {ChatColor} color - The color to use for this logger. Defaults to `ChatColor.RESET`.
*/
constructor(level, name, color = ChatColor.RESET) {
this.level = level;
this.name = name;
this.color = color;
}
static All = new _LogLevel(-2, "all");
static Trace = new _LogLevel(-2, "trace", ChatColor.DARK_AQUA);
static Debug = new _LogLevel(-1, "debug", ChatColor.AQUA);
static Info = new _LogLevel(0, "info", ChatColor.GREEN);
static Warn = new _LogLevel(1, "warn", ChatColor.GOLD);
static Error = new _LogLevel(2, "error", ChatColor.RED);
static Fatal = new _LogLevel(3, "fatal", ChatColor.DARK_RED);
static Off = new _LogLevel(100, "off");
/**
* The list of all available log levels.
*/
static values = [
_LogLevel.All,
_LogLevel.Trace,
_LogLevel.Debug,
_LogLevel.Info,
_LogLevel.Warn,
_LogLevel.Error,
_LogLevel.Fatal,
_LogLevel.Off
];
/**
* Return the logging level as a string.
*
* @returns {string} The string representation of the logging level.
*/
toString() {
return this.color + this.name.toUpperCase() + ChatColor.RESET;
}
/**
* Parse a string to get the corresponding `LogLevel`.
*
* @param {string} str - The string to parse.
* @returns {LogLevel} The corresponding `LogLevel`, or `undefined` if none was found.
*/
static parse(str) {
str = str.toLowerCase();
for (const level of _LogLevel.values) {
if (level.name === str)
return level;
}
const num = parseInt(str);
if (!isNaN(num)) {
for (const level of _LogLevel.values) {
if (level.level === num)
return level;
}
}
return void 0;
}
};
function starMatch(pattern, str) {
if (pattern === "*")
return true;
if (pattern.includes("*")) {
if (pattern.startsWith("*")) {
return str.endsWith(pattern.substring(1));
}
if (pattern.endsWith("*")) {
return str.startsWith(pattern.substring(0, pattern.length - 1));
}
const regex = new RegExp(pattern.replace(/\*/g, ".*"));
return regex.test(str);
}
return pattern === str;
}
var loggingSettings = {
level: LogLevel.Info,
filter: ["*"],
outputTags: false,
formatFunction: (level, logger, message, tags = void 0) => {
const _tags = tags !== void 0 ? `\xA77${tags.map((tag) => `[${tag}]`).join("")}\xA7r` : "";
return `[${level}][${ChatColor.MATERIAL_EMERALD}${logger.name}${ChatColor.RESET}]${_tags} ${message}`;
},
messagesJoinFunction: (messages) => {
return messages.join(" ");
},
jsonFormatter: ColorJSON.DEFAULT,
outputConfig: {
[LogLevel.Trace.level]: [0 /* Chat */, 1 /* ConsoleInfo */],
[LogLevel.Debug.level]: [0 /* Chat */, 1 /* ConsoleInfo */],
[LogLevel.Info.level]: [0 /* Chat */, 1 /* ConsoleInfo */],
[LogLevel.Warn.level]: [
0 /* Chat */,
1 /* ConsoleInfo */,
2 /* ConsoleWarn */
],
[LogLevel.Error.level]: [
0 /* Chat */,
1 /* ConsoleInfo */,
3 /* ConsoleError */
],
[LogLevel.Fatal.level]: [
0 /* Chat */,
1 /* ConsoleInfo */,
3 /* ConsoleError */
]
}
};
var Logger = class _Logger {
/**
* Construct a new Logger
*
* @param {string} name - The name of the Logger.
* @param {string[]} tags - The tags for the logger as strings.
*/
constructor(name, tags = []) {
this.name = name;
this.tags = tags;
}
static initialized = false;
/**
* Initialize logger class
*/
static init() {
LOGGING: {
if (_Logger.initialized)
return;
_Logger.initialized = true;
system.afterEvents.scriptEventReceive.subscribe((ev) => {
if (ev.id === "logging:level" || ev.id === "log:level") {
if (!ev.message) {
loggingSettings.level = LogLevel.Info;
world.sendMessage(
`${ChatColor.AQUA}Logging level set to ${ChatColor.BOLD}${loggingSettings.level}`
);
} else {
const level = LogLevel.parse(ev.message);
if (level) {
loggingSettings.level = level;
world.sendMessage(
`${ChatColor.AQUA}Logging level set to ${ChatColor.BOLD}${loggingSettings.level}`
);
} else {
world.sendMessage(
`${ChatColor.DARK_RED}Invalid logging level: ${ev.message}`
);
}
}
} else if (ev.id === "logging:filter" || ev.id === "log:filter") {
if (!ev.message) {
loggingSettings.filter = ["*"];
} else {
loggingSettings.filter = ev.message.split(",");
}
world.sendMessage(
`${ChatColor.AQUA}Logging filter set to ${ChatColor.BOLD}${loggingSettings.filter.join(", ")}`
);
}
});
}
}
/**
* @param {LogLevel} level - The level to set.
*/
static setLevel(level) {
loggingSettings.level = level;
}
/**
* Filter the loggers by the given tags. Tags can use the `*` wildcard.
* @param {'*' | string[]} filter - The filter to set.
*/
static setFilter(filter) {
loggingSettings.filter = filter;
}
/**
* Set the format function for the logger.
* @param {function} func - The function to set.
*/
static setFormatFunction(func) {
loggingSettings.formatFunction = func;
}
/**
* Set the function, that joins multiple messages into one for the logger.
* @param {function} func - The function to set.
*/
static setMessagesJoinFunction(func) {
loggingSettings.messagesJoinFunction = func;
}
/**
* Set the tag visibility for the logger. When true, tags will be printed in the log. Disabled by default.
* @param visible
*/
static setTagsOutputVisibility(visible) {
loggingSettings.outputTags = visible;
}
/**
* Set the JSON formatter for the logger.
* @param {ColorJSON} formatter - The json formatter to set.
*/
static setJsonFormatter(formatter) {
loggingSettings.jsonFormatter = formatter;
}
/**
* Get the output configuration for the logger.
* @returns {OutputConfig} The output configuration.
*/
static getOutputConfig() {
return loggingSettings.outputConfig;
}
/**
* Returns a new Logger.
*
* @param {string} name - The name of the Logger.
* @param {string[]} tags - The tags for the Logger as strings.
*
* @returns {Logger} A new Logger.
*/
static getLogger(name, ...tags) {
LOGGING: {
if (!_Logger.initialized) {
_Logger.init();
}
}
return new _Logger(name, tags);
}
/**
* Log messages with the level set.
*
* @param {LogLevel} level - The LogLevel to log the messages at.
* @param {array} message - An array of the messages to log.
*/
log(level, ...message) {
LOGGING: {
if (level.level < loggingSettings.level.level)
return;
if (loggingSettings.filter.length === 0 || this.tags.length === 0) {
this.logRaw(level, ...message);
return;
}
for (const filter of loggingSettings.filter) {
if (filter.startsWith("!")) {
if (starMatch(filter.substring(1), this.name) || this.tags.some((tag) => starMatch(filter.substring(1), tag))) {
return;
}
}
if (starMatch(filter, this.name) || this.tags.some((tag) => starMatch(filter, tag))) {
this.logRaw(level, ...message);
return;
}
}
}
}
stringifyError(x) {
let stack = x.stack ?? "";
if (sourceMapping) {
const stackLineRegex = /\(([^)]+\.js):(\d+)(?::(\d+))?\)/;
stack = stack.split("\n").map((line) => {
const match = stackLineRegex.exec(line);
if (match) {
const filePath = match[1];
const lineNumber = parseInt(match[2], 10) - sourceMapping.metadata.offset;
if (filePath.includes(sourceMapping.metadata.filePath)) {
const mappingEntry = globalSourceMapping[lineNumber];
if (mappingEntry) {
const replacement = `(${mappingEntry.source}:${mappingEntry.originalLine})`;
return line.replace(stackLineRegex, replacement);
}
}
}
return line;
}).join("\n");
}
return `${ChatColor.DARK_RED}${ChatColor.BOLD}${x.message}
${ChatColor.RESET}${ChatColor.GRAY}${ChatColor.ITALIC}${stack}${ChatColor.RESET}`;
}
/**
* Internal function to log messages with the level set, that bypasses the filters.
*
* @param {LogLevel} level - The LogLevel to log the messages at.
* @param {array} message - An array of the messages to log.
*/
logRaw(level, ...message) {
LOGGING: {
const msgs = message.map((x) => {
if (x === void 0) {
return ChatColor.GOLD + "undefined" + ChatColor.RESET;
}
if (x === null) {
return ChatColor.GOLD + "null" + ChatColor.RESET;
}
if (x && x instanceof Error) {
return this.stringifyError(x);
}
if (typeof x === "object" || Array.isArray(x)) {
return loggingSettings.jsonFormatter.stringify(x) + ChatColor.RESET;
}
return x.toString() + ChatColor.RESET;
});
const formatted = loggingSettings.formatFunction(
level,
this,
loggingSettings.messagesJoinFunction(msgs),
loggingSettings.outputTags ? this.tags : void 0
);
const outputs = loggingSettings.outputConfig[level.level] || [
0 /* Chat */,
1 /* ConsoleInfo */
];
if (outputs.includes(0 /* Chat */)) {
try {
world.sendMessage(formatted);
} catch (_) {
system.run(() => {
world.sendMessage(formatted);
});
}
}
if (outputs.includes(1 /* ConsoleInfo */)) {
if (console.originalLog) {
console.originalLog(ChatColor.stripColor(formatted));
} else {
console.log(ChatColor.stripColor(formatted));
}
}
if (outputs.includes(2 /* ConsoleWarn */)) {
console.warn(formatted);
}
if (outputs.includes(3 /* ConsoleError */)) {
console.error(formatted);
}
}
}
/**
* Logs a trace message.
*
* @param {...unknown} message - The message(s) to be logged.
*/
trace(...message) {
LOGGING:
this.log(LogLevel.Trace, ...message);
}
/**
* Logs debug message.
*
* @param {...unknown[]} message - The message(s) to be logged.
*/
debug(...message) {
LOGGING:
this.log(LogLevel.Debug, ...message);
}
/**
* Logs an informational message.
*
* @param {...unknown[]} message - The message(s) to be logged.
*/
info(...message) {
LOGGING:
this.log(LogLevel.Info, ...message);
}
/**
* Logs a warning message.
*
* @param {...unknown[]} message - The warning message or messages to be logged.
*/
warn(...message) {
LOGGING:
this.log(LogLevel.Warn, ...message);
}
/**
* Logs an error message.
*
* @param {...unknown[]} message - The error message(s) to log.
*/
error(...message) {
LOGGING:
this.log(LogLevel.Error, ...message);
}
/**
* Logs a fatal error.
*
* @param {unknown[]} message - The error message to log.
*/
fatal(...message) {
LOGGING:
this.log(LogLevel.Fatal, ...message);
}
};
// src/Vec3.ts
var Vec3 = class _Vec3 {
static log = Logger.getLogger(
"vec3",
"vec3",
"bedrock-boost"
);
/**
* Zero vector
*/
static Zero = new _Vec3(0, 0, 0);
/**
* Down vector, negative towards Y
*/
static Down = new _Vec3(Direction.Down);
/**
* Up vector, positive towards Y
*/
static Up = new _Vec3(Direction.Up);
/**
* North vector, negative towards Z
*/
static North = new _Vec3(Direction.North);
/**
* South vector, positive towards Z
*/
static South = new _Vec3(Direction.South);
/**
* East vector, positive towards X
*/
static East = new _Vec3(Direction.East);
/**
* West vector, negative towards X
*/
static West = new _Vec3(Direction.West);
x;
y;
z;
constructor(x, y, z) {
if (x === Direction.Down) {
this.x = 0;
this.y = -1;
this.z = 0;
} else if (x === Direction.Up) {
this.x = 0;
this.y = 1;
this.z = 0;
} else if (x === Direction.North) {
this.x = 0;
this.y = 0;
this.z = -1;
} else if (x === Direction.South) {
this.x = 0;
this.y = 0;
this.z = 1;
} else if (x === Direction.East) {
this.x = 1;
this.y = 0;
this.z = 0;
} else if (x === Direction.West) {
this.x = -1;
this.y = 0;
this.z = 0;
} else if (typeof x === "number") {
this.x = x;
this.y = y;
this.z = z;
} else if (Array.isArray(x)) {
this.x = x[0];
this.y = x[1];
this.z = x[2];
} else if (x instanceof _Vec3) {
this.x = x.x;
this.y = x.y;
this.z = x.z;
} else {
if (!x || !x.x && x.x !== 0 || !x.y && x.y !== 0 || !x.z && x.z !== 0) {
_Vec3.log.error(new Error("Invalid vector"), x);
throw new Error("Invalid vector");
}
this.x = x.x;
this.y = x.y;
this.z = x.z;
}
}
static from(x, y, z) {
if (x instanceof _Vec3)
return x;
if (typeof x === "number" && y !== void 0 && z !== void 0) {
return new _Vec3(x, y, z);
}
if (Array.isArray(x)) {
return new _Vec3(x);
}
if (x === Direction.Down)
return _Vec3.Down;
if (x === Direction.Up)
return _Vec3.Up;
if (x === Direction.North)
return _Vec3.North;
if (x === Direction.South)
return _Vec3.South;
if (x === Direction.East)
return _Vec3.East;
if (x === Direction.West)
return _Vec3.West;
if (!x || !x.x && x.x !== 0 || !x.y && x.y !== 0 || !x.z && x.z !== 0) {
_Vec3.log.error(new Error("Invalid arguments"), x, y, z);
throw new Error("Invalid arguments");
}
return new _Vec3(
x.x,
x.y,
x.z
);
}
static _from(x, y, z) {
if (x instanceof _Vec3)
return x;
if (typeof x === "number" && y !== void 0 && z !== void 0) {
return new _Vec3(x, y, z);
}
if (Array.isArray(x)) {
return new _Vec3(x);
}
if (x === Direction.Down)
return _Vec3.Down;
if (x === Direction.Up)
return _Vec3.Up;
if (x === Direction.North)
return _Vec3.North;
if (x === Direction.South)
return _Vec3.South;
if (x === Direction.East)
return _Vec3.East;
if (x === Direction.West)
return _Vec3.West;
if (!x || !x.x && x.x !== 0 || !x.y && x.y !== 0 || !x.z && x.z !== 0) {
_Vec3.log.error(new Error("Invalid arguments"), x, y, z);
throw new Error("Invalid arguments");
}
return new _Vec3(
x.x,
x.y,
x.z
);
}
/**
* Creates a copy of the current vector.
*
* @returns A new vector with the same values as the current vector.
*/
copy() {
return new _Vec3(this.x, this.y, this.z);
}
static fromYawPitch(yawOrRotation, pitch) {
let yaw;
if (typeof yawOrRotation === "number") {
yaw = yawOrRotation;
pitch = pitch;
} else {
yaw = yawOrRotation.y;
pitch = yawOrRotation.x;
}
const psi = yaw * (Math.PI / 180);
const theta = pitch * (Math.PI / 180);
const x = Math.cos(theta) * Math.sin(psi);
const y = Math.sin(theta);
const z = Math.cos(theta) * Math.cos(psi);
return new _Vec3(x, y, z);
}
static fromRotation(yawOrRotation, pitch) {
let yaw;
if (typeof yawOrRotation === "number") {
yaw = yawOrRotation;
pitch = pitch;
} else {
yaw = yawOrRotation.y;
pitch = yawOrRotation.x;
}
const psi = yaw * (Math.PI / 180);
const theta = pitch * (Math.PI / 180);
const x = -Math.cos(theta) * Math.sin(psi);
const y = -Math.sin(theta);
const z = Math.cos(theta) * Math.cos(psi);
return new _Vec3(x, y, z);
}
/**
* Converts the normal vector to yaw and pitch values.
*
* @returns A Vector2 containing the yaw and pitch values.
* @deprecated Use toRotation() instead. This method returns inverted values and will be removed in the future.
*/
toYawPitch() {
if (this.isZero()) {
_Vec3.log.error(
new Error("Cannot convert zero-length vector to direction")
);
throw new Error("Cannot convert zero-length vector to direction");
}
const direction = this.normalize();
const yaw = Math.atan2(direction.x, direction.z) * (180 / Math.PI);
const pitch = Math.asin(direction.y) * (180 / Math.PI);
return {
x: pitch,
y: yaw
};
}
/**
* Converts the normal vector to yaw and pitch values.
*
* @returns A Vector2 containing the yaw and pitch values.
*/
toRotation() {
if (this.isZero()) {
_Vec3.log.error(
new Error("Cannot convert zero-length vector to direction")
);
throw new Error("Cannot convert zero-length vector to direction");
}
const direction = this.normalize();
const yaw = -Math.atan2(direction.x, direction.z) * (180 / Math.PI);
const pitch = Math.asin(-direction.y) * (180 / Math.PI);
return {
x: pitch,
y: yaw
};
}
add(x, y, z) {
const v = _Vec3._from(x, y, z);
return _Vec3.from(v.x + this.x, v.y + this.y, v.z + this.z);
}
subtract(x, y, z) {
const v = _Vec3._from(x, y, z);
return _Vec3.from(this.x - v.x, this.y - v.y, this.z - v.z);
}
multiply(x, y, z) {
if (typeof x === "number" && y === void 0 && z === void 0) {
return _Vec3.from(this.x * x, this.y * x, this.z * x);
}
const v = _Vec3._from(x, y, z);
return _Vec3.from(v.x * this.x, v.y * this.y, v.z * this.z);
}
/**
* Scales the current vector by a scalar.
*
* @param scalar - The scalar to scale the vector by.
* @returns The updated vector after scaling.
*/
scale(scalar) {
return _Vec3.from(this.x * scalar, this.y * scalar, this.z * scalar);
}
divide(x, y, z) {
if (typeof x === "number" && y === void 0 && z === void 0) {
if (x === 0)
throw new Error("Cannot divide by zero");
return _Vec3.from(this.x / x, this.y / x, this.z / x);
}
const v = _Vec3._from(x, y, z);
if (v.x === 0 || v.y === 0 || v.z === 0)
throw new Error("Cannot divide by zero");
return _Vec3.from(this.x / v.x, this.y / v.y, this.z / v.z);
}
/**
* Normalizes the vector to have a length (magnitude) of 1.
* Normalized vectors are often used as a direction vectors.
*
* @returns The normalized vector.
*/
normalize() {
if (this.isZero()) {
_Vec3.log.error(new Error("Cannot normalize zero-length vector"));
throw new Error("Cannot normalize zero-length vector");
}
const len = this.length();
return _Vec3.from(this.x / len, this.y / len, this.z / len);
}
/**
* Computes the length (magnitude) of the vector.
*
* @returns The length of the vector.
*/
length() {
return Math.hypot(this.x, this.y, this.z);
}
/**
* Computes the squared length of the vector.
* This is faster than computing the actual length and can be useful for comparison purposes.
*
* @returns The squared length of the vector.
*/
lengthSquared() {
return this.x * this.x + this.y * this.y + this.z * this.z;
}
cross(x, y, z) {
const v = _Vec3._from(x, y, z);
return _Vec3.from(
this.y * v.z - this.z * v.y,
this.z * v.x - this.x * v.z,
this.x * v.y - this.y * v.x
);
}
distance(x, y, z) {
const v = _Vec3._from(x, y, z);
return this.subtract(v).length();
}
distanceSquared(x, y, z) {
const v = _Vec3._from(x, y, z);
return this.subtract(v).lengthSquared();
}
/**
* Computes the linear interpolation between the current vector and another vector, when t is in the range [0, 1].
* Computes the extrapolation when t is outside this range.
*
* @param v - The other vector.
* @param t - The interpolation factor.
* @returns A new vector after performing the lerp operation.
*/
lerp(v, t) {
if (!v || !t)
return _Vec3.from(this);
if (t === 1)
return _Vec3.from(v);
if (t === 0)
return _Vec3.from(this);
return _Vec3.from(
this.x + (v.x - this.x) * t,
this.y + (v.y - this.y) * t,
this.z + (v.z - this.z) * t
);
}
/**
* Computes the spherical linear interpolation between the current vector and another vector, when t is in the range [0, 1].
* Computes the extrapolation when t is outside this range.
*
* @param v - The other vector.
* @param t - The interpolation factor.
* @returns A new vector after performing the slerp operation.
*/
slerp(v, t) {
if (!v || !t)
return _Vec3.from(this);
if (t === 1)
return _Vec3.from(v);
if (t === 0)
return _Vec3.from(this);
const dot = this.dot(v);
const theta = Math.acos(dot) * t;
const relative = _Vec3.from(v).subtract(this.multiply(dot)).normalize();
return this.multiply(Math.cos(theta)).add(
relative.multiply(Math.sin(theta))
);
}
dot(x, y, z) {
const v = _Vec3._from(x, y, z);
return this.x * v.x + this.y * v.y + this.z * v.z;
}
angleBetween(x, y, z) {
const v = _Vec3._from(x, y, z);
const dotProduct = this.dot(v);
const lenSq1 = this.lengthSquared();
if (lenSq1 === 0) {
return 0;
}
const lenSq2 = v.lengthSquared();
if (lenSq2 === 0) {
return 0;
}
const denom = Math.sqrt(lenSq1 * lenSq2);
const cosAngle = Math.min(1, Math.max(-1, dotProduct / denom));
return Math.acos(cosAngle);
}
projectOnto(x, y, z) {
const v = _Vec3._from(x, y, z);
if (v.isZero()) {
return _Vec3.Zero;
}
const denom = v.dot(v);
if (denom === 0) {
return _Vec3.Zero;
}
const scale = this.dot(v) / denom;
return _Vec3.from(v.x * scale, v.y * scale, v.z * scale);
}
reflect(x, y, z) {
const normal = _Vec3._from(x, y, z);
const proj = this.projectOnto(normal);
return this.subtract(proj.multiply(2));
}
/**
* Rotates the current normalized vector by a given angle around a given axis.
*
* @param axis - The axis of rotation.
* @param angle - The angle of rotation in degrees.
* @returns The rotated vector.
*/
rotate(axis, angle) {
const halfAngle = angle * Math.PI / 180 / 2;
const w = Math.cos(halfAngle);
const x = axis.x * Math.sin(halfAngle);
const y = axis.y * Math.sin(halfAngle);
const z = axis.z * Math.sin(halfAngle);
const v = this;
const qv_x = w * w * v.x + 2 * y * w * v.z - 2 * z * w * v.y + x * x * v.x + 2 * y * x * v.y + 2 * z * x * v.z - z * z * v.x - y * y * v.x;
const qv_y = 2 * x * y * v.x + y * y * v.y + 2 * z * y * v.z + 2 * w * z * v.x - z * z * v.y + w * w * v.y - 2 * x * w * v.z - x * x * v.y;
const qv_z = 2 * x * z * v.x + 2 * y * z * v.y + z * z * v.z - 2 * w * y * v.x - y * y * v.z + 2 * w * x * v.y - x * x * v.z + w * w * v.z;
return new _Vec3(qv_x, qv_y, qv_z);
}
/**
* Updates the X, Y, and Z components of the vector.
*
* @param x - The function to use to update the X value.
* @param y - The function to use to update the Y value.
* @param z - The function to use to update the Z value.
* @returns The updated vector with the new values.
*/
update(x, y, z) {
if (!x) {
x = (value) => value;
}
if (!y) {
y = (value) => value;
}
if (!z) {
z = (value) => value;
}
return new _Vec3(x(this.x), y(this.y), z(this.z));
}
setX(value) {
if (typeof value === "number") {
return new _Vec3(value, this.y, this.z);
}
return new _Vec3(value(this.x), this.y, this.z);
}
setY(value) {
if (typeof value === "number") {
return new _Vec3(this.x, value, this.z);
}
return new _Vec3(this.x, value(this.y), this.z);
}
setZ(value) {
if (typeof value === "number") {
return new _Vec3(this.x, this.y, value);
}
return new _Vec3(this.x, this.y, value(this.z));
}
/**
* Calculates the shortest distance between a point (represented by this Vector3 instance) and a line segment.
*
* This method finds the perpendicular projection of the point onto the line defined by the segment. If this
* projection lies outside the line segment, then the method calculates the distance from the point to the
* nearest segment endpoint.
*
* @param start - The starting point of the line segment.
* @param end - The ending point of the line segment.
* @returns The shortest distance between the point and the line segment.
*/
distanceToLineSegment(start, end) {
const lineDirection = _Vec3.from(end).subtract(start);
if (lineDirection.lengthSquared() === 0) {
return this.subtract(start).length();
}
const t = Math.max(
0,
Math.min(
1,
this.subtract(start).dot(lineDirection) / lineDirection.dot(lineDirection)
)
);
const projection = _Vec3.from(start).add(lineDirection.multiply(t));
return this.subtract(projection).length();
}
/**
* Floors the X, Y, and Z components of the vector.
* @returns A new vector with the floored components.
*/
floor() {
return this.update(Math.floor, Math.floor, Math.floor);
}
/**
* Floors the X component of the vector.
* @returns A new vector with the floored X component.
*/
floorX() {
return this.setX(Math.floor);
}
/**
* Floors the Y component of the vector.
* @returns A new vector with the floored Y component.
*/
floorY() {
return this.setY(Math.floor);
}
/**
* Floors the Z component of the vector.
* @returns A new vector with the floored Z component.
*/
floorZ() {
return this.setZ(Math.floor);
}
/**
* Ceils the X, Y, and Z components of the vector.
* @returns A new vector with the ceiled components.
*/
ceil() {
return new _Vec3(Math.ceil(this.x), Math.ceil(this.y), Math.ceil(this.z));
}
/**
* Ceils the X component of the vector.
* @returns A new vector with the ceiled X component.
*/
ceilX() {
return this.setX(Math.ceil);
}
/**
* Ceils the Y component of the vector.
* @returns A new vector with the ceiled Y component.
*/
ceilY() {
return this.setY(Math.ceil);
}
/**
* Ceils the Z component of the vector.
* @returns A new vector with the ceiled Z component.
*/
ceilZ() {
return this.setZ(Math.ceil);
}
/**
* Rounds the X, Y, and Z components of the vector.
* @returns A new vector with the rounded components.
*/
round() {
return this.update(Math.round, Math.round, Math.round);
}
/**
* Rounds the X component of the vector.
* @returns A new vector with the rounded X component.
*/
roundX() {
return this.setX(Math.round);
}
/**
* Rounds the Y component of the vector.
* @returns A new vector with the rounded Y component.
*/
roundY() {
return this.setY(Math.round);
}
/**
* Rounds the Z component of the vector.
* @returns A new vector with the rounded Z component.
*/
roundZ() {
return this.setZ(Math.round);
}
/**
* Returns a new vector offset from the current vector up by 1 block.
* @returns A new vector offset from the current vector up by 1 block.
*/
up() {
return this.add(_Vec3.Up);
}
/**
* Returns a new vector offset from the current vector down by 1 block.
* @returns A new vector offset from the current vector down by 1 block.
*/
down() {
return this.add(_Vec3.Down);
}
/**
* Returns a new vector offset from the current vector north by 1 block.
* @returns A new vector offset from the current vector north by 1 block.
*/
north() {
return this.add(_Vec3.North);
}
/**
* Returns a new vector offset from the current vector south by 1 block.
* @returns A new vector offset from the current vector south by 1 block.
*/
south() {
return this.add(_Vec3.South);
}
/**
* Returns a new vector offset from the current vector east by 1 block.
* @returns A new vector offset from the current vector east by 1 block.
*/
east() {
return this.add(_Vec3.East);
}
/**
* Returns a new vector offset from the current vector west by 1 block.
* @returns A new vector offset from the current vector west by 1 block.
*/
west() {
return this.add(_Vec3.West);
}
/**
* Checks if the current vector is equal to the zero vector.
* @returns true if the vector is equal to the zero vector, else returns false.
*/
isZero() {
return this.x === 0 && this.y === 0 && this.z === 0;
}
/**
* Converts the vector to an array containing the X, Y, and Z components of the vector.
* @returns An array containing the X, Y, and Z components of the vector.
*/
toArray() {
return [this.x, this.y, this.z];
}
/**
* Converts the vector to a direction.
* If the vector is not a unit vector, then it will be normalized and rounded to the nearest direction.
*/
toDirection() {
if (this.isZero()) {
_Vec3.log.error(
new Error("Cannot convert zero-length vector to direction")
);
throw new Error("Cannot convert zero-length vector to direction");
}
const normalized = this.normalize();
const maxValue = Math.max(
Math.abs(normalized.x),
Math.abs(normalized.y),
Math.abs(normalized.z)
);
if (maxValue === normalized.x)
return Direction.East;
if (maxValue === -normalized.x)
return Direction.West;
if (maxValue === normalized.y)
return Direction.Up;
if (maxValue === -normalized.y)
return Direction.Down;
if (maxValue === normalized.z)
return Direction.South;
if (maxValue === -normalized.z)
return Direction.North;
_Vec3.log.error(new Error("Cannot convert vector to direction"), this);
throw new Error("Cannot convert vector to direction");
}
/**
* Returns a new vector with the X, Y, and Z components rounded to the nearest block location.
*/
toBlockLocation() {
return _Vec3.from(
(this.x << 0) - (this.x < 0 && this.x !== this.x << 0 ? 1 : 0),
(this.y << 0) - (this.y < 0 && this.y !== this.y << 0 ? 1 : 0),
(this.z << 0) - (this.z < 0 && this.z !== this.z << 0 ? 1 : 0)
);
}
almostEqual(x, y, z, delta) {
try {
let other;
if (typeof x !== "number" && z === void 0) {
other = _Vec3._from(x, void 0, void 0);
delta = y;
} else {
other = _Vec3._from(x, y, z);
}
return Math.abs(this.x - other.x) <= delta && Math.abs(this.y - other.y) <= delta && Math.abs(this.z - other.z) <= delta;
} catch (e) {
return false;
}
}
equals(x, y, z) {
try {
const other = _Vec3._from(x, y, z);
return this.x === other.x && this.y === other.y && this.z === other.z;
} catch (e) {
return false;
}
}
/**
* Converts the vector to a string representation.
*
* @param format - The format of the string representation. Defaults to "long".
* @param separator - The separator to use between components. Defaults to ", ".
* @returns The string representation of the vector.
* @remarks
* The "long" format is "Vec3(x, y, z)".
* The "short" format is "x, y, z".
*/
toString(format = "long", separator = ", ") {
const result = `${this.x + separator + this.y + separator + this.z}`;
return format === "long" ? `Vec3(${result})`