Guest User

Untitled

a guest
Jun 1st, 2025
26
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
TypeScript 55.30 KB | Source Code | 0 0
  1.  
  2. import { world, system, Block, BlockComponentPlayerInteractEvent, BlockComponentPlayerDestroyEvent, BlockComponentOnPlaceEvent, BlockComponentTickEvent, StartupEvent, ShutdownEvent, Player, Dimension } from "@minecraft/server";
  3. import { ModalFormData } from "@minecraft/server-ui";
  4.  
  5. // Configuration
  6. let CONFIG = {
  7.     UPDATE_INTERVAL: 1,
  8.     ANIMATION_INTERVAL: 1,
  9.     MAX_STRESS: 2147483647,
  10.     RPM_LIMITS: { min: -256, max: 256 },
  11.     NUMBER_TOLERANCE: .1,
  12. };
  13.  
  14. // Enums
  15. enum CONNECTION_TYPES {
  16.     SHAFT = "SHAFT",
  17.     MESH = "MESH",
  18.     LARGE_MESH = "LARGE_MESH"
  19. };
  20.  
  21. enum DIRECTIONS {
  22.     NORTH = "north",
  23.     SOUTH = "south",
  24.     EAST = "east",
  25.     WEST = "west",
  26.     UP = "up",
  27.     DOWN = "down"
  28. };
  29.  
  30. enum FACES {
  31.     FRONT = "front",
  32.     BACK = "back",
  33.     LEFT = "left",
  34.     RIGHT = "right",
  35.     UP = "up",
  36.     DOWN = "down"
  37. };
  38.  
  39. interface IVector3 {
  40.     x: number;
  41.     y: number;
  42.     z: number;
  43. };
  44.  
  45. class Vector3 {
  46.     x: number;
  47.     y: number;
  48.     z: number;
  49.     constructor(x: number = 0, y: number = 0, z: number = 0) {
  50.         this.x = x; this.y = y; this.z = z;
  51.     }
  52.  
  53.     static from(pos: IVector3): Vector3 {
  54.         return new Vector3(pos.x, pos.y, pos.z);
  55.     }
  56.     add(v: Vector3): Vector3 {
  57.         return new Vector3(this.x + v.x, this.y + v.y, this.z + v.z);
  58.     }
  59.     equals(v: Vector3, tolerance: number = CONFIG.NUMBER_TOLERANCE) {
  60.         return Math.abs(this.x - v.x) < tolerance &&
  61.             Math.abs(this.y - v.y) < tolerance &&
  62.             Math.abs(this.z - v.z) < tolerance;
  63.     }
  64.     toString(): string {
  65.         return `${Math.floor(this.x)}_${Math.floor(this.y)}_${Math.floor(this.z)}`;
  66.     }
  67. }
  68.  
  69. class RELATIVE_OFFSETS {
  70.     static readonly FRONT = new Vector3(0, 0, -1);
  71.     static readonly BACK = new Vector3(0, 0, 1);
  72.     static readonly LEFT = new Vector3(-1, 0, 0);
  73.     static readonly RIGHT = new Vector3(1, 0, 0);
  74.     static readonly UP = new Vector3(0, -1, 0);
  75.     static readonly DOWN = new Vector3(0, 1, 0);
  76. };
  77.  
  78. interface BlockConnection {
  79.     type: CONNECTION_TYPES,
  80.     relative_direction: Vector3,
  81.     connected: boolean
  82. }
  83.  
  84. class Node {
  85.     data: any;
  86.     next: any;
  87.     constructor(data) {
  88.         this.data = data;
  89.         this.next = null;
  90.     }
  91. }
  92.  
  93. class Queue {
  94.     front: any;
  95.     rear: any;
  96.     size: number;
  97.     constructor() {
  98.         this.front = null;
  99.         this.rear = null;
  100.         this.size = 0;
  101.     }
  102.     enqueue(data) {
  103.         const newNode = new Node(data);
  104.         if (this.isEmpty()) {
  105.             this.front = newNode;
  106.             this.rear = newNode;
  107.         } else {
  108.             this.rear.next = newNode;
  109.             this.rear = newNode;
  110.         }
  111.         this.size++;
  112.     }
  113.     dequeue() {
  114.         if (this.isEmpty()) {
  115.             return null;
  116.         }
  117.         const removedNode = this.front;
  118.         this.front = this.front.next;
  119.         if (this.front === null) {
  120.             this.rear = null;
  121.         }
  122.         this.size--;
  123.         return removedNode.data;
  124.     }
  125.     peek() {
  126.         if (this.isEmpty()) {
  127.             return null;
  128.         }
  129.         return this.front.data;
  130.     }
  131.     isEmpty() {
  132.         return this.size === 0;
  133.     }
  134.     getSize() {
  135.         return this.size;
  136.     }
  137.     print() {
  138.         let current = this.front;
  139.         const elements = [];
  140.         while (current) {
  141.             elements.push(current.data);
  142.             current = current.next;
  143.         }
  144.         console.log(elements.join(' -> '));
  145.     }
  146. }
  147.  
  148. function getFacingDirectionMultiplier(facingDirecion: "north" | "south" | "east" | "west" | "up" | "down"): number {
  149.     if (["south", "east", "down"].includes(facingDirecion)) {
  150.         return -1;
  151.     }
  152.     return 1;
  153. }
  154.  
  155. function areFacingDirectionsOnSameAxis(facingDirection1: "north" | "south" | "east" | "west" | "up" | "down", facingDirection2: "north" | "south" | "east" | "west" | "up" | "down"): boolean {
  156.     const sameAxisFacingDirections: string[][] = [
  157.         ["north", "south"],
  158.         ["east", "west"],
  159.         ["up", "down"]
  160.     ]
  161.  
  162.     for (const sameAxisFacingDirectionsElement of sameAxisFacingDirections) {
  163.         if (sameAxisFacingDirectionsElement.includes(facingDirection1) && sameAxisFacingDirectionsElement.includes(facingDirection2)) {
  164.             return true;
  165.         }
  166.     }
  167.  
  168.     return false;
  169. }
  170.  
  171. function translateAbsoluteOffsetToRelative(offset: Vector3, facingDirection: "north" | "south" | "east" | "west" | "up" | "down"): Vector3 {
  172.     switch (facingDirection) {
  173.         case "north": // facing -z, no rotation needed (this is our reference)
  174.             return new Vector3(offset.x, offset.y, offset.z);
  175.  
  176.         case "south": // facing +z, rotate 180° around Y
  177.             return new Vector3(-offset.x, offset.y, -offset.z);
  178.  
  179.         case "east": // facing +x, rotate 90° clockwise around Y
  180.             return new Vector3(-offset.z, offset.y, offset.x);
  181.  
  182.         case "west": // facing -x, rotate 90° counter-clockwise around Y
  183.             return new Vector3(offset.z, offset.y, -offset.x);
  184.  
  185.         case "up": // facing -y, rotate 90° around X
  186.             return new Vector3(offset.x, offset.z, -offset.y);
  187.  
  188.         case "down": // facing +y, rotate -90° around X
  189.             return new Vector3(offset.x, -offset.z, offset.y);
  190.  
  191.         default:
  192.             return offset;
  193.     }
  194. }
  195.  
  196. // Creative Motor Component
  197. class CreativeMotorComponent {
  198.     connections: BlockConnection[];
  199.     setRPM: number;
  200.     generatedRPM: number | null;
  201.     RPM: number;
  202.     generatedSU: number;
  203.     consumedSU: number;
  204.     SU: number;
  205.     block: Block;
  206.  
  207.     readonly interactable: boolean = true;
  208.     readonly animated: boolean = false;
  209.     readonly requestsSUInfo = false;
  210.     readonly identifier: string = "createbedrock:creative_motor";
  211.  
  212.     constructor(block: Block) {
  213.         const facingDirection: "north" | "south" | "east" | "west" | "up" | "down" = block.permutation.getState("minecraft:facing_direction");
  214.  
  215.         this.connections = [
  216.             {
  217.                 type: CONNECTION_TYPES.SHAFT,
  218.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.FRONT, facingDirection),
  219.                 connected: false
  220.             }
  221.         ]
  222.  
  223.         this.setRPM = 16;
  224.         this.generatedRPM = getFacingDirectionMultiplier(facingDirection) * 16;
  225.         this.RPM = this.generatedRPM;
  226.         this.generatedSU = 2147483647;
  227.         this.consumedSU = 0;
  228.         this.SU = 2147483647;
  229.         this.block = block;
  230.         //console.log(this.generatedRPM);
  231.     }
  232.  
  233.     onInteract(event: BlockComponentPlayerInteractEvent) {
  234.         const player: Player = event.player;
  235.         const block: Block = event.block;
  236.         const facingDirection: "north" | "south" | "east" | "west" | "up" | "down" = block.permutation.getState("minecraft:facing_direction");
  237.  
  238.         try {
  239.             const form = new ModalFormData()
  240.                 .title('Creative Motor Configuration')
  241.                 .slider('RPM', CONFIG.RPM_LIMITS.min, CONFIG.RPM_LIMITS.max, { defaultValue: this.setRPM })
  242.                 .submitButton('Submit')
  243.  
  244.             form.show(player).then(response => {
  245.                 if (!response.canceled && response.formValues) {
  246.                     const [generatedRPM] = response.formValues;
  247.                     if (typeof generatedRPM === 'number') {
  248.                         this.setRPM = generatedRPM;
  249.                         this.generatedRPM = getFacingDirectionMultiplier(facingDirection) * this.setRPM;
  250.                         this.RPM = this.generatedRPM;
  251.                         // Update the rotation network
  252.                         rotationSystem.needsUpdate = true;
  253.                     }
  254.                 }
  255.             }).catch(error => {
  256.                 console.error('Form error:', error);
  257.             });
  258.         } catch (error) {
  259.             console.warn('Failed to create form:', error);
  260.         }
  261.     }
  262. }
  263.  
  264. // Other component classes
  265. class ShaftComponent {
  266.     connections: BlockConnection[];
  267.     generatedRPM: number | null;
  268.     RPM: number;
  269.     generatedSU: number;
  270.     consumedSU: number;
  271.     SU: number;
  272.     block: Block;
  273.  
  274.     readonly interactable: boolean = false;
  275.     readonly animated: boolean = true;
  276.     readonly requestsSUInfo = false;
  277.     readonly identifier: string = "createbedrock:shaft";
  278.  
  279.     constructor(block: Block) {
  280.         const facingDirection: "north" | "south" | "east" | "west" | "up" | "down" = block.permutation.getState("minecraft:facing_direction");
  281.  
  282.         this.connections = [
  283.             {
  284.                 type: CONNECTION_TYPES.SHAFT,
  285.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.FRONT, facingDirection),
  286.                 connected: false
  287.             },
  288.             {
  289.                 type: CONNECTION_TYPES.SHAFT,
  290.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.BACK, facingDirection),
  291.                 connected: false
  292.             }
  293.         ]
  294.  
  295.         this.generatedRPM = null;
  296.         this.RPM = 0;
  297.         this.generatedSU = 0;
  298.         this.consumedSU = 0;
  299.         this.SU = 0;
  300.         this.block = block;
  301.     }
  302. }
  303.  
  304. class StressometerComponent {
  305.     connections: BlockConnection[];
  306.     generatedRPM: number | null;
  307.     RPM: number;
  308.     generatedSU: number;
  309.     generatedSUInfo: number;
  310.     consumedSU: number;
  311.     consumedSUInfo: number;
  312.     SU: number;
  313.     block: Block;
  314.  
  315.     readonly interactable: boolean = true;
  316.     readonly animated: boolean = false;
  317.     readonly requestsSUInfo = true;
  318.     readonly identifier: string = "createbedrock:stressometer";
  319.  
  320.     constructor(block: Block) {
  321.         const facingDirection: "north" | "south" | "east" | "west" | "up" | "down" = block.permutation.getState("minecraft:facing_direction");
  322.  
  323.         this.connections = [
  324.             {
  325.                 type: CONNECTION_TYPES.SHAFT,
  326.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.FRONT, facingDirection),
  327.                 connected: false
  328.             },
  329.             {
  330.                 type: CONNECTION_TYPES.SHAFT,
  331.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.BACK, facingDirection),
  332.                 connected: false
  333.             }
  334.         ]
  335.  
  336.         this.generatedRPM = null;
  337.         this.RPM = 0;
  338.         this.generatedSU = 0;
  339.         this.generatedSUInfo = 0;
  340.         this.consumedSU = 0;
  341.         this.consumedSUInfo = 0;
  342.         this.SU = 0;
  343.         this.block = block;
  344.     }
  345.  
  346.     onInteract(event: BlockComponentPlayerInteractEvent) {
  347.         const player: Player = event.player;
  348.         const stressPercentage = this.generatedSUInfo > 0
  349.             ? Math.round((this.consumedSUInfo / this.generatedSUInfo) * 100)
  350.             : 0;
  351.  
  352.         let stressLevel;
  353.         if (this.consumedSUInfo - this.generatedSUInfo > CONFIG.NUMBER_TOLERANCE) {
  354.             stressLevel = "§c■■■ Overstressed";
  355.         } else if (stressPercentage > 75) {
  356.             stressLevel = "§6■■■ High";
  357.         } else if (stressPercentage > 50) {
  358.             stressLevel = "§e■■▧ Moderate";
  359.         } else if (this.generatedSUInfo > CONFIG.NUMBER_TOLERANCE) {
  360.             stressLevel = "§a■▧▧ Low";
  361.         } else {
  362.             stressLevel = "§7▧▧▧ No rotation";
  363.         }
  364.         player.onScreenDisplay.setActionBar(`§fGauge Information:\n§7Network Stress\n ${stressLevel} §f(${stressPercentage}%)`)
  365.     }
  366. }
  367.  
  368. class SpeedometerComponent {
  369.     connections: BlockConnection[];
  370.     generatedRPM: number | null;
  371.     RPM: number;
  372.     generatedSU: number;
  373.     generatedSUInfo: number;
  374.     consumedSU: number;
  375.     consumedSUInfo: number;
  376.     SU: number;
  377.     block: Block;
  378.  
  379.     readonly interactable: boolean = false;
  380.     readonly animated: boolean = false;
  381.     readonly requestsSUInfo = true;
  382.     readonly identifier: string = "createbedrock:speedometer";
  383.  
  384.     constructor(block: Block) {
  385.         const facingDirection: "north" | "south" | "east" | "west" | "up" | "down" = block.permutation.getState("minecraft:facing_direction");
  386.         this.connections = [
  387.             {
  388.                 type: CONNECTION_TYPES.SHAFT,
  389.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.FRONT, facingDirection),
  390.                 connected: false
  391.             },
  392.             {
  393.                 type: CONNECTION_TYPES.SHAFT,
  394.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.BACK, facingDirection),
  395.                 connected: false
  396.             }
  397.         ]
  398.  
  399.         this.generatedRPM = null;
  400.         this.RPM = 0;
  401.         this.generatedSU = 0;
  402.         this.generatedSUInfo = 0;
  403.         this.consumedSU = 0;
  404.         this.consumedSUInfo = 0;
  405.         this.SU = 0;
  406.         this.block = block;
  407.     }
  408.  
  409.     onInteract(event: BlockComponentPlayerInteractEvent) {
  410.         const rpm = Math.abs(this.RPM);
  411.         const player = event.player;
  412.         let speedLevel: string;
  413.  
  414.         if (rpm > 99) {
  415.             speedLevel = "§d■■■ Fast";
  416.         } else if (rpm > 29) {
  417.             speedLevel = "§b■■▧ Moderate";
  418.         } else if (rpm > 1) {
  419.             speedLevel = "§a■▧▧ Slow";
  420.         } else {
  421.             speedLevel = "§7▧▧▧ None"
  422.         }
  423.  
  424.         if (this.consumedSUInfo - this.generatedSUInfo > CONFIG.NUMBER_TOLERANCE) {
  425.             speedLevel = "§7§m" + speedLevel;
  426.         }
  427.         player.onScreenDisplay.setActionBar(`§fGauge Information:\n§7Rotation Speed\n ${speedLevel} §f(${Math.round(rpm)} RPM)`);
  428.     }
  429. }
  430.  
  431. class CogwheelComponent {
  432.     connections: BlockConnection[];
  433.     generatedRPM: number | null;
  434.     RPM: number;
  435.     generatedSU: number;
  436.     consumedSU: number;
  437.     SU: number;
  438.     block: Block;
  439.  
  440.     readonly interactable: boolean = false;
  441.     readonly animated: boolean = true;
  442.     readonly requestsSUInfo = false;
  443.     readonly identifier: string = "createbedrock:cogwheel";
  444.  
  445.     constructor(block: Block) {
  446.         const facingDirection: "north" | "south" | "east" | "west" | "up" | "down" = block.permutation.getState("minecraft:facing_direction");
  447.  
  448.         this.connections = [
  449.             {
  450.                 type: CONNECTION_TYPES.SHAFT,
  451.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.FRONT, facingDirection),
  452.                 connected: false
  453.             },
  454.             {
  455.                 type: CONNECTION_TYPES.SHAFT,
  456.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.BACK, facingDirection),
  457.                 connected: false
  458.             },
  459.             {
  460.                 type: CONNECTION_TYPES.MESH,
  461.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.RIGHT, facingDirection),
  462.                 connected: false
  463.             },
  464.             {
  465.                 type: CONNECTION_TYPES.MESH,
  466.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.LEFT, facingDirection),
  467.                 connected: false
  468.             },
  469.             {
  470.                 type: CONNECTION_TYPES.MESH,
  471.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.UP, facingDirection),
  472.                 connected: false
  473.             },
  474.             {
  475.                 type: CONNECTION_TYPES.MESH,
  476.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.DOWN, facingDirection),
  477.                 connected: false
  478.             }
  479.         ]
  480.  
  481.         this.generatedRPM = null;
  482.         this.RPM = 0;
  483.         this.generatedSU = 0;
  484.         this.consumedSU = 0;
  485.         this.SU = 0;
  486.         this.block = block;
  487.     }
  488. }
  489.  
  490. class LargeCogwheelComponent {
  491.     connections: BlockConnection[];
  492.     generatedRPM: number | null;
  493.     RPM: number;
  494.     generatedSU: number;
  495.     consumedSU: number;
  496.     SU: number;
  497.     block: Block;
  498.  
  499.     readonly interactable: boolean = false;
  500.     readonly animated: boolean = true;
  501.     readonly requestsSUInfo = false;
  502.     readonly identifier: string = "createbedrock:cogwheel";
  503.  
  504.     constructor(block: Block) {
  505.         const facingDirection: "north" | "south" | "east" | "west" | "up" | "down" = block.permutation.getState("minecraft:facing_direction");
  506.  
  507.         this.connections = [
  508.             {
  509.                 type: CONNECTION_TYPES.SHAFT,
  510.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.FRONT, facingDirection),
  511.                 connected: false
  512.             },
  513.             {
  514.                 type: CONNECTION_TYPES.SHAFT,
  515.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.BACK, facingDirection),
  516.                 connected: false
  517.             },
  518.             {
  519.                 type: CONNECTION_TYPES.LARGE_MESH,
  520.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.RIGHT, facingDirection),
  521.                 connected: false
  522.             },
  523.             {
  524.                 type: CONNECTION_TYPES.LARGE_MESH,
  525.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.LEFT, facingDirection),
  526.                 connected: false
  527.             },
  528.             {
  529.                 type: CONNECTION_TYPES.MESH,
  530.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.UP, facingDirection),
  531.                 connected: false
  532.             },
  533.             {
  534.                 type: CONNECTION_TYPES.MESH,
  535.                 relative_direction: translateAbsoluteOffsetToRelative(RELATIVE_OFFSETS.DOWN, facingDirection),
  536.                 connected: false
  537.             }
  538.         ]
  539.  
  540.         this.generatedRPM = null;
  541.         this.RPM = 0;
  542.         this.generatedSU = 0;
  543.         this.consumedSU = 0;
  544.         this.SU = 0;
  545.         this.block = block;
  546.     }
  547. }
  548.  
  549. interface IComponent {
  550.     connections: BlockConnection[];
  551.     setRPM?: number;
  552.     generatedRPM: number | null;
  553.     RPM: number;
  554.     generatedSU: number;
  555.     generatedSUInfo?: number;
  556.     consumedSU: number;
  557.     consumedSUInfo?: number;
  558.     SU: number;
  559.     block: Block;
  560.     onPlace?: (event: BlockComponentOnPlaceEvent) => void;
  561.     onDestroy?: (event: BlockComponentPlayerDestroyEvent) => void;
  562.     onTick?: (event: BlockComponentTickEvent) => void;
  563.     onInteract?: (event: BlockComponentPlayerInteractEvent) => void;
  564.     readonly interactable: boolean;
  565.     readonly animated: boolean;
  566.     readonly requestsSUInfo: boolean;
  567.     readonly identifier: string;
  568. }
  569.  
  570. interface ISerializableComponent {
  571.     connections: BlockConnection[];
  572.     setRPM?: number;
  573.     generatedRPM: number | null;
  574.     RPM: number;
  575.     generatedSU: number;
  576.     generatedSUInfo?: number;
  577.     consumedSU: number;
  578.     consumedSUInfo?: number;
  579.     SU: number;
  580.     blockDimension: string;
  581.     blockLocation: IVector3;
  582.     onPlace?: (event: BlockComponentOnPlaceEvent) => void;
  583.     onDestroy?: (event: BlockComponentPlayerDestroyEvent) => void;
  584.     onTick?: (event: BlockComponentTickEvent) => void;
  585.     onInteract?: (event: BlockComponentPlayerInteractEvent) => void;
  586.     readonly interactable: boolean;
  587.     readonly animated: boolean;
  588.     readonly requestsSUInfo: boolean;
  589.     readonly identifier: string;
  590. }
  591.  
  592. class RotationSystem {
  593.     components: Map<string, IComponent> = new Map();
  594.     // FP - For Propagation (purposes)
  595.     needsUpdate: boolean;
  596.     private updateInterval: number;
  597.     private animationUpdateInterval: number;
  598.  
  599.     // Helper method to clear save data (useful for debugging)
  600.  
  601.     save(): void {
  602.         try {
  603.             //console.log(`§6[RotationSystem] Starting save process with ${this.components.size} components`);
  604.  
  605.             const serializableComponents: any[] = [];
  606.  
  607.             for (const [key, component] of this.components) {
  608.                 const serializableComponent = {
  609.                     identifier: component.identifier,
  610.                     connections: component.connections.map(connection => ({
  611.                         type: connection.type,
  612.                         relative_direction: {
  613.                             x: connection.relative_direction.x,
  614.                             y: connection.relative_direction.y,
  615.                             z: connection.relative_direction.z
  616.                         },
  617.                         connected: connection.connected
  618.                     })),
  619.                     setRPM: component.setRPM,
  620.                     generatedRPM: component.generatedRPM,
  621.                     RPM: component.RPM,
  622.                     generatedSU: component.generatedSU,
  623.                     generatedSUInfo: component.generatedSUInfo,
  624.                     consumedSU: component.consumedSU,
  625.                     consumedSUInfo: component.consumedSUInfo,
  626.                     SU: component.SU,
  627.                     blockDimension: component.block.dimension.id,
  628.                     blockLocation: {
  629.                         x: component.block.location.x,
  630.                         y: component.block.location.y,
  631.                         z: component.block.location.z
  632.                     },
  633.  
  634.                     interactable: component.interactable,
  635.                     animated: component.animated,
  636.                     requestsSUInfo: component.requestsSUInfo
  637.                 };
  638.  
  639.                 serializableComponents.push(serializableComponent);
  640.             }
  641.  
  642.             const saveData = {
  643.                 components: serializableComponents,
  644.                 version: "1.0.0",
  645.                 timestamp: Date.now()
  646.             };
  647.             const saveDataString = JSON.stringify(saveData);
  648.  
  649.             const numberSaveDataParts = saveDataString.length / 32767;
  650.  
  651.             for (let i = 0; i < numberSaveDataParts; ++i) {
  652.                 world.setDynamicProperty(`createbedrock:rotation_system_components_${i}`, saveDataString.slice(i * 32767, Math.min((i + 1) * 32767, saveDataString.length)));
  653.             }
  654.  
  655.             world.setDynamicProperty(`createbedrock:rotation_system_components_${numberSaveDataParts}`, undefined);
  656.  
  657.             //console.log(`§a[RotationSystem] Successfully saved ${serializableComponents.length} components`);
  658.  
  659.         } catch (error) {
  660.             console.error(`§c[RotationSystem] Save failed:`, error);
  661.         }
  662.     }
  663.  
  664.     load(): void {
  665.         try {
  666.             //console.log(`§6[RotationSystem] Starting load process`);
  667.  
  668.             let saveDataStringPart: string | undefined;
  669.             let saveDataString: string = "";
  670.  
  671.             for (let i = 0; saveDataStringPart = (world.getDynamicProperty(`createbedrock:rotation_system_components_${i}`) as string | undefined); ++i) {
  672.                 saveDataString += saveDataStringPart;
  673.             }
  674.  
  675.             //console.log(saveDataString);
  676.  
  677.             if (!saveDataString) {
  678.                 //console.log(`§7[RotationSystem] No save data found, starting with empty system`);
  679.                 this.components = new Map<string, IComponent>();
  680.                 return;
  681.             }
  682.  
  683.             const saveData = JSON.parse(saveDataString);
  684.             //console.log(`§6[RotationSystem] Found save data version ${saveData.version || 'unknown'}`);
  685.  
  686.             if (!saveData.components || !Array.isArray(saveData.components)) {
  687.                 console.warn(`§e[RotationSystem] Invalid save data structure, starting fresh`);
  688.                 this.components = new Map<string, IComponent>();
  689.                 return;
  690.             }
  691.  
  692.             this.components = new Map<string, IComponent>();
  693.             let loadedCount = 0;
  694.             let skippedCount = 0;
  695.  
  696.             for (const savedComponent of saveData.components) {
  697.                 try {
  698.  
  699.                     if (!savedComponent.identifier || !savedComponent.blockDimension || !savedComponent.blockLocation) {
  700.                         console.warn(`§e[RotationSystem] Skipping component with missing required fields`);
  701.                         skippedCount++;
  702.                         continue;
  703.                     }
  704.  
  705.  
  706.                     const block = world.getDimension(savedComponent.blockDimension).getBlock(savedComponent.blockLocation);
  707.                     if (!block) {
  708.                         console.warn(`§e[RotationSystem] Block not found at ${savedComponent.blockLocation.x}, ${savedComponent.blockLocation.y}, ${savedComponent.blockLocation.z}`);
  709.                         skippedCount++;
  710.                         continue;
  711.                     }
  712.  
  713.                     let component: IComponent | null = null;
  714.  
  715.                     switch (savedComponent.identifier) {
  716.                         case "createbedrock:creative_motor":
  717.                             component = new CreativeMotorComponent(block);
  718.                             // Restore specific properties
  719.                             if (typeof savedComponent.setRPM === 'number') {
  720.                                 (component as CreativeMotorComponent).setRPM = savedComponent.setRPM;
  721.                             }
  722.                             break;
  723.                         case "createbedrock:shaft":
  724.                             component = new ShaftComponent(block);
  725.                             break;
  726.                         case "createbedrock:stressometer":
  727.                             component = new StressometerComponent(block);
  728.                             break;
  729.                         case "createbedrock:speedometer":
  730.                             component = new SpeedometerComponent(block);
  731.                             break;
  732.                         case "createbedrock:cogwheel":
  733.                             component = new CogwheelComponent(block);
  734.                             break;
  735.                         default:
  736.                             console.warn(`§e[RotationSystem] Unknown component type: ${savedComponent.identifier}`);
  737.                             skippedCount++;
  738.                             continue;
  739.                     }
  740.  
  741.                     if (component) {
  742.                         // Restore common properties
  743.                         component.generatedRPM = savedComponent.generatedRPM ?? component.generatedRPM;
  744.                         component.RPM = savedComponent.RPM ?? component.RPM;
  745.                         component.generatedSU = savedComponent.generatedSU ?? component.generatedSU;
  746.                         component.consumedSU = savedComponent.consumedSU ?? component.consumedSU;
  747.                         component.SU = savedComponent.SU ?? component.SU;
  748.  
  749.                         // Restore SU info for components that track it
  750.                         if (component.requestsSUInfo) {
  751.                             (component as any).generatedSUInfo = savedComponent.generatedSUInfo ?? 0;
  752.                             (component as any).consumedSUInfo = savedComponent.consumedSUInfo ?? 0;
  753.                         }
  754.  
  755.                         if (savedComponent.connections && Array.isArray(savedComponent.connections)) {
  756.                             for (let i = 0; i < Math.min(component.connections.length, savedComponent.connections.length); i++) {
  757.                                 const savedConn = savedComponent.connections[i];
  758.                                 if (savedConn.relative_direction) {
  759.                                     component.connections[i].relative_direction = new Vector3(
  760.                                         savedConn.relative_direction.x,
  761.                                         savedConn.relative_direction.y,
  762.                                         savedConn.relative_direction.z
  763.                                     );
  764.                                     component.connections[i].type = savedConn.type;
  765.                                     // Don't restore 'connected' state - it will be recalculated
  766.                                 }
  767.                             }
  768.                         }
  769.  
  770.                         this.components.set(this.getBlockKey(block), component);
  771.                         loadedCount++;
  772.                     }
  773.                 } catch (componentError) {
  774.                     console.error(`§c[RotationSystem] Failed to load component:`, componentError);
  775.                     skippedCount++;
  776.                 }
  777.             }
  778.  
  779.             //console.log(`§a[RotationSystem] Load complete: ${loadedCount} loaded, ${skippedCount} skipped`);
  780.  
  781.         } catch (error) {
  782.             console.error(`§c[RotationSystem] Load failed:`, error);
  783.             //console.log(`§e[RotationSystem] Starting with empty system due to load failure`);
  784.             this.components = new Map<string, IComponent>();
  785.         }
  786.         this.needsUpdate = true;
  787.     }
  788.  
  789.     // Helper method to clear save data (useful for debugging)
  790.     clearSaveData(): void {
  791.         try {
  792.             world.setDynamicProperty("createbedrock:rotation_system_components", undefined);
  793.             //console.log(`§a[RotationSystem] Save data cleared`);
  794.         } catch (error) {
  795.             console.error(`§c[RotationSystem] Failed to clear save data:`, error);
  796.         }
  797.     }
  798.  
  799.     init(): void {
  800.         system.run(() => {
  801.             this.load();
  802.         });
  803.         this.needsUpdate = true;
  804.         //console.log("§6[RotationSystem] Initializing rotation system...");
  805.  
  806.         // Start the update loop
  807.         this.updateInterval = system.runInterval(async () => {
  808.             this.update();
  809.         }, CONFIG.UPDATE_INTERVAL);
  810.  
  811.         this.animationUpdateInterval = system.runInterval(async () => {
  812.             this.animationUpdate();
  813.         }, CONFIG.ANIMATION_INTERVAL);
  814.  
  815.         //console.log(`§6[RotationSystem] Update interval set to ${CONFIG.UPDATE_INTERVAL}ms`);
  816.         //console.log("§aRotation system initialized!");
  817.     }
  818.  
  819.     async addComponent(component: IComponent, waitForNetwork: boolean = false): Promise<void> {
  820.         const key: string = this.getBlockKey(component.block);
  821.         //console.log(`§b[RotationSystem] Adding component at ${key}`);
  822.         //console.log(`§b[RotationSystem] Component type: ${component.block.type.id}`);
  823.  
  824.         this.components.set(key, component);
  825.         this.needsUpdate = true;
  826.  
  827.         //console.log(`§b[RotationSystem] Component added. Total components: ${this.components.size}`);
  828.         //console.log(`§b[RotationSystem] Marked system for update`);
  829.     }
  830.  
  831.     getComponent(block: Block): IComponent {
  832.         const key = this.getBlockKey(block);
  833.         const component = this.components.get(key);
  834.  
  835.         //console.log(`§7[RotationSystem] Getting component at ${key}`);
  836.         //console.log(`§7[RotationSystem] Component found: ${component ? 'Yes' : 'No'}`);
  837.  
  838.         return component;
  839.     }
  840.  
  841.     async setComponent(component: IComponent, waitForNetwork: boolean = false): Promise<void> {
  842.         const key = this.getBlockKey(component.block);
  843.         //console.log(`§e[RotationSystem] Setting component at ${key}`);
  844.         //console.log(`§e[RotationSystem] Component type: ${component.block.type.id}`);
  845.  
  846.         this.components.set(key, component);
  847.         this.needsUpdate = true;
  848.  
  849.         //console.log(`§e[RotationSystem] Component set. Marked system for update`);
  850.     }
  851.  
  852.     async removeComponent(block: Block, waitForNetwork: boolean = false): Promise<void> {
  853.         const key = this.getBlockKey(block);
  854.         //console.log(`§c[RotationSystem] Removing component at ${key}`);
  855.  
  856.         const existed = this.components.has(key);
  857.         this.components.delete(key);
  858.         this.needsUpdate = true;
  859.  
  860.         //console.log(`§c[RotationSystem] Component ${existed ? 'removed' : 'was not found'}. Total components: ${this.components.size}`);
  861.         //console.log(`§c[RotationSystem] Marked system for update`);
  862.     }
  863.  
  864.     private getBlockKey(block: Block): string {
  865.         const key = `createbedrock:rotation_system_block_${block.dimension.id}_${block.location.x}_${block.location.y}_${block.location.z}`;
  866.         //console.log(`§8[RotationSystem] Generated block key: ${key}`);
  867.         return key;
  868.     }
  869.  
  870.     private getBlockAt(dimension: string | Dimension, pos: Vector3): Block | null {
  871.         //console.log(`§8[RotationSystem] Getting block at position ${pos.x}, ${pos.y}, ${pos.z}`);
  872.  
  873.         let block: Block | null = null;
  874.         if (typeof dimension === "string") {
  875.             //console.log(`§8[RotationSystem] Using dimension string: ${dimension}`);
  876.             block = world.getDimension(dimension as string).getBlock(pos);
  877.         } else {
  878.             //console.log(`§8[RotationSystem] Using dimension object: ${dimension.id}`);
  879.             block = (dimension as Dimension).getBlock(pos);
  880.         }
  881.  
  882.         //console.log(`§8[RotationSystem] Block found: ${block ? block.type.id : 'null'}`);
  883.         return block;
  884.     }
  885.  
  886.     private getConnectedComponent(component: IComponent, connection: BlockConnection): IComponent | null {
  887.         //console.log(`§9[RotationSystem] Checking connection from ${this.getBlockKey(component.block)}`);
  888.         //console.log(`§9[RotationSystem] Connection type: ${connection.type}`);
  889.         //console.log(`§9[RotationSystem] Relative direction: ${connection.relative_direction.x}, ${connection.relative_direction.y}, ${connection.relative_direction.z}`);
  890.  
  891.         const connectedPos: Vector3 = Vector3.from(component.block.location).add(connection.relative_direction);
  892.         //console.log(`§9[RotationSystem] Connected position: ${connectedPos.x}, ${connectedPos.y}, ${connectedPos.z}`);
  893.  
  894.         const connectedBlock: Block = this.getBlockAt(component.block.dimension, connectedPos);
  895.  
  896.         if (!connectedBlock) {
  897.             //console.log(`§9[RotationSystem] No block found at connected position`);
  898.             return null;
  899.         }
  900.  
  901.         //console.log(`§9[RotationSystem] Found connected block: ${connectedBlock.type.id}`);
  902.  
  903.         const connectedComponent: IComponent = this.getComponent(connectedBlock);
  904.         if (!connectedComponent) {
  905.             //console.log(`§9[RotationSystem] No component found for connected block`);
  906.             return null;
  907.         }
  908.  
  909.         //console.log(`§9[RotationSystem] Found connected component`);
  910.  
  911.         // Check if the connected component has a matching connection back to this component
  912.         const reverseDirection = new Vector3(-connection.relative_direction.x, -connection.relative_direction.y, -connection.relative_direction.z);
  913.         //console.log(`§9[RotationSystem] Checking reverse direction: ${reverseDirection.x}, ${reverseDirection.y}, ${reverseDirection.z}`);
  914.  
  915.         for (const connectedComponentConnection of connectedComponent.connections) {
  916.             //console.log(`§9[RotationSystem] Checking connected component connection: ${connectedComponentConnection.relative_direction.x}, ${connectedComponentConnection.relative_direction.y}, ${connectedComponentConnection.relative_direction.z}`);
  917.  
  918.             if (connectedComponentConnection.relative_direction.equals(reverseDirection) &&
  919.                 connectedComponentConnection.type === connection.type) {
  920.  
  921.                 //console.log(`§9[RotationSystem] Found matching reverse connection`);
  922.  
  923.                 if (connection.type === CONNECTION_TYPES.SHAFT) {
  924.                     //console.log(`§9[RotationSystem] Returning SHAFT connection for ${connectedComponent.block.type.id}`);
  925.                     return connectedComponent;
  926.                 }
  927.                 else if (connection.type === CONNECTION_TYPES.MESH) {
  928.                     const componentFacing = component.block.permutation.getState("minecraft:facing_direction");
  929.                     const connectedFacing = connectedComponent.block.permutation.getState("minecraft:facing_direction");
  930.  
  931.                     //console.log(`§9[RotationSystem] MESH connection - Component facing: ${componentFacing}, Connected facing: ${connectedFacing}`);
  932.  
  933.                     if (areFacingDirectionsOnSameAxis(componentFacing, connectedFacing)) {
  934.                         //console.log(`§9[RotationSystem] MESH components are on same axis - connection valid`);
  935.                         return connectedComponent;
  936.                     } else {
  937.                         //console.log(`§9[RotationSystem] MESH components are NOT on same axis - connection invalid`);
  938.                     }
  939.                 }
  940.             }
  941.         }
  942.  
  943.         //console.log(`§9[RotationSystem] No valid reverse connection found`);
  944.         return null;
  945.     }
  946.  
  947.     private updateConnections(): void {
  948.         //console.log(`§d[RotationSystem] Updating connections for ${this.components.size} components`);
  949.  
  950.         // maybe use for later ?
  951.         let totalConnections = 0;
  952.         let connectedCount = 0;
  953.  
  954.         // Update all connection states
  955.         for (const component of this.components.values()) {
  956.             const componentKey = this.getBlockKey(component.block);
  957.             //console.log(`§d[RotationSystem] Updating connections for component at ${componentKey}`);
  958.  
  959.             for (const connection of component.connections) {
  960.                 totalConnections++;
  961.                 const connectedComponent = this.getConnectedComponent(component, connection);
  962.                 const wasConnected = connection.connected;
  963.                 connection.connected = connectedComponent !== null;
  964.  
  965.                 if (connection.connected) connectedCount++;
  966.             }
  967.         }
  968.  
  969.         //console.log(`§d[RotationSystem] Connection update complete. ${connectedCount}/${totalConnections} connections active`);
  970.     }
  971.  
  972.     private findNetworks(): IComponent[][] {
  973.         //console.log(`§a[RotationSystem] Finding networks among ${this.components.size} components`);
  974.  
  975.         const visited: Set<string> = new Set<string>();
  976.         const networks: IComponent[][] = [];
  977.  
  978.         for (const component of this.components.values()) {
  979.             const componentKey: string = this.getBlockKey(component.block);
  980.  
  981.             if (visited.has(componentKey)) {
  982.                 //console.log(`§a[RotationSystem] Component ${componentKey} already visited, skipping`);
  983.                 continue;
  984.             }
  985.  
  986.             //console.log(`§a[RotationSystem] Starting network discovery from ${componentKey}`);
  987.  
  988.             const network: IComponent[] = [];
  989.             const queue: IComponent[] = [component];
  990.             const networkVisited: Set<string> = new Set<string>();
  991.  
  992.             while (queue.length) {
  993.                 const currentComponent: IComponent = queue.shift()!;
  994.                 const currentComponentKey: string = this.getBlockKey(currentComponent.block);
  995.  
  996.                 if (networkVisited.has(currentComponentKey)) {
  997.                     //console.log(`§a[RotationSystem] Component ${currentComponentKey} already in current network, skipping`);
  998.                     continue;
  999.                 }
  1000.  
  1001.                 //console.log(`§a[RotationSystem] Adding component ${currentComponentKey} to network`);
  1002.                 networkVisited.add(currentComponentKey);
  1003.                 visited.add(currentComponentKey);
  1004.                 network.push(currentComponent);
  1005.  
  1006.                 //console.log(`§a[RotationSystem] Checking ${currentComponent.connections.length} connections for ${currentComponentKey}`);
  1007.  
  1008.                 for (const connection of currentComponent.connections) {
  1009.                     if (!connection.connected) {
  1010.                         //console.log(`§a[RotationSystem] Connection not active, skipping`);
  1011.                         continue;
  1012.                     }
  1013.  
  1014.                     const connectedComponent = this.getConnectedComponent(currentComponent, connection);
  1015.  
  1016.                     if (connectedComponent) {
  1017.                         const connectedComponentKey = this.getBlockKey(connectedComponent.block);
  1018.                         if (!networkVisited.has(connectedComponentKey)) {
  1019.                             //console.log(`§a[RotationSystem] Adding connected component ${connectedComponentKey} to queue`);
  1020.                             queue.push(connectedComponent);
  1021.                         } else {
  1022.                             //console.log(`§a[RotationSystem] Connected component ${connectedComponentKey} already in network`);
  1023.                         }
  1024.                     }
  1025.                 }
  1026.             }
  1027.  
  1028.             if (network.length) {
  1029.                 //console.log(`§a[RotationSystem] Network complete with ${network.length} components`);
  1030.                 networks.push(network);
  1031.             }
  1032.         }
  1033.  
  1034.         //console.log(`§a[RotationSystem] Found ${networks.length} networks total`);
  1035.  
  1036.         for (let i = 0; i < networks.length; i++) {
  1037.             //console.log(`§a[RotationSystem] ~~~ NETWORK ${i + 1} ~~~`);
  1038.             //console.log(`§a[RotationSystem] Network ${i + 1} has ${networks[i].length} components:`);
  1039.             for (const component of networks[i]) {
  1040.                 //console.log(`§a[RotationSystem] - ${this.getBlockKey(component.block)} (${component.block.type.id})`);
  1041.             }
  1042.         }
  1043.  
  1044.         return networks;
  1045.     }
  1046.  
  1047.     private async propagateRotation(network: IComponent[]): Promise<void> {
  1048.         //console.log(`§2[RotationSystem] Propagating rotation for network with ${network.length} components`);
  1049.  
  1050.         if (!network.length) {
  1051.             return;
  1052.         }
  1053.  
  1054.         let totalGeneratedSU: number = 0;
  1055.         let totalConsumedSU: number = 0;
  1056.  
  1057.         const generators: IComponent[] = network.filter((component) => {
  1058.             const isGenerator = component.generatedRPM !== null;
  1059.             if (isGenerator) {
  1060.                 totalGeneratedSU += component.generatedSU;
  1061.             }
  1062.             else {
  1063.                 totalConsumedSU += component.consumedSU;
  1064.             }
  1065.             return isGenerator;
  1066.         });
  1067.  
  1068.         //console.log(`§2[RotationSystem] Found ${generators.length} generators in network`);
  1069.  
  1070.         if (!generators.length) {
  1071.             //console.log(`§2[RotationSystem] No generators found - setting all components to 0 RPM/SU`);
  1072.             for (const component of network) {
  1073.                 component.RPM = 0;
  1074.                 component.SU = 0;
  1075.                 if (component.requestsSUInfo) {
  1076.                     component.generatedSUInfo! = 0;
  1077.                     component.consumedSUInfo! = 0;
  1078.                 }
  1079.             }
  1080.             return;
  1081.         }
  1082.  
  1083.  
  1084.         //console.log(`§2[RotationSystem] Base RPM set to: ${baseRPM}`);
  1085.  
  1086.         //console.log(`§2[RotationSystem] Total SU: ${totalGeneratedSU} generated / ${totalConsumedSU} consumed`);
  1087.  
  1088.         if (totalConsumedSU - totalGeneratedSU > CONFIG.NUMBER_TOLERANCE) {
  1089.             //console.log(`§4[RotationSystem] OVERSTRESS DETECTED! Consumed (${totalConsumedSU}) > Generated (${totalGeneratedSU})`);
  1090.             // OVERSTRESS !!!!!!!!!
  1091.             for (const component of network) {
  1092.                 component.RPM = 0;
  1093.                 component.SU = 0;
  1094.                 if (component.requestsSUInfo) {
  1095.                     component.generatedSUInfo! = totalGeneratedSU;
  1096.                     component.consumedSUInfo! = totalConsumedSU;
  1097.                 }
  1098.             }
  1099.             //console.log(`§4[RotationSystem] All components in overstressed network set to 0 RPM`);
  1100.             return;
  1101.         }
  1102.  
  1103.         //console.log(`§2[RotationSystem] Network has sufficient SU - propagating rotation`);
  1104.  
  1105.         const visited: Set<string> = new Set<string>();
  1106.         const queue: Queue = new Queue();
  1107.  
  1108.         for (const generator of generators) {
  1109.             //console.log(`§2[RotationSystem] Queueing generator ${this.getBlockKey(generator.block)} with RPM ${initialRPM} (multiplier: ${multiplier})`);
  1110.             queue.enqueue({ currentComponent: generator, currentComponentRPM: generator.generatedRPM });
  1111.         }
  1112.  
  1113.         //let propagationStep = 0;
  1114.         while (queue.size) {
  1115.             //propagationStep++;
  1116.             const { currentComponent, currentComponentRPM } = queue.dequeue();
  1117.             const currentComponentKey = this.getBlockKey(currentComponent.block);
  1118.  
  1119.             //console.log(`§2[RotationSystem] Step ${propagationStep}: Processing ${currentComponentKey} with RPM ${currentComponentRPM}`);
  1120.  
  1121.             currentComponent.RPM = currentComponentRPM;
  1122.             currentComponent.SU = totalGeneratedSU - totalConsumedSU;
  1123.  
  1124.             if (currentComponent.requestsSUInfo) {
  1125.                 //console.log(`§2[RotationSystem] Setting SU info for ${currentComponentKey}: Generated=${totalGeneratedSU}, Consumed=${totalConsumedSU}`);
  1126.                 currentComponent.generatedSUInfo! = totalGeneratedSU;
  1127.                 currentComponent.consumedSUInfo! = totalConsumedSU;
  1128.             }
  1129.  
  1130.             //console.log(`§2[RotationSystem] Checking ${currentComponent.connections.length} connections for ${currentComponentKey}`);
  1131.  
  1132.             for (const currentComponentConnection of currentComponent.connections) {
  1133.                 if (!currentComponentConnection) {
  1134.                     //console.log(`§2[RotationSystem] Null connection found, skipping`);
  1135.                     continue;
  1136.                 }
  1137.  
  1138.                 const currentConnectedComponent = this.getConnectedComponent(currentComponent, currentComponentConnection);
  1139.  
  1140.                 if (!currentConnectedComponent) {
  1141.                     //console.log(`§2[RotationSystem] No connected component found for this connection`);
  1142.                     continue;
  1143.                 }
  1144.  
  1145.                 const currentConnectedComponentKey = this.getBlockKey(currentConnectedComponent.block);
  1146.                 //console.log(`§2[RotationSystem] Found connected component: ${currentConnectedComponent.block.type.id}`);
  1147.  
  1148.                 if (visited.has(currentComponentKey)) {
  1149.                     //console.log(`§2[RotationSystem] Current component already visited - checking for conflicts`);
  1150.  
  1151.                     const currentComponentRPMPositive = currentComponentRPM > 0;
  1152.                     const currentConnectedComponentRPMPositive = currentConnectedComponent.RPM > 0;
  1153.  
  1154.                     if (
  1155.                         (
  1156.                             (
  1157.                                 currentComponentConnection.type === CONNECTION_TYPES.SHAFT &&
  1158.                                 (
  1159.                                     currentConnectedComponentRPMPositive !== currentComponentRPMPositive
  1160.                                 )
  1161.  
  1162.                             ) ||
  1163.                             (
  1164.                                 currentComponentConnection.type === CONNECTION_TYPES.MESH &&
  1165.                                 currentConnectedComponentRPMPositive === currentComponentRPMPositive
  1166.                             )
  1167.                         ) &&
  1168.                         (
  1169.                             Math.abs(currentComponentRPM) > CONFIG.NUMBER_TOLERANCE
  1170.                         ) &&
  1171.                         (
  1172.                             Math.abs(currentConnectedComponent.RPM) > CONFIG.NUMBER_TOLERANCE
  1173.                         )
  1174.                     ) {
  1175.                         //console.log(`§4[RotationSystem] ROTATION CONFLICT DETECTED! Destroying block at ${currentComponentKey}`);
  1176.                         //console.log(`§4[RotationSystem] Current RPM: ${currentComponentRPM}, Connected RPM: ${currentConnectedComponent.RPM}, Connection type: ${currentComponentConnection.type}`);
  1177.  
  1178.                         world.getDimension(currentComponent.block.dimension.id).runCommand(`setblock ${currentComponent.block.location.x} ${currentComponent.block.location.y} ${currentComponent.block.location.z} air destroy`);
  1179.                         this.removeComponent(currentComponent.block, true);
  1180.                         continue;
  1181.                     }
  1182.                     else if (Math.abs(currentConnectedComponent.RPM) >= Math.abs(currentComponentRPM)) {
  1183.                         //console.log(currentConnectedComponent.RPM, currentComponentRPM);
  1184.                         currentComponent.RPM = (currentComponentConnection.type == CONNECTION_TYPES.MESH ? -currentConnectedComponent.RPM : currentConnectedComponent.RPM);
  1185.                         //console.log(`§2[RotationSystem] Connected component already has appropriate RPM, skipping.`);
  1186.                         continue;
  1187.                     }
  1188.                     //console.log(`§2[RotationSystem] No conflict detected, continuing propagation`);
  1189.                 }
  1190.  
  1191.                 let currentConnectedComponentRPM = currentComponentRPM;
  1192.  
  1193.                 if (currentComponentConnection.type === CONNECTION_TYPES.MESH) {
  1194.                     //console.log(`§2[RotationSystem] MESH connection - inverting RPM`);
  1195.                     currentConnectedComponentRPM = -currentConnectedComponentRPM;
  1196.                 }
  1197.  
  1198.                 //console.log(`§2[RotationSystem] Connected component will have RPM: ${currentConnectedComponentRPM}`);
  1199.  
  1200.                 if (currentConnectedComponentRPM > CONFIG.RPM_LIMITS.max || currentConnectedComponentRPM < CONFIG.RPM_LIMITS.min) {
  1201.                     //console.log(`§4[RotationSystem] RPM LIMIT EXCEEDED! Destroying block at ${currentConnectedComponentKey}`);
  1202.                     //console.log(`§4[RotationSystem] RPM ${currentConnectedComponentRPM} is outside limits [${CONFIG.RPM_LIMITS.min}, ${CONFIG.RPM_LIMITS.max}]`);
  1203.  
  1204.                     world.getDimension(currentConnectedComponent.block.dimension.id).runCommand(`setblock ${currentConnectedComponent.block.location.x} ${currentConnectedComponent.block.location.y} ${currentConnectedComponent.block.location.z} air destroy`);
  1205.                     this.removeComponent(currentComponent.block, true);
  1206.                     continue;
  1207.                 }
  1208.  
  1209.                 //console.log(`§2[RotationSystem] Adding connected component to propagation queue`);
  1210.  
  1211.                 queue.enqueue({ currentComponent: currentConnectedComponent, currentComponentRPM: currentConnectedComponentRPM });
  1212.             }
  1213.             visited.add(currentComponentKey);
  1214.         }
  1215.  
  1216.         //console.log(`§2[RotationSystem] Rotation propagation complete for network (${propagationStep} steps)`);
  1217.     }
  1218.     update(): void {
  1219.         ////console.log(`§f[RotationSystem] Update called - needsUpdate: ${this.needsUpdate}`);
  1220.  
  1221.         if (this.needsUpdate) {
  1222.             this.needsUpdate = false;
  1223.             //console.log(`§f[RotationSystem] Starting full system update`);
  1224.             //console.log(`§f[RotationSystem] Current component count: ${this.components.size}`);
  1225.  
  1226.             this.updateConnections();
  1227.             //console.log(`§f[RotationSystem] Connections updated`);
  1228.  
  1229.             const networks: IComponent[][] = this.findNetworks();
  1230.             //console.log(`§f[RotationSystem] Found ${networks.length} networks`);
  1231.  
  1232.             for (let i = 0; i < networks.length; i++) {
  1233.                 //console.log(`§f[RotationSystem] Processing network ${i + 1} with ${networks[i].length} components`);
  1234.                 this.propagateRotation(networks[i]);
  1235.             }
  1236.  
  1237.             //console.log(`§f[RotationSystem] System update complete - needsUpdate set to false`);
  1238.         } else {
  1239.             //console.log(`§f[RotationSystem] No update needed, skipping`);
  1240.         }
  1241.     }
  1242.  
  1243.     animationUpdate(): void {
  1244.         if (this.needsUpdate) {
  1245.             return;
  1246.         }
  1247.         for (const component of this.components.values()) {
  1248.             if (!component.animated) {
  1249.                 continue;
  1250.             }
  1251.  
  1252.             const currentTickStage = system.currentTick % 1200 / 1200;
  1253.             let rotation = Math.round(Math.abs(component.RPM) * currentTickStage * 90 / 15) * 15 % 90;
  1254.  
  1255.             if (component.RPM < 0) {
  1256.                 rotation = (90 - rotation) % 90;
  1257.             }
  1258.  
  1259.             if (["south", "east", "down"].includes(component.block.permutation.getState("minecraft:facing_direction"))) {
  1260.                 rotation = (90 - rotation) % 90;
  1261.             }
  1262.  
  1263.             component.block.setPermutation(component.block.permutation.withState("createbedrock:rotation", rotation));
  1264.         }
  1265.     }
  1266. }
  1267.  
  1268. // Initialize the system
  1269. const rotationSystem = new RotationSystem();
  1270.  
  1271. // Component Registration
  1272. system.beforeEvents.startup.subscribe((event: StartupEvent) => {
  1273.     try {
  1274.         // Register Creative Motor Component
  1275.         event.blockComponentRegistry.registerCustomComponent("createbedrock:creative_motor_component", {
  1276.             onPlace: (event: BlockComponentOnPlaceEvent) => {
  1277.                 const component = new CreativeMotorComponent(event.block);
  1278.                 rotationSystem.addComponent(component, true);
  1279.             },
  1280.  
  1281.             onPlayerInteract: (event: BlockComponentPlayerInteractEvent) => {
  1282.                 const component = rotationSystem.getComponent(event.block) as CreativeMotorComponent;
  1283.                 if (component) {
  1284.                     component.onInteract(event);
  1285.                 }
  1286.             },
  1287.  
  1288.             onPlayerDestroy: (event: BlockComponentPlayerDestroyEvent) => {
  1289.                 rotationSystem.removeComponent(event.block, true);
  1290.             }
  1291.         });
  1292.  
  1293.         // Register Shaft Component
  1294.         event.blockComponentRegistry.registerCustomComponent("createbedrock:shaft_component", {
  1295.             onPlace: (event: BlockComponentOnPlaceEvent) => {
  1296.                 const component = new ShaftComponent(event.block);
  1297.                 rotationSystem.addComponent(component, true);
  1298.             },
  1299.  
  1300.             onPlayerDestroy: (event: BlockComponentPlayerDestroyEvent) => {
  1301.                 rotationSystem.removeComponent(event.block, true);
  1302.             }
  1303.         });
  1304.  
  1305.         // Register Stressometer Component
  1306.         event.blockComponentRegistry.registerCustomComponent("createbedrock:stressometer_component", {
  1307.             onPlace: (event: BlockComponentOnPlaceEvent) => {
  1308.                 const component = new StressometerComponent(event.block);
  1309.                 rotationSystem.addComponent(component, true);
  1310.             },
  1311.  
  1312.             onPlayerInteract: (event: BlockComponentPlayerInteractEvent) => {
  1313.                 const component = rotationSystem.getComponent(event.block) as StressometerComponent;
  1314.                 if (component) {
  1315.                     component.onInteract(event);
  1316.                 }
  1317.             },
  1318.  
  1319.             onPlayerDestroy: (event: BlockComponentPlayerDestroyEvent) => {
  1320.                 rotationSystem.removeComponent(event.block, true);
  1321.             }
  1322.         });
  1323.  
  1324.         event.blockComponentRegistry.registerCustomComponent("createbedrock:speedometer_component", {
  1325.             onPlace: (event: BlockComponentOnPlaceEvent) => {
  1326.                 const component = new SpeedometerComponent(event.block);
  1327.                 rotationSystem.addComponent(component, true);
  1328.             },
  1329.  
  1330.             onPlayerInteract: (event: BlockComponentPlayerInteractEvent) => {
  1331.                 const component = rotationSystem.getComponent(event.block) as SpeedometerComponent;
  1332.                 if (component) {
  1333.                     component.onInteract(event);
  1334.                 }
  1335.             },
  1336.  
  1337.             onPlayerDestroy: (event: BlockComponentPlayerDestroyEvent) => {
  1338.                 rotationSystem.removeComponent(event.block, true);
  1339.             }
  1340.         });
  1341.  
  1342.         event.blockComponentRegistry.registerCustomComponent("createbedrock:cogwheel_component", {
  1343.             onPlace: (event: BlockComponentOnPlaceEvent) => {
  1344.                 const component = new CogwheelComponent(event.block);
  1345.                 rotationSystem.addComponent(component, true);
  1346.             },
  1347.  
  1348.             onPlayerDestroy: (event: BlockComponentPlayerDestroyEvent) => {
  1349.                 rotationSystem.removeComponent(event.block, true);
  1350.             }
  1351.         });
  1352.  
  1353.         //console.log("§aRotation components registered successfully!");
  1354.  
  1355.         // Initialize the system after registration
  1356.         rotationSystem.init();
  1357.  
  1358.     } catch (error) {
  1359.         console.error("Component registration failed:", error);
  1360.     }
  1361. });
  1362.  
  1363. //console.log("§aRotation system script loaded!");
  1364.  
  1365. system.beforeEvents.shutdown.subscribe((event: ShutdownEvent) => {
  1366.     rotationSystem.save();
  1367. });
Advertisement
Add Comment
Please, Sign In to add comment