From 2d9988da23d0ab19090d5ade5eaa1fefa10eb3da Mon Sep 17 00:00:00 2001 From: Jayly <65847850+JaylyDev@users.noreply.github.com> Date: Mon, 18 Dec 2023 18:08:57 +0800 Subject: [PATCH] Scripts Update: 18/12/2023 (#336) * Content Update * remove internal .d.ts file * add header * Update README.md * Update index.ts * Update README.md --- scripts/anti-32k-event/index.js | 66 ++++--- scripts/anti-32k-event/index.ts | 79 ++++++++ scripts/anti-32k/index.js | 48 +++-- scripts/anti-32k/index.ts | 43 ++++ scripts/chat-rank/chat-rank.js | 27 +-- scripts/chat-ranks/index.js | 5 +- scripts/chat-ranks/index.ts | 8 +- scripts/entity-death-event/index.js | 4 - scripts/events-log/index.js | 54 ------ scripts/force-show/index.js | 29 +-- scripts/force-show/index.ts | 30 +++ scripts/force-show/tests.js | 4 +- scripts/get-item-amount/index.js | 4 - scripts/minecraft-language/index.js | 3 - scripts/minecraft-language/tests.js | 17 -- scripts/offline-player/README.md | 175 +++++++++++++++++ scripts/offline-player/index.js | 138 +++++++++++++ scripts/offline-player/index.ts | 259 +++++++++++++++++++++++++ scripts/vector3-polyfill/README.md | 2 +- scripts/vector3-polyfill/Vector.js | 24 +-- scripts/vector3-polyfill/Vector3.js | 144 ++++++++------ scripts/vector3-polyfill/Vector3.ts | 37 +++- scripts/vector3-polyfill/tsconfig.json | 1 + 23 files changed, 945 insertions(+), 256 deletions(-) create mode 100644 scripts/anti-32k-event/index.ts create mode 100644 scripts/anti-32k/index.ts create mode 100644 scripts/force-show/index.ts delete mode 100644 scripts/minecraft-language/tests.js create mode 100644 scripts/offline-player/README.md create mode 100644 scripts/offline-player/index.js create mode 100644 scripts/offline-player/index.ts diff --git a/scripts/anti-32k-event/index.js b/scripts/anti-32k-event/index.js index dc7a4680..948c8ddb 100644 --- a/scripts/anti-32k-event/index.js +++ b/scripts/anti-32k-event/index.js @@ -1,56 +1,52 @@ // Script example for ScriptAPI // Author: JaylyMC // Project: https://github.com/JaylyDev/ScriptAPI - -import { Enchantment, Entity, EntityInventoryComponent, ItemEnchantsComponent, ItemStack, system, TicksPerSecond, world } from '@minecraft/server'; -const tickInterval = TicksPerSecond; +import { EntityInventoryComponent, ItemEnchantableComponent, system, TicksPerSecond, world } from '@minecraft/server'; +/** + * Represents an event indicating incompatible enchantments on an item. + */ class IncompatibleEnchantmentAlertEvent { + /** + * Creates a new instance of IncompatibleEnchantmentAlertEvent. + * @param {boolean} exceedMaxLevel - Indicates whether the enchantment exceeds its maximum level. + * @param {boolean} incompatibleEnchantmentType - Indicates whether the enchantment type is incompatible. + * @param {Enchantment} enchantment - The enchantment causing the alert. + * @param {ItemStack} item - The item with the incompatible enchantment. + * @param {Entity} source - The entity triggering the alert. + */ constructor(exceedMaxLevel, incompatibleEnchantmentType, enchantment, item, source) { - /** - * @type {boolean} - */ this.exceedMaxLevel = exceedMaxLevel; - /** - * @type {boolean} - */ this.incompatibleEnchantmentType = incompatibleEnchantmentType; - /** - * @type {Enchantment} - */ this.enchantment = enchantment; - /** - * @type {ItemStack} - */ this.item = item; - /** - * @type {Entity} - */ this.source = source; } ; } ; +/** + * Signal class for subscribing to events related to incompatible enchantments. + */ class IncompatibleEnchantmentAlertEventSignal { /** - * @param {(arg0: IncompatibleEnchantmentAlertEvent) => void} callback - */ + * Subscribes to the incompatible enchantment alert event and specifies a callback function. + * @param {(arg0: IncompatibleEnchantmentAlertEvent) => void} callback - The callback function to be invoked when an alert occurs. + * Accepts a single parameter of type IncompatibleEnchantmentAlertEvent. + * @returns {number} - An identifier for the subscription, which can be used for unsubscribing. + */ subscribe(callback) { return system.runInterval(function () { for (const player of world.getAllPlayers()) { - /** - * @type {EntityInventoryComponent} - */ - // @ts-ignore const inventory = player.getComponent(EntityInventoryComponent.componentId); for (let index = 0; index < inventory.container.size; index++) { const item = inventory.container.getItem(index); - /** @type {ItemEnchantsComponent} */ - // @ts-ignore - const enchantments = item === null || item === void 0 ? void 0 : item.getComponent(ItemEnchantsComponent.componentId); - if (!item || !enchantments) + if (!item) continue; - for (const enchantment of enchantments.enchantments) { - const enchantmentIsIncompatible = enchantments.enchantments.canAddEnchantment(new Enchantment(enchantment.type)) === false; + const enchantable = item.getComponent(ItemEnchantableComponent.componentId); + for (const enchantment of enchantable.getEnchantments()) { + const enchantmentIsIncompatible = enchantable.canAddEnchantment(enchantment) === false; + if (typeof enchantment.type !== 'object') + continue; const enchantmentExcceedsMaxLevel = enchantment.level > enchantment.type.maxLevel; if (!enchantmentIsIncompatible && !enchantmentExcceedsMaxLevel) continue; @@ -58,13 +54,21 @@ class IncompatibleEnchantmentAlertEventSignal { } } } - }, tickInterval); + }, TicksPerSecond); } ; + /** + * Unsubscribes from the incompatible enchantment alert event using the provided subscription identifier. + * @param {number} id - The identifier of the subscription to be removed. + */ unsubscribe(id) { system.clearRun(id); } ; } ; +/** + * Global instance of IncompatibleEnchantmentAlertEventSignal for easy access and usage. + * @type {IncompatibleEnchantmentAlertEventSignal} + */ export const incompatibleEnchantment = new IncompatibleEnchantmentAlertEventSignal(); diff --git a/scripts/anti-32k-event/index.ts b/scripts/anti-32k-event/index.ts new file mode 100644 index 00000000..5b5854a6 --- /dev/null +++ b/scripts/anti-32k-event/index.ts @@ -0,0 +1,79 @@ +// Script example for ScriptAPI +// Author: JaylyMC +// Project: https://github.com/JaylyDev/ScriptAPI + +import { Enchantment, Entity, EntityInventoryComponent, ItemEnchantableComponent, ItemStack, system, TicksPerSecond, world } from '@minecraft/server'; + +/** + * Represents an event indicating incompatible enchantments on an item. + */ +class IncompatibleEnchantmentAlertEvent { + exceedMaxLevel: boolean; + incompatibleEnchantmentType: boolean; + enchantment: Enchantment; + item: ItemStack; + source: Entity; + /** + * Creates a new instance of IncompatibleEnchantmentAlertEvent. + * @param {boolean} exceedMaxLevel - Indicates whether the enchantment exceeds its maximum level. + * @param {boolean} incompatibleEnchantmentType - Indicates whether the enchantment type is incompatible. + * @param {Enchantment} enchantment - The enchantment causing the alert. + * @param {ItemStack} item - The item with the incompatible enchantment. + * @param {Entity} source - The entity triggering the alert. + */ + constructor(exceedMaxLevel: boolean, incompatibleEnchantmentType: boolean, enchantment: Enchantment, item: ItemStack, source: Entity) { + this.exceedMaxLevel = exceedMaxLevel; + this.incompatibleEnchantmentType = incompatibleEnchantmentType; + this.enchantment = enchantment; + this.item = item; + this.source = source; + }; +}; + +/** + * Signal class for subscribing to events related to incompatible enchantments. + */ +class IncompatibleEnchantmentAlertEventSignal { + /** + * Subscribes to the incompatible enchantment alert event and specifies a callback function. + * @param {(arg0: IncompatibleEnchantmentAlertEvent) => void} callback - The callback function to be invoked when an alert occurs. + * Accepts a single parameter of type IncompatibleEnchantmentAlertEvent. + * @returns {number} - An identifier for the subscription, which can be used for unsubscribing. + */ + subscribe(callback: (arg0: IncompatibleEnchantmentAlertEvent) => void): number { + return system.runInterval(function () { + for (const player of world.getAllPlayers()) { + const inventory = player.getComponent(EntityInventoryComponent.componentId); + for (let index = 0; index < inventory.container.size; index++) { + const item = inventory.container.getItem(index); + if (!item) continue; + + const enchantable = item.getComponent(ItemEnchantableComponent.componentId); + + for (const enchantment of enchantable.getEnchantments()) { + const enchantmentIsIncompatible = enchantable.canAddEnchantment(enchantment) === false; + if (typeof enchantment.type !== 'object') continue; + const enchantmentExcceedsMaxLevel = enchantment.level > enchantment.type.maxLevel; + if (!enchantmentIsIncompatible && !enchantmentExcceedsMaxLevel) + continue; + callback(new IncompatibleEnchantmentAlertEvent(enchantmentExcceedsMaxLevel, enchantmentIsIncompatible, enchantment, item, player)); + } + } + } + }, TicksPerSecond); + }; + + /** + * Unsubscribes from the incompatible enchantment alert event using the provided subscription identifier. + * @param {number} id - The identifier of the subscription to be removed. + */ + unsubscribe(id: number) { + system.clearRun(id); + }; +}; + +/** + * Global instance of IncompatibleEnchantmentAlertEventSignal for easy access and usage. + * @type {IncompatibleEnchantmentAlertEventSignal} + */ +export const incompatibleEnchantment: IncompatibleEnchantmentAlertEventSignal = new IncompatibleEnchantmentAlertEventSignal(); \ No newline at end of file diff --git a/scripts/anti-32k/index.js b/scripts/anti-32k/index.js index 899790da..573f0ae3 100644 --- a/scripts/anti-32k/index.js +++ b/scripts/anti-32k/index.js @@ -3,7 +3,6 @@ // JaylyMC // Remember M9 // Project: https://github.com/JaylyDev/ScriptAPI - /** * Minecraft Bedrock Anti Hacked Items * @license MIT @@ -16,32 +15,29 @@ * -------------------------------------------------------------------------- */ import * as mc from "@minecraft/server"; - const { world, system } = mc; - function onTick() { - for (const player of world.getPlayers()) { - /** @type {mc.EntityInventoryComponent} */ - // @ts-ignore - const inventory = player.getComponent("minecraft:inventory"); - const { container, inventorySize } = inventory; - if (container.emptySlotsCount == inventorySize) continue; - for (let slot = 0; slot < inventorySize; slot++) { - const item = container.getItem(slot); - if (!item) continue; - /** @type {mc.ItemEnchantsComponent} */ - // @ts-ignore - const enchants = item.getComponent("enchantments"); - const enchantments = enchants.enchantments; - const newEnchants = new mc.EnchantmentList(enchantments.slot); - for (let enchant of enchantments) { - if (newEnchants.addEnchantment(enchant)) continue; - container.setItem(slot); - break; - } + for (const player of world.getPlayers()) { + /** @type {mc.EntityInventoryComponent} */ + // @ts-ignore + const inventory = player.getComponent("minecraft:inventory"); + const { container, inventorySize } = inventory; + if (container.emptySlotsCount == inventorySize) + continue; + for (let slot = 0; slot < inventorySize; slot++) { + const item = container.getItem(slot); + if (!item) + continue; + const enchantable = item.getComponent("minecraft:enchantable"); + if (!enchantable) + continue; + for (const enchantment of enchantable.getEnchantments()) { + if (enchantable.canAddEnchantment(enchantment)) + continue; + enchantable.removeEnchantment(enchantment.type); + } + } } - } -}; - - +} +; system.runInterval(onTick); diff --git a/scripts/anti-32k/index.ts b/scripts/anti-32k/index.ts new file mode 100644 index 00000000..3641b325 --- /dev/null +++ b/scripts/anti-32k/index.ts @@ -0,0 +1,43 @@ +// Script example for ScriptAPI +// Author: Smell of curry +// JaylyMC +// Remember M9 +// Project: https://github.com/JaylyDev/ScriptAPI + +/** + * Minecraft Bedrock Anti Hacked Items + * @license MIT + * @author Smell of curry & JaylyMC + * @version 1.1.0 + * -------------------------------------------------------------------------- + * This is a anti hacked items, meaning it checks a players inventory every + * tick then it tests if they have any banned items, then checks if they have + * items that have hacked enchants and clears the item from inventory + * -------------------------------------------------------------------------- + */ +import * as mc from "@minecraft/server"; + +const { world, system } = mc; + +function onTick() { + for (const player of world.getPlayers()) { + /** @type {mc.EntityInventoryComponent} */ + // @ts-ignore + const inventory = player.getComponent("minecraft:inventory"); + const { container, inventorySize } = inventory; + if (container.emptySlotsCount == inventorySize) continue; + for (let slot = 0; slot < inventorySize; slot++) { + const item = container.getItem(slot); + if (!item) continue; + const enchantable = item.getComponent("minecraft:enchantable"); + if (!enchantable) continue; + for (const enchantment of enchantable.getEnchantments()) { + if (enchantable.canAddEnchantment(enchantment)) continue; + enchantable.removeEnchantment(enchantment.type); + } + } + } +}; + + +system.runInterval(onTick); diff --git a/scripts/chat-rank/chat-rank.js b/scripts/chat-rank/chat-rank.js index c69b43f2..0ab38782 100644 --- a/scripts/chat-rank/chat-rank.js +++ b/scripts/chat-rank/chat-rank.js @@ -1,14 +1,19 @@ import { world } from "@minecraft/server"; world.beforeEvents.chatSend.subscribe((data) => { - data.sendToTargets = true - data.setTargets([]) -}) - -world.afterEvents.chatSend.subscribe((data) => { - try { - data.sender.runCommandAsync(`tellraw @a ${JSON.stringify({rawtext:[{text: "§l§8[§r" + ((data.sender.getTags().find(tag => tag.startsWith("rank:"))?.substring(5)?.replaceAll("--", "§r§l§8][§r")) ?? "§bMember") + `§l§8]§r §7${data.sender.nameTag}:§r ${data.message}`}]})}`) - } catch (error) { - return console.warn(`${error}, ${error.stack}`); - } -});  + world.sendMessage({ + rawtext: [ + { + text: + "§l§8[§r" + + (data.sender + .getTags() + .find((tag) => tag.startsWith("rank:")) + ?.substring(5) + ?.replaceAll("--", "§r§l§8][§r") ?? "§bMember") + + `§l§8]§r §7${data.sender.nameTag}:§r ${data.message}`, + }, + ], + }); + data.cancel = true; +}); diff --git a/scripts/chat-ranks/index.js b/scripts/chat-ranks/index.js index 7ed03503..80c244f9 100644 --- a/scripts/chat-ranks/index.js +++ b/scripts/chat-ranks/index.js @@ -28,11 +28,8 @@ function getRanks(player) { return ranks.length == 0 ? [DEFAULT_RANK] : ranks; } world.beforeEvents.chatSend.subscribe((data) => { - data.sendToTargets = true; - data.setTargets([]); -}); -world.afterEvents.chatSend.subscribe((data) => { const ranks = getRanks(data.sender).join("§r§l§8][§r"); const message = data.message; world.sendMessage(`§r§l§8[§r${ranks}§r§l§8]§r§7 ${data.sender.name}:§r ${message}`); + data.cancel = true; }); diff --git a/scripts/chat-ranks/index.ts b/scripts/chat-ranks/index.ts index cbff5656..fa3e18c4 100644 --- a/scripts/chat-ranks/index.ts +++ b/scripts/chat-ranks/index.ts @@ -31,12 +31,8 @@ function getRanks(player: Player): string[] { } world.beforeEvents.chatSend.subscribe((data) => { - data.sendToTargets = true; - data.setTargets([]); -}); - -world.afterEvents.chatSend.subscribe((data) => { const ranks = getRanks(data.sender).join("§r§l§8][§r"); const message = data.message; world.sendMessage(`§r§l§8[§r${ranks}§r§l§8]§r§7 ${data.sender.name}:§r ${message}`); -}); \ No newline at end of file + data.cancel = true; +}); diff --git a/scripts/entity-death-event/index.js b/scripts/entity-death-event/index.js index 046537e6..7f2fd658 100644 --- a/scripts/entity-death-event/index.js +++ b/scripts/entity-death-event/index.js @@ -17,13 +17,9 @@ const callbacks = []; // backend world.afterEvents.entityHurt.subscribe((event) => { const { hurtEntity } = event; - if (!hurtEntity) return; - /** @type {EntityHealthComponent} */ - // @ts-expect-error const health = hurtEntity.getComponent(EntityHealthComponent.componentId); - if (health.currentValue > 0) return; for (const callback of callbacks) { diff --git a/scripts/events-log/index.js b/scripts/events-log/index.js index d59c8fd5..8440f57e 100644 --- a/scripts/events-log/index.js +++ b/scripts/events-log/index.js @@ -8,58 +8,4 @@ const callback = (event) => { console.log(JSON.stringify(event)); world.sendMessage(system.currentTick + ' - ' + event.constructor.name); }; -system.beforeEvents.watchdogTerminate.subscribe(callback); system.afterEvents.scriptEventReceive.subscribe(callback); -world.beforeEvents.chatSend.subscribe(callback); -world.beforeEvents.dataDrivenEntityTriggerEvent.subscribe(callback); -world.beforeEvents.explosion.subscribe(callback); -world.beforeEvents.itemDefinitionEvent.subscribe(callback); -world.beforeEvents.itemUse.subscribe(callback); -world.beforeEvents.itemUseOn.subscribe(callback); -world.beforeEvents.playerBreakBlock.subscribe(callback); -world.beforeEvents.playerDimensionChange.subscribe(callback); -world.beforeEvents.playerInteractWithBlock.subscribe(callback); -world.beforeEvents.playerInteractWithEntity.subscribe(callback); -world.beforeEvents.playerBreakBlock.subscribe(callback); -world.beforeEvents.pistonActivate.subscribe(callback); -world.afterEvents.playerBreakBlock.subscribe(callback); -world.afterEvents.blockExplode.subscribe(callback); -world.afterEvents.playerPlaceBlock.subscribe(callback); -world.afterEvents.playerDimensionChange.subscribe(callback); -world.afterEvents.playerInteractWithBlock.subscribe(callback); -world.afterEvents.playerInteractWithEntity.subscribe(callback); -world.afterEvents.buttonPush.subscribe(callback); -world.afterEvents.chatSend.subscribe(callback); -world.afterEvents.dataDrivenEntityTriggerEvent.subscribe(callback); -world.afterEvents.effectAdd.subscribe(callback); -world.afterEvents.entityDie.subscribe(callback); -world.afterEvents.entityHealthChanged.subscribe(callback); -world.afterEvents.entityHitBlock.subscribe(callback); -world.afterEvents.entityHitEntity.subscribe(callback); -world.afterEvents.entityHurt.subscribe(callback); -world.afterEvents.entityRemove.subscribe(callback); -world.afterEvents.entitySpawn.subscribe(callback); -world.afterEvents.explosion.subscribe(callback); -world.afterEvents.itemCompleteUse.subscribe(callback); -world.afterEvents.itemDefinitionEvent.subscribe(callback); -world.afterEvents.itemReleaseUse.subscribe(callback); -world.afterEvents.itemStartUse.subscribe(callback); -world.afterEvents.itemStartUseOn.subscribe(callback); -world.afterEvents.itemStopUse.subscribe(callback); -world.afterEvents.itemStopUseOn.subscribe(callback); -world.afterEvents.itemUse.subscribe(callback); -world.afterEvents.itemUseOn.subscribe(callback); -world.afterEvents.leverAction.subscribe(callback); -world.afterEvents.messageReceive.subscribe(callback); -world.afterEvents.pistonActivate.subscribe(callback); -world.afterEvents.playerJoin.subscribe(callback); -world.afterEvents.playerLeave.subscribe(callback); -world.afterEvents.playerSpawn.subscribe(callback); -world.afterEvents.pressurePlatePop.subscribe(callback); -world.afterEvents.pressurePlatePush.subscribe(callback); -world.afterEvents.projectileHitBlock.subscribe(callback); -world.afterEvents.projectileHitEntity.subscribe(callback); -world.afterEvents.targetBlockHit.subscribe(callback); -world.afterEvents.tripWireTrip.subscribe(callback); -world.afterEvents.weatherChange.subscribe(callback); -world.afterEvents.worldInitialize.subscribe(callback); diff --git a/scripts/force-show/index.js b/scripts/force-show/index.js index dc51c6d4..6a891c3d 100644 --- a/scripts/force-show/index.js +++ b/scripts/force-show/index.js @@ -1,25 +1,28 @@ // Script example for ScriptAPI -// Author: Jayly#1397 +// Author: Jayly // Worldwidebrine#9037 // Project: https://github.com/JaylyDev/ScriptAPI - -import { Player, system } from "@minecraft/server"; -import { ActionFormData, FormCancelationReason, MessageFormData, ModalFormData } from "@minecraft/server-ui"; - +import { system } from "@minecraft/server"; +import { FormCancelationReason } from "@minecraft/server-ui"; /** - * @template {ActionFormData | MessageFormData | ModalFormData} Form - * @param {Player} player - * @param {Form} form - * @param {number} timeout - * @returns {Promise>>} + * @remarks + * Creates and force the API to show a popup form to player. + * Returns asynchronously when the player confirms or cancels the dialog. + * @param player Player to show this dialog to. + * @param form Dialog to show the player to. + * @param timeout Amount of time, in ticks, before the request times out and is abandoned. + * @throws This function can throw errors. */ export async function forceShow(player, form, timeout = Infinity) { const startTick = system.currentTick; while ((system.currentTick - startTick) < timeout) { - const response = await /** @type {ReturnType} */(form.show(player)); + const response = await form.show(player); if (response.cancelationReason !== FormCancelationReason.UserBusy) { return response; } - }; + ; + } + ; throw new Error(`Timed out after ${timeout} ticks`); -}; \ No newline at end of file +} +; diff --git a/scripts/force-show/index.ts b/scripts/force-show/index.ts new file mode 100644 index 00000000..392c7154 --- /dev/null +++ b/scripts/force-show/index.ts @@ -0,0 +1,30 @@ +// Script example for ScriptAPI +// Author: Jayly +// Worldwidebrine#9037 +// Project: https://github.com/JaylyDev/ScriptAPI + +import { Player, system } from "@minecraft/server"; +import { ActionFormData, FormCancelationReason, MessageFormData, ModalFormData } from "@minecraft/server-ui"; + +type FormData = ActionFormData | MessageFormData | ModalFormData; +type FormResponse = Awaited>; + +/** + * @remarks + * Creates and force the API to show a popup form to player. + * Returns asynchronously when the player confirms or cancels the dialog. + * @param player Player to show this dialog to. + * @param form Dialog to show the player to. + * @param timeout Amount of time, in ticks, before the request times out and is abandoned. + * @throws This function can throw errors. + */ +export async function forceShow
(player: Player, form: Form, timeout: number = Infinity): Promise> { + const startTick = system.currentTick; + while ((system.currentTick - startTick) < timeout) { + const response = await form.show(player); + if (response.cancelationReason !== FormCancelationReason.UserBusy) { + return response as FormResponse; + }; + }; + throw new Error(`Timed out after ${timeout} ticks`); +}; \ No newline at end of file diff --git a/scripts/force-show/tests.js b/scripts/force-show/tests.js index 366a2bed..aa2a71d5 100644 --- a/scripts/force-show/tests.js +++ b/scripts/force-show/tests.js @@ -1,9 +1,9 @@ // Script example for ScriptAPI -// Author: Jayly#1397 +// Author: Jayly // Project: https://github.com/JaylyDev/ScriptAPI import { world, system, Player } from "@minecraft/server"; import { ModalFormData, ActionFormData, MessageFormData } from "@minecraft/server-ui"; -import { forceShow } from "force-show/index"; +import { forceShow } from "./index"; world.beforeEvents.chatSend.subscribe(async (event) => { event.cancel = true; diff --git a/scripts/get-item-amount/index.js b/scripts/get-item-amount/index.js index fa7c5c2c..9694b2a5 100644 --- a/scripts/get-item-amount/index.js +++ b/scripts/get-item-amount/index.js @@ -12,10 +12,6 @@ import { EntityInventoryComponent, Player } from "@minecraft/server"; * @returns {number} item amount */ export function checkItemAmount(player, itemId, clearItems = false) { - /** - * @type {EntityInventoryComponent} - */ - // @ts-expect-error const component = player.getComponent("minecraft:inventory"); const inventory = component.container; let itemAmount = 0; diff --git a/scripts/minecraft-language/index.js b/scripts/minecraft-language/index.js index f7f14218..a638829b 100644 --- a/scripts/minecraft-language/index.js +++ b/scripts/minecraft-language/index.js @@ -1,6 +1,3 @@ -// Script example for ScriptAPI -// Author: bot174 -// Project: https://github.com/JaylyDev/ScriptAPI export const languageKeys = [ "accessibility.disableTTS", "accessibility.enableTTS", diff --git a/scripts/minecraft-language/tests.js b/scripts/minecraft-language/tests.js deleted file mode 100644 index 248833ff..00000000 --- a/scripts/minecraft-language/tests.js +++ /dev/null @@ -1,17 +0,0 @@ -import { world } from "@minecraft/server"; -import { MinecraftLanguageKeys } from "./index"; - -world.beforeEvents.chatSend.subscribe((event) => { - event.setTargets([]); - event.sendToTargets = true; -}); - -world.afterEvents.chatSend.subscribe((event) => { - /** - * @type {import("@minecraft/server").RawMessage} - */ - // @ts-ignore - const rawtext = MinecraftLanguageKeys["chat.type.text"]; - rawtext.with = [event.sender.name, event.message]; - world.sendMessage(rawtext); -}); \ No newline at end of file diff --git a/scripts/offline-player/README.md b/scripts/offline-player/README.md new file mode 100644 index 00000000..966933a2 --- /dev/null +++ b/scripts/offline-player/README.md @@ -0,0 +1,175 @@ +# Offline Player + +Represents a reference to a player identity and the data belonging to a player that is stored on the disk and can, thus, be retrieved without the player needing to be online. + +## Summary + +Using either `index.js` or `index.ts` file: + +```js +import { OfflinePlayer } from "offline-player/index"; + +// Get data via player.id (Recommended) +const player = OfflinePlayer.get('-68719476735'); +// Or get via player.name +const player = OfflinePlayer.get('JaylyPlays'); +``` + +## Properties +- [level](#level) +- [name](#name) +- [totalXpNeededForNextLevel](#totalxpneededfornextlevel) +- [xpEarnedAtCurrentLevel](#xpearnedatcurrentlevel) +- [gameMode](#gamemode) +- [lastPlayed](#lastplayed) + +### **level** +`readonly level: number;` + +The current overall level for the player, based on their experience. + +Type: *number* + +### **name** +`readonly name: string;` + +Name of the player. + +Type: *string* + +### **totalXpNeededForNextLevel** +`readonly totalXpNeededForNextLevel: number;` + +The overall total set of experience needed to achieve the next level for a player. + +Type: *number* + +### **xpEarnedAtCurrentLevel** +`readonly xpEarnedAtCurrentLevel: number;` + +The current set of experience achieved for the player. + +Type: *number* + +### **gameMode** +`readonly gameMode: GameMode;` + +The current gamemode for the player. + +Type: *GameMode* + +### **lastPlayed** +`readonly lastPlayed: number;` + +Gets the last date and time that this player was witnessed on this server. It will return Date of last log-in for this player in the amount of milliseconds since midnight, January 1, 1970 UTC. + +Type: *number* + +## Methods +- [get](#get) +- [get](#get-1) +- [getSpawnPoint](#getspawnpoint) +- [getTotalXp](#gettotalxp) +- [isOp](#isop) +- [getPlayer](#getplayer) + +### **get** +` +static get(id: string): OfflinePlayer; +` + +Gets the player by the given ID, regardless if they are offline or online. This will return an object even if the player does not exist. To this method, all players will exist. + +#### **Parameters** +- **id**: *string* + + the ID of the player to retrieve. + +#### **Returns** *OfflinePlayer* + +### **get** + +` +static get(name: string): OfflinePlayer; +` + +Gets the player by the given name, regardless if they are offline or online. This will return an object even if the player does not exist. To this method, all players will exist. + +> [!CAUTION] +> Persistent storage of users should be by ID as names are no longer unique past a single session. + +#### **Parameters** +- **name**: *string* + + the name of the player to retrieve. + +#### **Returns** *OfflinePlayer* + +### **getSpawnPoint** +` +getSpawnPoint(): DimensionLocation | undefined +` + +Gets the current spawn point of the player. + +#### **Returns** *DimensionLocation* | *undefined* + +### **getTotalXp** +` +getTotalXp(): number +` + + Gets the total experience of the Player. + +#### **Returns** *number* + +### **isOp** +` +isOp(): boolean +` + +Returns true if this player has operator-level permissions. + +#### **Returns** *boolean* + +> [!IMPORTANT] +> This function can only be used within Beta APIs. + +### **getPlayer** +` +getPlayer(): Player | undefined +` + +If the player is online, this will return that player corresponds to. + +#### **Returns** *Player | undefined* + +## Schema + +```ts +import { Dimension, DimensionLocation, GameMode, Player, Vector3 } from "@minecraft/server"; +export class OfflinePlayer { + private constructor(); + static get(id: `${number}`): OfflinePlayer; + static get(name: string): OfflinePlayer; + readonly dimension: Dimension; + readonly id: string; + readonly isSneaking: boolean; + readonly location: Vector3; + readonly typeId = "minecraft:player"; + readonly level: number; + readonly name: string; + readonly totalXpNeededForNextLevel: number; + readonly xpEarnedAtCurrentLevel: number; + readonly gameMode: GameMode; + readonly lastPlayed: number; + getSpawnPoint(): DimensionLocation | undefined; + getTotalXp(): number; + isOp(): boolean; + getPlayer(): Player | undefined; +} +``` + +## License + +This package is licensed under the MIT License. diff --git a/scripts/offline-player/index.js b/scripts/offline-player/index.js new file mode 100644 index 00000000..003383a5 --- /dev/null +++ b/scripts/offline-player/index.js @@ -0,0 +1,138 @@ +// Script example for ScriptAPI +// Author: Jayly +// Project: https://github.com/JaylyDev/ScriptAPI +import { GameMode, world } from "@minecraft/server"; +; +/** + * @description + * Represents a reference to a player identity and the data + * belonging to a player that is stored on the disk and can, + * thus, be retrieved without the player needing to be online. + */ +class OfflinePlayer { + constructor(data) { + /** + * @remarks + * Identifier of the type of the entity - for example, + * 'minecraft:skeleton'. This property is accessible even if + * {@link Entity.isValid} is false. + * + */ + this.typeId = "minecraft:player"; + this.dimension = world.getDimension(data.dimension); + this.id = data.id; + this.isSneaking = data.isSneaking; + this.location = data.location; + this.typeId = data.typeId; + this.level = data.level; + this.name = data.name; + this.totalXpNeededForNextLevel = data.totalXpNeededForNextLevel; + this.xpEarnedAtCurrentLevel = data.xpEarnedAtCurrentLevel; + this.getSpawnPoint = () => data.spawnPoint; + this.getTotalXp = () => data.totalXp; + this.isOp = () => data.isOp; + this.getPlayer = () => world.getAllPlayers().find((player) => player.id === this.id); + } + static get(idOrName) { + // check if string is an integer + const isId = /^\d+$/.test(idOrName); + if (isId) { + const value = world.getDynamicProperty(`jayly:player_${idOrName}`); + if (!value) + throw new Error(`Player with id ${idOrName} does not exist`); + const data = JSON.parse(value); + return new OfflinePlayer(data); + } + else if (typeof idOrName === "string") { + // try to find the dynamic property by name in every object + const ids = world.getDynamicPropertyIds().filter(id => id.startsWith('jayly:player_')); + const value = ids.find(id => { + const data = world.getDynamicProperty(id); + const parsed = JSON.parse(data); + return parsed.name === idOrName; + }); + if (!value) + throw new Error(`Player with name ${idOrName} does not exist`); + return new OfflinePlayer(JSON.parse(world.getDynamicProperty(value))); + } + else + throw new Error("Invalid argument"); + } + /** + * @internal + */ + static createProfile(player, additionalProperties) { + const data = { + format_version: 1, + dimension: player.dimension.id, + id: player.id, + isSneaking: player.isSneaking, + location: additionalProperties.location, + typeId: "minecraft:player", + level: player.level, + name: player.name, + totalXpNeededForNextLevel: player.totalXpNeededForNextLevel, + xpEarnedAtCurrentLevel: player.xpEarnedAtCurrentLevel, + spawnPoint: player.getSpawnPoint(), + totalXp: player.getTotalXp(), + isOp: player.isOp(), + gameMode: additionalProperties.gameMode, + lastPlayed: Date.now() + }; + world.setDynamicProperty(`jayly:player_${player.id}`, JSON.stringify(data)); + } + ; + /** + * @remarks + * Gets the current spawn point of the player. + * + */ + getSpawnPoint() { + throw new TypeError("Illegal invocation"); + } + /** + * @remarks + * Gets the total experience of the Player. + * + */ + getTotalXp() { + throw new TypeError("Illegal invocation"); + } + /** + * @beta + * @remarks + * Returns true if this player has operator-level permissions. + * + */ + isOp() { + throw new TypeError("Illegal invocation"); + } + /** + * @remarks + * If the player is online, this will return that player corresponds to. + * + */ + getPlayer() { + throw new TypeError("Illegal invocation"); + } +} +world.beforeEvents.playerLeave.subscribe(({ player }) => { + let playerGameMode; + let playerLocation = { + x: player.location.x > 1e6 ? Math.round(player.location.x) : parseFloat(player.location.x.toPrecision(7)), + y: player.location.y > 1e6 ? Math.round(player.location.y) : parseFloat(player.location.y.toPrecision(7)), + z: player.location.z > 1e6 ? Math.round(player.location.z) : parseFloat(player.location.z.toPrecision(7)) + }; + for (const key in GameMode) { + const gameMode = GameMode[key]; + if (player.matches({ gameMode: gameMode })) + playerGameMode = gameMode; + } + if (!playerGameMode) + throw new Error("Player gamemode not found"); + OfflinePlayer.createProfile(player, { + gameMode: playerGameMode, + location: playerLocation + }); +}); +export { OfflinePlayer }; diff --git a/scripts/offline-player/index.ts b/scripts/offline-player/index.ts new file mode 100644 index 00000000..119de5ec --- /dev/null +++ b/scripts/offline-player/index.ts @@ -0,0 +1,259 @@ +// Script example for ScriptAPI +// Author: Jayly +// Project: https://github.com/JaylyDev/ScriptAPI +import { Dimension, DimensionLocation, GameMode, Player, Vector3, world } from "@minecraft/server"; + +/** + * @internal + * Offline player data object stored in dynamic property + */ +interface IOfflinePlayer { + readonly format_version: number; + // Entity + readonly dimension: string; + readonly id: string; + readonly isSneaking: boolean; + readonly location: Vector3; + readonly typeId: "minecraft:player"; + // Player + readonly level: number; + readonly name: string; + readonly totalXpNeededForNextLevel: number; + readonly xpEarnedAtCurrentLevel: number; + readonly spawnPoint: DimensionLocation | undefined; + readonly totalXp: number; + readonly isOp: boolean; + readonly gameMode: GameMode; + readonly lastPlayed: number; +} + +/** + * @internal + */ +interface PlayerAdditionalProperties { + location: Vector3; + gameMode: GameMode; +}; + +/** + * @description + * Represents a reference to a player identity and the data + * belonging to a player that is stored on the disk and can, + * thus, be retrieved without the player needing to be online. + */ +class OfflinePlayer { + private constructor(data: IOfflinePlayer) { + this.dimension = world.getDimension(data.dimension); + this.id = data.id; + this.isSneaking = data.isSneaking; + this.location = data.location; + this.typeId = data.typeId; + this.level = data.level; + this.name = data.name; + this.totalXpNeededForNextLevel = data.totalXpNeededForNextLevel; + this.xpEarnedAtCurrentLevel = data.xpEarnedAtCurrentLevel; + this.getSpawnPoint = () => data.spawnPoint; + this.getTotalXp = () => data.totalXp; + this.isOp = () => data.isOp; + this.getPlayer = () => world.getAllPlayers().find((player) => player.id === this.id); + } + /** + * @description + * Gets the player by the given ID, regardless if they are offline or online. + * This will return an object even if the player does not exist. To this method, all players will exist. + * @param id the ID of the player to retrieve + * @returns an offline player. + */ + static get(id: `${number}`): OfflinePlayer; + /** + * @deprecated + * Persistent storage of users should be by ID as names are no longer unique past a single session. + * @description + * Gets the player by the given name, regardless if they are offline or online. + * This will return an object even if the player does not exist. To this method, all players will exist. + * @param name the name the player to retrieve + * @returns an offline player. + */ + static get(name: string): OfflinePlayer; + static get(idOrName: `${number}` | string): OfflinePlayer { + // check if string is an integer + const isId = /^\d+$/.test(idOrName); + if (isId) { + const value = world.getDynamicProperty(`jayly:player_${idOrName}`) as string | undefined; + if (!value) throw new Error(`Player with id ${idOrName} does not exist`); + const data = JSON.parse(value) as IOfflinePlayer; + return new OfflinePlayer(data); + } + else if (typeof idOrName === "string") { + // try to find the dynamic property by name in every object + const ids = world.getDynamicPropertyIds().filter(id => id.startsWith('jayly:player_')); + const value = ids.find(id => { + const data = world.getDynamicProperty(id) as string; + const parsed = JSON.parse(data) as IOfflinePlayer; + return parsed.name === idOrName; + }); + if (!value) throw new Error(`Player with name ${idOrName} does not exist`); + return new OfflinePlayer(JSON.parse(world.getDynamicProperty(value) as string)); + } + else throw new Error("Invalid argument"); + } + /** + * @internal + */ + static createProfile(player: Player, additionalProperties: PlayerAdditionalProperties) { + const data: IOfflinePlayer = { + format_version: 1, + dimension: player.dimension.id, + id: player.id, + isSneaking: player.isSneaking, + location: additionalProperties.location, + typeId: "minecraft:player", + level: player.level, + name: player.name, + totalXpNeededForNextLevel: player.totalXpNeededForNextLevel, + xpEarnedAtCurrentLevel: player.xpEarnedAtCurrentLevel, + spawnPoint: player.getSpawnPoint(), + totalXp: player.getTotalXp(), + isOp: player.isOp(), + gameMode: additionalProperties.gameMode, + lastPlayed: Date.now() + }; + world.setDynamicProperty(`jayly:player_${player.id}`, JSON.stringify(data)); + }; + /** + * @remarks + * Dimension that the entity is currently within. + * + */ + readonly dimension: Dimension; + /** + * @remarks + * Unique identifier of the entity. This identifier is intended + * to be consistent across loads of a world instance. No + * meaning should be inferred from the value and structure of + * this unique identifier - do not parse or interpret it. This + * property is accessible even if {@link Entity.isValid} is + * false. + * + */ + readonly id: string; + /** + * @remarks + * Whether the entity is sneaking - that is, moving more slowly + * and more quietly. + * + */ + readonly isSneaking: boolean; + /** + * @remarks + * Current location of the entity. + * + */ + readonly location: Vector3; + /** + * @remarks + * Identifier of the type of the entity - for example, + * 'minecraft:skeleton'. This property is accessible even if + * {@link Entity.isValid} is false. + * + */ + readonly typeId = "minecraft:player"; + // Player + /** + * @remarks + * The current overall level for the player, based on their + * experience. + * + */ + readonly level: number; + /** + * @remarks + * Name of the player. + * + */ + readonly name: string; + /** + * @remarks + * The overall total set of experience needed to achieve the + * next level for a player. + * + */ + readonly totalXpNeededForNextLevel: number; + /** + * @remarks + * The current set of experience achieved for the player. + * + */ + readonly xpEarnedAtCurrentLevel: number; + /** + * @remarks + * The current gamemode for the player. + * + */ + readonly gameMode: GameMode; + /** + * @remarks + * Gets the last date and time that this player was witnessed + * on this server. + * It will return Date of last log-in for this player in the + * amount of milliseconds since midnight, January 1, 1970 UTC. + * + */ + readonly lastPlayed: number; + /** + * @remarks + * Gets the current spawn point of the player. + * + */ + getSpawnPoint(): DimensionLocation | undefined { + throw new TypeError("Illegal invocation"); + } + /** + * @remarks + * Gets the total experience of the Player. + * + */ + getTotalXp(): number { + throw new TypeError("Illegal invocation"); + } + /** + * @beta + * @remarks + * Returns true if this player has operator-level permissions. + * + */ + isOp(): boolean { + throw new TypeError("Illegal invocation"); + } + /** + * @remarks + * If the player is online, this will return that player corresponds to. + * + */ + getPlayer(): Player | undefined { + throw new TypeError("Illegal invocation"); + } +} + +world.beforeEvents.playerLeave.subscribe(({ player }) => { + let playerGameMode: GameMode | undefined; + let playerLocation: Vector3 = { + x: player.location.x > 1e6 ? Math.round(player.location.x) : parseFloat(player.location.x.toPrecision(7)), + y: player.location.y > 1e6 ? Math.round(player.location.y) : parseFloat(player.location.y.toPrecision(7)), + z: player.location.z > 1e6 ? Math.round(player.location.z) : parseFloat(player.location.z.toPrecision(7)) + }; + + for (const key in GameMode) { + const gameMode = GameMode[key]; + if (player.matches({ gameMode: gameMode })) playerGameMode = gameMode; + } + + if (!playerGameMode) throw new Error("Player gamemode not found"); + + OfflinePlayer.createProfile(player, { + gameMode: playerGameMode, + location: playerLocation + }); +}); + +export { OfflinePlayer }; diff --git a/scripts/vector3-polyfill/README.md b/scripts/vector3-polyfill/README.md index 9be15d39..5849e93b 100644 --- a/scripts/vector3-polyfill/README.md +++ b/scripts/vector3-polyfill/README.md @@ -13,4 +13,4 @@ for everything in a class use `Vector3.ts` ## Credits -These scripts were written by [bot174](https://github.com/bot174) +These scripts were written by [JaylyDev](https://github.com/JaylyDev) diff --git a/scripts/vector3-polyfill/Vector.js b/scripts/vector3-polyfill/Vector.js index eab86283..a2d4856e 100644 --- a/scripts/vector3-polyfill/Vector.js +++ b/scripts/vector3-polyfill/Vector.js @@ -59,7 +59,7 @@ export class Vector { const DirectionX = this.x / magnitude; const DirectionY = this.y / magnitude; const DirectionZ = this.z / magnitude; - return new _a(DirectionX, DirectionY, DirectionZ); + return new Vector(DirectionX, DirectionY, DirectionZ); } /** * @remarks @@ -69,7 +69,7 @@ export class Vector { * @returns {Vector} */ static add(a, b) { - const vector = new _a(a.x, a.y, a.z); + const vector = new Vector(a.x, a.y, a.z); vector.x += b.x; vector.y += b.y; vector.z += b.z; @@ -83,7 +83,7 @@ export class Vector { * @returns {Vector} */ static cross(a, b) { - return new _a(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); + return new Vector(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); } /** * @remarks @@ -107,7 +107,7 @@ export class Vector { * @returns {Vector} */ static divide(a, b) { - const vector = new _a(a.x, a.y, a.z); + const vector = new Vector(a.x, a.y, a.z); if (typeof b === "number") { vector.x /= b; vector.y /= b; @@ -130,7 +130,7 @@ export class Vector { * @returns {Vector} */ static lerp(a, b, t) { - const dest = new _a(a.x, a.y, a.z); + const dest = new Vector(a.x, a.y, a.z); dest.x += (b.x - a.x) * t; dest.y += (b.y - a.y) * t; dest.z += (b.z - a.z) * t; @@ -146,11 +146,11 @@ export class Vector { */ static max(a, b) { const vectors = [a, b]; - const arr = vectors.map(({ x, y, z }) => new _a(x, y, z).length()); + const arr = vectors.map(({ x, y, z }) => new Vector(x, y, z).length()); const max = Math.max(...arr); const index = arr.indexOf(max); const vector3 = vectors[index]; - return new _a(vector3.x, vector3.y, vector3.z); + return new Vector(vector3.x, vector3.y, vector3.z); } /** * @remarks @@ -162,11 +162,11 @@ export class Vector { */ static min(a, b) { const vectors = [a, b]; - const arr = vectors.map(({ x, y, z }) => new _a(x, y, z).length()); + const arr = vectors.map(({ x, y, z }) => new Vector(x, y, z).length()); const min = Math.min(...arr); const index = arr.indexOf(min); const vector3 = vectors[index]; - return new _a(vector3.x, vector3.y, vector3.z); + return new Vector(vector3.x, vector3.y, vector3.z); } /** * @remarks @@ -176,7 +176,7 @@ export class Vector { * @returns {Vector} */ static multiply(a, b) { - const vector = new _a(a.x, a.y, a.z); + const vector = new Vector(a.x, a.y, a.z); if (typeof b === "number") { vector.x *= b; vector.y *= b; @@ -210,7 +210,7 @@ export class Vector { const θ = Math.acos(MathDot([a.x, a.y, a.z], [b.x, b.y, b.z])); const factor1 = Math.sin(θ * (1 - s)) / Math.sin(θ); const factor2 = Math.sin(θ * s) / Math.sin(θ); - return new _a(a.x * factor1 + b.x * factor2, a.y * factor1 + b.y * factor2, a.z * factor1 + b.z * factor2); + return new Vector(a.x * factor1 + b.x * factor2, a.y * factor1 + b.y * factor2, a.z * factor1 + b.z * factor2); } /** * @remarks @@ -220,7 +220,7 @@ export class Vector { * @returns {Vector} */ static subtract(a, b) { - const vector = new _a(a.x, a.y, a.z); + const vector = new Vector(a.x, a.y, a.z); vector.x -= b.x; vector.y -= b.y; vector.z -= b.z; diff --git a/scripts/vector3-polyfill/Vector3.js b/scripts/vector3-polyfill/Vector3.js index fa368839..c6c36b8b 100644 --- a/scripts/vector3-polyfill/Vector3.js +++ b/scripts/vector3-polyfill/Vector3.js @@ -1,4 +1,3 @@ -var _a; /** * Wrapper class of Vector3 */ @@ -18,6 +17,74 @@ export class Vector3 { this.y = y; this.z = z; } + /** + * A constant vector that represents (0, 0, -1). + * @readonly + */ + static get back() { + return new this(0, 0, -1); + } + ; + /** + * A constant vector that represents (0, -1, 0). + * @readonly + */ + static get down() { + return new this(0, -1, 0); + } + ; + /** + * A constant vector that represents (0, 0, 1). + * @readonly + */ + static get forward() { + return new this(0, 0, 1); + } + ; + /** + * A constant vector that represents (-1, 0, 0). + * @readonly + */ + static get left() { + return new this(-1, 0, 0); + } + ; + /** + * A constant vector that represents (1, 1, 1). + * @readonly + */ + static get one() { + return new this(1, 1, 1); + } + ; + /** + * A constant vector that represents (1, 0, 0). + * @readonly + */ + static get right() { + return new this(1, 0, 0); + } + ; + /** + * A constant vector that represents (0, 1, 0). + * @readonly + */ + static get up() { + return new this(0, 1, 0); + } + ; + /** + * A constant vector that represents (0, 0, 0). + * @readonly + */ + static get zero() { + return new this(0, 0, 0); + } + ; + static from(vec3) { + return new Vector3(vec3.x, vec3.y, vec3.z); + } + ; /** * @remarks * Retur @@ -44,7 +111,7 @@ export class Vector3 { const DirectionX = this.x / magnitude; const DirectionY = this.y / magnitude; const DirectionZ = this.z / magnitude; - return new _a(DirectionX, DirectionY, DirectionZ); + return new Vector3(DirectionX, DirectionY, DirectionZ); } /** * @remarks @@ -54,7 +121,7 @@ export class Vector3 { * @returns {Vector3} */ static add(a, b) { - const vector = new _a(a.x, a.y, a.z); + const vector = new Vector3(a.x, a.y, a.z); vector.x += b.x; vector.y += b.y; vector.z += b.z; @@ -68,7 +135,7 @@ export class Vector3 { * @returns {Vector3} */ static cross(a, b) { - return new _a(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); + return new Vector3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); } /** * @remarks @@ -92,7 +159,7 @@ export class Vector3 { * @returns {Vector3} */ static divide(a, b) { - const vector = new _a(a.x, a.y, a.z); + const vector = new Vector3(a.x, a.y, a.z); if (typeof b === "number") { vector.x /= b; vector.y /= b; @@ -115,7 +182,7 @@ export class Vector3 { * @returns {Vector3} */ static lerp(a, b, t) { - const dest = new _a(a.x, a.y, a.z); + const dest = new Vector3(a.x, a.y, a.z); dest.x += (b.x - a.x) * t; dest.y += (b.y - a.y) * t; dest.z += (b.z - a.z) * t; @@ -131,11 +198,11 @@ export class Vector3 { */ static max(a, b) { const vectors = [a, b]; - const arr = vectors.map(({ x, y, z }) => new _a(x, y, z).length()); + const arr = vectors.map(({ x, y, z }) => new Vector3(x, y, z).length()); const max = Math.max(...arr); const index = arr.indexOf(max); const vector3 = vectors[index]; - return new _a(vector3.x, vector3.y, vector3.z); + return new Vector3(vector3.x, vector3.y, vector3.z); } /** * @remarks @@ -147,11 +214,11 @@ export class Vector3 { */ static min(a, b) { const vectors = [a, b]; - const arr = vectors.map(({ x, y, z }) => new _a(x, y, z).length()); + const arr = vectors.map(({ x, y, z }) => new Vector3(x, y, z).length()); const min = Math.min(...arr); const index = arr.indexOf(min); const vector3 = vectors[index]; - return new _a(vector3.x, vector3.y, vector3.z); + return new Vector3(vector3.x, vector3.y, vector3.z); } /** * @remarks @@ -161,7 +228,7 @@ export class Vector3 { * @returns {Vector3} */ static multiply(a, b) { - const vector = new _a(a.x, a.y, a.z); + const vector = new Vector3(a.x, a.y, a.z); if (typeof b === "number") { vector.x *= b; vector.y *= b; @@ -195,7 +262,7 @@ export class Vector3 { const θ = Math.acos(MathDot([a.x, a.y, a.z], [b.x, b.y, b.z])); const factor1 = Math.sin(θ * (1 - s)) / Math.sin(θ); const factor2 = Math.sin(θ * s) / Math.sin(θ); - return new _a(a.x * factor1 + b.x * factor2, a.y * factor1 + b.y * factor2, a.z * factor1 + b.z * factor2); + return new Vector3(a.x * factor1 + b.x * factor2, a.y * factor1 + b.y * factor2, a.z * factor1 + b.z * factor2); } /** * @remarks @@ -205,7 +272,7 @@ export class Vector3 { * @returns {Vector3} */ static subtract(a, b) { - const vector = new _a(a.x, a.y, a.z); + const vector = new Vector3(a.x, a.y, a.z); vector.x -= b.x; vector.y -= b.y; vector.z -= b.z; @@ -215,7 +282,7 @@ export class Vector3 { * Returns a Vector3 with its coordinate floored */ floor() { - return new _a(Math.floor(this.x), Math.floor(this.y), Math.floor(this.z)); + return new Vector3(Math.floor(this.x), Math.floor(this.y), Math.floor(this.z)); } /** * @remarks @@ -223,7 +290,7 @@ export class Vector3 { * (that is, y + 1). */ above() { - return new _a(this.x, this.y + 1, this.z); + return new Vector3(this.x, this.y + 1, this.z); } /** * @remarks @@ -249,7 +316,7 @@ export class Vector3 { const coordY = y + this.y; for (let z = 0; z <= distanceZ; z++) { const coordZ = z + this.z; - Vector3s.push(new _a(coordX, coordY, coordZ)); + Vector3s.push(new Vector3(coordX, coordY, coordZ)); } } } @@ -285,7 +352,7 @@ export class Vector3 { * Vector3. */ offset(x, y, z) { - return new _a(x + this.x, y + this.y, z + this.z); + return new Vector3(x + this.x, y + this.y, z + this.z); } /** * @remarks @@ -301,47 +368,6 @@ export class Vector3 { * each other. */ isNear(other, epsilon) { - return _a.distance(this, other) <= epsilon; + return Vector3.distance(this, other) <= epsilon; } } -_a = Vector3; -/** - * A constant vector that represents (0, 0, -1). - * @readonly - */ -Vector3.back = new _a(0, 0, -1); -/** - * A constant vector that represents (0, -1, 0). - * @readonly - */ -Vector3.down = new _a(0, -1, 0); -/** - * A constant vector that represents (0, 0, 1). - * @readonly - */ -Vector3.forward = new _a(0, 0, 1); -/** - * A constant vector that represents (-1, 0, 0). - * @readonly - */ -Vector3.left = new _a(-1, 0, 0); -/** - * A constant vector that represents (1, 1, 1). - * @readonly - */ -Vector3.one = new _a(1, 1, 1); -/** - * A constant vector that represents (1, 0, 0). - * @readonly - */ -Vector3.right = new _a(1, 0, 0); -/** - * A constant vector that represents (0, 1, 0). - * @readonly - */ -Vector3.up = new _a(0, 1, 0); -/** - * A constant vector that represents (0, 0, 0). - * @readonly - */ -Vector3.zero = new _a(0, 0, 0); diff --git a/scripts/vector3-polyfill/Vector3.ts b/scripts/vector3-polyfill/Vector3.ts index 9a48b3d0..0013cf85 100644 --- a/scripts/vector3-polyfill/Vector3.ts +++ b/scripts/vector3-polyfill/Vector3.ts @@ -35,42 +35,61 @@ export class Vector3 implements IVec3 { * A constant vector that represents (0, 0, -1). * @readonly */ - static back = new this(0, 0, -1); + static get back() { + return new this(0, 0, -1); + }; /** * A constant vector that represents (0, -1, 0). * @readonly */ - static down = new this(0, -1, 0); + static get down() { + return new this(0, -1, 0); + }; /** * A constant vector that represents (0, 0, 1). * @readonly */ - static forward = new this(0, 0, 1); + static get forward() { + return new this(0, 0, 1); + }; /** * A constant vector that represents (-1, 0, 0). * @readonly */ - static left = new this(-1, 0, 0); + static get left() { + return new this(-1, 0, 0); + }; /** * A constant vector that represents (1, 1, 1). * @readonly */ - static one = new this(1, 1, 1); + static get one() { + return new this(1, 1, 1); + }; /** * A constant vector that represents (1, 0, 0). * @readonly */ - static right = new this(1, 0, 0); + static get right() { + return new this(1, 0, 0); + }; /** * A constant vector that represents (0, 1, 0). * @readonly */ - static up = new this(0, 1, 0); + static get up() { + return new this(0, 1, 0); + }; /** * A constant vector that represents (0, 0, 0). * @readonly */ - static zero = new this(0, 0, 0); + static get zero() { + return new this(0, 0, 0); + }; + static from(vec3: IVec3) { + return new Vector3(vec3.x, vec3.y, vec3.z); + }; /** * @remarks * Retur @@ -380,4 +399,4 @@ export class Vector3 implements IVec3 { isNear(other: Vector3, epsilon: number): boolean { return Vector3.distance(this, other) <= epsilon; } -} +} \ No newline at end of file diff --git a/scripts/vector3-polyfill/tsconfig.json b/scripts/vector3-polyfill/tsconfig.json index 59683dd4..7457404f 100644 --- a/scripts/vector3-polyfill/tsconfig.json +++ b/scripts/vector3-polyfill/tsconfig.json @@ -4,6 +4,7 @@ "target": "es2020", "allowJs": true, "checkJs": true, + "moduleResolution": "node", "allowSyntheticDefaultImports": false, }, "files": [