init
This commit is contained in:
13
scripts/Commandeer/Trigger/CCTrigger.ts
Normal file
13
scripts/Commandeer/Trigger/CCTrigger.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Trigger } from "./trigger";
|
||||
import { Maker } from "./maker";
|
||||
import { Manager } from "./manager";
|
||||
|
||||
export * from "./trigger";
|
||||
export * from "./maker";
|
||||
export * from "./manager";
|
||||
|
||||
export const CCTrigger = {
|
||||
Trigger,
|
||||
Maker,
|
||||
Manager,
|
||||
};
|
||||
204
scripts/Commandeer/Trigger/maker.ts
Normal file
204
scripts/Commandeer/Trigger/maker.ts
Normal file
@@ -0,0 +1,204 @@
|
||||
import { Trigger } from "./trigger";
|
||||
|
||||
import {
|
||||
Block,
|
||||
ChatSendAfterEvent,
|
||||
PaletteColor,
|
||||
EntityInventoryComponent,
|
||||
ItemStack,
|
||||
ItemUseOnBeforeEvent,
|
||||
MolangVariableMap,
|
||||
Player,
|
||||
Vector3,
|
||||
world,
|
||||
} from "@minecraft/server";
|
||||
import { vector3, vector3Distance } from "../utils/vectorUtils";
|
||||
import { Mindkeeper, StoreType } from "../mindKeeper";
|
||||
import { spawnParticle } from "../utils/particleUtils";
|
||||
import { Manager } from "./manager";
|
||||
|
||||
export class Maker {
|
||||
private manager: Manager;
|
||||
|
||||
log: Map<string, number> = new Map();
|
||||
|
||||
currentTrigger: Trigger | null = null;
|
||||
waitingForPoint2: boolean = false;
|
||||
point1: Vector3 = vector3(0, 0, 0);
|
||||
point2: Vector3 = vector3(0, 0, 0);
|
||||
|
||||
mindKeeper: Mindkeeper;
|
||||
|
||||
constructor(mindKeeper: Mindkeeper, manager: Manager) {
|
||||
this.mindKeeper = mindKeeper;
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
OnChat(event: ChatSendAfterEvent) {
|
||||
if (event.message === "!toggleTriggers") {
|
||||
this.mindKeeper.set("ShowTriggers", (this.mindKeeper.get("ShowTriggers") as boolean) ? false : true);
|
||||
}
|
||||
if (event.message === "!TWand") {
|
||||
const item = new ItemStack("minecraft:stick");
|
||||
item.nameTag = "MakeTrigger";
|
||||
((event.sender as Player).getComponent("inventory") as EntityInventoryComponent).container!.addItem(item);
|
||||
world.sendMessage("Thou shall have the Powah");
|
||||
}
|
||||
|
||||
if (event.message === "!deleteCurrentTrigger") {
|
||||
let currentTriggerdTrigger = this.manager
|
||||
.GetTriggers()
|
||||
.filter((trigger) => trigger.IsPlayerInside(event.sender as Player));
|
||||
if (currentTriggerdTrigger.length > 0) {
|
||||
this.manager.GetTriggers().splice(this.manager.GetTriggers().indexOf(currentTriggerdTrigger[0]), 1);
|
||||
world.sendMessage("Trigger deleted");
|
||||
} else {
|
||||
world.sendMessage("No trigger to delete");
|
||||
}
|
||||
this.manager.Save();
|
||||
}
|
||||
const command = event.message.split(" ")[0];
|
||||
if (command == "!setFunction") {
|
||||
const name = event.message.split(" ")[1];
|
||||
const trigger = this.manager.GetCurrentActiveTriggers()[0];
|
||||
|
||||
if (trigger === undefined) {
|
||||
world.sendMessage("No trigger selected");
|
||||
return;
|
||||
}
|
||||
|
||||
trigger.eventToDispatch = name;
|
||||
this.manager.Save();
|
||||
world.sendMessage(`Function set to ${name}`);
|
||||
}
|
||||
}
|
||||
|
||||
OnItemUse(event: ItemUseOnBeforeEvent) {
|
||||
const currentItemHeld: ItemStack = event.itemStack;
|
||||
const blockInteracted: Block = event.block;
|
||||
const player: Player = event.source as Player;
|
||||
const oldLog = this.log.get(player.name)!;
|
||||
this.log.set(player.name, Date.now());
|
||||
if (oldLog + 150 >= Date.now()) return;
|
||||
|
||||
if (currentItemHeld.typeId == "minecraft:stick" && currentItemHeld.nameTag == "MakeTrigger") {
|
||||
if (this.waitingForPoint2) {
|
||||
this.point2 = vector3(blockInteracted.location.x, blockInteracted.location.y, blockInteracted.location.z);
|
||||
|
||||
let minX = Math.min(this.point1.x, this.point2.x);
|
||||
let maxX = Math.max(this.point1.x, this.point2.x) + 1;
|
||||
let minY = Math.min(this.point1.y, this.point2.y);
|
||||
let maxY = Math.max(this.point1.y, this.point2.y) + 1;
|
||||
let minZ = Math.min(this.point1.z, this.point2.z);
|
||||
let maxZ = Math.max(this.point1.z, this.point2.z) + 1;
|
||||
|
||||
//Take the outer bounds of the two points
|
||||
this.point1 = vector3(minX, minY, minZ);
|
||||
this.point2 = vector3(maxX, maxY, maxZ);
|
||||
|
||||
this.currentTrigger = new Trigger(this.point1, this.point2);
|
||||
|
||||
this.manager.AddTrigger(this.currentTrigger!);
|
||||
this.currentTrigger = null;
|
||||
this.waitingForPoint2 = false;
|
||||
world.sendMessage(`Trigger added`);
|
||||
this.manager.Save();
|
||||
return;
|
||||
} else {
|
||||
this.point1 = vector3(event.block.location.x, event.block.location.y, event.block.location.z);
|
||||
this.waitingForPoint2 = true;
|
||||
world.sendMessage(`Select a second point`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DrawLine(pos1: Vector3, pos2: Vector3, color: PaletteColor): void {
|
||||
if (pos1 != null && pos2 != null) {
|
||||
//draw a line with particles
|
||||
const xStep = pos2.x - pos1.x;
|
||||
const yStep = pos2.y - pos1.y;
|
||||
const zStep = pos2.z - pos1.z;
|
||||
|
||||
const steps = Math.max(Math.abs(xStep), Math.abs(yStep), Math.abs(zStep));
|
||||
for (let i = 0; i <= steps; i++) {
|
||||
const x = pos1.x + (xStep / steps) * i;
|
||||
const y = pos1.y + (yStep / steps) * i;
|
||||
const z = pos1.z + (zStep / steps) * i;
|
||||
|
||||
//make the ends and starts a different color
|
||||
let map = new MolangVariableMap();
|
||||
if (i == 0 || i == steps) {
|
||||
map.setColorRGB("variable.color", { red: 0, green: 255, blue: 0 });
|
||||
const particleData: MolangVariableMap = new MolangVariableMap();
|
||||
particleData.setColorRGB("variable.color", {
|
||||
red: 0,
|
||||
green: 1,
|
||||
blue: 0,
|
||||
});
|
||||
spawnParticle(vector3(x, y + 0.1, z), "codecosmos:point", particleData);
|
||||
} else {
|
||||
map.setColorRGB("variable.color", { red: 0, green: 255, blue: 0 });
|
||||
const particleData: MolangVariableMap = new MolangVariableMap();
|
||||
particleData.setColorRGB("variable.color", {
|
||||
red: 1,
|
||||
green: 1,
|
||||
blue: 1,
|
||||
});
|
||||
spawnParticle(vector3(x, y + 0.1, z), "codecosmos:point", particleData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Update() {
|
||||
let shouldRender = this.mindKeeper.get("ShowTriggers") as boolean;
|
||||
this.manager.GetTriggers().forEach((trigger: Trigger) => {
|
||||
trigger.Update();
|
||||
|
||||
if (shouldRender) {
|
||||
const players = world.getAllPlayers();
|
||||
const triggerCenter = vector3(
|
||||
(trigger.point1.x + trigger.point2.x) / 2,
|
||||
(trigger.point1.y + trigger.point2.y) / 2,
|
||||
(trigger.point1.z + trigger.point2.z) / 2
|
||||
);
|
||||
const distnaces = players.map((player) => {
|
||||
return {
|
||||
player: player,
|
||||
distance: vector3Distance(player.location, triggerCenter),
|
||||
};
|
||||
});
|
||||
|
||||
distnaces.sort((a, b) => a.distance - b.distance);
|
||||
const closestPlayer = distnaces[0].player;
|
||||
const distance = distnaces[0].distance;
|
||||
|
||||
if (distance > 25) return;
|
||||
|
||||
const p1 = trigger.point1;
|
||||
const p2 = vector3(trigger.point1.x, trigger.point2.y, trigger.point1.z);
|
||||
const p3 = vector3(trigger.point2.x, trigger.point1.y, trigger.point1.z);
|
||||
const p4 = vector3(trigger.point2.x, trigger.point2.y, trigger.point1.z);
|
||||
const p5 = vector3(trigger.point1.x, trigger.point1.y, trigger.point2.z);
|
||||
const p6 = vector3(trigger.point1.x, trigger.point2.y, trigger.point2.z);
|
||||
const p7 = vector3(trigger.point2.x, trigger.point1.y, trigger.point2.z);
|
||||
const p8 = trigger.point2;
|
||||
|
||||
//is there a player inside this trigger
|
||||
const color = trigger.IsAnyPlayerInside() ? PaletteColor.Red : PaletteColor.White;
|
||||
this.DrawLine(p1, p2, color);
|
||||
this.DrawLine(p2, p4, color);
|
||||
this.DrawLine(p4, p3, color);
|
||||
this.DrawLine(p3, p1, color);
|
||||
this.DrawLine(p5, p6, color);
|
||||
this.DrawLine(p6, p8, color);
|
||||
this.DrawLine(p8, p7, color);
|
||||
this.DrawLine(p7, p5, color);
|
||||
this.DrawLine(p1, p5, color);
|
||||
this.DrawLine(p2, p6, color);
|
||||
this.DrawLine(p3, p7, color);
|
||||
this.DrawLine(p4, p8, color);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
117
scripts/Commandeer/Trigger/manager.ts
Normal file
117
scripts/Commandeer/Trigger/manager.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import { ChatSendAfterEvent, ItemUseOnBeforeEvent, Player, system, world } from "@minecraft/server";
|
||||
import { Mindkeeper, StoreType } from "../mindKeeper";
|
||||
import { vector3 } from "../utils/vectorUtils";
|
||||
import { Maker } from "./maker";
|
||||
import { Trigger } from "./trigger";
|
||||
|
||||
export class TriggerEvent {
|
||||
player: Player;
|
||||
trigger: Trigger;
|
||||
|
||||
constructor(player: Player, trigger: Trigger) {
|
||||
this.player = player;
|
||||
this.trigger = trigger;
|
||||
}
|
||||
}
|
||||
|
||||
export type TriggerEventHandler = (event: TriggerEvent) => void;
|
||||
|
||||
export class Manager {
|
||||
private triggers: Trigger[] = [];
|
||||
private functionTriggers: Map<string, TriggerEventHandler> = new Map();
|
||||
private mindKeeper: Mindkeeper;
|
||||
private maker: Maker;
|
||||
|
||||
constructor(mindKeeper: Mindkeeper) {
|
||||
this.mindKeeper = mindKeeper;
|
||||
this.maker = new Maker(mindKeeper, this);
|
||||
}
|
||||
|
||||
RegisterStores() {
|
||||
this.mindKeeper.registerStore("triggers", StoreType.string);
|
||||
this.mindKeeper.registerStore("ShowTriggers", StoreType.boolean);
|
||||
}
|
||||
|
||||
OnItemUse(event: ItemUseOnBeforeEvent) {
|
||||
this.maker.OnItemUse(event);
|
||||
}
|
||||
|
||||
OnChat(event: ChatSendAfterEvent) {
|
||||
this.maker.OnChat(event);
|
||||
}
|
||||
//the func should have a TriggerEvent as a parameter
|
||||
RegisterFunctionTrigger(name: string, func: TriggerEventHandler) {
|
||||
this.functionTriggers.set(name, func);
|
||||
}
|
||||
|
||||
//#region Loading / Saving
|
||||
|
||||
Load() {
|
||||
this.LoadTriggers();
|
||||
}
|
||||
|
||||
Save() {
|
||||
this.SaveTriggers();
|
||||
}
|
||||
|
||||
private LoadTriggers() {
|
||||
const triggers = this.mindKeeper.get("triggers") as string;
|
||||
if (triggers === undefined) return;
|
||||
|
||||
const data = JSON.parse(triggers);
|
||||
data.forEach((trigger: any) => {
|
||||
let point1 = vector3(trigger.point1.x, trigger.point1.y, trigger.point1.z);
|
||||
let point2 = vector3(trigger.point2.x, trigger.point2.y, trigger.point2.z);
|
||||
let eventToDispatch = trigger.eventToDispatch;
|
||||
|
||||
let newTrigger = new Trigger(point1, point2);
|
||||
newTrigger.eventToDispatch = eventToDispatch;
|
||||
|
||||
this.triggers.push(newTrigger);
|
||||
});
|
||||
}
|
||||
|
||||
private SaveTriggers() {
|
||||
this.mindKeeper.set("triggers", JSON.stringify(this.triggers));
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
AddTrigger(trigger: Trigger) {
|
||||
this.triggers.push(trigger);
|
||||
}
|
||||
|
||||
GetCurrentActiveTriggers(): Trigger[] {
|
||||
return this.triggers.filter((trigger) => trigger.IsAnyPlayerInside());
|
||||
}
|
||||
|
||||
Update() {
|
||||
const players = world.getAllPlayers();
|
||||
|
||||
this.maker.Update();
|
||||
this.triggers.forEach((trigger: Trigger) => {
|
||||
trigger.Update();
|
||||
|
||||
players.forEach((player) => {
|
||||
// player.sendMessage(`Player ${player.name} is in trigger ${trigger.IsPlayerInside(player)}`);
|
||||
if (trigger.hasPlayerEnterdTrigger(player)) {
|
||||
world.sendMessage(`Player ${player.name} entered trigger`);
|
||||
//Check if a function trigger is set
|
||||
const isFunctionSet = this.functionTriggers.has(trigger.eventToDispatch);
|
||||
|
||||
if (isFunctionSet) {
|
||||
const event = new TriggerEvent(player, trigger);
|
||||
|
||||
this.functionTriggers.get(trigger.eventToDispatch)!(event);
|
||||
} else {
|
||||
world.sendMessage(`Triggered ${trigger.eventToDispatch}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
GetTriggers(): Trigger[] {
|
||||
return this.triggers;
|
||||
}
|
||||
}
|
||||
82
scripts/Commandeer/Trigger/trigger.ts
Normal file
82
scripts/Commandeer/Trigger/trigger.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { Player, Vector3, world } from "@minecraft/server";
|
||||
import { vector3 } from "../utils/vectorUtils";
|
||||
|
||||
export class Trigger {
|
||||
point1: Vector3 = vector3(0, 0, 0);
|
||||
point2: Vector3 = vector3(0, 0, 0);
|
||||
eventToDispatch: string = "";
|
||||
|
||||
isPlayerInTrigger: Map<string, boolean> = new Map();
|
||||
|
||||
hasTriggerd: boolean = false;
|
||||
|
||||
constructor(point1: Vector3, point2: Vector3) {
|
||||
this.point1 = point1;
|
||||
this.point2 = point2;
|
||||
}
|
||||
|
||||
hasPlayerEnterdTrigger(player: Player): boolean {
|
||||
const minX = Math.min(this.point1.x, this.point2.x);
|
||||
const maxX = Math.max(this.point1.x, this.point2.x);
|
||||
const minY = Math.min(this.point1.y, this.point2.y);
|
||||
const maxY = Math.max(this.point1.y, this.point2.y);
|
||||
const minZ = Math.min(this.point1.z, this.point2.z);
|
||||
const maxZ = Math.max(this.point1.z, this.point2.z);
|
||||
|
||||
const playerPos = player.location;
|
||||
|
||||
const inside =
|
||||
playerPos.x >= minX &&
|
||||
playerPos.x <= maxX &&
|
||||
playerPos.y >= minY &&
|
||||
playerPos.y + 1 <= maxY &&
|
||||
playerPos.z >= minZ &&
|
||||
playerPos.z <= maxZ;
|
||||
|
||||
let entererdTrigger = false;
|
||||
if (!this.isPlayerInTrigger.get(player.name) && inside) {
|
||||
entererdTrigger = true;
|
||||
}
|
||||
|
||||
this.isPlayerInTrigger.set(player.name, inside);
|
||||
|
||||
return entererdTrigger;
|
||||
}
|
||||
|
||||
IsPlayerInside(player: Player): boolean {
|
||||
return this.isPlayerInTrigger.get(player.name) || false;
|
||||
}
|
||||
|
||||
IsAnyPlayerInside(): boolean {
|
||||
let isInside = false;
|
||||
world.getAllPlayers().forEach((player) => {
|
||||
if (this.isPlayerInTrigger.get(player.name)) {
|
||||
isInside = true;
|
||||
}
|
||||
});
|
||||
return isInside;
|
||||
}
|
||||
|
||||
ShouldTrigger(): boolean {
|
||||
let isSomethingInTrigger = false;
|
||||
const players = world.getAllPlayers();
|
||||
players.forEach((player) => {
|
||||
if (this.hasPlayerEnterdTrigger(player)) {
|
||||
isSomethingInTrigger = true;
|
||||
}
|
||||
});
|
||||
return isSomethingInTrigger;
|
||||
}
|
||||
|
||||
Update() {
|
||||
world
|
||||
.getDimension("overworld")
|
||||
.getEntities({ type: "minecraft:player" })
|
||||
.forEach((player) => {
|
||||
//Check if the distance between the player and the trigger is less than the width of the trigger
|
||||
// if (this.hasPlayerEnterdTrigger(player.location)) {
|
||||
// world.sendMessage(`Player ${player.nameTag} is in trigger`);
|
||||
// }
|
||||
});
|
||||
}
|
||||
}
|
||||
70
scripts/Commandeer/chalk.ts
Normal file
70
scripts/Commandeer/chalk.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
class Chalk {
|
||||
static red(text: string): string {
|
||||
return "§c" + text + "§r";
|
||||
}
|
||||
static yellow(text: string): string {
|
||||
return "§e" + text + "§r";
|
||||
}
|
||||
static green(text: string): string {
|
||||
return "§a" + text + "§r";
|
||||
}
|
||||
static blue(text: string): string {
|
||||
return "§9" + text + "§r";
|
||||
}
|
||||
static aqua(text: string): string {
|
||||
return "§b" + text + "§r";
|
||||
}
|
||||
static white(text: string): string {
|
||||
return "§f" + text + "§r";
|
||||
}
|
||||
static black(text: string): string {
|
||||
return "§0" + text + "§r";
|
||||
}
|
||||
static gold(text: string): string {
|
||||
return "§6" + text + "§r";
|
||||
}
|
||||
static gray(text: string): string {
|
||||
return "§7" + text + "§r";
|
||||
}
|
||||
static darkRed(text: string): string {
|
||||
return "§4" + text + "§r";
|
||||
}
|
||||
static darkGreen(text: string): string {
|
||||
return "§2" + text + "§r";
|
||||
}
|
||||
static darkBlue(text: string): string {
|
||||
return "§1" + text + "§r";
|
||||
}
|
||||
static darkAqua(text: string): string {
|
||||
return "§3" + text + "§r";
|
||||
}
|
||||
static darkPurple(text: string): string {
|
||||
return "§5" + text + "§r";
|
||||
}
|
||||
static darkGray(text: string): string {
|
||||
return "§8" + text + "§r";
|
||||
}
|
||||
static lightPurple(text: string): string {
|
||||
return "§d" + text + "§r";
|
||||
}
|
||||
static bold(text: string): string {
|
||||
return "§l" + text + "§r";
|
||||
}
|
||||
static italic(text: string): string {
|
||||
return "§o" + text + "§r";
|
||||
}
|
||||
static underline(text: string): string {
|
||||
return "§n" + text + "§r";
|
||||
}
|
||||
static strikethrough(text: string): string {
|
||||
return "§m" + text + "§r";
|
||||
}
|
||||
static obfuscated(text: string): string {
|
||||
return "§k" + text + "§r";
|
||||
}
|
||||
static reset(text: string): string {
|
||||
return "§r" + text + "§r";
|
||||
}
|
||||
}
|
||||
|
||||
export default Chalk;
|
||||
99
scripts/Commandeer/command/command.ts
Normal file
99
scripts/Commandeer/command/command.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { CommandResult, Dimension, Entity, world, Player } from "@minecraft/server";
|
||||
|
||||
export class Command {
|
||||
private __player: Player;
|
||||
public argv: IterableIterator<string>;
|
||||
public get player(): Player {
|
||||
return this.__player;
|
||||
}
|
||||
public get argv0(): string {
|
||||
return this.argv.next().value;
|
||||
}
|
||||
constructor(argv: string[], player: Player) {
|
||||
this.argv = (function* () {
|
||||
for (let arg of argv) yield arg;
|
||||
})();
|
||||
this.__player = player;
|
||||
}
|
||||
}
|
||||
|
||||
export class Commands {
|
||||
/**
|
||||
* @remarks
|
||||
* Runs a particular command synchronously from the context.
|
||||
* @param commandString
|
||||
* Command to run. Note that command strings should not start
|
||||
* with slash.
|
||||
* @param target
|
||||
* Target to be used as context for the command to run
|
||||
* within.
|
||||
* @returns
|
||||
* For commands that return data, returns a CommandResult with
|
||||
* an indicator of command results.
|
||||
* @throws This function can throw errors.
|
||||
*/
|
||||
static run(commandString: string, target: Dimension | Entity = world.getDimension("overworld")): CommandResult {
|
||||
if (target instanceof Dimension || Entity) return target.runCommand(commandString);
|
||||
else throw TypeError("Native type conversion failed");
|
||||
}
|
||||
/**
|
||||
* @remarks
|
||||
* Runs a particular command asynchronously from the context.
|
||||
* Where possible - and especially for
|
||||
* long-running operations - you should use runCommandAsync
|
||||
* over runCommand.
|
||||
* @param commandString
|
||||
* Command to run. Note that command strings should not start
|
||||
* with slash.
|
||||
* @param target
|
||||
* Target to be used as context for the command to run
|
||||
* within.
|
||||
* @returns
|
||||
* For commands that return data, returns a CommandResult with
|
||||
* an indicator of command results.
|
||||
* @throws This function can throw errors.
|
||||
*/
|
||||
static async runAsync(
|
||||
commandString: string,
|
||||
target: Dimension | Entity = world.getDimension("overworld")
|
||||
): Promise<CommandResult> {
|
||||
if (target instanceof Dimension || Entity) return await target.runCommandAsync(commandString);
|
||||
else throw TypeError("Native type conversion failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* @remarks
|
||||
* Registers a new custom command. This command will become
|
||||
* available in Minecraft via [prefix][command].
|
||||
* @param prefix
|
||||
* The prefix of this specific command. (Case sensitive)
|
||||
* @param command
|
||||
* Name of this specific command. (Case sensitive)
|
||||
* @param commandFunction
|
||||
* Implementation of the command function.
|
||||
* @throws
|
||||
* This function can throw error: You are not allow to register a new slash command.
|
||||
* @example example1.js
|
||||
* ```typescript
|
||||
* Commands.register("!", "test", function (arg) {
|
||||
* arg.player.runCommandAsync(`say ${arg.argv0} ${JSON.stringify([...arg.argv])}`);
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
public static register(prefix: string, command: string, commandFunction: (arg: Command) => void): void {
|
||||
if (prefix.startsWith("/")) throw Error("Unable to register slash commands.");
|
||||
world.beforeEvents.chatSend.subscribe((arg) => {
|
||||
var argv = arg.message.split(/(".*?"|[^"\s]+)+(?=\s*|\s*$)/g).filter((e) => e.trim().length > 0);
|
||||
if (argv[0] === `${prefix}${command}`) {
|
||||
arg.cancel = true;
|
||||
try {
|
||||
commandFunction(new Command(argv, arg.sender));
|
||||
} catch (err) {
|
||||
let { statusMessage } = JSON.parse(err as string);
|
||||
console.error(err);
|
||||
arg.sender.sendMessage(`§c${statusMessage}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
abstract class AbstractLevelCondition {
|
||||
constructor() {}
|
||||
|
||||
abstract checkCondition(): boolean;
|
||||
}
|
||||
|
||||
export default AbstractLevelCondition;
|
||||
|
||||
//Interface could be better
|
||||
24
scripts/Commandeer/completionCondition/BlockCondition.ts
Normal file
24
scripts/Commandeer/completionCondition/BlockCondition.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { BlockType, Vector3, world } from "@minecraft/server";
|
||||
import AbstractLevelCondition from "./AbstractCondition";
|
||||
import { Vector3ToString } from "../utils/vectorUtils";
|
||||
|
||||
class BlockCondition extends AbstractLevelCondition {
|
||||
position: Vector3;
|
||||
blockType: BlockType;
|
||||
|
||||
constructor(position: Vector3, blockType: BlockType) {
|
||||
super();
|
||||
this.position = position;
|
||||
this.blockType = blockType;
|
||||
}
|
||||
|
||||
checkCondition(): boolean {
|
||||
const block = world.getDimension("overworld").getBlock(this.position);
|
||||
if (!block) {
|
||||
return false;
|
||||
}
|
||||
return block.typeId === this.blockType.id;
|
||||
}
|
||||
}
|
||||
|
||||
export default BlockCondition;
|
||||
@@ -0,0 +1,21 @@
|
||||
import { BlockType, Vector3, world } from "@minecraft/server";
|
||||
import AbstractLevelCondition from "./AbstractCondition";
|
||||
|
||||
class ButtonPushCondition extends AbstractLevelCondition {
|
||||
position: Vector3;
|
||||
|
||||
constructor(position: Vector3) {
|
||||
super();
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
checkCondition(): boolean {
|
||||
const button = world.getDimension("overworld").getBlock(this.position);
|
||||
if (!button || !button.getRedstonePower()) {
|
||||
return false;
|
||||
}
|
||||
return button.getRedstonePower()! > 0;
|
||||
}
|
||||
}
|
||||
|
||||
export default ButtonPushCondition;
|
||||
52
scripts/Commandeer/level/level.ts
Normal file
52
scripts/Commandeer/level/level.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { World } from "@minecraft/server";
|
||||
|
||||
class Level {
|
||||
levelCompleteCallback: Function;
|
||||
levelCheckCallback: Function;
|
||||
levelSetupCallback: Function;
|
||||
levelUpdateCallback: Function;
|
||||
levelResetCallback: Function;
|
||||
isCompleted: boolean = false;
|
||||
isSetup: boolean = false;
|
||||
|
||||
constructor(
|
||||
levelSetupCallback: Function,
|
||||
levelUpdateCallback: Function,
|
||||
levelCompleteCallback: Function,
|
||||
levelCheckCallback: Function,
|
||||
levelResetCallback: Function = () => {}
|
||||
) {
|
||||
this.levelSetupCallback = levelSetupCallback;
|
||||
this.levelCompleteCallback = levelCompleteCallback;
|
||||
this.levelCheckCallback = levelCheckCallback;
|
||||
this.levelUpdateCallback = levelUpdateCallback;
|
||||
this.levelResetCallback = levelResetCallback;
|
||||
}
|
||||
|
||||
setup() {
|
||||
this.levelSetupCallback();
|
||||
}
|
||||
|
||||
update() {
|
||||
if (!this.isSetup) {
|
||||
this.setup();
|
||||
this.isSetup = true;
|
||||
}
|
||||
this.levelUpdateCallback();
|
||||
if (this.levelCheckCallback() && !this.isCompleted) {
|
||||
this.levelCompleteCallback();
|
||||
this.isCompleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.levelResetCallback();
|
||||
this.isCompleted = false;
|
||||
}
|
||||
}
|
||||
|
||||
//nextlevel
|
||||
//mindkeeper
|
||||
//pupeteer
|
||||
|
||||
export default Level;
|
||||
44
scripts/Commandeer/level/levelTypes.ts
Normal file
44
scripts/Commandeer/level/levelTypes.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { BlockType, Vector3, World } from "@minecraft/server";
|
||||
|
||||
export type blockCondition = {
|
||||
block: string;
|
||||
position: Vector3;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if there is a lever at the specified position in the world.
|
||||
*
|
||||
* @param world - The world object.
|
||||
* @param position - The position of the lever.
|
||||
* @returns Returns true if there is a lever at the specified position and it has a redstone power of 15, otherwise returns false.
|
||||
* @throws Throws an error if there is no lever at the specified position.
|
||||
*/
|
||||
export function leverOn(world: World, position: Vector3): boolean {
|
||||
let lever = world.getDimension("overworld").getBlock(position);
|
||||
if (!(lever?.typeId == "minecraft:lever")) {
|
||||
throw new Error(`No lever at ${position}`);
|
||||
}
|
||||
return lever.getRedstonePower() == 15;
|
||||
}
|
||||
|
||||
export type LeverCondition = {
|
||||
position: Vector3;
|
||||
state: boolean;
|
||||
};
|
||||
|
||||
export type LevelBlockCondition = {
|
||||
conditions: blockCondition[];
|
||||
};
|
||||
|
||||
export type LevelLeverCondition = {
|
||||
conditions: LeverCondition[];
|
||||
};
|
||||
|
||||
export type AgentNoGoZone = {
|
||||
//Reason for needing to use is because the Agent can't be queried for its location in minecraft
|
||||
position: Vector3;
|
||||
};
|
||||
|
||||
export type LevelNoGoZone = {
|
||||
zones: AgentNoGoZone[];
|
||||
};
|
||||
230
scripts/Commandeer/mindKeeper.ts
Normal file
230
scripts/Commandeer/mindKeeper.ts
Normal file
@@ -0,0 +1,230 @@
|
||||
import { ChatSendAfterEvent, Vector3, World, system } from "@minecraft/server";
|
||||
|
||||
class Store {
|
||||
type: StoreType;
|
||||
name: string;
|
||||
|
||||
constructor(type: StoreType, name: string) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
getType(): StoreType {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
enum StoreType {
|
||||
string = "string",
|
||||
number = "number",
|
||||
boolean = "boolean",
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a Mindkeeper, responsible for managing stores and dynamic properties in a world.
|
||||
*/
|
||||
class Mindkeeper {
|
||||
registerdStores: Array<Store> = [];
|
||||
// propertyManager = new DynamicPropertiesDefinition();
|
||||
world: World;
|
||||
initialised: boolean = false;
|
||||
debugLog: string[] = [];
|
||||
|
||||
/**
|
||||
* Creates a new instance of Mindkeeper.
|
||||
* @param world The world associated with the Mindkeeper.
|
||||
*/
|
||||
constructor(world: World) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a store with the specified name and type.
|
||||
* @param store The name of the store.
|
||||
* @param type The type of the store.
|
||||
*/
|
||||
registerStore(store: string, type: StoreType): void {
|
||||
this.registerdStores.push(new Store(type, store));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of registered stores.
|
||||
* @returns An array of registered stores.
|
||||
*/
|
||||
getStores() {
|
||||
return this.registerdStores;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the debug log by sending each log entry as a message to the world.
|
||||
*/
|
||||
printDebug() {
|
||||
this.debugLog.forEach((t) => {
|
||||
this.world.sendMessage(t);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the dynamic properties to the world's property registry.
|
||||
* @param propertyRegistry The property registry of the world.
|
||||
*/
|
||||
registerToWorld() {
|
||||
for (let i = 0; i < this.registerdStores.length; i++) {
|
||||
let isAlreadyDefined = true;
|
||||
|
||||
try {
|
||||
let test = this.world.getDynamicProperty(this.registerdStores[i].getName());
|
||||
if (test === undefined) {
|
||||
isAlreadyDefined = false;
|
||||
}
|
||||
} catch (e) {
|
||||
isAlreadyDefined = false;
|
||||
}
|
||||
if (isAlreadyDefined) {
|
||||
continue;
|
||||
}
|
||||
switch (this.registerdStores[i].getType()) {
|
||||
case StoreType.string:
|
||||
this.world.setDynamicProperty(this.registerdStores[i].getName(), "");
|
||||
this.debugLog.push("registerd string" + this.registerdStores[i].getName());
|
||||
break;
|
||||
case StoreType.number:
|
||||
this.world.setDynamicProperty(this.registerdStores[i].getName(), 0);
|
||||
this.debugLog.push("registerd number" + this.registerdStores[i].getName());
|
||||
break;
|
||||
case StoreType.boolean:
|
||||
this.world.setDynamicProperty(this.registerdStores[i].getName(), false);
|
||||
this.debugLog.push("registerd boolean" + this.registerdStores[i].getName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.initialised = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a store.
|
||||
* @param store The name of the store.
|
||||
* @param value The value to set.
|
||||
*/
|
||||
set(store: string, value: string | number | boolean | Vector3): void {
|
||||
if (this.registerdStores.find((s) => s.getName() === store)?.getType() != typeof value) {
|
||||
this.world.sendMessage(`Store ${store} is not of type ${typeof value}`);
|
||||
return;
|
||||
}
|
||||
system.run(() => {
|
||||
this.world.setDynamicProperty(store, value);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the value of a store.
|
||||
* @param store The name of the store.
|
||||
* @returns The value of the store, or undefined if the store is not defined.
|
||||
*/
|
||||
get(store: string): string | number | boolean | Vector3 | undefined {
|
||||
try {
|
||||
let data = this.world.getDynamicProperty(store);
|
||||
if (data === undefined) {
|
||||
this.world.sendMessage(`Store ${store} is not defined`);
|
||||
return undefined;
|
||||
}
|
||||
return data;
|
||||
} catch (e) {
|
||||
// this.world.sendMessage(`Store ${store} is not defined`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the value of a store if it is a number.
|
||||
* @param store The name of the store.
|
||||
*/
|
||||
increment(store: string): void {
|
||||
let data = this.get(store);
|
||||
if (typeof data === "number") {
|
||||
this.set(store, data + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles chat commands by executing the corresponding actions.
|
||||
* @param event The chat send after event.
|
||||
*/
|
||||
private secondWarning = false;
|
||||
chatCommands(event: ChatSendAfterEvent) {
|
||||
const command = event.message.split(" ")[0];
|
||||
const args = event.message.split(" ").slice(1);
|
||||
|
||||
if (command === "!get") {
|
||||
const store = event.message.split(" ")[1];
|
||||
const value = this.get(store);
|
||||
this.world.sendMessage(`Value of ${store} is ${value}`);
|
||||
}
|
||||
if (command === "!set") {
|
||||
const store = event.message.split(" ")[1];
|
||||
if (store === undefined) {
|
||||
this.world.sendMessage(`Please provide a store to set`);
|
||||
return;
|
||||
}
|
||||
const value = event.message.split(" ")[2];
|
||||
if (value === undefined) {
|
||||
this.world.sendMessage(`Please provide a value to set for ${store}`);
|
||||
return;
|
||||
}
|
||||
const type = event.message.split(" ")[3];
|
||||
|
||||
let actualType = this.getStores()
|
||||
.find((s) => s.getName() === store)
|
||||
?.getType();
|
||||
|
||||
if (actualType === undefined) {
|
||||
this.world.sendMessage(`Store ${store} is not defined`);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (actualType) {
|
||||
case StoreType.string:
|
||||
this.set(store, String(value));
|
||||
break;
|
||||
case StoreType.number:
|
||||
if (isNaN(Number(value))) {
|
||||
this.world.sendMessage(`Can't parse ${value} as a number`);
|
||||
return;
|
||||
}
|
||||
this.set(store, Number(value));
|
||||
break;
|
||||
case StoreType.boolean:
|
||||
const ActualValue = value.toLowerCase();
|
||||
this.set(store, ActualValue === "true");
|
||||
break;
|
||||
}
|
||||
this.world.sendMessage(`Value of ${store} is ${value}`);
|
||||
}
|
||||
if (event.message.startsWith("!listStores")) {
|
||||
this.getStores().forEach((store) => {
|
||||
this.world.sendMessage(`${store.getName()} is ${store.getType()}`);
|
||||
});
|
||||
}
|
||||
if (command === "!deleteStores") {
|
||||
this.world.sendMessage("ARE YOU SURE YOU WANT TO DELETE ALL STORES? THIS COULD CAUSE ISSUES");
|
||||
this.world.sendMessage("If you are sure, type !deleteStoresConfirm");
|
||||
this.secondWarning = true;
|
||||
}
|
||||
if (this.secondWarning) {
|
||||
if (command === "!deleteStoresConfirm") {
|
||||
this.getStores().forEach((store) => {
|
||||
this.world.sendMessage(`Deleting ${store.getName()}`);
|
||||
this.world.sendMessage("This feature no longer works, thanks minecraft ");
|
||||
// this.world.dynami(store.getName());
|
||||
});
|
||||
this.secondWarning = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { Mindkeeper, Store, StoreType };
|
||||
16
scripts/Commandeer/nextLevel.ts
Normal file
16
scripts/Commandeer/nextLevel.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
class NextLevel {
|
||||
currentState = 0;
|
||||
states: Array<Function> = [];
|
||||
|
||||
constructor(states: Array<Function>) {
|
||||
this.states = states;
|
||||
}
|
||||
|
||||
update() {
|
||||
this.states[this.currentState]();
|
||||
}
|
||||
|
||||
next() {
|
||||
this.currentState++;
|
||||
}
|
||||
}
|
||||
112
scripts/Commandeer/pupeteer.ts
Normal file
112
scripts/Commandeer/pupeteer.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import {
|
||||
EntityInventoryComponent,
|
||||
ItemStack,
|
||||
Player,
|
||||
RawText,
|
||||
TicksPerSecond,
|
||||
TitleDisplayOptions,
|
||||
Vector3,
|
||||
World,
|
||||
system,
|
||||
world,
|
||||
} from "@minecraft/server";
|
||||
import { delayedRun } from "./utils/waitUtil";
|
||||
|
||||
class Pupeteer {
|
||||
private static getActualString(message: string): string | RawText {
|
||||
if (message.startsWith("%")) {
|
||||
const key = message.substring(1);
|
||||
return { rawtext: [{ translate: key }] };
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
static setActionBarTimed(message: string, duration: number): void {
|
||||
world.getPlayers().forEach((player) => {
|
||||
system.run(() => {
|
||||
player.onScreenDisplay.setActionBar(this.getActualString(message));
|
||||
});
|
||||
});
|
||||
delayedRun(() => {
|
||||
this.clearActionBar();
|
||||
}, duration * TicksPerSecond);
|
||||
}
|
||||
|
||||
static setActionBar(message: string): void {
|
||||
world.getPlayers().forEach((player) => {
|
||||
system.run(() => {
|
||||
player.onScreenDisplay.setActionBar(this.getActualString(message));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static sendWorldMessage(message: string): void {
|
||||
world.sendMessage(this.getActualString(message));
|
||||
}
|
||||
|
||||
static setTitleTimed(message: string, duration: number): void {
|
||||
world.getPlayers().forEach((player) => {
|
||||
let options: TitleDisplayOptions = {
|
||||
fadeInDuration: 20,
|
||||
fadeOutDuration: 20,
|
||||
stayDuration: duration * TicksPerSecond,
|
||||
};
|
||||
player.onScreenDisplay.setTitle(this.getActualString(message), options);
|
||||
});
|
||||
}
|
||||
|
||||
static setTitle(message: string): void {
|
||||
world.getPlayers().forEach((player) => {
|
||||
player.onScreenDisplay.setTitle(message);
|
||||
});
|
||||
}
|
||||
|
||||
static updateSubtitle(message: string): void {
|
||||
world.getPlayers().forEach((player) => {
|
||||
player.onScreenDisplay.updateSubtitle(this.getActualString(message));
|
||||
});
|
||||
}
|
||||
|
||||
static clearTitle(): void {
|
||||
world.getPlayers().forEach((player) => {
|
||||
player.onScreenDisplay.setTitle("");
|
||||
});
|
||||
}
|
||||
|
||||
static clearSubtitle(): void {
|
||||
world.getPlayers().forEach((player) => {
|
||||
player.onScreenDisplay.updateSubtitle("");
|
||||
});
|
||||
}
|
||||
|
||||
static clearActionBar(): void {
|
||||
world.getPlayers().forEach((player) => {
|
||||
player.onScreenDisplay.setActionBar("");
|
||||
});
|
||||
}
|
||||
|
||||
static testForLocation(location: Vector3, radius: number): boolean {
|
||||
let isPlayerInArea = false;
|
||||
world.getPlayers().forEach((player) => {
|
||||
let dx = location.x - player.location.x;
|
||||
let dy = location.y - player.location.y;
|
||||
let dz = location.z - player.location.z;
|
||||
|
||||
let distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
if (distance < radius) {
|
||||
isPlayerInArea = true;
|
||||
}
|
||||
});
|
||||
return isPlayerInArea;
|
||||
}
|
||||
|
||||
static setNpcText(npcTag: string, sceneName: string) {
|
||||
world.getDimension("overworld").runCommand(`/dialogue change @e[tag=${npcTag}] ${sceneName} @a`);
|
||||
}
|
||||
|
||||
static givePlayerItem(player: Player, item: ItemStack) {
|
||||
(player.getComponent("inventory") as EntityInventoryComponent).container!.addItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
export default Pupeteer;
|
||||
85
scripts/Commandeer/trail/trailEngine.ts
Normal file
85
scripts/Commandeer/trail/trailEngine.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { MolangVariableMap, Vector3, world } from "@minecraft/server";
|
||||
import { Vector3Add } from "../utils/vectorUtils";
|
||||
import { TrailType } from "./trailTypes";
|
||||
|
||||
class TrailPoint {
|
||||
postion: Vector3;
|
||||
index: number;
|
||||
|
||||
constructor(position: Vector3, index: number) {
|
||||
this.postion = position;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
spawn() {
|
||||
// let spawnPosition: Vector3 = Vector3Add(this.postion, { x: 0.5, y: 0.5, z: 0.5 });
|
||||
let spawnPosition: Vector3 = this.postion;
|
||||
try {
|
||||
world
|
||||
.getDimension("overworld")
|
||||
.spawnParticle("minecraft:balloon_gas_particle", spawnPosition, new MolangVariableMap());
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
class Trail {
|
||||
id: string;
|
||||
points: TrailPoint[] = [];
|
||||
currentPoint: number = 0;
|
||||
wrapIndex: number = 0;
|
||||
nextParticleTimer: number = 0;
|
||||
currentParticleCounter: number = 0;
|
||||
|
||||
calculatedLength: number = 0;
|
||||
constructor(id: string, nextParticleTimer: number = 5, wrapIndex: number = 0) {
|
||||
this.id = id;
|
||||
this.nextParticleTimer = nextParticleTimer;
|
||||
this.wrapIndex = wrapIndex;
|
||||
}
|
||||
|
||||
addPoint(point: TrailPoint) {
|
||||
this.points.push(point);
|
||||
|
||||
//this could be a one liner,
|
||||
let maxlength: number = 0;
|
||||
this.points.forEach((point) => {
|
||||
if (point.index > maxlength) {
|
||||
maxlength = point.index;
|
||||
}
|
||||
});
|
||||
this.calculatedLength = maxlength;
|
||||
}
|
||||
|
||||
fromTrail(trail: TrailType) {
|
||||
trail.points.forEach((point) => {
|
||||
this.addPoint(new TrailPoint(point.position, point.index));
|
||||
});
|
||||
}
|
||||
|
||||
spawnNext() {
|
||||
if (this.currentParticleCounter >= this.nextParticleTimer) {
|
||||
this.currentParticleCounter = 0;
|
||||
//wrapindex is in how many segments the trail is divided into
|
||||
let pointsPerInterval = this.wrapIndex > 0 ? this.calculatedLength / this.wrapIndex : 0;
|
||||
this.points
|
||||
.filter((point) => {
|
||||
return (
|
||||
point.index === this.currentPoint ||
|
||||
(this.wrapIndex > 0 && point.index % pointsPerInterval === this.currentPoint)
|
||||
);
|
||||
})
|
||||
.forEach((point) => {
|
||||
point.spawn();
|
||||
});
|
||||
|
||||
this.currentPoint++;
|
||||
if (this.currentPoint >= this.calculatedLength) {
|
||||
this.currentPoint = 0;
|
||||
}
|
||||
} else {
|
||||
this.currentParticleCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { Trail, TrailPoint };
|
||||
212
scripts/Commandeer/trail/trailMaker.ts
Normal file
212
scripts/Commandeer/trail/trailMaker.ts
Normal file
@@ -0,0 +1,212 @@
|
||||
import {
|
||||
Block,
|
||||
ChatSendAfterEvent,
|
||||
EntityInventoryComponent,
|
||||
ItemStack,
|
||||
ItemUseOnBeforeEvent,
|
||||
MolangVariableMap,
|
||||
Player,
|
||||
world,
|
||||
} from "@minecraft/server";
|
||||
import { Vector3 } from "@minecraft/server";
|
||||
import { Vector3Add, Vector3ToString, vector3 } from "../utils/vectorUtils";
|
||||
import { spawnParticle } from "../utils/particleUtils";
|
||||
import Pupeteer from "../pupeteer";
|
||||
import Chalk from "../chalk";
|
||||
|
||||
export namespace TrailMaker {
|
||||
export class Maker {
|
||||
currentTrail: Trail;
|
||||
log: Map<string, number> = new Map();
|
||||
selectedIndex: number = 0;
|
||||
|
||||
//Line
|
||||
point1: Vector3 = vector3(0, 0, 0);
|
||||
point2: Vector3 = vector3(0, 0, 0);
|
||||
|
||||
waitingForPoint2: boolean = false;
|
||||
|
||||
OnChat(event: ChatSendAfterEvent) {
|
||||
if (event.message == "!trailWand") {
|
||||
let item: ItemStack = new ItemStack("minecraft:stick");
|
||||
item.nameTag = "AddPoint";
|
||||
Pupeteer.givePlayerItem(event.sender as Player, item);
|
||||
world.sendMessage("Thou shall have the Trailing Powah");
|
||||
}
|
||||
if (event.message == "!trailDeleteWand") {
|
||||
let item: ItemStack = new ItemStack("minecraft:stick");
|
||||
item.nameTag = "DeletePoint";
|
||||
Pupeteer.givePlayerItem(event.sender as Player, item);
|
||||
world.sendMessage("Luke, i'm NOT your father");
|
||||
}
|
||||
if (event.message == "!trailLineWand") {
|
||||
let item: ItemStack = new ItemStack("minecraft:stick");
|
||||
item.nameTag = "AddLine";
|
||||
Pupeteer.givePlayerItem(event.sender as Player, item);
|
||||
world.sendMessage(`This is where i draw the ${Chalk.red("Line")} >:(`);
|
||||
}
|
||||
if (event.message == "!trailExport") {
|
||||
this.Export();
|
||||
}
|
||||
}
|
||||
OnItemUse(event: ItemUseOnBeforeEvent) {
|
||||
const currentItemHeld: ItemStack = event.itemStack;
|
||||
const blockInteracted: Block = event.block;
|
||||
const player: Player = event.source as Player;
|
||||
const oldLog = this.log.get(player.name)!;
|
||||
this.log.set(player.name, Date.now());
|
||||
if (oldLog + 150 >= Date.now()) return;
|
||||
|
||||
if (event.itemStack.typeId == "minecraft:stick" && event.itemStack.nameTag == "AddPoint") {
|
||||
let block = event.block;
|
||||
let pos = this.BlockToParticlePosition(block);
|
||||
world.sendMessage(`Added Point ${Vector3ToString(pos)}`);
|
||||
this.currentTrail.points.push(new Point(pos, this.currentTrail.currentPoint));
|
||||
|
||||
this.currentTrail.currentPoint++;
|
||||
Pupeteer.setActionBarTimed(`Added point ${this.currentTrail.currentPoint}`, 3);
|
||||
}
|
||||
|
||||
if (event.itemStack.typeId == "minecraft:stick" && event.itemStack.nameTag == "DeletePoint") {
|
||||
let block = event.block;
|
||||
let pos = this.BlockToParticlePosition(block);
|
||||
|
||||
let point = this.currentTrail.points.find((point) => Vector3ToString(point.position) == Vector3ToString(pos));
|
||||
if (point) {
|
||||
this.currentTrail.points.splice(this.currentTrail.points.indexOf(point), 1);
|
||||
Pupeteer.setActionBarTimed(`Deleted point ${point.index}`, 3);
|
||||
} else {
|
||||
Pupeteer.setActionBarTimed(`No point found`, 3);
|
||||
}
|
||||
}
|
||||
|
||||
if (event.itemStack.typeId == "minecraft:stick" && event.itemStack.nameTag == "AddLine") {
|
||||
world.sendMessage(`Waiting for point 2: ${this.waitingForPoint2}`);
|
||||
if (!this.waitingForPoint2) {
|
||||
// this.point1 = vector3(blockInteracted.location.x, blockInteracted.location.y, blockInteracted.location.z);
|
||||
this.point1 = this.BlockToParticlePosition(blockInteracted);
|
||||
|
||||
this.waitingForPoint2 = true;
|
||||
Pupeteer.setActionBar("Select a second point");
|
||||
world.sendMessage("Select a second point");
|
||||
|
||||
return;
|
||||
} else {
|
||||
this.point2 = this.BlockToParticlePosition(blockInteracted);
|
||||
|
||||
//Calculate the blocks between these 2 points, andd add them to the trail
|
||||
//Assume point1 is the start, and point2 is the end
|
||||
let x1 = this.point1.x;
|
||||
let x2 = this.point2.x;
|
||||
let y1 = this.point1.y;
|
||||
let y2 = this.point2.y;
|
||||
let z1 = this.point1.z;
|
||||
let z2 = this.point2.z;
|
||||
|
||||
//Find out what axis is the movement on, throw an error if it's on more than one axis
|
||||
|
||||
let xDiff = Math.abs(x2 - x1);
|
||||
let yDiff = Math.abs(y2 - y1);
|
||||
let zDiff = Math.abs(z2 - z1);
|
||||
|
||||
let axis = "";
|
||||
|
||||
if (xDiff > 0 && yDiff == 0 && zDiff == 0) {
|
||||
axis = "x";
|
||||
} else if (xDiff == 0 && yDiff > 0 && zDiff == 0) {
|
||||
axis = "y";
|
||||
} else if (xDiff == 0 && yDiff == 0 && zDiff > 0) {
|
||||
axis = "z";
|
||||
} else {
|
||||
Pupeteer.setActionBarTimed("Invalid line", 3);
|
||||
return;
|
||||
}
|
||||
|
||||
let start = 0;
|
||||
let end = 0;
|
||||
|
||||
if (axis == "x") {
|
||||
start = Math.min(x1, x2);
|
||||
end = Math.max(x1, x2);
|
||||
} else if (axis == "y") {
|
||||
start = Math.min(y1, y2);
|
||||
end = Math.max(y1, y2);
|
||||
} else if (axis == "z") {
|
||||
start = Math.min(z1, z2);
|
||||
end = Math.max(z1, z2);
|
||||
}
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
let pos = vector3(0, 0, 0);
|
||||
if (axis == "x") {
|
||||
pos = vector3(i, y1, z1);
|
||||
} else if (axis == "y") {
|
||||
pos = vector3(x1, i, z1);
|
||||
} else if (axis == "z") {
|
||||
pos = vector3(x1, y1, i);
|
||||
}
|
||||
|
||||
this.currentTrail.points.push(new Point(pos, this.currentTrail.currentPoint));
|
||||
this.currentTrail.currentPoint++;
|
||||
}
|
||||
|
||||
this.waitingForPoint2 = false;
|
||||
Pupeteer.setActionBarTimed("Added line", 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Update() {
|
||||
this.currentTrail.points.forEach((point) => {
|
||||
spawnParticle(point.position, "minecraft:balloon_gas_particle", new MolangVariableMap());
|
||||
});
|
||||
}
|
||||
|
||||
Export() {
|
||||
let output = "";
|
||||
for (let i = 0; i < this.currentTrail.points.length; i++) {
|
||||
let point = this.currentTrail.points[i];
|
||||
let actualPos = point.position;
|
||||
output += `{ index: ${point.index}, position: vector3(${actualPos.x}, ${actualPos.y}, ${actualPos.z}) },\n`;
|
||||
}
|
||||
console.warn(output);
|
||||
}
|
||||
|
||||
private BlockToParticlePosition(block: Block): Vector3 {
|
||||
let pos = vector3(block.location.x, block.location.y, block.location.z);
|
||||
pos = Vector3Add(pos, vector3(0.5, 0, 0.5));
|
||||
//If block is a slab or stair, offset by half a block
|
||||
|
||||
let isHalfBlock = block.typeId.includes("slab") || block.typeId.includes("stair");
|
||||
if (isHalfBlock) {
|
||||
pos = Vector3Add(pos, vector3(0, 0.5, 0));
|
||||
} else {
|
||||
pos = Vector3Add(pos, vector3(0, 1.1, 0));
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.currentTrail = new Trail();
|
||||
}
|
||||
}
|
||||
|
||||
class Trail {
|
||||
points: Point[] = [];
|
||||
currentPoint: number = 0;
|
||||
nextParticleTimer: number = 0;
|
||||
currentParticleCounter: number = 0;
|
||||
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
class Point {
|
||||
position: Vector3;
|
||||
index: number;
|
||||
|
||||
constructor(position: Vector3, index: number) {
|
||||
this.position = position;
|
||||
this.index = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
scripts/Commandeer/trail/trailTypes.ts
Normal file
13
scripts/Commandeer/trail/trailTypes.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Vector3 } from "@minecraft/server";
|
||||
|
||||
type TrailPointType = {
|
||||
index: number;
|
||||
position: Vector3;
|
||||
};
|
||||
|
||||
type TrailType = {
|
||||
name: string;
|
||||
points: TrailPointType[];
|
||||
};
|
||||
|
||||
export { TrailPointType, TrailType };
|
||||
40
scripts/Commandeer/utils/agentUtils.ts
Normal file
40
scripts/Commandeer/utils/agentUtils.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Entity, Vector3, world } from "@minecraft/server";
|
||||
import { Vector3ToString, vector3 } from "./vectorUtils";
|
||||
import { mindKeeper } from "../../main";
|
||||
function teleportAgent(position: Vector3) {
|
||||
world
|
||||
.getDimension("overworld")
|
||||
.runCommand(`/execute as @a run tp @e[type=agent] ${position.x} ${position.y} ${position.z}`);
|
||||
}
|
||||
|
||||
function isAgentAt(position: Vector3): boolean {
|
||||
let isAgentAt: boolean = false;
|
||||
world
|
||||
.getDimension("overworld")
|
||||
.getEntitiesAtBlockLocation(position)
|
||||
.forEach((entity) => {
|
||||
if (!entity.isValid()) {
|
||||
world.sendMessage("INVALID ENTITY");
|
||||
return;
|
||||
}
|
||||
if (entity.typeId == "minecraft:agent") {
|
||||
isAgentAt = true;
|
||||
}
|
||||
});
|
||||
return isAgentAt;
|
||||
}
|
||||
|
||||
function getAgent(): Entity {
|
||||
let agent = world.getEntity(mindKeeper.get("agentid") as string);
|
||||
return agent!;
|
||||
}
|
||||
|
||||
function getAgentLocation(): Vector3 {
|
||||
let agentLocation: Vector3 = vector3(0, 0, 0);
|
||||
let agent = world.getEntity(mindKeeper.get("agentid") as string);
|
||||
agentLocation = agent!.location;
|
||||
|
||||
return agentLocation;
|
||||
}
|
||||
|
||||
export { teleportAgent, isAgentAt, getAgentLocation, getAgent };
|
||||
62
scripts/Commandeer/utils/arrow.ts
Normal file
62
scripts/Commandeer/utils/arrow.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { MolangVariableMap, Vector3, world } from "@minecraft/server";
|
||||
import { Vector3Add, vector3 } from "./vectorUtils";
|
||||
import { PARTICLES, spawnParticle } from "./particleUtils";
|
||||
|
||||
let arrowTemplate: Vector3[] = [
|
||||
vector3(0, 0, 0),
|
||||
|
||||
vector3(1, 1, 0),
|
||||
vector3(-1, 1, 0),
|
||||
|
||||
vector3(1.5, 2, 0),
|
||||
vector3(-1.5, 2, 0),
|
||||
|
||||
vector3(2, 3, 0),
|
||||
vector3(-2, 3, 0),
|
||||
|
||||
vector3(0, 1, 0),
|
||||
vector3(0, 2, 0),
|
||||
vector3(0, 3, 0),
|
||||
vector3(0, 4, 0),
|
||||
vector3(0, 5, 0),
|
||||
];
|
||||
|
||||
let offset: Vector3 = vector3(0, 0, 0);
|
||||
|
||||
let angleOffset = 0;
|
||||
let heightBobbing = 0;
|
||||
let tickCounter = 0;
|
||||
|
||||
function rotate(pos: Vector3, angle: number) {
|
||||
let x = pos.x;
|
||||
let z = pos.z;
|
||||
|
||||
let newX = x * Math.cos(angle) - z * Math.sin(angle);
|
||||
let newZ = x * Math.sin(angle) + z * Math.cos(angle);
|
||||
|
||||
return vector3(newX, pos.y, newZ);
|
||||
}
|
||||
|
||||
const particleData = new MolangVariableMap();
|
||||
particleData.setColorRGB("variable.color", {
|
||||
red: 1,
|
||||
green: 1,
|
||||
blue: 1,
|
||||
});
|
||||
|
||||
function drawArrow(offsetPos: Vector3) {
|
||||
tickCounter++;
|
||||
if (tickCounter % 2 == 0) {
|
||||
angleOffset += 0.1;
|
||||
heightBobbing += 0.3;
|
||||
offset = vector3(46.5, 75, 220.5);
|
||||
arrowTemplate.forEach((pos) => {
|
||||
let rotatedPos = rotate(pos, angleOffset);
|
||||
let finalPos = Vector3Add(offsetPos, rotatedPos);
|
||||
finalPos.y += Math.sin(heightBobbing) / 2;
|
||||
spawnParticle(finalPos, PARTICLES.point, particleData);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { drawArrow };
|
||||
24
scripts/Commandeer/utils/levelUtils.ts
Normal file
24
scripts/Commandeer/utils/levelUtils.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { BlockType, BlockTypes, BlockVolume, Vector3, world } from "@minecraft/server";
|
||||
import { MinecraftBlockTypes } from "../../vanilla-data/mojang-block";
|
||||
|
||||
type Wall = {
|
||||
startPos: Vector3;
|
||||
endPos: Vector3;
|
||||
};
|
||||
|
||||
function clearWall(wall: Wall) {
|
||||
let volume: BlockVolume = new BlockVolume(wall.startPos, wall.endPos);
|
||||
world.getDimension("overworld").fillBlocks(volume, MinecraftBlockTypes.Air);
|
||||
}
|
||||
|
||||
function fillWall(wall: Wall, block: BlockType) {
|
||||
let volume: BlockVolume = new BlockVolume(wall.startPos, wall.endPos);
|
||||
world.getDimension("overworld").fillBlocks(volume, block);
|
||||
}
|
||||
|
||||
function startLevel(commandBlockPos: Vector3) {
|
||||
let volume: BlockVolume = new BlockVolume(commandBlockPos, commandBlockPos);
|
||||
world.getDimension("overworld").fillBlocks(volume, MinecraftBlockTypes.RedstoneBlock);
|
||||
}
|
||||
BlockTypes;
|
||||
export { Wall, clearWall, fillWall, startLevel };
|
||||
232
scripts/Commandeer/utils/particleUtils.ts
Normal file
232
scripts/Commandeer/utils/particleUtils.ts
Normal file
@@ -0,0 +1,232 @@
|
||||
import { MolangVariableMap, Vector3, world } from "@minecraft/server";
|
||||
import { Vector3Add, vector3 } from "./vectorUtils";
|
||||
|
||||
const bedrockParticles = [
|
||||
"minecraft:mobspell_emitter",
|
||||
"minecraft:villager_angry",
|
||||
"minecraft:bleach",
|
||||
"minecraft:breaking_item_icon",
|
||||
"minecraft:blockdust",
|
||||
"minecraft:bubble_column_up_particle",
|
||||
"minecraft:compfire_smoke_particle",
|
||||
"minecraft:campfire_tall_smoke_particle",
|
||||
"minecraft:cherry_leaves_particle",
|
||||
"minecraft:crop_growth_emitter",
|
||||
"minecraft:conduit_particle",
|
||||
"minecraft:critical_hit_emitter",
|
||||
"minecraft:bubble_column_down_particle",
|
||||
"minecraft:dolphin_move_particle",
|
||||
"minecraft:dragon_breath_trail",
|
||||
"minecraft:dragon_breath_lingering",
|
||||
"minecraft:lava_drip_particle",
|
||||
"minecraft:water_drip_particle",
|
||||
"minecraft:redstone_wire_dust_particle",
|
||||
"minecraft:sculk_sensor_redstone_particle",
|
||||
"minecraft:splash_spell_emitter",
|
||||
"minecraft:electric_spark__particle",
|
||||
"minecraft:enchanting_table_particle",
|
||||
"minecraft:endrod",
|
||||
"minecraft:balloon_gas_particle",
|
||||
"minecraft:evoker_spell",
|
||||
"minecraft:huge_explosion_emitter",
|
||||
"minecraft:falling_dust_red_sand_particle",
|
||||
"minecraft:falling_dust_sand_particle",
|
||||
"minecraft:falling_dust_gravel_particle",
|
||||
"minecraft:falling_dust_top_snow_particle",
|
||||
"minecraft:falling_dust_dragon_egg_particle",
|
||||
"minecraft:falling_dust_concrete_particle",
|
||||
"minecraft:falling_dust_scaffolding_particle",
|
||||
"minecraft:honey_drip_particle",
|
||||
"minecraft:nectar_drip_particle",
|
||||
"minecraft:obsidian_tear_particle",
|
||||
"minecraft:spore_blossom_shower_particle",
|
||||
"minecraft:water_splash_particle",
|
||||
"minecraft:sparkler_emitter",
|
||||
"minecraft:water_wake_particle",
|
||||
"minecraft:basic_flame_particle",
|
||||
"minecraft:flash",
|
||||
"minecraft:glow_particle",
|
||||
"minecraft:villager_happy",
|
||||
"minecraft:heart_particle",
|
||||
"minecraft:water_evaporation_actor_emitter",
|
||||
"minecraft:lava_particle",
|
||||
"minecraft:mobflame_emitter",
|
||||
"minecraft:mobflame_single",
|
||||
"minecraft:mycelium_dust_particle",
|
||||
"minecraft:note_particle",
|
||||
"minecraft:explode",
|
||||
"minecraft:mob_portal",
|
||||
"minecraft:rainsplash",
|
||||
"minecraft:basic_smoke_particle",
|
||||
"minecraft:snowflake_particle",
|
||||
"minecraft:soul_particle",
|
||||
"minecraft:blue_flame_particle",
|
||||
"minecraft:spore_blossom_ambient_particle",
|
||||
"minecraft:watersplash",
|
||||
"minecraft:terrain",
|
||||
"minecraft:totem_particle",
|
||||
"minecraft:tracking_emitter",
|
||||
"minecraft:vibration_signal",
|
||||
"minecraft:wax_particle",
|
||||
"minecraft:witchspell",
|
||||
];
|
||||
|
||||
const PARTICLES = {
|
||||
mobspell_emitter: "minecraft:mobspell_emitter",
|
||||
villager_angry: "minecraft:villager_angry",
|
||||
bleach: "minecraft:bleach",
|
||||
breaking_item_icon: "minecraft:breaking_item_icon",
|
||||
blockdust: "minecraft:blockdust",
|
||||
bubble_column_up_particle: "minecraft:bubble_column_up_particle",
|
||||
compfire_smoke_particle: "minecraft:compfire_smoke_particle",
|
||||
campfire_tall_smoke_particle: "minecraft:campfire_tall_smoke_particle",
|
||||
cherry_leaves_particle: "minecraft:cherry_leaves_particle",
|
||||
crop_growth_emitter: "minecraft:crop_growth_emitter",
|
||||
conduit_particle: "minecraft:conduit_particle",
|
||||
critical_hit_emitter: "minecraft:critical_hit_emitter",
|
||||
bubble_column_down_particle: "minecraft:bubble_column_down_particle",
|
||||
dolphin_move_particle: "minecraft:dolphin_move_particle",
|
||||
dragon_breath_trail: "minecraft:dragon_breath_trail",
|
||||
dragon_breath_lingering: "minecraft:dragon_breath_lingering",
|
||||
lava_drip_particle: "minecraft:lava_drip_particle",
|
||||
water_drip_particle: "minecraft:water_drip_particle",
|
||||
redstone_wire_dust_particle: "minecraft:redstone_wire_dust_particle",
|
||||
sculk_sensor_redstone_particle: "minecraft:sculk_sensor_redstone_particle",
|
||||
splash_spell_emitter: "minecraft:splash_spell_emitter",
|
||||
electric_spark__particle: "minecraft:electric_spark__particle",
|
||||
enchanting_table_particle: "minecraft:enchanting_table_particle",
|
||||
endrod: "minecraft:endrod",
|
||||
balloon_gas_particle: "minecraft:balloon_gas_particle",
|
||||
evoker_spell: "minecraft:evoker_spell",
|
||||
huge_explosion_emitter: "minecraft:huge_explosion_emitter",
|
||||
falling_dust_red_sand_particle: "minecraft:falling_dust_red_sand_particle",
|
||||
falling_dust_sand_particle: "minecraft:falling_dust_sand_particle",
|
||||
falling_dust_gravel_particle: "minecraft:falling_dust_gravel_particle",
|
||||
falling_dust_top_snow_particle: "minecraft:falling_dust_top_snow_particle",
|
||||
falling_dust_dragon_egg_particle: "minecraft:falling_dust_dragon_egg_particle",
|
||||
falling_dust_concrete_particle: "minecraft:falling_dust_concrete_particle",
|
||||
falling_dust_scaffolding_particle: "minecraft:falling_dust_scaffolding_particle",
|
||||
honey_drip_particle: "minecraft:honey_drip_particle",
|
||||
nectar_drip_particle: "minecraft:nectar_drip_particle",
|
||||
obsidian_tear_particle: "minecraft:obsidian_tear_particle",
|
||||
spore_blossom_shower_particle: "minecraft:spore_blossom_shower_particle",
|
||||
water_splash_particle: "minecraft:water_splash_particle",
|
||||
sparkler_emitter: "minecraft:sparkler_emitter",
|
||||
water_wake_particle: "minecraft:water_wake_particle",
|
||||
basic_flame_particle: "minecraft:basic_flame_particle",
|
||||
flash: "minecraft:flash",
|
||||
glow_particle: "minecraft:glow_particle",
|
||||
villager_happy: "minecraft:villager_happy",
|
||||
heart_particle: "minecraft:heart_particle",
|
||||
water_evaporation_actor_emitter: "minecraft:water_evaporation_actor_emitter",
|
||||
lava_particle: "minecraft:lava_particle",
|
||||
mobflame_emitter: "minecraft:mobflame_emitter",
|
||||
mobflame_single: "minecraft:mobflame_single",
|
||||
mycelium_dust_particle: "minecraft:mycelium_dust_particle",
|
||||
note_particle: "minecraft:note_particle",
|
||||
explode: "minecraft:explode",
|
||||
mob_portal: "minecraft:mob_portal",
|
||||
rainsplash: "minecraft:rainsplash",
|
||||
basic_smoke_particle: "minecraft:basic_smoke_particle",
|
||||
snowflake_particle: "minecraft:snowflake_particle",
|
||||
soul_particle: "minecraft:soul_particle",
|
||||
blue_flame_particle: "minecraft:blue_flame_particle",
|
||||
spore_blossom_ambient_particle: "minecraft:spore_blossom_ambient_particle",
|
||||
watersplash: "minecraft:watersplash",
|
||||
terrain: "minecraft:terrain",
|
||||
totem_particle: "minecraft:totem_particle",
|
||||
tracking_emitter: "minecraft:tracking_emitter",
|
||||
vibration_signal: "minecraft:vibration_signal",
|
||||
wax_particle: "minecraft:wax_particle",
|
||||
witchspell: "minecraft:witchspell",
|
||||
point: "codecosmos:point",
|
||||
};
|
||||
|
||||
class ParticleColumn {
|
||||
pos: Vector3;
|
||||
radius: number;
|
||||
pointsPerLayer: number;
|
||||
layerCount: number;
|
||||
particle: string;
|
||||
points: Vector3[] = [];
|
||||
speed: number;
|
||||
anglePerLayer: number[] = [];
|
||||
tickCounter: number = 0;
|
||||
|
||||
constructor(
|
||||
pos: Vector3,
|
||||
radius: number,
|
||||
pointsPerLayer: number,
|
||||
layerCount: number,
|
||||
speed: number,
|
||||
particle: string
|
||||
) {
|
||||
this.pos = pos;
|
||||
this.radius = radius;
|
||||
this.particle = particle;
|
||||
this.pointsPerLayer = pointsPerLayer;
|
||||
this.layerCount = layerCount;
|
||||
this.speed = speed;
|
||||
this.generatePoints();
|
||||
}
|
||||
|
||||
generatePoints() {
|
||||
for (let layer = 0; layer < this.layerCount; layer++) {
|
||||
let layerRadius = this.radius - layer;
|
||||
for (let point = 0; point < this.pointsPerLayer; point++) {
|
||||
let angle = (point / this.pointsPerLayer) * (Math.PI * 2);
|
||||
this.anglePerLayer.push(angle);
|
||||
let x = Math.cos(angle) * layerRadius;
|
||||
let z = Math.sin(angle) * layerRadius;
|
||||
let y = layer;
|
||||
this.points.push(Vector3Add(this.pos, vector3(x, y, z)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
//update each point by increasing the angle by the speed
|
||||
let layerCount = 0;
|
||||
let pointCount = 0;
|
||||
this.tickCounter++;
|
||||
if (this.tickCounter % 2 == 0) {
|
||||
this.points.forEach((point, index) => {
|
||||
let layer = Math.floor(index / this.pointsPerLayer);
|
||||
let angle = this.anglePerLayer[index];
|
||||
angle += this.speed * (layer / 5);
|
||||
this.anglePerLayer[index] = angle;
|
||||
let layerRadius = this.radius - Math.floor(index / this.pointsPerLayer);
|
||||
let calcAngle = angle;
|
||||
let x = Math.cos(calcAngle) * this.radius;
|
||||
let z = Math.sin(calcAngle) * this.radius;
|
||||
let y = Math.floor(index / this.pointsPerLayer) + (this.tickCounter % 2);
|
||||
this.points[index] = Vector3Add(this.pos, vector3(x, y, z));
|
||||
});
|
||||
}
|
||||
}
|
||||
draw() {
|
||||
this.points.forEach((point) => {
|
||||
spawnParticle(point);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function spawnParticle(
|
||||
position: Vector3,
|
||||
particle: string = PARTICLES.balloon_gas_particle,
|
||||
map: MolangVariableMap = new MolangVariableMap()
|
||||
) {
|
||||
//check if the chunk is loaded
|
||||
const chunk = world.getDimension("overworld").getBlock(position);
|
||||
if (!chunk?.isValid()) {
|
||||
return;
|
||||
}
|
||||
map.setVector3("variable.direction", vector3(0, 0, 0));
|
||||
|
||||
const dimension = world.getDimension("overworld");
|
||||
if (dimension) {
|
||||
dimension.spawnParticle(particle, position, map);
|
||||
}
|
||||
}
|
||||
|
||||
export { PARTICLES, bedrockParticles, ParticleColumn, spawnParticle };
|
||||
71
scripts/Commandeer/utils/vectorUtils.ts
Normal file
71
scripts/Commandeer/utils/vectorUtils.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { Vector3 } from "@minecraft/server";
|
||||
|
||||
function vector3(x: number, y: number, z: number): Vector3 {
|
||||
return { x: x, y: y, z: z };
|
||||
}
|
||||
|
||||
function Vector3ToString(vector: Vector3) {
|
||||
return vector.x + "," + vector.y + "," + vector.z;
|
||||
}
|
||||
|
||||
function Vector3ToCommandString(vector: Vector3) {
|
||||
return `${vector.x} ${vector.y} ${vector.z}`;
|
||||
}
|
||||
|
||||
function Vector3ToFancyString(vector: Vector3) {
|
||||
return `{X: ${Math.floor(vector.x)}, Y: ${Math.floor(vector.y)}, Z: ${Math.floor(vector.z)}}`;
|
||||
}
|
||||
|
||||
function Vector3Add(vector1: Vector3, vector2: Vector3): Vector3 {
|
||||
return { x: vector1.x + vector2.x, y: vector1.y + vector2.y, z: vector1.z + vector2.z };
|
||||
}
|
||||
|
||||
function Vector3Subtract(vector1: Vector3, vector2: Vector3): Vector3 {
|
||||
return { x: vector1.x - vector2.x, y: vector1.y - vector2.y, z: vector1.z - vector2.z };
|
||||
}
|
||||
|
||||
function Vector3Multiply(vector1: Vector3, vector2: Vector3): Vector3 {
|
||||
return { x: vector1.x * vector2.x, y: vector1.y * vector2.y, z: vector1.z * vector2.z };
|
||||
}
|
||||
|
||||
function Vector3Divide(vector1: Vector3, vector2: Vector3): Vector3 {
|
||||
return { x: vector1.x / vector2.x, y: vector1.y / vector2.y, z: vector1.z / vector2.z };
|
||||
}
|
||||
|
||||
function Vector3Floor(vector: Vector3): Vector3 {
|
||||
return { x: Math.floor(vector.x), y: Math.floor(vector.y), z: Math.floor(vector.z) };
|
||||
}
|
||||
|
||||
function Vector3Ceil(vector: Vector3): Vector3 {
|
||||
return { x: Math.ceil(vector.x), y: Math.ceil(vector.y), z: Math.ceil(vector.z) };
|
||||
}
|
||||
|
||||
function Vector3Round(vector: Vector3): Vector3 {
|
||||
return { x: Math.round(vector.x), y: Math.round(vector.y), z: Math.round(vector.z) };
|
||||
}
|
||||
|
||||
function Vector3Abs(vector: Vector3): Vector3 {
|
||||
return { x: Math.abs(vector.x), y: Math.abs(vector.y), z: Math.abs(vector.z) };
|
||||
}
|
||||
|
||||
function vector3Distance(vector1: Vector3, vector2: Vector3): number {
|
||||
return Math.sqrt(
|
||||
Math.pow(vector2.x - vector1.x, 2) + Math.pow(vector2.y - vector1.y, 2) + Math.pow(vector2.z - vector1.z, 2)
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
Vector3ToString,
|
||||
Vector3ToFancyString,
|
||||
Vector3Add,
|
||||
Vector3Subtract,
|
||||
Vector3Multiply,
|
||||
Vector3Divide,
|
||||
Vector3Floor,
|
||||
Vector3Ceil,
|
||||
Vector3Round,
|
||||
Vector3Abs,
|
||||
vector3Distance,
|
||||
Vector3ToCommandString,
|
||||
vector3,
|
||||
};
|
||||
16
scripts/Commandeer/utils/waitUtil.ts
Normal file
16
scripts/Commandeer/utils/waitUtil.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { system } from "@minecraft/server";
|
||||
|
||||
function delayedRun(callback: Function, delay: number) {
|
||||
let timer = system.runTimeout(() => {
|
||||
callback();
|
||||
system.clearRun(timer);
|
||||
}, delay);
|
||||
}
|
||||
|
||||
function delay(t: number) {
|
||||
return new Promise((r: any) => {
|
||||
system.runTimeout(r, t);
|
||||
});
|
||||
}
|
||||
|
||||
export { delayedRun, delay };
|
||||
34
scripts/Commandeer/utils/worldEditUtils.ts
Normal file
34
scripts/Commandeer/utils/worldEditUtils.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Vector3, world } from "@minecraft/server";
|
||||
|
||||
function clone(startPos: Vector3, endPos: Vector3, destination: Vector3) {
|
||||
world
|
||||
.getDimension("overworld")
|
||||
.runCommand(
|
||||
`clone ${startPos.x} ${startPos.y} ${startPos.z} ${endPos.x} ${endPos.y} ${endPos.z} ${destination.x} ${destination.y} ${destination.z} replace normal`
|
||||
);
|
||||
}
|
||||
|
||||
enum LeverDirection {
|
||||
DownEastWest = "down_east_west",
|
||||
DownNorthSouth = "down_north_south",
|
||||
East = "east",
|
||||
North = "north",
|
||||
South = "south",
|
||||
UpEastWest = "up_east_west",
|
||||
UpNorthSouth = "up_north_south",
|
||||
West = "west",
|
||||
}
|
||||
|
||||
function setLever(pos: Vector3, direction: LeverDirection, isOpen: boolean) {
|
||||
world
|
||||
.getDimension("overworld")
|
||||
.runCommandAsync(
|
||||
`/setblock ${pos.x} ${pos.y} ${pos.z} lever["lever_direction":"${direction}","open_bit":${
|
||||
isOpen ? "true" : "false"
|
||||
}]`
|
||||
);
|
||||
|
||||
///setblock 53 70 216 lever["lever_direction"="down_east_west","open_bit"=false]
|
||||
}
|
||||
|
||||
export { clone, LeverDirection, setLever };
|
||||
Reference in New Issue
Block a user