Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import { world, system, Block, BlockComponentPlayerInteractEvent, BlockComponentPlayerDestroyEvent, BlockComponentOnPlaceEvent, BlockComponentTickEvent, StartupEvent, ShutdownEvent, Player, Dimension } from "@minecraft/server";
- import { ModalFormData } from "@minecraft/server-ui";
- // Configuration
- let CONFIG = {
- UPDATE_INTERVAL: 1,
- ANIMATION_INTERVAL: 1,
- MAX_STRESS: 2147483647,
- RPM_LIMITS: { min: -256, max: 256 },
- NUMBER_TOLERANCE: .1,
- };
- // Enums
- enum CONNECTION_TYPES {
- SHAFT = "SHAFT",
- MESH = "MESH",
- LARGE_MESH = "LARGE_MESH"
- };
- enum DIRECTIONS {
- NORTH = "north",
- SOUTH = "south",
- EAST = "east",
- WEST = "west",
- UP = "up",
- DOWN = "down"
- };
- enum FACES {
- FRONT = "front",
- BACK = "back",
- LEFT = "left",
- RIGHT = "right",
- UP = "up",
- DOWN = "down"
- };
- interface IVector3 {
- x: number;
- y: number;
- z: number;
- };
- class Vector3 {
- x: number;
- y: number;
- z: number;
- constructor(x: number = 0, y: number = 0, z: number = 0) {
- this.x = x; this.y = y; this.z = z;
- }
- static from(pos: IVector3): Vector3 {
- return new Vector3(pos.x, pos.y, pos.z);
- }
- add(v: Vector3): Vector3 {
- return new Vector3(this.x + v.x, this.y + v.y, this.z + v.z);
- }
- equals(v: Vector3, tolerance: number = CONFIG.NUMBER_TOLERANCE) {
- return Math.abs(this.x - v.x) < tolerance &&
- Math.abs(this.y - v.y) < tolerance &&
- Math.abs(this.z - v.z) < tolerance;
- }
- toString(): string {
- return `${Math.floor(this.x)}_${Math.floor(this.y)}_${Math.floor(this.z)}`;
- }
- }
- class RELATIVE_OFFSETS {
- static readonly FRONT = new Vector3(0, 0, -1);
- static readonly BACK = new Vector3(0, 0, 1);
- static readonly LEFT = new Vector3(-1, 0, 0);
- static readonly RIGHT = new Vector3(1, 0, 0);
- static readonly UP = new Vector3(0, -1, 0);
- static readonly DOWN = new Vector3(0, 1, 0);
- };
- interface BlockConnection {
- type: CONNECTION_TYPES,
- relative_direction: Vector3,
- connected: boolean
- }
- class Node {
- data: any;
- next: any;
- constructor(data) {
- this.data = data;
- this.next = null;
- }
- }
- class Queue {
- front: any;
- rear: any;
- size: number;
- constructor() {
- this.front = null;
- this.rear = null;
- this.size = 0;
- }
- enqueue(data) {
- const newNode = new Node(data);
- if (this.isEmpty()) {
- this.front = newNode;
- this.rear = newNode;
- } else {
- this.rear.next = newNode;
- this.rear = newNode;
- }
- this.size++;
- }
- dequeue() {
- if (this.isEmpty()) {
- return null;
- }
- const removedNode = this.front;
- this.front = this.front.next;
- if (this.front === null) {
- this.rear = null;
- }
- this.size--;
- return removedNode.data;
- }
- peek() {
- if (this.isEmpty()) {
- return null;
- }
- return this.front.data;
- }
- isEmpty() {
- return this.size === 0;
- }
- getSize() {
- return this.size;
- }
- print() {
- let current = this.front;
- const elements = [];
- while (current) {
- elements.push(current.data);
- current = current.next;
- }
- console.log(elements.join(' -> '));
- }
- }
- function getFacingDirectionMultiplier(facingDirecion: "north" | "south" | "east" | "west" | "up" | "down"): number {
- if (["south", "east", "down"].includes(facingDirecion)) {
- return -1;
- }
- return 1;
- }
- function areFacingDirectionsOnSameAxis(facingDirection1: "north" | "south" | "east" | "west" | "up" | "down", facingDirection2: "north" | "south" | "east" | "west" | "up" | "down"): boolean {
- const sameAxisFacingDirections: string[][] = [
- ["north", "south"],
- ["east", "west"],
- ["up", "down"]
- ]
- for (const sameAxisFacingDirectionsElement of sameAxisFacingDirections) {
- if (sameAxisFacingDirectionsElement.includes(facingDirection1) && sameAxisFacingDirectionsElement.includes(facingDirection2)) {
- return true;
- }
- }
- return false;
- }
- function translateAbsoluteOffsetToRelative(offset: Vector3, facingDirection: "north" | "south" | "east" | "west" | "up" | "down"): Vector3 {
- switch (facingDirection) {
- case "north": // facing -z, no rotation needed (this is our reference)
- return new Vector3(offset.x, offset.y, offset.z);
- case "south": // facing +z, rotate 180° around Y
- return new Vector3(-offset.x, offset.y, -offset.z);
- case "east": // facing +x, rotate 90° clockwise around Y
- return new Vector3(-offset.z, offset.y, offset.x);
- case "west": // facing -x, rotate 90° counter-clockwise around Y
- return new Vector3(offset.z, offset.y, -offset.x);
- case "up": // facing -y, rotate 90° around X
- return new Vector3(offset.x, offset.z, -offset.y);
- case "down": // facing +y, rotate -90° around X
- return new Vector3(offset.x, -offset.z, offset.y);
- default:
- return offset;
- }
- }
- // Creative Motor Component
- class CreativeMotorComponent {
- connections: BlockConnection[];
- setRPM: number;
- generatedRPM: number | null;
- RPM: number;
- generatedSU: number;
- consumedSU: number;
- SU: number;
- block: Block;
- readonly interactable: boolean = true;
- readonly animated: boolean = false;
- readonly requestsSUInfo = false;
- readonly identifier: string = "createbedrock:creative_motor";
- constructor(block: Block) {
- const facingDirection: "north" | "south" | "east" | "west" | "up" | "down" = block.permutation.getState("minecraft:facing_direction");
- this.connections = [
- {
- type: CONNECTION_TYPES.SHAFT,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.FRONT, facingDirection),
- connected: false
- }
- ]
- this.setRPM = 16;
- this.generatedRPM = getFacingDirectionMultiplier(facingDirection) * 16;
- this.RPM = this.generatedRPM;
- this.generatedSU = 2147483647;
- this.consumedSU = 0;
- this.SU = 2147483647;
- this.block = block;
- //console.log(this.generatedRPM);
- }
- onInteract(event: BlockComponentPlayerInteractEvent) {
- const player: Player = event.player;
- const block: Block = event.block;
- const facingDirection: "north" | "south" | "east" | "west" | "up" | "down" = block.permutation.getState("minecraft:facing_direction");
- try {
- const form = new ModalFormData()
- .title('Creative Motor Configuration')
- .slider('RPM', CONFIG.RPM_LIMITS.min, CONFIG.RPM_LIMITS.max, { defaultValue: this.setRPM })
- .submitButton('Submit')
- form.show(player).then(response => {
- if (!response.canceled && response.formValues) {
- const [generatedRPM] = response.formValues;
- if (typeof generatedRPM === 'number') {
- this.setRPM = generatedRPM;
- this.generatedRPM = getFacingDirectionMultiplier(facingDirection) * this.setRPM;
- this.RPM = this.generatedRPM;
- // Update the rotation network
- rotationSystem.needsUpdate = true;
- }
- }
- }).catch(error => {
- console.error('Form error:', error);
- });
- } catch (error) {
- console.warn('Failed to create form:', error);
- }
- }
- }
- // Other component classes
- class ShaftComponent {
- connections: BlockConnection[];
- generatedRPM: number | null;
- RPM: number;
- generatedSU: number;
- consumedSU: number;
- SU: number;
- block: Block;
- readonly interactable: boolean = false;
- readonly animated: boolean = true;
- readonly requestsSUInfo = false;
- readonly identifier: string = "createbedrock:shaft";
- constructor(block: Block) {
- const facingDirection: "north" | "south" | "east" | "west" | "up" | "down" = block.permutation.getState("minecraft:facing_direction");
- this.connections = [
- {
- type: CONNECTION_TYPES.SHAFT,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.FRONT, facingDirection),
- connected: false
- },
- {
- type: CONNECTION_TYPES.SHAFT,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.BACK, facingDirection),
- connected: false
- }
- ]
- this.generatedRPM = null;
- this.RPM = 0;
- this.generatedSU = 0;
- this.consumedSU = 0;
- this.SU = 0;
- this.block = block;
- }
- }
- class StressometerComponent {
- connections: BlockConnection[];
- generatedRPM: number | null;
- RPM: number;
- generatedSU: number;
- generatedSUInfo: number;
- consumedSU: number;
- consumedSUInfo: number;
- SU: number;
- block: Block;
- readonly interactable: boolean = true;
- readonly animated: boolean = false;
- readonly requestsSUInfo = true;
- readonly identifier: string = "createbedrock:stressometer";
- constructor(block: Block) {
- const facingDirection: "north" | "south" | "east" | "west" | "up" | "down" = block.permutation.getState("minecraft:facing_direction");
- this.connections = [
- {
- type: CONNECTION_TYPES.SHAFT,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.FRONT, facingDirection),
- connected: false
- },
- {
- type: CONNECTION_TYPES.SHAFT,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.BACK, facingDirection),
- connected: false
- }
- ]
- this.generatedRPM = null;
- this.RPM = 0;
- this.generatedSU = 0;
- this.generatedSUInfo = 0;
- this.consumedSU = 0;
- this.consumedSUInfo = 0;
- this.SU = 0;
- this.block = block;
- }
- onInteract(event: BlockComponentPlayerInteractEvent) {
- const player: Player = event.player;
- const stressPercentage = this.generatedSUInfo > 0
- ? Math.round((this.consumedSUInfo / this.generatedSUInfo) * 100)
- : 0;
- let stressLevel;
- if (this.consumedSUInfo - this.generatedSUInfo > CONFIG.NUMBER_TOLERANCE) {
- stressLevel = "§c■■■ Overstressed";
- } else if (stressPercentage > 75) {
- stressLevel = "§6■■■ High";
- } else if (stressPercentage > 50) {
- stressLevel = "§e■■▧ Moderate";
- } else if (this.generatedSUInfo > CONFIG.NUMBER_TOLERANCE) {
- stressLevel = "§a■▧▧ Low";
- } else {
- stressLevel = "§7▧▧▧ No rotation";
- }
- player.onScreenDisplay.setActionBar(`§fGauge Information:\n§7Network Stress\n ${stressLevel} §f(${stressPercentage}%)`)
- }
- }
- class SpeedometerComponent {
- connections: BlockConnection[];
- generatedRPM: number | null;
- RPM: number;
- generatedSU: number;
- generatedSUInfo: number;
- consumedSU: number;
- consumedSUInfo: number;
- SU: number;
- block: Block;
- readonly interactable: boolean = false;
- readonly animated: boolean = false;
- readonly requestsSUInfo = true;
- readonly identifier: string = "createbedrock:speedometer";
- constructor(block: Block) {
- const facingDirection: "north" | "south" | "east" | "west" | "up" | "down" = block.permutation.getState("minecraft:facing_direction");
- this.connections = [
- {
- type: CONNECTION_TYPES.SHAFT,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.FRONT, facingDirection),
- connected: false
- },
- {
- type: CONNECTION_TYPES.SHAFT,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.BACK, facingDirection),
- connected: false
- }
- ]
- this.generatedRPM = null;
- this.RPM = 0;
- this.generatedSU = 0;
- this.generatedSUInfo = 0;
- this.consumedSU = 0;
- this.consumedSUInfo = 0;
- this.SU = 0;
- this.block = block;
- }
- onInteract(event: BlockComponentPlayerInteractEvent) {
- const rpm = Math.abs(this.RPM);
- const player = event.player;
- let speedLevel: string;
- if (rpm > 99) {
- speedLevel = "§d■■■ Fast";
- } else if (rpm > 29) {
- speedLevel = "§b■■▧ Moderate";
- } else if (rpm > 1) {
- speedLevel = "§a■▧▧ Slow";
- } else {
- speedLevel = "§7▧▧▧ None"
- }
- if (this.consumedSUInfo - this.generatedSUInfo > CONFIG.NUMBER_TOLERANCE) {
- speedLevel = "§7§m" + speedLevel;
- }
- player.onScreenDisplay.setActionBar(`§fGauge Information:\n§7Rotation Speed\n ${speedLevel} §f(${Math.round(rpm)} RPM)`);
- }
- }
- class CogwheelComponent {
- connections: BlockConnection[];
- generatedRPM: number | null;
- RPM: number;
- generatedSU: number;
- consumedSU: number;
- SU: number;
- block: Block;
- readonly interactable: boolean = false;
- readonly animated: boolean = true;
- readonly requestsSUInfo = false;
- readonly identifier: string = "createbedrock:cogwheel";
- constructor(block: Block) {
- const facingDirection: "north" | "south" | "east" | "west" | "up" | "down" = block.permutation.getState("minecraft:facing_direction");
- this.connections = [
- {
- type: CONNECTION_TYPES.SHAFT,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.FRONT, facingDirection),
- connected: false
- },
- {
- type: CONNECTION_TYPES.SHAFT,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.BACK, facingDirection),
- connected: false
- },
- {
- type: CONNECTION_TYPES.MESH,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.RIGHT, facingDirection),
- connected: false
- },
- {
- type: CONNECTION_TYPES.MESH,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.LEFT, facingDirection),
- connected: false
- },
- {
- type: CONNECTION_TYPES.MESH,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.UP, facingDirection),
- connected: false
- },
- {
- type: CONNECTION_TYPES.MESH,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.DOWN, facingDirection),
- connected: false
- }
- ]
- this.generatedRPM = null;
- this.RPM = 0;
- this.generatedSU = 0;
- this.consumedSU = 0;
- this.SU = 0;
- this.block = block;
- }
- }
- class LargeCogwheelComponent {
- connections: BlockConnection[];
- generatedRPM: number | null;
- RPM: number;
- generatedSU: number;
- consumedSU: number;
- SU: number;
- block: Block;
- readonly interactable: boolean = false;
- readonly animated: boolean = true;
- readonly requestsSUInfo = false;
- readonly identifier: string = "createbedrock:cogwheel";
- constructor(block: Block) {
- const facingDirection: "north" | "south" | "east" | "west" | "up" | "down" = block.permutation.getState("minecraft:facing_direction");
- this.connections = [
- {
- type: CONNECTION_TYPES.SHAFT,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.FRONT, facingDirection),
- connected: false
- },
- {
- type: CONNECTION_TYPES.SHAFT,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.BACK, facingDirection),
- connected: false
- },
- {
- type: CONNECTION_TYPES.LARGE_MESH,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.RIGHT, facingDirection),
- connected: false
- },
- {
- type: CONNECTION_TYPES.LARGE_MESH,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.LEFT, facingDirection),
- connected: false
- },
- {
- type: CONNECTION_TYPES.MESH,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.UP, facingDirection),
- connected: false
- },
- {
- type: CONNECTION_TYPES.MESH,
- relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.DOWN, facingDirection),
- connected: false
- }
- ]
- this.generatedRPM = null;
- this.RPM = 0;
- this.generatedSU = 0;
- this.consumedSU = 0;
- this.SU = 0;
- this.block = block;
- }
- }
- interface IComponent {
- connections: BlockConnection[];
- setRPM?: number;
- generatedRPM: number | null;
- RPM: number;
- generatedSU: number;
- generatedSUInfo?: number;
- consumedSU: number;
- consumedSUInfo?: number;
- SU: number;
- block: Block;
- onPlace?: (event: BlockComponentOnPlaceEvent) => void;
- onDestroy?: (event: BlockComponentPlayerDestroyEvent) => void;
- onTick?: (event: BlockComponentTickEvent) => void;
- onInteract?: (event: BlockComponentPlayerInteractEvent) => void;
- readonly interactable: boolean;
- readonly animated: boolean;
- readonly requestsSUInfo: boolean;
- readonly identifier: string;
- }
- interface ISerializableComponent {
- connections: BlockConnection[];
- setRPM?: number;
- generatedRPM: number | null;
- RPM: number;
- generatedSU: number;
- generatedSUInfo?: number;
- consumedSU: number;
- consumedSUInfo?: number;
- SU: number;
- blockDimension: string;
- blockLocation: IVector3;
- onPlace?: (event: BlockComponentOnPlaceEvent) => void;
- onDestroy?: (event: BlockComponentPlayerDestroyEvent) => void;
- onTick?: (event: BlockComponentTickEvent) => void;
- onInteract?: (event: BlockComponentPlayerInteractEvent) => void;
- readonly interactable: boolean;
- readonly animated: boolean;
- readonly requestsSUInfo: boolean;
- readonly identifier: string;
- }
- class RotationSystem {
- components: Map<string, IComponent> = new Map();
- // FP - For Propagation (purposes)
- needsUpdate: boolean;
- private updateInterval: number;
- private animationUpdateInterval: number;
- // Helper method to clear save data (useful for debugging)
- save(): void {
- try {
- //console.log(`§6[RotationSystem] Starting save process with ${this.components.size} components`);
- const serializableComponents: any[] = [];
- for (const [key, component] of this.components) {
- const serializableComponent = {
- identifier: component.identifier,
- connections: component.connections.map(connection => ({
- type: connection.type,
- relative_direction: {
- x: connection.relative_direction.x,
- y: connection.relative_direction.y,
- z: connection.relative_direction.z
- },
- connected: connection.connected
- })),
- setRPM: component.setRPM,
- generatedRPM: component.generatedRPM,
- RPM: component.RPM,
- generatedSU: component.generatedSU,
- generatedSUInfo: component.generatedSUInfo,
- consumedSU: component.consumedSU,
- consumedSUInfo: component.consumedSUInfo,
- SU: component.SU,
- blockDimension: component.block.dimension.id,
- blockLocation: {
- x: component.block.location.x,
- y: component.block.location.y,
- z: component.block.location.z
- },
- interactable: component.interactable,
- animated: component.animated,
- requestsSUInfo: component.requestsSUInfo
- };
- serializableComponents.push(serializableComponent);
- }
- const saveData = {
- components: serializableComponents,
- version: "1.0.0",
- timestamp: Date.now()
- };
- const saveDataString = JSON.stringify(saveData);
- const numberSaveDataParts = saveDataString.length / 32767;
- for (let i = 0; i < numberSaveDataParts; ++i) {
- world.setDynamicProperty(`createbedrock:rotation_system_components_${i}`, saveDataString.slice(i * 32767, Math.min((i + 1) * 32767, saveDataString.length)));
- }
- world.setDynamicProperty(`createbedrock:rotation_system_components_${numberSaveDataParts}`, undefined);
- //console.log(`§a[RotationSystem] Successfully saved ${serializableComponents.length} components`);
- } catch (error) {
- console.error(`§c[RotationSystem] Save failed:`, error);
- }
- }
- load(): void {
- try {
- //console.log(`§6[RotationSystem] Starting load process`);
- let saveDataStringPart: string | undefined;
- let saveDataString: string = "";
- for (let i = 0; saveDataStringPart = (world.getDynamicProperty(`createbedrock:rotation_system_components_${i}`) as string | undefined); ++i) {
- saveDataString += saveDataStringPart;
- }
- //console.log(saveDataString);
- if (!saveDataString) {
- //console.log(`§7[RotationSystem] No save data found, starting with empty system`);
- this.components = new Map<string, IComponent>();
- return;
- }
- const saveData = JSON.parse(saveDataString);
- //console.log(`§6[RotationSystem] Found save data version ${saveData.version || 'unknown'}`);
- if (!saveData.components || !Array.isArray(saveData.components)) {
- console.warn(`§e[RotationSystem] Invalid save data structure, starting fresh`);
- this.components = new Map<string, IComponent>();
- return;
- }
- this.components = new Map<string, IComponent>();
- let loadedCount = 0;
- let skippedCount = 0;
- for (const savedComponent of saveData.components) {
- try {
- if (!savedComponent.identifier || !savedComponent.blockDimension || !savedComponent.blockLocation) {
- console.warn(`§e[RotationSystem] Skipping component with missing required fields`);
- skippedCount++;
- continue;
- }
- const block = world.getDimension(savedComponent.blockDimension).getBlock(savedComponent.blockLocation);
- if (!block) {
- console.warn(`§e[RotationSystem] Block not found at ${savedComponent.blockLocation.x}, ${savedComponent.blockLocation.y}, ${savedComponent.blockLocation.z}`);
- skippedCount++;
- continue;
- }
- let component: IComponent | null = null;
- switch (savedComponent.identifier) {
- case "createbedrock:creative_motor":
- component = new CreativeMotorComponent(block);
- // Restore specific properties
- if (typeof savedComponent.setRPM === 'number') {
- (component as CreativeMotorComponent).setRPM = savedComponent.setRPM;
- }
- break;
- case "createbedrock:shaft":
- component = new ShaftComponent(block);
- break;
- case "createbedrock:stressometer":
- component = new StressometerComponent(block);
- break;
- case "createbedrock:speedometer":
- component = new SpeedometerComponent(block);
- break;
- case "createbedrock:cogwheel":
- component = new CogwheelComponent(block);
- break;
- default:
- console.warn(`§e[RotationSystem] Unknown component type: ${savedComponent.identifier}`);
- skippedCount++;
- continue;
- }
- if (component) {
- // Restore common properties
- component.generatedRPM = savedComponent.generatedRPM ?? component.generatedRPM;
- component.RPM = savedComponent.RPM ?? component.RPM;
- component.generatedSU = savedComponent.generatedSU ?? component.generatedSU;
- component.consumedSU = savedComponent.consumedSU ?? component.consumedSU;
- component.SU = savedComponent.SU ?? component.SU;
- // Restore SU info for components that track it
- if (component.requestsSUInfo) {
- (component as any).generatedSUInfo = savedComponent.generatedSUInfo ?? 0;
- (component as any).consumedSUInfo = savedComponent.consumedSUInfo ?? 0;
- }
- if (savedComponent.connections && Array.isArray(savedComponent.connections)) {
- for (let i = 0; i < Math.min(component.connections.length, savedComponent.connections.length); i++) {
- const savedConn = savedComponent.connections[i];
- if (savedConn.relative_direction) {
- component.connections[i].relative_direction = new Vector3(
- savedConn.relative_direction.x,
- savedConn.relative_direction.y,
- savedConn.relative_direction.z
- );
- component.connections[i].type = savedConn.type;
- // Don't restore 'connected' state - it will be recalculated
- }
- }
- }
- this.components.set(this.getBlockKey(block), component);
- loadedCount++;
- }
- } catch (componentError) {
- console.error(`§c[RotationSystem] Failed to load component:`, componentError);
- skippedCount++;
- }
- }
- //console.log(`§a[RotationSystem] Load complete: ${loadedCount} loaded, ${skippedCount} skipped`);
- } catch (error) {
- console.error(`§c[RotationSystem] Load failed:`, error);
- //console.log(`§e[RotationSystem] Starting with empty system due to load failure`);
- this.components = new Map<string, IComponent>();
- }
- this.needsUpdate = true;
- }
- // Helper method to clear save data (useful for debugging)
- clearSaveData(): void {
- try {
- world.setDynamicProperty("createbedrock:rotation_system_components", undefined);
- //console.log(`§a[RotationSystem] Save data cleared`);
- } catch (error) {
- console.error(`§c[RotationSystem] Failed to clear save data:`, error);
- }
- }
- init(): void {
- system.run(() => {
- this.load();
- });
- this.needsUpdate = true;
- //console.log("§6[RotationSystem] Initializing rotation system...");
- // Start the update loop
- this.updateInterval = system.runInterval(async () => {
- this.update();
- }, CONFIG.UPDATE_INTERVAL);
- this.animationUpdateInterval = system.runInterval(async () => {
- this.animationUpdate();
- }, CONFIG.ANIMATION_INTERVAL);
- //console.log(`§6[RotationSystem] Update interval set to ${CONFIG.UPDATE_INTERVAL}ms`);
- //console.log("§aRotation system initialized!");
- }
- async addComponent(component: IComponent, waitForNetwork: boolean = false): Promise<void> {
- const key: string = this.getBlockKey(component.block);
- //console.log(`§b[RotationSystem] Adding component at ${key}`);
- //console.log(`§b[RotationSystem] Component type: ${component.block.type.id}`);
- this.components.set(key, component);
- this.needsUpdate = true;
- //console.log(`§b[RotationSystem] Component added. Total components: ${this.components.size}`);
- //console.log(`§b[RotationSystem] Marked system for update`);
- }
- getComponent(block: Block): IComponent {
- const key = this.getBlockKey(block);
- const component = this.components.get(key);
- //console.log(`§7[RotationSystem] Getting component at ${key}`);
- //console.log(`§7[RotationSystem] Component found: ${component ? 'Yes' : 'No'}`);
- return component;
- }
- async setComponent(component: IComponent, waitForNetwork: boolean = false): Promise<void> {
- const key = this.getBlockKey(component.block);
- //console.log(`§e[RotationSystem] Setting component at ${key}`);
- //console.log(`§e[RotationSystem] Component type: ${component.block.type.id}`);
- this.components.set(key, component);
- this.needsUpdate = true;
- //console.log(`§e[RotationSystem] Component set. Marked system for update`);
- }
- async removeComponent(block: Block, waitForNetwork: boolean = false): Promise<void> {
- const key = this.getBlockKey(block);
- //console.log(`§c[RotationSystem] Removing component at ${key}`);
- const existed = this.components.has(key);
- this.components.delete(key);
- this.needsUpdate = true;
- //console.log(`§c[RotationSystem] Component ${existed ? 'removed' : 'was not found'}. Total components: ${this.components.size}`);
- //console.log(`§c[RotationSystem] Marked system for update`);
- }
- private getBlockKey(block: Block): string {
- const key = `createbedrock:rotation_system_block_${block.dimension.id}_${block.location.x}_${block.location.y}_${block.location.z}`;
- //console.log(`§8[RotationSystem] Generated block key: ${key}`);
- return key;
- }
- private getBlockAt(dimension: string | Dimension, pos: Vector3): Block | null {
- //console.log(`§8[RotationSystem] Getting block at position ${pos.x}, ${pos.y}, ${pos.z}`);
- let block: Block | null = null;
- if (typeof dimension === "string") {
- //console.log(`§8[RotationSystem] Using dimension string: ${dimension}`);
- block = world.getDimension(dimension as string).getBlock(pos);
- } else {
- //console.log(`§8[RotationSystem] Using dimension object: ${dimension.id}`);
- block = (dimension as Dimension).getBlock(pos);
- }
- //console.log(`§8[RotationSystem] Block found: ${block ? block.type.id : 'null'}`);
- return block;
- }
- private getConnectedComponent(component: IComponent, connection: BlockConnection): IComponent | null {
- //console.log(`§9[RotationSystem] Checking connection from ${this.getBlockKey(component.block)}`);
- //console.log(`§9[RotationSystem] Connection type: ${connection.type}`);
- //console.log(`§9[RotationSystem] Relative direction: ${connection.relative_direction.x}, ${connection.relative_direction.y}, ${connection.relative_direction.z}`);
- const connectedPos: Vector3 = Vector3.from(component.block.location).add(connection.relative_direction);
- //console.log(`§9[RotationSystem] Connected position: ${connectedPos.x}, ${connectedPos.y}, ${connectedPos.z}`);
- const connectedBlock: Block = this.getBlockAt(component.block.dimension, connectedPos);
- if (!connectedBlock) {
- //console.log(`§9[RotationSystem] No block found at connected position`);
- return null;
- }
- //console.log(`§9[RotationSystem] Found connected block: ${connectedBlock.type.id}`);
- const connectedComponent: IComponent = this.getComponent(connectedBlock);
- if (!connectedComponent) {
- //console.log(`§9[RotationSystem] No component found for connected block`);
- return null;
- }
- //console.log(`§9[RotationSystem] Found connected component`);
- // Check if the connected component has a matching connection back to this component
- const reverseDirection = new Vector3(-connection.relative_direction.x, -connection.relative_direction.y, -connection.relative_direction.z);
- //console.log(`§9[RotationSystem] Checking reverse direction: ${reverseDirection.x}, ${reverseDirection.y}, ${reverseDirection.z}`);
- for (const connectedComponentConnection of connectedComponent.connections) {
- //console.log(`§9[RotationSystem] Checking connected component connection: ${connectedComponentConnection.relative_direction.x}, ${connectedComponentConnection.relative_direction.y}, ${connectedComponentConnection.relative_direction.z}`);
- if (connectedComponentConnection.relative_direction.equals(reverseDirection) &&
- connectedComponentConnection.type === connection.type) {
- //console.log(`§9[RotationSystem] Found matching reverse connection`);
- if (connection.type === CONNECTION_TYPES.SHAFT) {
- //console.log(`§9[RotationSystem] Returning SHAFT connection for ${connectedComponent.block.type.id}`);
- return connectedComponent;
- }
- else if (connection.type === CONNECTION_TYPES.MESH) {
- const componentFacing = component.block.permutation.getState("minecraft:facing_direction");
- const connectedFacing = connectedComponent.block.permutation.getState("minecraft:facing_direction");
- //console.log(`§9[RotationSystem] MESH connection - Component facing: ${componentFacing}, Connected facing: ${connectedFacing}`);
- if (areFacingDirectionsOnSameAxis(componentFacing, connectedFacing)) {
- //console.log(`§9[RotationSystem] MESH components are on same axis - connection valid`);
- return connectedComponent;
- } else {
- //console.log(`§9[RotationSystem] MESH components are NOT on same axis - connection invalid`);
- }
- }
- }
- }
- //console.log(`§9[RotationSystem] No valid reverse connection found`);
- return null;
- }
- private updateConnections(): void {
- //console.log(`§d[RotationSystem] Updating connections for ${this.components.size} components`);
- // maybe use for later ?
- let totalConnections = 0;
- let connectedCount = 0;
- // Update all connection states
- for (const component of this.components.values()) {
- const componentKey = this.getBlockKey(component.block);
- //console.log(`§d[RotationSystem] Updating connections for component at ${componentKey}`);
- for (const connection of component.connections) {
- totalConnections++;
- const connectedComponent = this.getConnectedComponent(component, connection);
- const wasConnected = connection.connected;
- connection.connected = connectedComponent !== null;
- if (connection.connected) connectedCount++;
- }
- }
- //console.log(`§d[RotationSystem] Connection update complete. ${connectedCount}/${totalConnections} connections active`);
- }
- private findNetworks(): IComponent[][] {
- //console.log(`§a[RotationSystem] Finding networks among ${this.components.size} components`);
- const visited: Set<string> = new Set<string>();
- const networks: IComponent[][] = [];
- for (const component of this.components.values()) {
- const componentKey: string = this.getBlockKey(component.block);
- if (visited.has(componentKey)) {
- //console.log(`§a[RotationSystem] Component ${componentKey} already visited, skipping`);
- continue;
- }
- //console.log(`§a[RotationSystem] Starting network discovery from ${componentKey}`);
- const network: IComponent[] = [];
- const queue: IComponent[] = [component];
- const networkVisited: Set<string> = new Set<string>();
- while (queue.length) {
- const currentComponent: IComponent = queue.shift()!;
- const currentComponentKey: string = this.getBlockKey(currentComponent.block);
- if (networkVisited.has(currentComponentKey)) {
- //console.log(`§a[RotationSystem] Component ${currentComponentKey} already in current network, skipping`);
- continue;
- }
- //console.log(`§a[RotationSystem] Adding component ${currentComponentKey} to network`);
- networkVisited.add(currentComponentKey);
- visited.add(currentComponentKey);
- network.push(currentComponent);
- //console.log(`§a[RotationSystem] Checking ${currentComponent.connections.length} connections for ${currentComponentKey}`);
- for (const connection of currentComponent.connections) {
- if (!connection.connected) {
- //console.log(`§a[RotationSystem] Connection not active, skipping`);
- continue;
- }
- const connectedComponent = this.getConnectedComponent(currentComponent, connection);
- if (connectedComponent) {
- const connectedComponentKey = this.getBlockKey(connectedComponent.block);
- if (!networkVisited.has(connectedComponentKey)) {
- //console.log(`§a[RotationSystem] Adding connected component ${connectedComponentKey} to queue`);
- queue.push(connectedComponent);
- } else {
- //console.log(`§a[RotationSystem] Connected component ${connectedComponentKey} already in network`);
- }
- }
- }
- }
- if (network.length) {
- //console.log(`§a[RotationSystem] Network complete with ${network.length} components`);
- networks.push(network);
- }
- }
- //console.log(`§a[RotationSystem] Found ${networks.length} networks total`);
- for (let i = 0; i < networks.length; i++) {
- //console.log(`§a[RotationSystem] ~~~ NETWORK ${i + 1} ~~~`);
- //console.log(`§a[RotationSystem] Network ${i + 1} has ${networks[i].length} components:`);
- for (const component of networks[i]) {
- //console.log(`§a[RotationSystem] - ${this.getBlockKey(component.block)} (${component.block.type.id})`);
- }
- }
- return networks;
- }
- private async propagateRotation(network: IComponent[]): Promise<void> {
- //console.log(`§2[RotationSystem] Propagating rotation for network with ${network.length} components`);
- if (!network.length) {
- return;
- }
- let totalGeneratedSU: number = 0;
- let totalConsumedSU: number = 0;
- const generators: IComponent[] = network.filter((component) => {
- const isGenerator = component.generatedRPM !== null;
- if (isGenerator) {
- totalGeneratedSU += component.generatedSU;
- }
- else {
- totalConsumedSU += component.consumedSU;
- }
- return isGenerator;
- });
- //console.log(`§2[RotationSystem] Found ${generators.length} generators in network`);
- if (!generators.length) {
- //console.log(`§2[RotationSystem] No generators found - setting all components to 0 RPM/SU`);
- for (const component of network) {
- component.RPM = 0;
- component.SU = 0;
- if (component.requestsSUInfo) {
- component.generatedSUInfo! = 0;
- component.consumedSUInfo! = 0;
- }
- }
- return;
- }
- //console.log(`§2[RotationSystem] Base RPM set to: ${baseRPM}`);
- //console.log(`§2[RotationSystem] Total SU: ${totalGeneratedSU} generated / ${totalConsumedSU} consumed`);
- if (totalConsumedSU - totalGeneratedSU > CONFIG.NUMBER_TOLERANCE) {
- //console.log(`§4[RotationSystem] OVERSTRESS DETECTED! Consumed (${totalConsumedSU}) > Generated (${totalGeneratedSU})`);
- // OVERSTRESS !!!!!!!!!
- for (const component of network) {
- component.RPM = 0;
- component.SU = 0;
- if (component.requestsSUInfo) {
- component.generatedSUInfo! = totalGeneratedSU;
- component.consumedSUInfo! = totalConsumedSU;
- }
- }
- //console.log(`§4[RotationSystem] All components in overstressed network set to 0 RPM`);
- return;
- }
- //console.log(`§2[RotationSystem] Network has sufficient SU - propagating rotation`);
- const visited: Set<string> = new Set<string>();
- const queue: Queue = new Queue();
- for (const generator of generators) {
- //console.log(`§2[RotationSystem] Queueing generator ${this.getBlockKey(generator.block)} with RPM ${initialRPM} (multiplier: ${multiplier})`);
- queue.enqueue({ currentComponent: generator, currentComponentRPM: generator.generatedRPM });
- }
- //let propagationStep = 0;
- while (queue.size) {
- //propagationStep++;
- const { currentComponent, currentComponentRPM } = queue.dequeue();
- const currentComponentKey = this.getBlockKey(currentComponent.block);
- //console.log(`§2[RotationSystem] Step ${propagationStep}: Processing ${currentComponentKey} with RPM ${currentComponentRPM}`);
- currentComponent.RPM = currentComponentRPM;
- currentComponent.SU = totalGeneratedSU - totalConsumedSU;
- if (currentComponent.requestsSUInfo) {
- //console.log(`§2[RotationSystem] Setting SU info for ${currentComponentKey}: Generated=${totalGeneratedSU}, Consumed=${totalConsumedSU}`);
- currentComponent.generatedSUInfo! = totalGeneratedSU;
- currentComponent.consumedSUInfo! = totalConsumedSU;
- }
- //console.log(`§2[RotationSystem] Checking ${currentComponent.connections.length} connections for ${currentComponentKey}`);
- for (const currentComponentConnection of currentComponent.connections) {
- if (!currentComponentConnection) {
- //console.log(`§2[RotationSystem] Null connection found, skipping`);
- continue;
- }
- const currentConnectedComponent = this.getConnectedComponent(currentComponent, currentComponentConnection);
- if (!currentConnectedComponent) {
- //console.log(`§2[RotationSystem] No connected component found for this connection`);
- continue;
- }
- const currentConnectedComponentKey = this.getBlockKey(currentConnectedComponent.block);
- //console.log(`§2[RotationSystem] Found connected component: ${currentConnectedComponent.block.type.id}`);
- if (visited.has(currentComponentKey)) {
- //console.log(`§2[RotationSystem] Current component already visited - checking for conflicts`);
- const currentComponentRPMPositive = currentComponentRPM > 0;
- const currentConnectedComponentRPMPositive = currentConnectedComponent.RPM > 0;
- if (
- (
- (
- currentComponentConnection.type === CONNECTION_TYPES.SHAFT &&
- (
- currentConnectedComponentRPMPositive !== currentComponentRPMPositive
- )
- ) ||
- (
- currentComponentConnection.type === CONNECTION_TYPES.MESH &&
- currentConnectedComponentRPMPositive === currentComponentRPMPositive
- )
- ) &&
- (
- Math.abs(currentComponentRPM) > CONFIG.NUMBER_TOLERANCE
- ) &&
- (
- Math.abs(currentConnectedComponent.RPM) > CONFIG.NUMBER_TOLERANCE
- )
- ) {
- //console.log(`§4[RotationSystem] ROTATION CONFLICT DETECTED! Destroying block at ${currentComponentKey}`);
- //console.log(`§4[RotationSystem] Current RPM: ${currentComponentRPM}, Connected RPM: ${currentConnectedComponent.RPM}, Connection type: ${currentComponentConnection.type}`);
- world.getDimension(currentComponent.block.dimension.id).runCommand(`setblock ${currentComponent.block.location.x} ${currentComponent.block.location.y} ${currentComponent.block.location.z} air destroy`);
- this.removeComponent(currentComponent.block, true);
- continue;
- }
- else if (Math.abs(currentConnectedComponent.RPM) >= Math.abs(currentComponentRPM)) {
- //console.log(currentConnectedComponent.RPM, currentComponentRPM);
- currentComponent.RPM = (currentComponentConnection.type == CONNECTION_TYPES.MESH ? -currentConnectedComponent.RPM : currentConnectedComponent.RPM);
- //console.log(`§2[RotationSystem] Connected component already has appropriate RPM, skipping.`);
- continue;
- }
- //console.log(`§2[RotationSystem] No conflict detected, continuing propagation`);
- }
- let currentConnectedComponentRPM = currentComponentRPM;
- if (currentComponentConnection.type === CONNECTION_TYPES.MESH) {
- //console.log(`§2[RotationSystem] MESH connection - inverting RPM`);
- currentConnectedComponentRPM = -currentConnectedComponentRPM;
- }
- //console.log(`§2[RotationSystem] Connected component will have RPM: ${currentConnectedComponentRPM}`);
- if (currentConnectedComponentRPM > CONFIG.RPM_LIMITS.max || currentConnectedComponentRPM < CONFIG.RPM_LIMITS.min) {
- //console.log(`§4[RotationSystem] RPM LIMIT EXCEEDED! Destroying block at ${currentConnectedComponentKey}`);
- //console.log(`§4[RotationSystem] RPM ${currentConnectedComponentRPM} is outside limits [${CONFIG.RPM_LIMITS.min}, ${CONFIG.RPM_LIMITS.max}]`);
- world.getDimension(currentConnectedComponent.block.dimension.id).runCommand(`setblock ${currentConnectedComponent.block.location.x} ${currentConnectedComponent.block.location.y} ${currentConnectedComponent.block.location.z} air destroy`);
- this.removeComponent(currentComponent.block, true);
- continue;
- }
- //console.log(`§2[RotationSystem] Adding connected component to propagation queue`);
- queue.enqueue({ currentComponent: currentConnectedComponent, currentComponentRPM: currentConnectedComponentRPM });
- }
- visited.add(currentComponentKey);
- }
- //console.log(`§2[RotationSystem] Rotation propagation complete for network (${propagationStep} steps)`);
- }
- update(): void {
- ////console.log(`§f[RotationSystem] Update called - needsUpdate: ${this.needsUpdate}`);
- if (this.needsUpdate) {
- this.needsUpdate = false;
- //console.log(`§f[RotationSystem] Starting full system update`);
- //console.log(`§f[RotationSystem] Current component count: ${this.components.size}`);
- this.updateConnections();
- //console.log(`§f[RotationSystem] Connections updated`);
- const networks: IComponent[][] = this.findNetworks();
- //console.log(`§f[RotationSystem] Found ${networks.length} networks`);
- for (let i = 0; i < networks.length; i++) {
- //console.log(`§f[RotationSystem] Processing network ${i + 1} with ${networks[i].length} components`);
- this.propagateRotation(networks[i]);
- }
- //console.log(`§f[RotationSystem] System update complete - needsUpdate set to false`);
- } else {
- //console.log(`§f[RotationSystem] No update needed, skipping`);
- }
- }
- animationUpdate(): void {
- if (this.needsUpdate) {
- return;
- }
- for (const component of this.components.values()) {
- if (!component.animated) {
- continue;
- }
- const currentTickStage = system.currentTick % 1200 / 1200;
- let rotation = Math.round(Math.abs(component.RPM) * currentTickStage * 90 / 15) * 15 % 90;
- if (component.RPM < 0) {
- rotation = (90 - rotation) % 90;
- }
- if (["south", "east", "down"].includes(component.block.permutation.getState("minecraft:facing_direction"))) {
- rotation = (90 - rotation) % 90;
- }
- component.block.setPermutation(component.block.permutation.withState("createbedrock:rotation", rotation));
- }
- }
- }
- // Initialize the system
- const rotationSystem = new RotationSystem();
- // Component Registration
- system.beforeEvents.startup.subscribe((event: StartupEvent) => {
- try {
- // Register Creative Motor Component
- event.blockComponentRegistry.registerCustomComponent("createbedrock:creative_motor_component", {
- onPlace: (event: BlockComponentOnPlaceEvent) => {
- const component = new CreativeMotorComponent(event.block);
- rotationSystem.addComponent(component, true);
- },
- onPlayerInteract: (event: BlockComponentPlayerInteractEvent) => {
- const component = rotationSystem.getComponent(event.block) as CreativeMotorComponent;
- if (component) {
- component.onInteract(event);
- }
- },
- onPlayerDestroy: (event: BlockComponentPlayerDestroyEvent) => {
- rotationSystem.removeComponent(event.block, true);
- }
- });
- // Register Shaft Component
- event.blockComponentRegistry.registerCustomComponent("createbedrock:shaft_component", {
- onPlace: (event: BlockComponentOnPlaceEvent) => {
- const component = new ShaftComponent(event.block);
- rotationSystem.addComponent(component, true);
- },
- onPlayerDestroy: (event: BlockComponentPlayerDestroyEvent) => {
- rotationSystem.removeComponent(event.block, true);
- }
- });
- // Register Stressometer Component
- event.blockComponentRegistry.registerCustomComponent("createbedrock:stressometer_component", {
- onPlace: (event: BlockComponentOnPlaceEvent) => {
- const component = new StressometerComponent(event.block);
- rotationSystem.addComponent(component, true);
- },
- onPlayerInteract: (event: BlockComponentPlayerInteractEvent) => {
- const component = rotationSystem.getComponent(event.block) as StressometerComponent;
- if (component) {
- component.onInteract(event);
- }
- },
- onPlayerDestroy: (event: BlockComponentPlayerDestroyEvent) => {
- rotationSystem.removeComponent(event.block, true);
- }
- });
- event.blockComponentRegistry.registerCustomComponent("createbedrock:speedometer_component", {
- onPlace: (event: BlockComponentOnPlaceEvent) => {
- const component = new SpeedometerComponent(event.block);
- rotationSystem.addComponent(component, true);
- },
- onPlayerInteract: (event: BlockComponentPlayerInteractEvent) => {
- const component = rotationSystem.getComponent(event.block) as SpeedometerComponent;
- if (component) {
- component.onInteract(event);
- }
- },
- onPlayerDestroy: (event: BlockComponentPlayerDestroyEvent) => {
- rotationSystem.removeComponent(event.block, true);
- }
- });
- event.blockComponentRegistry.registerCustomComponent("createbedrock:cogwheel_component", {
- onPlace: (event: BlockComponentOnPlaceEvent) => {
- const component = new CogwheelComponent(event.block);
- rotationSystem.addComponent(component, true);
- },
- onPlayerDestroy: (event: BlockComponentPlayerDestroyEvent) => {
- rotationSystem.removeComponent(event.block, true);
- }
- });
- //console.log("§aRotation components registered successfully!");
- // Initialize the system after registration
- rotationSystem.init();
- } catch (error) {
- console.error("Component registration failed:", error);
- }
- });
- //console.log("§aRotation system script loaded!");
- system.beforeEvents.shutdown.subscribe((event: ShutdownEvent) => {
- rotationSystem.save();
- });
Advertisement
Add Comment
Please, Sign In to add comment