├── packs ├── behaviors │ ├── scripts │ │ ├── plugin │ │ │ ├── nc │ │ │ │ ├── .gitignore │ │ │ │ ├── presetBuildingsInterface.js │ │ │ │ ├── preset │ │ │ │ │ └── songs.js │ │ │ │ └── utils.js │ │ │ ├── plugins.json │ │ │ └── zaofu │ │ │ │ ├── LICENSE │ │ │ │ └── index.js │ │ ├── utils.js │ │ ├── server │ │ │ └── server.js │ │ └── client │ │ │ └── client.js │ ├── pack_icon.png │ ├── functions │ │ └── getTools.mcfunction │ ├── items │ │ ├── execute.json │ │ ├── getAir.json │ │ ├── readTag.json │ │ ├── showMenu.json │ │ ├── getPosition.json │ │ ├── getDirection.json │ │ ├── showMetaMenu.json │ │ ├── showSavedData.json │ │ ├── removeLastPosition.json │ │ ├── chooseNextGenerator.json │ │ ├── removeLastBlockType.json │ │ └── removeLastDirection.json │ └── manifest.json └── resources │ ├── pack_icon.png │ ├── textures │ ├── items │ │ ├── slime.png │ │ ├── execute.png │ │ ├── getAir.png │ │ ├── showMenu.png │ │ ├── getDirection.png │ │ ├── getPosition.png │ │ ├── showSavedData.png │ │ ├── removeLastPosition.png │ │ ├── chooseNextGenerator.png │ │ ├── removeLastBlockType.png │ │ └── removeLastDirection.png │ └── item_texture.json │ ├── items │ ├── getAir.json │ ├── execute.json │ ├── readTag.json │ ├── showMenu.json │ ├── getPosition.json │ ├── getDirection.json │ ├── showMetaMenu.json │ ├── showSavedData.json │ ├── chooseNextGenerator.json │ ├── removeLastBlockType.json │ ├── removeLastDirection.json │ └── removeLastPosition.json │ ├── manifest.json │ ├── texts │ └── en_US.lang │ └── experimental_ui │ ├── HUD.html │ ├── styles.css │ ├── menu │ └── menu.html │ └── UIEngine.js ├── .gitignore ├── test.js ├── create-event-center.js ├── package.json ├── gulpfile.js ├── init.js ├── LICENSE ├── create-client.js ├── create-server.js ├── README.md ├── .github └── workflows │ └── main.yml └── file-generation.js /packs/behaviors/scripts/plugin/nc/.gitignore: -------------------------------------------------------------------------------- 1 | preset/song -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | out 3 | packs/behaviors/scripts/jsconfig.json -------------------------------------------------------------------------------- /packs/behaviors/pack_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorthernOceanS/NormaConstructor/HEAD/packs/behaviors/pack_icon.png -------------------------------------------------------------------------------- /packs/resources/pack_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorthernOceanS/NormaConstructor/HEAD/packs/resources/pack_icon.png -------------------------------------------------------------------------------- /packs/resources/textures/items/slime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorthernOceanS/NormaConstructor/HEAD/packs/resources/textures/items/slime.png -------------------------------------------------------------------------------- /packs/resources/textures/items/execute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorthernOceanS/NormaConstructor/HEAD/packs/resources/textures/items/execute.png -------------------------------------------------------------------------------- /packs/resources/textures/items/getAir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorthernOceanS/NormaConstructor/HEAD/packs/resources/textures/items/getAir.png -------------------------------------------------------------------------------- /packs/resources/textures/items/showMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorthernOceanS/NormaConstructor/HEAD/packs/resources/textures/items/showMenu.png -------------------------------------------------------------------------------- /packs/resources/textures/items/getDirection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorthernOceanS/NormaConstructor/HEAD/packs/resources/textures/items/getDirection.png -------------------------------------------------------------------------------- /packs/resources/textures/items/getPosition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorthernOceanS/NormaConstructor/HEAD/packs/resources/textures/items/getPosition.png -------------------------------------------------------------------------------- /packs/resources/textures/items/showSavedData.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorthernOceanS/NormaConstructor/HEAD/packs/resources/textures/items/showSavedData.png -------------------------------------------------------------------------------- /packs/resources/textures/items/removeLastPosition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorthernOceanS/NormaConstructor/HEAD/packs/resources/textures/items/removeLastPosition.png -------------------------------------------------------------------------------- /packs/resources/textures/items/chooseNextGenerator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorthernOceanS/NormaConstructor/HEAD/packs/resources/textures/items/chooseNextGenerator.png -------------------------------------------------------------------------------- /packs/resources/textures/items/removeLastBlockType.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorthernOceanS/NormaConstructor/HEAD/packs/resources/textures/items/removeLastBlockType.png -------------------------------------------------------------------------------- /packs/resources/textures/items/removeLastDirection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorthernOceanS/NormaConstructor/HEAD/packs/resources/textures/items/removeLastDirection.png -------------------------------------------------------------------------------- /packs/behaviors/scripts/plugin/nc/presetBuildingsInterface.js: -------------------------------------------------------------------------------- 1 | import subway_station from "./preset/subway_station.json" 2 | 3 | const presetBuildings = { subway_station } 4 | export { presetBuildings } -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | require('./create-client.js'); 2 | require('./out/bundled/behaviors/scripts/client/client.js'); 3 | require('./create-server.js'); 4 | require('./out/bundled/behaviors/scripts/server/server.js'); 5 | require('./init.js'); 6 | -------------------------------------------------------------------------------- /packs/behaviors/scripts/plugin/plugins.json: -------------------------------------------------------------------------------- 1 | { 2 | "nc": { 3 | "type": "inner", 4 | "enable": true 5 | }, 6 | "nz": { 7 | "type": "inner", 8 | "enable": true 9 | }, 10 | "zaofu": { 11 | "type": "inner", 12 | "enable": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packs/resources/items/getAir.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.12.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:get_air", 6 | "catagory":"Nature" 7 | }, 8 | "components": { 9 | "minecraft:icon": "getAir", 10 | "minecraft:render_offsets": "apple" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /packs/resources/items/execute.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.12.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:execute", 6 | "catagory":"Nature" 7 | }, 8 | "components": { 9 | "minecraft:icon": "execute", 10 | "minecraft:render_offsets": "apple" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /packs/resources/items/readTag.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.12.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:read_tag", 6 | "catagory":"Nature" 7 | }, 8 | "components": { 9 | "minecraft:icon": "readTag", 10 | "minecraft:render_offsets": "apple" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /packs/resources/items/showMenu.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.12.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:show_menu", 6 | "catagory":"Nature" 7 | }, 8 | "components": { 9 | "minecraft:icon": "showMenu", 10 | "minecraft:render_offsets": "apple" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /packs/resources/items/getPosition.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.12.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:get_position", 6 | "catagory":"Nature" 7 | }, 8 | "components": { 9 | "minecraft:icon": "getPosition", 10 | "minecraft:render_offsets": "apple" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /packs/resources/items/getDirection.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.12.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:get_direction", 6 | "catagory":"Nature" 7 | }, 8 | "components": { 9 | "minecraft:icon": "getDirection", 10 | "minecraft:render_offsets": "apple" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /packs/resources/items/showMetaMenu.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.12.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:show_meta_menu", 6 | "catagory":"Nature" 7 | }, 8 | "components": { 9 | "minecraft:icon": "showMetaMenu", 10 | "minecraft:render_offsets": "apple" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /packs/resources/items/showSavedData.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.12.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:show_saved_data", 6 | "catagory":"Nature" 7 | }, 8 | "components": { 9 | "minecraft:icon": "showSavedData", 10 | "minecraft:render_offsets": "apple" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /packs/resources/items/chooseNextGenerator.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.12.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:choose_next_generator", 6 | "catagory":"Nature" 7 | }, 8 | "components": { 9 | "minecraft:icon": "chooseNextGenerator", 10 | "minecraft:render_offsets": "apple" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /packs/resources/items/removeLastBlockType.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.12.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:remove_last_blocktype", 6 | "catagory":"Nature" 7 | }, 8 | "components": { 9 | "minecraft:icon": "removeLastBlockType", 10 | "minecraft:render_offsets": "apple" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /packs/resources/items/removeLastDirection.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.12.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:remove_last_direction", 6 | "catagory":"Nature" 7 | }, 8 | "components": { 9 | "minecraft:icon": "removeLastDirection", 10 | "minecraft:render_offsets": "apple" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /packs/resources/items/removeLastPosition.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.12.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:remove_last_position", 6 | "catagory":"Nature" 7 | }, 8 | "components": { 9 | "minecraft:icon": "removeLastPosition", 10 | "minecraft:render_offsets": "apple" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /packs/behaviors/functions/getTools.mcfunction: -------------------------------------------------------------------------------- 1 | give @s normaconstructor:choose_next_generator 2 | give @s normaconstructor:execute 3 | give @s normaconstructor:get_air 4 | give @s normaconstructor:get_position 5 | give @s normaconstructor:get_direction 6 | give @s normaconstructor:remove_last_position 7 | give @s normaconstructor:remove_last_direction 8 | give @s normaconstructor:remove_last_blocktype 9 | give @s normaconstructor:show_menu 10 | give @s normaconstructor:show_meta_menu 11 | give @s normaconstructor:show_saved_data -------------------------------------------------------------------------------- /packs/behaviors/scripts/utils.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-unused-vars 2 | import { Coordinate, BlockType, Direction, Generator } from "norma-core"; 3 | 4 | let utils = { 5 | setter: { 6 | setLogger: function (logger) { 7 | utils.logger = logger 8 | } 9 | }, 10 | misc: { 11 | generatePlayerIDFromUniqueID: function (uniqueID) { 12 | let low = uniqueID["64bit_low"] % 10000 13 | let high = uniqueID["64bit_high"] % 10000 14 | //hash function: 15 | 16 | return (low + high) * (low + high + 1) / 2 + high; 17 | } 18 | }, 19 | 20 | }; 21 | 22 | export { utils }; -------------------------------------------------------------------------------- /packs/behaviors/items/execute.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.16.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:execute" 6 | }, 7 | "components": { 8 | "minecraft:hand_equipped": false, 9 | "minecraft:stacked_by_data": true, 10 | "minecraft:foil": false, 11 | "minecraft:max_stack_size": 64, 12 | "minecraft:use_duration": 1, 13 | "minecraft:food": { 14 | "nutrition": 0, 15 | "saturation_modifier": "normal", 16 | "can_always_eat": true 17 | } 18 | }, 19 | "events": {} 20 | } 21 | } -------------------------------------------------------------------------------- /packs/behaviors/items/getAir.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.16.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:get_air" 6 | }, 7 | "components": { 8 | "minecraft:hand_equipped": false, 9 | "minecraft:stacked_by_data": true, 10 | "minecraft:foil": false, 11 | "minecraft:max_stack_size": 64, 12 | "minecraft:use_duration": 1, 13 | "minecraft:food": { 14 | "nutrition": 0, 15 | "saturation_modifier": "normal", 16 | "can_always_eat": true 17 | } 18 | }, 19 | "events": {} 20 | } 21 | } -------------------------------------------------------------------------------- /packs/behaviors/items/readTag.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.16.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:read_tag" 6 | }, 7 | "components": { 8 | "minecraft:hand_equipped": false, 9 | "minecraft:stacked_by_data": true, 10 | "minecraft:foil": false, 11 | "minecraft:max_stack_size": 64, 12 | "minecraft:use_duration": 1, 13 | "minecraft:food": { 14 | "nutrition": 0, 15 | "saturation_modifier": "normal", 16 | "can_always_eat": true 17 | } 18 | }, 19 | "events": {} 20 | } 21 | } -------------------------------------------------------------------------------- /packs/behaviors/items/showMenu.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.16.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:show_menu" 6 | }, 7 | "components": { 8 | "minecraft:hand_equipped": false, 9 | "minecraft:stacked_by_data": true, 10 | "minecraft:foil": false, 11 | "minecraft:max_stack_size": 64, 12 | "minecraft:use_duration": 1, 13 | "minecraft:food": { 14 | "nutrition": 0, 15 | "saturation_modifier": "normal", 16 | "can_always_eat": true 17 | } 18 | }, 19 | "events": {} 20 | } 21 | } -------------------------------------------------------------------------------- /packs/behaviors/items/getPosition.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.16.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:get_position" 6 | }, 7 | "components": { 8 | "minecraft:hand_equipped": false, 9 | "minecraft:stacked_by_data": true, 10 | "minecraft:foil": false, 11 | "minecraft:max_stack_size": 64, 12 | "minecraft:use_duration": 1, 13 | "minecraft:food": { 14 | "nutrition": 0, 15 | "saturation_modifier": "normal", 16 | "can_always_eat": true 17 | } 18 | }, 19 | "events": {} 20 | } 21 | } -------------------------------------------------------------------------------- /packs/behaviors/items/getDirection.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.16.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:get_direction" 6 | }, 7 | "components": { 8 | "minecraft:hand_equipped": false, 9 | "minecraft:stacked_by_data": true, 10 | "minecraft:foil": false, 11 | "minecraft:max_stack_size": 64, 12 | "minecraft:use_duration": 1, 13 | "minecraft:food": { 14 | "nutrition": 0, 15 | "saturation_modifier": "normal", 16 | "can_always_eat": true 17 | } 18 | }, 19 | "events": {} 20 | } 21 | } -------------------------------------------------------------------------------- /packs/behaviors/items/showMetaMenu.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.16.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:show_meta_menu" 6 | }, 7 | "components": { 8 | "minecraft:hand_equipped": false, 9 | "minecraft:stacked_by_data": true, 10 | "minecraft:foil": false, 11 | "minecraft:max_stack_size": 64, 12 | "minecraft:use_duration": 1, 13 | "minecraft:food": { 14 | "nutrition": 0, 15 | "saturation_modifier": "normal", 16 | "can_always_eat": true 17 | } 18 | }, 19 | "events": {} 20 | } 21 | } -------------------------------------------------------------------------------- /packs/behaviors/items/showSavedData.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.16.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:show_saved_data" 6 | }, 7 | "components": { 8 | "minecraft:hand_equipped": false, 9 | "minecraft:stacked_by_data": true, 10 | "minecraft:foil": false, 11 | "minecraft:max_stack_size": 64, 12 | "minecraft:use_duration": 1, 13 | "minecraft:food": { 14 | "nutrition": 0, 15 | "saturation_modifier": "normal", 16 | "can_always_eat": true 17 | } 18 | }, 19 | "events": {} 20 | } 21 | } -------------------------------------------------------------------------------- /packs/behaviors/items/removeLastPosition.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.16.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:remove_last_position" 6 | }, 7 | "components": { 8 | "minecraft:hand_equipped": false, 9 | "minecraft:stacked_by_data": true, 10 | "minecraft:foil": false, 11 | "minecraft:max_stack_size": 64, 12 | "minecraft:use_duration": 1, 13 | "minecraft:food": { 14 | "nutrition": 0, 15 | "saturation_modifier": "normal", 16 | "can_always_eat": true 17 | } 18 | }, 19 | "events": {} 20 | } 21 | } -------------------------------------------------------------------------------- /create-event-center.js: -------------------------------------------------------------------------------- 1 | class FakeEventCenter{ 2 | constructor(){ 3 | this.ports = [] 4 | } 5 | createPort(){ 6 | let port = new FakePort(this); 7 | this.ports.push(port); 8 | return port; 9 | } 10 | broadcastMessage(data){ 11 | for(let port of this.ports) { 12 | setTimeout(()=> port.onmessage({data}), 0); 13 | } 14 | } 15 | } 16 | 17 | class FakePort{ 18 | constructor(eventCenter){ 19 | this._eventCenter = eventCenter; 20 | } 21 | postMessage(data){ 22 | this._eventCenter.broadcastMessage(data); 23 | } 24 | } 25 | 26 | let eventCenter = new FakeEventCenter(); 27 | 28 | exports.eventCenter = eventCenter; 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "normaconstructor", 3 | "private": true, 4 | "scripts": { 5 | "build": "gulp build", 6 | "watch": "gulp watch", 7 | "installaddon": "gulp install", 8 | "uninstalladdon": "gulp uninstall", 9 | "packageaddon": "gulp package", 10 | "test": "gulp build && node test.js" 11 | }, 12 | "devDependencies": { 13 | "gulp": "^4.0.2", 14 | "minecraft-addon-toolchain": "^1.0.3", 15 | "minecraft-addon-toolchain-browserify": "^1.0.3" 16 | }, 17 | "dependencies": { 18 | "@babel/plugin-proposal-class-properties": "^7.14.5", 19 | "norma-core": "^0.2.15" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packs/behaviors/items/chooseNextGenerator.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.16.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:choose_next_generator" 6 | }, 7 | "components": { 8 | "minecraft:hand_equipped": false, 9 | "minecraft:stacked_by_data": true, 10 | "minecraft:foil": false, 11 | "minecraft:max_stack_size": 64, 12 | "minecraft:use_duration": 1, 13 | "minecraft:food": { 14 | "nutrition": 0, 15 | "saturation_modifier": "normal", 16 | "can_always_eat": true 17 | } 18 | }, 19 | "events": {} 20 | } 21 | } -------------------------------------------------------------------------------- /packs/behaviors/items/removeLastBlockType.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.16.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:remove_last_blocktype" 6 | }, 7 | "components": { 8 | "minecraft:hand_equipped": false, 9 | "minecraft:stacked_by_data": true, 10 | "minecraft:foil": false, 11 | "minecraft:max_stack_size": 64, 12 | "minecraft:use_duration": 1, 13 | "minecraft:food": { 14 | "nutrition": 0, 15 | "saturation_modifier": "normal", 16 | "can_always_eat": true 17 | } 18 | }, 19 | "events": {} 20 | } 21 | } -------------------------------------------------------------------------------- /packs/behaviors/items/removeLastDirection.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.16.0", 3 | "minecraft:item": { 4 | "description": { 5 | "identifier": "normaconstructor:remove_last_direction" 6 | }, 7 | "components": { 8 | "minecraft:hand_equipped": false, 9 | "minecraft:stacked_by_data": true, 10 | "minecraft:foil": false, 11 | "minecraft:max_stack_size": 64, 12 | "minecraft:use_duration": 1, 13 | "minecraft:food": { 14 | "nutrition": 0, 15 | "saturation_modifier": "normal", 16 | "can_always_eat": true 17 | } 18 | }, 19 | "events": {} 20 | } 21 | } -------------------------------------------------------------------------------- /packs/resources/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": 1, 3 | "header": { 4 | "name": "NormaConstructor Resources", 5 | "description": "Speed up your construction.Created by NorthernOceanS.", 6 | "uuid": "8b9a64ef-054c-4b3f-a247-820b4d0f15b6", 7 | "version": [ 8 | 1, 9 | 0, 10 | 2 11 | ] 12 | }, 13 | "modules": [ 14 | { 15 | "description": "Resources for NormaConstructor", 16 | "type": "resources", 17 | "uuid": "24ab1bd5-c617-4d67-a2de-7589f2407506", 18 | "version": [ 19 | 1, 20 | 0, 21 | 0 22 | ] 23 | } 24 | ], 25 | "capabilities": [ 26 | "experimental_custom_ui" 27 | ] 28 | } -------------------------------------------------------------------------------- /packs/resources/texts/en_US.lang: -------------------------------------------------------------------------------- 1 | item.normaconstructor:execute.name=Execute 2 | item.normaconstructor:get_air.name=Get Air 3 | item.normaconstructor:get_position.name=Get Position 4 | item.normaconstructor:get_direction.name=Get Direction 5 | item.normaconstructor:remove_last_position.name=Remove Last Position 6 | item.normaconstructor:remove_last_direction.name=Remove Last Direction 7 | item.normaconstructor:remove_last_blocktype.name=Remove Last BlockType 8 | item.normaconstructor:choose_next_generator.name=Choose Next Generator 9 | item.normaconstructor:show_menu.name=Show Menu 10 | item.normaconstructor:show_meta_menu.name=Show Meta Menu 11 | item.normaconstructor:show_saved_data.name=Show Saved Data 12 | item.normaconstructor:read_tag.name=Read Tag 13 | -------------------------------------------------------------------------------- /packs/behaviors/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": 1, 3 | "header": { 4 | "name": "NormaConstructor Behaviors", 5 | "description": "Speed up your construction.Created by NorthernOceanS.", 6 | "uuid": "7ba71189-28c4-47d1-85d3-aae28f4430b1", 7 | "version": [ 8 | 0, 9 | 13, 10 | 22 11 | ] 12 | }, 13 | "modules": [ 14 | { 15 | "description": "behaviours for NormaConstructor", 16 | "type": "client_data", 17 | "uuid": "6a95ee02-ac8e-456e-9f41-11a39ab3f93d", 18 | "version": [ 19 | 1, 20 | 0, 21 | 0 22 | ] 23 | } 24 | ], 25 | "dependencies": [ 26 | { 27 | "uuid": "8b9a64ef-054c-4b3f-a247-820b4d0f15b6", 28 | "version": [ 29 | 1, 30 | 0, 31 | 2 32 | ] 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const MinecraftAddonBuilder = require("minecraft-addon-toolchain/v1"); 2 | const BrowserifySupport = require("minecraft-addon-toolchain-browserify"); 3 | const AutoFileGenerationSupport = require("./file-generation.js"); 4 | 5 | const builder = new MinecraftAddonBuilder("NormaConstructor"); 6 | 7 | //!!!!!!!!!!!!!!!!!!!! 8 | const browserifySupport = new BrowserifySupport(); 9 | const autoFileGenerationSupport = new AutoFileGenerationSupport(); 10 | browserifySupport.bundleSources.push("scripts/**/*.*"); 11 | browserifySupport.babelOptions.plugins.push("@babel/plugin-proposal-class-properties"); 12 | autoFileGenerationSupport.bundleDir = browserifySupport.intermediateDir; 13 | 14 | builder.addPlugin(autoFileGenerationSupport); 15 | builder.addPlugin(browserifySupport); 16 | 17 | module.exports = builder.configureEverythingForMe(); 18 | -------------------------------------------------------------------------------- /packs/resources/experimental_ui/HUD.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 | 14 |
15 | 16 |
17 | 18 |
19 | 20 |
21 |
22 | 23 | 29 | 30 | -------------------------------------------------------------------------------- /init.js: -------------------------------------------------------------------------------- 1 | let {eventCenter} = require('./create-event-center.js'); 2 | 3 | let serverSystem = server._serverSystem; 4 | let clientSystem = client._clientSystem; 5 | 6 | function TimeoutPromise(ms) { 7 | return new Promise((reslove, reject) => { 8 | setTimeout(()=>{reslove()}, ms); 9 | }); 10 | } 11 | 12 | (async function(){ 13 | serverSystem.initialize(); 14 | clientSystem.initialize(); 15 | await TimeoutPromise(0) 16 | eventCenter.broadcastMessage({ 17 | eventIdentifier: "minecraft:client_entered_world", 18 | eventData: {data: {player:{__unique_id__: 1}}} 19 | }); 20 | await TimeoutPromise(0); 21 | for(let i = 0; i < 20; i++) { 22 | let wait = TimeoutPromise(1000/20); 23 | serverSystem.update && serverSystem.update(); 24 | clientSystem.update && clientSystem.update(); 25 | await wait; 26 | } 27 | await TimeoutPromise(0); 28 | clientSystem.shutdown && clientSystem.shutdown(); 29 | serverSystem.shutdown && serverSystem.shutdown(); 30 | })(); 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 NorthernOceanS 4 | Copyright (c) 2021 DrZaofu 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /packs/behaviors/scripts/plugin/zaofu/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 DrZaofu 4 | Copyright (c) 2021 NorthernOceanS 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /packs/resources/textures/item_texture.json: -------------------------------------------------------------------------------- 1 | { 2 | "resource_pack_name": "normaconstructor", 3 | "texture_name": "atlas.items", 4 | "texture_data": { 5 | "execute": { 6 | "textures": "textures/items/execute" 7 | }, 8 | "showSavedData": { 9 | "textures": "textures/items/showSavedData" 10 | }, 11 | "getPosition": { 12 | "textures": "textures/items/getPosition" 13 | }, 14 | "removeLastBlockType": { 15 | "textures": "textures/items/removeLastBlockType" 16 | }, 17 | "removeLastDirection": { 18 | "textures": "textures/items/removeLastDirection" 19 | }, 20 | "removeLastPosition": { 21 | "textures": "textures/items/removeLastPosition" 22 | }, 23 | "getDirection": { 24 | "textures": "textures/items/getDirection" 25 | }, 26 | "showMenu": { 27 | "textures": "textures/items/showMenu" 28 | }, 29 | "showMetaMenu": { 30 | "textures": "textures/items/slime" 31 | }, 32 | "chooseNextGenerator": { 33 | "textures": "textures/items/chooseNextGenerator" 34 | }, 35 | "getAir": { 36 | "textures": "textures/items/getAir" 37 | }, 38 | "readTag":{ 39 | "textures": "textures/items/slime" 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /create-client.js: -------------------------------------------------------------------------------- 1 | let {eventCenter} = require('./create-event-center.js'); 2 | 3 | class FakeClientSystem{ 4 | constructor(port){ 5 | let that = this; 6 | this._port = port; 7 | this.eventDataMap = new Map(); 8 | this.eventMap = new Map(); 9 | this._port.onmessage = function(event){ 10 | let {data} = event; 11 | let {eventIdentifier, eventData} = data; 12 | let eventCallback = that.eventMap.get(eventIdentifier); 13 | if(eventCallback !== undefined) { 14 | eventCallback(eventData); 15 | } 16 | } 17 | } 18 | createEventData(eventIdentifier){ 19 | let eventData = this.eventDataMap.get(eventIdentifier); 20 | if(eventData === undefined) { 21 | return {data: {}}; 22 | } else { 23 | return {data: eventData}; 24 | } 25 | } 26 | broadcastEvent(eventIdentifier, eventData){ 27 | this._port.postMessage({eventIdentifier, eventData}); 28 | return true; 29 | } 30 | listenForEvent(eventIdentifier, eventCallback){ 31 | this.eventMap.set(eventIdentifier, eventCallback); 32 | return true; 33 | } 34 | registerEventData(eventIdentifier, eventData){ 35 | this.eventDataMap.set(eventIdentifier, eventData); 36 | return true; 37 | } 38 | } 39 | 40 | class FakeClient{ 41 | constructor(port){ 42 | this._port = port; 43 | } 44 | log(){ 45 | // no-op 46 | } 47 | registerSystem(){ 48 | let clientSystem = new FakeClientSystem(this._port); 49 | this._clientSystem = clientSystem; 50 | return clientSystem; 51 | } 52 | } 53 | 54 | global.client = new FakeClient(eventCenter.createPort()); 55 | -------------------------------------------------------------------------------- /create-server.js: -------------------------------------------------------------------------------- 1 | let {eventCenter} = require('./create-event-center.js'); 2 | 3 | class FakeServerSystem{ 4 | constructor(port){ 5 | let that = this; 6 | this._port = port; 7 | this.eventDataMap = new Map(); 8 | this.eventMap = new Map(); 9 | this._port.onmessage = function(event){ 10 | let {data} = event; 11 | let {eventIdentifier, eventData} = data; 12 | let eventCallback = that.eventMap.get(eventIdentifier); 13 | if(eventCallback !== undefined) { 14 | eventCallback(eventData); 15 | } 16 | } 17 | } 18 | createEventData(eventIdentifier){ 19 | let eventData = this.eventDataMap.get(eventIdentifier); 20 | if(eventData === undefined) { 21 | return {data: {}}; 22 | } else { 23 | return {data: eventData}; 24 | } 25 | } 26 | broadcastEvent(eventIdentifier, eventData){ 27 | this._port.postMessage({eventIdentifier, eventData}); 28 | return true; 29 | } 30 | listenForEvent(eventIdentifier, eventCallback){ 31 | this.eventMap.set(eventIdentifier, eventCallback); 32 | return true; 33 | } 34 | registerEventData(eventIdentifier, eventData){ 35 | this.eventDataMap.set(eventIdentifier, eventData); 36 | return true; 37 | } 38 | } 39 | 40 | class FakeServer{ 41 | constructor(port){ 42 | this._port = port; 43 | } 44 | log(){ 45 | // no-op 46 | } 47 | registerSystem(){ 48 | let serverSystem = new FakeServerSystem(this._port); 49 | this._serverSystem = serverSystem; 50 | return serverSystem; 51 | } 52 | } 53 | 54 | global.server = new FakeServer(eventCenter.createPort()); 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NormaConstructor 2 | 3 | Everything that has a beginning has an ending. The scripting engine of bedrock [will be deprecated](https://www.minecraft.net/en-us/creator/article/removing-the-additional-modding-capabilities-feature), so the scripting backend of **NormaConstructor** will be deprecated at that time. We really miss the scripting engine and the scripting backend of **NormaConstructor**. However, **NormaConstructor** is designed to run in multiple platform, so the developing of **NormaConstructor** will still going on, on LiteLoader, bdsx, and gametest, the successor of scripting engine. If you want know more about **NormaConstructor**, see . 4 | 5 | 一切有开始的东西也有结束。基岩版的scripting引擎[将被弃用](https://www.minecraft.net/en-us/creator/article/removing-the-additional-modding-capabilities-feature),所以**NormaConstructor**的scripting后端也将被弃用。我们真的很想念scripting引擎和**NormaConstructor**的scripting后端。然而,**NormaConstructor**是设计为在多个平台上运行的,所以**NormaConstructor**的开发仍将在LiteLoader,bdsx和gametest,scripting引擎的继承者上继续。如果你想了解更多关于**NormaConstructor**的信息,请参见。 6 | 7 | ![CI](https://github.com/NorthernOceanS/NormaConstructor/workflows/CI/badge.svg) 8 | 9 | Speed up your construction.Created by NorthernOceanS. 10 | 11 | ## WARNING: The addon use @AtomicBlom 's toolchain, but modified. 12 | ``` 13 | this.bundleSources = ["scripts/**/*.js" ]; 14 | ``` 15 | ## to 16 | ``` 17 | this.bundleSources = ["scripts/**/*.*" ]; 18 | ``` 19 | # Credit 20 | Credits to reimarPB for CSS 21 | Credits to WavePlayz for block.js 22 | Credits to drzaofu for icons and CSS font solution. 23 | & Thanks @过期牛奶rlgou for the video! 24 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: CI 4 | 5 | # Controls when the action will run. Triggers the workflow on push or pull request 6 | # events but only for the master branch 7 | on: 8 | push: 9 | tags: 10 | - 'v*' 11 | 12 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 13 | jobs: 14 | # This workflow contains a single job called "build" 15 | build: 16 | # The type of runner that the job will run on 17 | runs-on: ubuntu-latest 18 | 19 | # Steps represent a sequence of tasks that will be executed as part of the job 20 | steps: 21 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 22 | - uses: actions/checkout@v2 23 | 24 | # Runs a single command using the runners shell 25 | - name: Package the addon 26 | run: | 27 | npm install 28 | npm run packageaddon 29 | - name: Create Release 30 | id: create_release 31 | uses: actions/create-release@latest 32 | env: 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token 34 | with: 35 | tag_name: ${{ github.ref }} 36 | release_name: Release ${{ github.ref }} 37 | body: '' 38 | draft: false 39 | prerelease: true 40 | 41 | - name: Upload Release Asset 42 | id: upload-release-asset 43 | uses: actions/upload-release-asset@v1 44 | env: 45 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 46 | with: 47 | upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps 48 | asset_path: ./out/packaged/NormaConstructor.mcaddon 49 | asset_name: NormaConstructor.mcaddon 50 | asset_content_type: application/zip 51 | -------------------------------------------------------------------------------- /packs/behaviors/scripts/plugin/nc/preset/songs.js: -------------------------------------------------------------------------------- 1 | 2 | const songs = [] 3 | /* 4 | import * as bas0 from "./song/Bad_Apple_slower_0.json" 5 | import * as bas1 from "./song/Bad_Apple_slower_1.json" 6 | songs.push(bas0, bas1)//0,1 7 | import * as croatian0 from "./song/Croatian Rhapsody-Maksim Mrvica_0.json" 8 | import * as croatian1 from "./song/Croatian Rhapsody-Maksim Mrvica_1.json" 9 | songs.push(croatian0, croatian1)//2,3 10 | import * as ha0 from "./song/Undertale_OST__Heartache_-_Piano_0.json" 11 | import * as ha1 from "./song/Undertale_OST__Heartache_-_Piano_1.json" 12 | songs.push(ha0, ha1)//4,5 13 | import * as re0 from "./song/Etude_in_C_Minor_Revolutionary_0.json" 14 | import * as re1 from "./song/Etude_in_C_Minor_Revolutionary_1.json" 15 | songs.push(re0, re1)//6,7 16 | import * as sa0 from "./song/Samurai with a Mission_0.json" 17 | import * as sa1 from "./song/Samurai with a Mission_1.json" 18 | songs.push(sa0, sa1)//8,9 19 | import * as tf0 from "./song/Time_Foward_0.json" 20 | import * as tf1 from "./song/Time_Foward_1.json" 21 | songs.push(tf0, tf1)//10,11 22 | import * as jl0 from "./song/千本樱 -初音ミク_0.json" 23 | import * as jl1 from "./song/千本樱 -初音ミク_1.json" 24 | songs.push(jl0, jl1)//12,13 25 | import * as as0 from "./song/A_story_you_wont_believe_0.json" 26 | import * as as1 from "./song/A_story_you_wont_believe_2.json" 27 | import * as as2 from "./song/A_story_you_wont_believe_4.json" 28 | import * as as3 from "./song/A_story_you_wont_believe_10.json" 29 | songs.push(as0, as1, as2, as3)//14,15,16,17 30 | import * as ws0 from "./song/为霜_0.json" 31 | import * as ws1 from "./song/为霜_1.json" 32 | songs.push(ws0, ws1)//18,19 33 | import * as fd0 from "./song/Flower Dance-Dj Okawari_0.json" 34 | import * as fd1 from "./song/Flower Dance-Dj Okawari_1.json" 35 | songs.push(fd0, fd1)//20,21 36 | import * as bwv0 from "./song/BWV847变奏曲_1.json" 37 | import * as bwv1 from "./song/BWV847变奏曲_2.json" 38 | songs.push(bwv0, bwv1)//22,23 39 | import * as luv0 from "./song/Luv letter -Dj Okawari_0.json" 40 | import * as luv1 from "./song/Luv letter -Dj Okawari_1.json" 41 | songs.push(luv0, luv1)//24,25 42 | import * as ml0 from "./song/Undertale_-_Megalovania_Piano_ver._3_0.json" 43 | import * as ml1 from "./song/Undertale_-_Megalovania_Piano_ver._3_1.json" 44 | songs.push(ml0, ml1)//26,27 45 | */ 46 | export { songs } -------------------------------------------------------------------------------- /file-generation.js: -------------------------------------------------------------------------------- 1 | /// 2 | const { series, dest } = require("gulp"); 3 | const fs = require("fs"); 4 | //const fsPromises = require("fs/promises"); 5 | 6 | // const tap = require("gulp-tap"); 7 | // const log = require("gulplog"); 8 | // const pump = require("pump"); 9 | const path = require("path"); 10 | 11 | /** 12 | * @type{IPlugin} 13 | */ 14 | class AutoFileGenerationSupport { 15 | constructor() { 16 | this.intermediateDir = "./out/before-plugin"; 17 | this.bundleSources = ""; 18 | this.writeBack = true; 19 | this.bundleDir = undefined; 20 | 21 | const _this = this; 22 | this.sourceTasks = [ 23 | { 24 | condition: this.bundleSources, 25 | preventDefault: false, 26 | task: pack => 27 | dest([path.posix.join(this.intermediateDir, pack.relativePath)]) 28 | 29 | } 30 | ]; 31 | } 32 | 33 | set builder(builder) { 34 | if (builder._version < 1) { 35 | throw new Error( 36 | "browserify support requires using a minecraft-addon-toolchain with at least version 1 or higher" 37 | ); 38 | } 39 | this._builder = builder; 40 | } 41 | 42 | addDefaultTasks(gulpTasks) { 43 | const generateFile = this._generateFile.bind(this); 44 | generateFile.displayName = "generateFile"; 45 | 46 | gulpTasks.buildSource = series(gulpTasks.buildSource, generateFile); 47 | } 48 | 49 | _generateFile(done) { 50 | return this._builder.foreachPack( 51 | "browserify", 52 | "behavior", 53 | (pack, packDone) => { 54 | const sourceDir = path.join( 55 | this._builder.sourceDir, 56 | pack.relativePath 57 | ); 58 | const destination = path.join( 59 | this.bundleDir || this._builder.bundleDir, 60 | pack.relativePath 61 | ); 62 | function getPluginsJSONSync() { 63 | try { 64 | let jsonData = fs.readFileSync(path.join( 65 | sourceDir, 66 | 'scripts/plugin/plugins.json' 67 | )); 68 | return JSON.parse(jsonData); 69 | } catch { 70 | return null; 71 | } 72 | } 73 | function havePluginJsSync() { 74 | try { 75 | fs.accessSync(path.join( 76 | sourceDir, 77 | 'scripts/plugin/index.js' 78 | )); 79 | return true; 80 | } catch { 81 | return false; 82 | } 83 | } 84 | function getPluginDirsSync() { 85 | let dirs = fs.readdirSync(path.join( 86 | sourceDir, 87 | 'scripts/plugin' 88 | )); 89 | return dirs.filter((dir) => { 90 | try { 91 | fs.accessSync(path.join( 92 | sourceDir, 93 | 'scripts/plugin', 94 | dir, 95 | 'index.js' 96 | )); 97 | return true; 98 | } catch { 99 | return false; 100 | } 101 | }); 102 | } 103 | if(havePluginJsSync()) { 104 | return packDone(); 105 | } 106 | let pluginJSON = getPluginsJSONSync(); 107 | let pluginDirs = getPluginDirsSync(); 108 | let isModified = false; 109 | if(pluginJSON === null) { 110 | pluginJSON = {}; 111 | isModified = true; 112 | } 113 | for(let dirName of pluginDirs) { 114 | if(pluginJSON[dirName] === undefined) { 115 | console.log(`Add dir ${dirName}`); 116 | pluginJSON[dirName] = { 117 | type: "inner", 118 | enable: true 119 | }; 120 | isModified = true; 121 | } 122 | } 123 | let pluginJs = ` 124 | /* 125 | ** This file is automatically generated, 126 | ** to know more, see file-generation.js 127 | */ 128 | ` 129 | + Object.keys(pluginJSON).map((pluginName) => { 130 | let plugin = pluginJSON[pluginName]; 131 | if(plugin === false) { 132 | return ''; 133 | } 134 | if(!plugin.enable) { 135 | return '\n'; 136 | } 137 | switch(plugin.type) { 138 | case 'inner': 139 | return `import './${pluginName}/index.js';\n`; 140 | break; 141 | default: 142 | let err = new Error( 143 | `Unknown type ${plugin.type} of plugin ${pluginName}` 144 | ); 145 | packDone(err); 146 | throw err; 147 | break; 148 | } 149 | }).join(''); 150 | if(this.writeBack && isModified) { 151 | fs.writeFileSync(path.join( 152 | sourceDir, 153 | 'scripts/plugin/plugins.json' 154 | ), JSON.stringify(pluginJSON, null, '\t').concat('\n')); 155 | } 156 | fs.writeFileSync(path.join( 157 | destination, 158 | 'scripts/plugin/index.js' 159 | ), pluginJs); 160 | return packDone(); 161 | }, 162 | done 163 | ); 164 | } 165 | } 166 | 167 | module.exports = AutoFileGenerationSupport; 168 | -------------------------------------------------------------------------------- /packs/resources/experimental_ui/styles.css: -------------------------------------------------------------------------------- 1 | /* 2 | Vanilla UI for Minecraft Bedrock Scripting API v0.0.1 3 | Created by ReimarPB 4 | This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License. 5 | */ 6 | @font-face { 7 | font-family:"NotoSerifSC-Regular"; 8 | src:url("id://NotoSansCJK-Regular"); 9 | } 10 | * { 11 | font-family:"NotoSerifSC-Regular"; 12 | } 13 | .body1 { 14 | height:100%; 15 | display: flex; 16 | justify-content:center; 17 | align-items:center; 18 | } 19 | .row { 20 | display:flex; 21 | flex-direction: row; 22 | } 23 | .minecraft-container { 24 | margin-top: 40px; 25 | font-size:16px; 26 | color:#4C4C4C; 27 | font-family:"NotoSerifSC-Regular"; 28 | position:relative; 29 | margin-top:10vh; 30 | background-color:#C6C6C6; 31 | padding:7px; 32 | padding-top:none; 33 | box-shadow: 34 | /* Right & bottom */ 35 | 4px 0 #555, 36 | 6px 0 black, 37 | 0 4px #555, 38 | 0 6px black, 39 | /* Left & top */ 40 | -4px 0 white, 41 | -6px 0 black, 42 | 0 -4px white, 43 | 0 -6px black, 44 | /* Corner right bottom */ 45 | 4px 2px #555, 46 | 2px 4px #555, 47 | 2px 6px black, 48 | 6px 2px black, 49 | 4px 4px black, 50 | /* Corner top right */ 51 | 2px -2px #C6C6C6, 52 | 4px -2px black, 53 | 2px -4px black, 54 | /* Corner top left */ 55 | -4px -2px white, 56 | -2px -4px white, 57 | -2px -6px black, 58 | -6px -2px black, 59 | -4px -4px black, 60 | /* Corner bottom left */ 61 | -2px 2px #C6C6C6, 62 | -4px 2px black, 63 | -2px 4px black; 64 | } 65 | .minecraft-container1 { 66 | margin-top: 10px; 67 | font-size:19px; 68 | color:#4C4C4C; 69 | font-family:"NotoSerifSC-Regular"; 70 | position:relative; 71 | background-color:#C6C6C6; 72 | padding:3px; 73 | padding-top:none; 74 | box-shadow: 75 | /* Right & bottom */ 76 | 4px 0 #555, 77 | 6px 0 black, 78 | 0 4px #555, 79 | 0 6px black, 80 | /* Left & top */ 81 | -4px 0 white, 82 | -6px 0 black, 83 | 0 -4px white, 84 | 0 -6px black, 85 | /* Corner right bottom */ 86 | 4px 2px #555, 87 | 2px 4px #555, 88 | 2px 6px black, 89 | 6px 2px black, 90 | 4px 4px black, 91 | /* Corner top right */ 92 | 2px -2px #C6C6C6, 93 | 4px -2px black, 94 | 2px -4px black, 95 | /* Corner top left */ 96 | -4px -2px white, 97 | -2px -4px white, 98 | -2px -6px black, 99 | -6px -2px black, 100 | -4px -4px black, 101 | /* Corner bottom left */ 102 | -2px 2px #C6C6C6, 103 | -4px 2px black, 104 | -2px 4px black; 105 | } 106 | .minecraft-container-dark { 107 | display:flex; 108 | flex-direction:column; 109 | line-height:50px; 110 | color:white; 111 | margin-top:13px; 112 | background-color:#6B6B6B; 113 | padding:5px 7px 5px 7px; 114 | box-shadow: 115 | /* Right & bottom */ 116 | 2px 2px white, 117 | 2px 0 white, 118 | 0 2px white, 119 | /* Left & top */ 120 | -2px -2px #393939, 121 | -2px 0 #393939, 122 | 0 -2px #393939, 123 | /* Corner top right */ 124 | 2px -2px #6B6B6B, 125 | /* Corner bottom left */ 126 | -2px 2px #6B6B6B; 127 | } 128 | .minecraft-container-darkcommand { 129 | display:flex; 130 | flex-direction:column; 131 | line-height:35px; 132 | color:white; 133 | margin-top:13px; 134 | position:fixed; 135 | background-color:#6B6B6B; 136 | padding:5px 7px 5px 7px; 137 | box-shadow: 138 | /* Right & bottom */ 139 | 2px 2px white, 140 | 2px 0 white, 141 | 0 2px white, 142 | /* Left & top */ 143 | -2px -2px #393939, 144 | -2px 0 #393939, 145 | 0 -2px #393939, 146 | /* Corner top right */ 147 | 2px -2px #6B6B6B, 148 | /* Corner bottom left */ 149 | -2px 2px #6B6B6B; 150 | } 151 | .minecraft-container-dark > * { 152 | margin-top:3px; 153 | margin-bottom:3px; 154 | } 155 | .minecraft-container-darkcommand > * { 156 | margin-top:3px; 157 | margin-bottom:3px; 158 | } 159 | .button { 160 | color:#4C4C4C; 161 | font-family:"NotoSerifSC-Regular"; 162 | background-color:#C6C6C6; 163 | padding:12px; 164 | margin:5px 0 5px 0; 165 | width:100%; 166 | text-align:center; 167 | box-shadow: 168 | /* Right & bottom */ 169 | 2px 2px #555, 170 | 2px 0 #555, 171 | 0 2px #555, 172 | /* Left & top */ 173 | -2px -2px white, 174 | -2px 0 white, 175 | 0 -2px white, 176 | /* Corner top right */ 177 | 2px -2px #C6C6C6, 178 | /* Corner bottom left */ 179 | -2px 2px #C6C6C6, 180 | /* Border */ 181 | 4px 4px black, 182 | 0 4px black, 183 | 4px 0 black, 184 | -4px -4px black, 185 | 0 -4px black, 186 | -4px 0 black, 187 | 4px -4px black, 188 | -4px 4px black; 189 | } 190 | .button:hover { 191 | color:white; 192 | background-color:#43A01C; 193 | box-shadow: 194 | /* Right & bottom */ 195 | 2px 2px #037300, 196 | 2px 0 #037300, 197 | 0 2px #037300, 198 | /* Left & top */ 199 | -2px -2px #37D61E, 200 | -2px 0 #37D61E, 201 | 0 -2px #37D61E, 202 | /* Corner top right */ 203 | 2px -2px #43A01C, 204 | /* Corner bottom left */ 205 | -2px 2px #43A01C, 206 | /* Border */ 207 | 4px 4px white, 208 | 0 4px white, 209 | 4px 0 white, 210 | -4px -4px white, 211 | 0 -4px white, 212 | -4px 0 white, 213 | 4px -4px white, 214 | -4px 4px white; 215 | } 216 | .minecraft-input { 217 | font-family:"NotoSerifSC-Regular"; 218 | padding:10px 5px 0 5px; 219 | width:100%; 220 | height:50px; 221 | background-color:#6B6B6B; 222 | border:none; 223 | border-top:2px solid #444; 224 | border-bottom:2px solid #B0B0B0; 225 | box-shadow: 226 | 2px 2px black, 227 | 0 2px black, 228 | 2px 0 black, 229 | -2px -2px black, 230 | 0 -2px black, 231 | -2px 0 black, 232 | 2px -2px black, 233 | -2px 2px black; 234 | } 235 | .minecraft-input:hover { 236 | box-shadow: 237 | 2px 2px white, 238 | 0 2px white, 239 | 2px 0 white, 240 | -2px -2px white, 241 | 0 -2px white, 242 | -2px 0 white, 243 | 2px -2px white, 244 | -2px 2px white; 245 | } 246 | .close-button { 247 | font-family:"NotoSerifSC-Regular"; 248 | position:absolute; 249 | right:2px; 250 | top:2px; 251 | padding:0 8px 5px 10px; 252 | } 253 | .close-button:hover { 254 | background-color:#AEAEAE; 255 | } 256 | .column { 257 | display: flex; 258 | flex-direction: column; 259 | } 260 | .keyboard { 261 | height: 50px; 262 | width: 50px; 263 | color:#4C4C4C; 264 | font-family:"NotoSerifSC-Regular"; 265 | background-color:#C6C6C6; 266 | margin:5px 0 5px 0; 267 | text-align:center; 268 | box-shadow: 269 | /* Right & bottom */ 270 | 2px 2px #555, 271 | 2px 0 #555, 272 | 0 2px #555, 273 | /* Left & top */ 274 | -2px -2px white, 275 | -2px 0 white, 276 | 0 -2px white, 277 | /* Corner top right */ 278 | 2px -2px #C6C6C6, 279 | /* Corner bottom left */ 280 | -2px 2px #C6C6C6, 281 | /* Border */ 282 | 4px 4px black, 283 | 0 4px black, 284 | 4px 0 black, 285 | -4px -4px black, 286 | 0 -4px black, 287 | -4px 0 black, 288 | 4px -4px black, 289 | -4px 4px black; 290 | 291 | } 292 | .margin { 293 | margin-top: 10px; 294 | margin-bottom: 10px; 295 | } 296 | .rightleft { 297 | margin-right: 20px; 298 | margin-left: 20px; 299 | } 300 | .keyboardspace { 301 | height: 50px; 302 | width: 65px; 303 | color:#4C4C4C; 304 | font-family:"NotoSerifSC-Regular"; 305 | background-color:#C6C6C6; 306 | margin:5px 0 5px 0; 307 | text-align:center; 308 | box-shadow: 309 | /* Right & bottom */ 310 | 2px 2px #555, 311 | 2px 0 #555, 312 | 0 2px #555, 313 | /* Left & top */ 314 | -2px -2px white, 315 | -2px 0 white, 316 | 0 -2px white, 317 | /* Corner top right */ 318 | 2px -2px #C6C6C6, 319 | /* Corner bottom left */ 320 | -2px 2px #C6C6C6, 321 | /* Border */ 322 | 4px 4px black, 323 | 0 4px black, 324 | 4px 0 black, 325 | -4px -4px black, 326 | 0 -4px black, 327 | -4px 0 black, 328 | 4px -4px black, 329 | -4px 4px black; 330 | } 331 | .keyboardbspace { 332 | height: 50px; 333 | width: 130px; 334 | color:#4C4C4C; 335 | font-family:"NotoSerifSC-Regular"; 336 | background-color:#C6C6C6; 337 | margin:5px 0 5px 0; 338 | text-align:center; 339 | box-shadow: 340 | /* Right & bottom */ 341 | 2px 2px #555, 342 | 2px 0 #555, 343 | 0 2px #555, 344 | /* Left & top */ 345 | -2px -2px white, 346 | -2px 0 white, 347 | 0 -2px white, 348 | /* Corner top right */ 349 | 2px -2px #C6C6C6, 350 | /* Corner bottom left */ 351 | -2px 2px #C6C6C6, 352 | /* Border */ 353 | 4px 4px black, 354 | 0 4px black, 355 | 4px 0 black, 356 | -4px -4px black, 357 | 0 -4px black, 358 | -4px 0 black, 359 | 4px -4px black, 360 | -4px 4px black; 361 | } 362 | .keyboard:hover { 363 | color:white; 364 | background-color:#43A01C; 365 | box-shadow: 366 | /* Right & bottom */ 367 | 2px 2px #037300, 368 | 2px 0 #037300, 369 | 0 2px #037300, 370 | /* Left & top */ 371 | -2px -2px #37D61E, 372 | -2px 0 #37D61E, 373 | 0 -2px #37D61E, 374 | /* Corner top right */ 375 | 2px -2px #43A01C, 376 | /* Corner bottom left */ 377 | -2px 2px #43A01C, 378 | /* Border */ 379 | 4px 4px white, 380 | 0 4px white, 381 | 4px 0 white, 382 | -4px -4px white, 383 | 0 -4px white, 384 | -4px 0 white, 385 | 4px -4px white, 386 | -4px 4px white; 387 | } 388 | .keyboardspace:hover { 389 | color:white; 390 | background-color:#43A01C; 391 | box-shadow: 392 | /* Right & bottom */ 393 | 2px 2px #037300, 394 | 2px 0 #037300, 395 | 0 2px #037300, 396 | /* Left & top */ 397 | -2px -2px #37D61E, 398 | -2px 0 #37D61E, 399 | 0 -2px #37D61E, 400 | /* Corner top right */ 401 | 2px -2px #43A01C, 402 | /* Corner bottom left */ 403 | -2px 2px #43A01C, 404 | /* Border */ 405 | 4px 4px white, 406 | 0 4px white, 407 | 4px 0 white, 408 | -4px -4px white, 409 | 0 -4px white, 410 | -4px 0 white, 411 | 4px -4px white, 412 | -4px 4px white; 413 | } 414 | .keyboardbspace:hover { 415 | color:white; 416 | background-color:#43A01C; 417 | box-shadow: 418 | /* Right & bottom */ 419 | 2px 2px #037300, 420 | 2px 0 #037300, 421 | 0 2px #037300, 422 | /* Left & top */ 423 | -2px -2px #37D61E, 424 | -2px 0 #37D61E, 425 | 0 -2px #37D61E, 426 | /* Corner top right */ 427 | 2px -2px #43A01C, 428 | /* Corner bottom left */ 429 | -2px 2px #43A01C, 430 | /* Border */ 431 | 4px 4px white, 432 | 0 4px white, 433 | 4px 0 white, 434 | -4px -4px white, 435 | 0 -4px white, 436 | -4px 0 white, 437 | 4px -4px white, 438 | -4px 4px white; 439 | } 440 | .buttoncommand { 441 | color:#4C4C4C; 442 | font-family:"NotoSerifSC-Regular"; 443 | background-color:#C6C6C6; 444 | padding:8px; 445 | margin:5px 0 5px 0; 446 | width:100%; 447 | text-align:center; 448 | box-shadow: 449 | /* Right & bottom */ 450 | 2px 2px #555, 451 | 2px 0 #555, 452 | 0 2px #555, 453 | /* Left & top */ 454 | -2px -2px white, 455 | -2px 0 white, 456 | 0 -2px white, 457 | /* Corner top right */ 458 | 2px -2px #C6C6C6, 459 | /* Corner bottom left */ 460 | -2px 2px #C6C6C6, 461 | /* Border */ 462 | 4px 4px black, 463 | 0 4px black, 464 | 4px 0 black, 465 | -4px -4px black, 466 | 0 -4px black, 467 | -4px 0 black, 468 | 4px -4px black, 469 | -4px 4px black; 470 | } 471 | .buttoncommand:hover { 472 | color:white; 473 | background-color:#43A01C; 474 | box-shadow: 475 | /* Right & bottom */ 476 | 2px 2px #037300, 477 | 2px 0 #037300, 478 | 0 2px #037300, 479 | /* Left & top */ 480 | -2px -2px #37D61E, 481 | -2px 0 #37D61E, 482 | 0 -2px #37D61E, 483 | /* Corner top right */ 484 | 2px -2px #43A01C, 485 | /* Corner bottom left */ 486 | -2px 2px #43A01C, 487 | /* Border */ 488 | 4px 4px white, 489 | 0 4px white, 490 | 4px 0 white, 491 | -4px -4px white, 492 | 0 -4px white, 493 | -4px 0 white, 494 | 4px -4px white, 495 | -4px 4px white; 496 | } -------------------------------------------------------------------------------- /packs/behaviors/scripts/server/server.js: -------------------------------------------------------------------------------- 1 | import '../plugin/index.js'; 2 | import { systemInstance as system, emptyPlatform, Coordinate, Position, BlockType, Direction, Block } from 'norma-core'; 3 | 4 | import { utils } from '../utils.js' 5 | 6 | emptyPlatform.use(system); 7 | const platform = { 8 | use: function (system) { 9 | var serverSystem = server.registerSystem(0, 0); 10 | this.init(serverSystem, system) 11 | }, 12 | init: function (serverSystem, system) { 13 | system.inject(platform); 14 | serverSystem.initialize = function () { 15 | const scriptLoggerConfig = serverSystem.createEventData("minecraft:script_logger_config"); 16 | scriptLoggerConfig.data.log_errors = true; 17 | scriptLoggerConfig.data.log_information = true; 18 | scriptLoggerConfig.data.log_warnings = true; 19 | serverSystem.broadcastEvent("minecraft:script_logger_config", scriptLoggerConfig); 20 | 21 | let compiler = { 22 | raw: function (blockArray) { 23 | return blockArray 24 | }, 25 | clone: function ({ startCoordinate, endCoordinate, targetCoordinate }) { 26 | if (startCoordinate.x >= endCoordinate.x) { 27 | let temp = startCoordinate.x 28 | startCoordinate.x = endCoordinate.x 29 | endCoordinate.x = temp 30 | } 31 | if (startCoordinate.y >= endCoordinate.y) { 32 | let temp = startCoordinate.y 33 | startCoordinate.y = endCoordinate.y 34 | endCoordinate.y = temp 35 | } 36 | if (startCoordinate.z >= endCoordinate.z) { 37 | let temp = startCoordinate.z 38 | startCoordinate.z = endCoordinate.z 39 | endCoordinate.z = temp 40 | } 41 | for (let x = startCoordinate.x; x <= endCoordinate.x; x += 32) 42 | for (let y = startCoordinate.y; y <= endCoordinate.y; y += 32) 43 | for (let z = startCoordinate.z; z <= endCoordinate.z; z += 32) 44 | serverSystem.executeCommand(`/clone ${x} ${y} ${z} 45 | ${Math.min(x + 31, endCoordinate.x)} 46 | ${Math.min(y + 31, endCoordinate.y)} 47 | ${Math.min(z + 31, endCoordinate.z)} 48 | ${targetCoordinate.x + x - startCoordinate.x} 49 | ${targetCoordinate.y + y - startCoordinate.y} 50 | ${targetCoordinate.z + z - startCoordinate.z} 51 | masked force`, (commandResultData) => { }); 52 | 53 | return [] 54 | }, 55 | fill: function ({ blockType, startCoordinate, endCoordinate }) { 56 | 57 | if (startCoordinate.x >= endCoordinate.x) { 58 | let temp = startCoordinate.x 59 | startCoordinate.x = endCoordinate.x 60 | endCoordinate.x = temp 61 | } 62 | if (startCoordinate.y >= endCoordinate.y) { 63 | let temp = startCoordinate.y 64 | startCoordinate.y = endCoordinate.y 65 | endCoordinate.y = temp 66 | } 67 | if (startCoordinate.z >= endCoordinate.z) { 68 | let temp = startCoordinate.z 69 | startCoordinate.z = endCoordinate.z 70 | endCoordinate.z = temp 71 | } 72 | 73 | //Bypass the restriction of 32767 blocks 74 | for (let x = startCoordinate.x; x <= endCoordinate.x; x += 32) 75 | for (let y = startCoordinate.y; y <= endCoordinate.y; y += 32) 76 | for (let z = startCoordinate.z; z <= endCoordinate.z; z += 32) 77 | serverSystem.executeCommand(`/fill ${x} ${y} ${z} 78 | ${Math.min(x + 31, endCoordinate.x)} 79 | ${Math.min(y + 31, endCoordinate.y)} 80 | ${Math.min(z + 31, endCoordinate.z)} 81 | ${blockType.blockIdentifier.slice(blockType.blockIdentifier.indexOf(":") + 1)} 82 | [${blockType.blockState == null ? "" : JSON.stringify(blockType.blockState).slice(1, -1)}] replace`, (commandResultData) => { } 83 | ); 84 | 85 | return [] 86 | }, 87 | writeBuildingStructure: function ({ startCoordinate, endCoordinate, referenceCoordinate, tickingArea }) { 88 | if (startCoordinate.x >= endCoordinate.x) [startCoordinate.x, endCoordinate.x] = [endCoordinate.x, startCoordinate.x] 89 | if (startCoordinate.y >= endCoordinate.y) [startCoordinate.y, endCoordinate.y] = [endCoordinate.y, startCoordinate.y] 90 | if (startCoordinate.z >= endCoordinate.z) [startCoordinate.z, endCoordinate.z] = [endCoordinate.z, startCoordinate.z] 91 | for (let x = startCoordinate.x; x <= endCoordinate.x; x++) 92 | for (let y = startCoordinate.y; y <= endCoordinate.y; y++) 93 | for (let z = startCoordinate.z; z <= endCoordinate.z; z++) { 94 | let blockType = new BlockType(undefined, undefined) 95 | let block = serverSystem.getBlock(tickingArea, new Coordinate(x, y, z)) 96 | blockType.blockIdentifier = block.__identifier__ 97 | blockType.blockState = serverSystem.getComponent(block, "minecraft:blockstate").data 98 | server.log(JSON.stringify({ coordinate: new Coordinate(x - referenceCoordinate.x, y - referenceCoordinate.y, z - referenceCoordinate.z), blockType: blockType }, null, ' ')) 99 | } 100 | return [] 101 | }, 102 | setblockWithTiledata: function ({ x, y, z, blockIdentifier, tiledata }) { 103 | serverSystem.executeCommand(`/setblock ${x} ${y} ${z} ${blockIdentifier.slice(blockIdentifier.indexOf(":") + 1)} ${tiledata} replace`, (commandResultData) => { 104 | }); 105 | return [] 106 | } 107 | } 108 | 109 | serverSystem.registerEventData("NormaConstructor:displayChatToClient", { 110 | message: undefined, 111 | playerID: undefined 112 | }) 113 | 114 | serverSystem.registerEventData("NormaConstructor:command", { 115 | command: undefined, 116 | additionalData: { 117 | direction: new Direction(undefined, undefined), 118 | tickingArea: undefined, 119 | playerRequest: { 120 | "position": false, 121 | "direction": false, 122 | "blockType": false 123 | } 124 | }, 125 | playerID: undefined 126 | }) 127 | serverSystem.registerEventData("NormaConstructor:serveData", { 128 | blockType: undefined, 129 | position: undefined, 130 | direction: undefined, 131 | playerID: undefined 132 | }) 133 | 134 | serverSystem.registerEventData("NZConstructor:blockFetchResponse", { 135 | blockType: undefined, 136 | playerID: undefined, 137 | requestID: undefined 138 | }) 139 | 140 | serverSystem.registerEventData("NormaConstructor:ExecutionRequest", { playerID: undefined }) 141 | 142 | 143 | serverSystem.listenForEvent("NormaConstructor:setServerSideOption", (eventData) => { 144 | if (!system.hasUser(eventData.data.playerID)) { 145 | system.createUser(eventData.data.playerID); 146 | } 147 | let user = system.getUser(eventData.data.playerID) 148 | user.session[eventData.data.option.key] = eventData.data.option.value 149 | }) 150 | serverSystem.listenForEvent("minecraft:player_placed_block", (eventData) => { 151 | //TODO: Break down the parameter. 152 | function getBlockType(eventData) { 153 | let blockType = new BlockType(undefined, undefined) 154 | 155 | let tickingArea = serverSystem.getComponent(eventData.data.player, "minecraft:tick_world").data.ticking_area 156 | let block = serverSystem.getBlock(tickingArea, eventData.data.block_position) 157 | blockType.blockIdentifier = block.__identifier__ 158 | blockType.blockState = serverSystem.getComponent(block, "minecraft:blockstate").data 159 | 160 | return blockType 161 | 162 | } 163 | function getPosition(eventData) { 164 | let position = new Position( 165 | new Coordinate(undefined, undefined, undefined), 166 | undefined 167 | ) 168 | 169 | position.coordinate = eventData.data.block_position 170 | position.tickingArea = serverSystem.getComponent(eventData.data.player, "minecraft:tick_world").data.ticking_area 171 | 172 | return position 173 | } 174 | function getDirection(eventData) { 175 | let direction = new Direction(undefined, undefined) 176 | direction = serverSystem.getComponent(eventData.data.player, "minecraft:rotation").data 177 | return direction 178 | } 179 | let serveDataEventData = serverSystem.createEventData("NormaConstructor:serveData") 180 | serveDataEventData.data.blockType = getBlockType(eventData) 181 | let playerID = utils.misc.generatePlayerIDFromUniqueID(eventData.data.player.__unique_id__) 182 | let user = system.getUser(playerID) 183 | if (user.session["__requestAdditionalPosition"]) serveDataEventData.data.position = getPosition(eventData) 184 | if (user.session["__requestAdditionalDirection"]) serveDataEventData.data.direction = getDirection(eventData) 185 | serveDataEventData.data.playerID = playerID 186 | serverSystem.broadcastEvent("NormaConstructor:serveData", serveDataEventData) 187 | }) 188 | serverSystem.listenForEvent("NormaConstructor:queryBlockType", (eventData) => { 189 | let blockType = new BlockType(undefined, undefined) 190 | let block = serverSystem.getBlock(eventData.data.position.tickingArea, eventData.data.position.coordinate) 191 | blockType.blockIdentifier = block.__identifier__ 192 | blockType.blockState = serverSystem.getComponent(block, "minecraft:blockstate").data 193 | 194 | let serveDataEventData = serverSystem.createEventData("NormaConstructor:serveData") 195 | serveDataEventData.data.blockType = blockType 196 | serveDataEventData.data.playerID = eventData.data.playerID 197 | serverSystem.broadcastEvent("NormaConstructor:serveData", serveDataEventData) 198 | }) 199 | serverSystem.listenForEvent("NZConstructor:blockFetchRequest", (eventData) => { 200 | let blockType = new BlockType(undefined, undefined) 201 | let block = serverSystem.getBlock(eventData.data.position.tickingArea, eventData.data.position.coordinate) 202 | blockType.blockIdentifier = block.__identifier__ 203 | blockType.blockState = serverSystem.getComponent(block, "minecraft:blockstate").data 204 | 205 | let blockFetchResponseEventData = serverSystem.createEventData("NZConstructor:blockFetchResponse") 206 | blockFetchResponseEventData.data.blockType = blockType 207 | blockFetchResponseEventData.data.playerID = eventData.data.playerID 208 | blockFetchResponseEventData.data.requestID = eventData.data.requestID 209 | serverSystem.broadcastEvent("NZConstructor:blockFetchResponse", blockFetchResponseEventData) 210 | }) 211 | serverSystem.listenForEvent("NZConstructor:setBlock", (eventData) => { 212 | let { x, y, z, blockIdentifier, blockState } = eventData.data 213 | serverSystem.executeCommand(`/setblock ${x} ${y} ${z} ${blockIdentifier.slice(blockIdentifier.indexOf(":") + 1)} [${blockType.blockState == null ? "" : JSON.stringify(blockType.blockState).slice(1, -1)}] replace`, (commandResultData) => { }) 214 | }) 215 | 216 | //I suppose I have to make an explanation. 217 | //The input ("get data") mechanism is drasticly changed due to the 1.16 update as "block_interacted_with" is no longer useful. 218 | //Now the server serves the data through one event:"serveData". 219 | //When a block is placed, except that all three types of data will be sent in one event, things remain largely the same. 220 | //For position and direction, it is now initiated through fake food. Then the following code will obtain player's direction, and list what types of data the player request. 221 | //Then the client will process the data. For position, the client will track the position the player is looking at in advance, and with direction it can calculate the block position. 222 | //Finally...it won't obtain blocktype as additional data ever since...? 223 | serverSystem.listenForEvent("minecraft:entity_use_item", (eventData) => { 224 | if (eventData.data.item_stack.__identifier__.startsWith("normaconstructor:")) { 225 | let playerID = utils.misc.generatePlayerIDFromUniqueID(eventData.data.entity.__unique_id__) 226 | let user = system.getUser(playerID) 227 | let command = eventData.data.item_stack.__identifier__.slice(eventData.data.item_stack.__identifier__.indexOf(":") + 1) 228 | //TODO: Explain how 'get_air' works. 229 | if (command == "get_position" || command == "get_direction" || command == "get_air") { 230 | let additionalData = { 231 | direction: serverSystem.getComponent(eventData.data.entity, "minecraft:rotation").data, 232 | tickingArea: serverSystem.getComponent(eventData.data.entity, "minecraft:tick_world").data.ticking_area, 233 | playerRequest: { 234 | "position": ((command == "get_position") || user.session["__requestAdditionalPosition"]), 235 | "direction": ((command == "get_direction") || user.session["__requestAdditionalDirection"]), 236 | "blockType": ((command == "get_air") ? false : user.session["__requestAdditionalBlockType"]) 237 | }, 238 | isGetAir: (command == "get_air") 239 | } 240 | sendCommand("get_data", playerID, additionalData) 241 | } 242 | else if (command == "read_tag") { 243 | sendCommand( 244 | command, playerID, 245 | Array.from(serverSystem.getComponent(eventData.data.entity, "minecraft:tag").data, (tag) => { 246 | if (tag.startsWith("nc:")) { 247 | return tag.slice(3) 248 | } 249 | }) 250 | ) 251 | } 252 | else sendCommand(command, playerID) 253 | } 254 | }) 255 | serverSystem.listenForEvent("NormaConstructor:ExecutionResponse", (eventData) => { 256 | for (let buildInstruction of eventData.data.buildInstructions) { 257 | //I know it looks silly... "Compatibility reason". 258 | if (!buildInstruction.hasOwnProperty("type")) setBlock(buildInstruction) 259 | else { 260 | //Another compromise... 261 | //'Compliers' don't just complie: the fill() method can be invoked in which block will be placed directly. 262 | let blocks = compiler[buildInstruction.type](buildInstruction.data) 263 | for (let block of blocks) setBlock(block) 264 | } 265 | } 266 | }) 267 | function displayObject(object, playerID) { 268 | displayChat(JSON.stringify(object, null, ' '), playerID) 269 | } 270 | function displayChat(message, playerID) { 271 | if (playerID === undefined) { 272 | let eventData = serverSystem.createEventData("minecraft:display_chat_event"); 273 | eventData.data.message = message; 274 | serverSystem.broadcastEvent("minecraft:display_chat_event", eventData); 275 | } 276 | else { 277 | let eventData = serverSystem.createEventData("NormaConstructor:displayChatToClient"); 278 | eventData.data.message = message; 279 | eventData.data.playerID = playerID; 280 | serverSystem.broadcastEvent("NormaConstructor:displayChatToClient", eventData); 281 | } 282 | } 283 | 284 | 285 | function sendCommand(command, playerID, additionalData) { 286 | let commandEventData = serverSystem.createEventData("NormaConstructor:command") 287 | commandEventData.data.command = command 288 | commandEventData.data.playerID = playerID 289 | commandEventData.data.additionalData = additionalData 290 | serverSystem.broadcastEvent("NormaConstructor:command", commandEventData) 291 | } 292 | function setBlock(block) { 293 | 294 | //displayChat("§b We all agree, NZ is JULAO!") 295 | let blockType = block.blockType 296 | let position = block.position 297 | let coordinate = position.coordinate 298 | //Thank you, WavePlayz! 299 | 300 | //TODO: 301 | //It currently use destroy mode to force replace the old block, but will leave tons of items. 302 | //Might change to set air block first. 303 | serverSystem.executeCommand(`/setblock ${coordinate.x} ${coordinate.y} ${coordinate.z} ${blockType.blockIdentifier.slice(blockType.blockIdentifier.indexOf(":") + 1)} [${blockType.blockState == null ? "" : JSON.stringify(blockType.blockState).slice(1, -1)}] replace`, (commandResultData) => { 304 | 305 | // var targerBlock = serverSystem.getBlock(position.tickingArea, coordinate.x, coordinate.y, coordinate.z) 306 | 307 | // var targetBlockStateComponent = serverSystem.getComponent(targerBlock, "minecraft:blockstate") 308 | // targetBlockStateComponent.data = blockType.blockState 309 | // serverSystem.applyComponentChanges(targerBlock, targetBlockStateComponent) 310 | }); 311 | } 312 | 313 | } 314 | }, 315 | createRuntime(id) { 316 | let user = system.getUser(id); 317 | return {}; 318 | } 319 | 320 | 321 | } 322 | 323 | 324 | 325 | platform.use(system) 326 | -------------------------------------------------------------------------------- /packs/resources/experimental_ui/menu/menu.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |
15 |
16 |
17 |
18 |
19 |
Master Switch
20 |
21 | 23 | 25 |
26 | 27 |
28 |
29 |
30 |
31 |
32 |
33 |
Request Additional Position
34 |
35 | 37 | 39 |
40 | 41 |
42 |
43 |
44 |
45 |
46 |
47 |
Request Additional BlockType
48 |
49 | 51 | 53 |
54 | 55 |
56 |
57 |
58 |
59 |
60 |
61 |
Request Additional Direction
62 |
63 | 65 | 67 |
68 | 69 |
70 |
71 |
72 |
73 |
74 |
75 |
Log level:
76 |
77 | 79 | 81 | 83 | 85 | 87 | 89 |
90 | 91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
Constructor panel
99 | 101 |
102 | 103 |
104 |
105 | 106 | 107 | 108 |
109 | 127 | 128 |
129 |
130 |
132 |
133 |
134 |
19260817
135 |
136 |
137 |
138 | 140 | 142 | 144 |
145 |
146 | 148 | 150 | 152 |
153 |
154 | 156 | 158 | 160 |
161 |
162 | 164 | 166 | 168 |
169 |
170 |
171 |
173 | 175 | 177 |
178 |
179 | 180 |
181 | 182 |
183 |
184 |
185 | 186 | 358 | 359 | -------------------------------------------------------------------------------- /packs/resources/experimental_ui/UIEngine.js: -------------------------------------------------------------------------------- 1 | /// The `engine` module contains all functions for communication between the UI and the game / application. 2 | (function (factory) { 3 | if (typeof module === 'object' && module.exports) { 4 | module.exports = factory(global, global.engine, false); 5 | } else { 6 | engine = factory(this, engine, true); 7 | } 8 | })(function (global, engine, hasOnLoad) { 9 | 'use strict'; 10 | 11 | var VERSION = [1, 5, 0, 8]; 12 | 13 | /** 14 | * Event emitter 15 | * 16 | * @class Emitter 17 | */ 18 | function Emitter() { 19 | this.events = {}; 20 | } 21 | 22 | function Handler(code, context) { 23 | this.code = code; 24 | this.context = context; 25 | } 26 | 27 | Emitter.prototype._createClear = function (object, name, handler) { 28 | return function() { 29 | var handlers = object.events[name]; 30 | if (handlers) { 31 | var index = -1; 32 | // this was in native previously 33 | if(handler === undefined) 34 | { 35 | for(var i = 0; i < handlers.length; ++i) 36 | { 37 | if(handlers[i].wasInCPP !== undefined) 38 | { 39 | index = i; 40 | break; 41 | } 42 | } 43 | } 44 | else 45 | { 46 | index = handlers.indexOf(handler); 47 | } 48 | if (index != -1) { 49 | handlers.splice(index, 1); 50 | if (handlers.length === 0) { 51 | delete object.events[name]; 52 | } 53 | } 54 | } else { 55 | if(engine.RemoveOnHandler !== undefined) { 56 | engine.RemoveOnHandler(name); 57 | } 58 | } 59 | }; 60 | }; 61 | 62 | /** 63 | * Add a handler for an event 64 | * 65 | * @method on 66 | * @param name the event name 67 | * @param callback function to be called when the event is triggered 68 | * @param context this binding for executing the handler, defaults to the Emitter 69 | * @return connection object 70 | */ 71 | Emitter.prototype.on = function (name, callback, context) { 72 | var handlers = this.events[name]; 73 | if (handlers === undefined) 74 | handlers = this.events[name] = []; 75 | 76 | var handler = new Handler(callback, context || this); 77 | handlers.push(handler); 78 | return { clear: this._createClear(this, name, handler) }; 79 | }; 80 | 81 | /** 82 | * Remove a handler from an event 83 | * 84 | * @method off 85 | * @param name the event name 86 | * @param callback function to be called when the event is triggered 87 | * @param context this binding for executing the handler, defaults to the Emitter 88 | * @return connection object 89 | */ 90 | Emitter.prototype.off = function (name, handler, context) { 91 | var handlers = this.events[name]; 92 | 93 | if (handlers !== undefined) { 94 | context = context || this; 95 | 96 | var index; 97 | var length = handlers.length; 98 | for (index = 0; index < length; ++index) { 99 | var reg = handlers[index]; 100 | if (reg.code == handler && reg.context == context) { 101 | break; 102 | } 103 | } 104 | if (index < length) { 105 | handlers.splice(index, 1); 106 | if (handlers.length === 0) { 107 | delete this.events[name]; 108 | } 109 | } 110 | } 111 | else 112 | { 113 | engine.RemoveOnHandler(name); 114 | } 115 | }; 116 | 117 | 118 | var isAttached = engine !== undefined; 119 | engine = engine || {}; 120 | /// @var {bool} engine.isAttached 121 | /// Indicates whether the script is currently running inside the UI Engine 122 | engine.isAttached = isAttached; 123 | 124 | engine.onEventsReplayed = null; 125 | Emitter.prototype.trigger = function(name) { 126 | var handlers = this.events[name]; 127 | 128 | if (handlers !== undefined) { 129 | var args = Array.prototype.slice.call(arguments, 1); 130 | 131 | handlers.forEach(function (handler) { 132 | handler.code.apply(handler.context, args); 133 | }); 134 | } 135 | }; 136 | 137 | Emitter.prototype.merge = function (emitter) { 138 | var lhs = this.events, 139 | rhs = emitter.events, 140 | push = Array.prototype.push, 141 | events; 142 | 143 | for (var e in rhs) { 144 | events = lhs[e] = lhs[e] || []; 145 | push.apply(events, rhs[e]); 146 | } 147 | }; 148 | 149 | var pending = 'pending'; 150 | var fulfilled = 'fulfilled'; 151 | var broken = 'broken'; 152 | 153 | function callAsync(code, context, argument) { 154 | var async = function () { 155 | code.call(context, argument); 156 | }; 157 | setTimeout(async, 1); 158 | } 159 | 160 | function Promise () { 161 | this.emitter = new Emitter(); 162 | this.state = pending; 163 | this.result = null; 164 | } 165 | 166 | Promise.prototype.resolve = function (result) { 167 | this.state = fulfilled; 168 | this.result = result; 169 | 170 | this.emitter.trigger(fulfilled, result); 171 | }; 172 | 173 | Promise.prototype.reject = function (result) { 174 | this.state = broken; 175 | this.result = result; 176 | 177 | this.emitter.trigger(broken, result); 178 | }; 179 | 180 | Promise.prototype.success = function (code, context) { 181 | if (this.state !== fulfilled) { 182 | this.emitter.on(fulfilled, code, context); 183 | } else { 184 | callAsync(code, context || this, this.result); 185 | } 186 | return this; 187 | }; 188 | 189 | Promise.prototype.always = function (code, context) { 190 | this.success(code, context); 191 | this.otherwise(code, context); 192 | return this; 193 | }; 194 | 195 | Promise.prototype.otherwise = function (code, context) { 196 | if (this.state !== broken) { 197 | this.emitter.on(broken, code, context); 198 | } else { 199 | callAsync(code, context || this, this.result); 200 | } 201 | return this; 202 | }; 203 | 204 | Promise.prototype.merge = function (other) { 205 | if (this.state === pending) { 206 | this.emitter.merge(other.emitter); 207 | } else { 208 | var handlers = other.emitter.events[this.state]; 209 | var self = this; 210 | if (handlers !== undefined) { 211 | handlers.forEach(function (handler) { 212 | handler.code.call(handler.context, self.result); 213 | }); 214 | } 215 | } 216 | }; 217 | 218 | Promise.prototype.make_chain = function (handler, promise, ok) { 219 | return function (result) { 220 | var handlerResult; 221 | try { 222 | handlerResult = handler.code.call(handler.context, result); 223 | if (handlerResult instanceof Promise) { 224 | handlerResult.merge(promise); 225 | } else if (this.state === ok) { 226 | promise.resolve(handlerResult); 227 | } else { 228 | promise.reject(handlerResult); 229 | } 230 | } catch (error) { 231 | promise.reject(error); 232 | } 233 | }; 234 | }; 235 | 236 | function makeDefaultHandler(promise) { 237 | return function () { 238 | return promise; 239 | }; 240 | } 241 | 242 | Promise.prototype.then = function (callback, errback) { 243 | var promise = new Promise(); 244 | 245 | var handler = new Handler(callback || makeDefaultHandler(this), this); 246 | 247 | this.success(this.make_chain(handler, promise, fulfilled), this); 248 | 249 | var errorHandler = new Handler(errback || makeDefaultHandler(this), this); 250 | this.otherwise(this.make_chain(errorHandler, promise, broken), this); 251 | 252 | 253 | return promise; 254 | }; 255 | 256 | if (!engine.isAttached) { 257 | Emitter.prototype.on = function (name, callback, context) { 258 | var handlers = this.events[name]; 259 | if (this.browserCallbackOn) { 260 | this.browserCallbackOn(name, callback, context); 261 | } 262 | 263 | if (handlers === undefined) { 264 | handlers = this.events[name] = []; 265 | } 266 | 267 | var handler = new Handler(callback, context || this); 268 | handlers.push(handler); 269 | return { clear: this._createClear(this, name, handler) }; 270 | }; 271 | Emitter.prototype.off = function (name, handler, context) { 272 | var handlers = this.events[name]; 273 | 274 | if (handlers !== undefined) { 275 | context = context || this; 276 | 277 | var index; 278 | var length = handlers.length; 279 | for (index = 0; index < length; ++index) { 280 | var reg = handlers[index]; 281 | if (reg.code == handler && reg.context == context) { 282 | break; 283 | } 284 | } 285 | if (index < length) { 286 | handlers.splice(index, 1); 287 | if (handlers.length === 0) { 288 | delete this.events[name]; 289 | 290 | if (this.browserCallbackOff) { 291 | this.browserCallbackOff(name, handler, context); 292 | } 293 | } 294 | } 295 | } 296 | }; 297 | 298 | engine.SendMessage = function (name, id) { 299 | var args = Array.prototype.slice.call(arguments, 2); 300 | var deferred = engine._ActiveRequests[id]; 301 | 302 | delete engine._ActiveRequests[id]; 303 | var call = function () { 304 | var mock = engine._mocks[name]; 305 | 306 | if (mock !== undefined) { 307 | deferred.resolve(mock.apply(engine, args)); 308 | } 309 | }; 310 | 311 | window.setTimeout(call, 16); 312 | }; 313 | 314 | engine.TriggerEvent = function () { 315 | var args = Array.prototype.slice.call(arguments); 316 | 317 | var trigger = function () { 318 | var mock = engine._mocks[args[0]]; 319 | 320 | if (mock !== undefined) { 321 | mock.apply(engine, args.slice(1)); 322 | } 323 | }; 324 | window.setTimeout(trigger, 16); 325 | }; 326 | 327 | engine.BindingsReady = function () { 328 | engine._OnReady(); 329 | }; 330 | 331 | engine.__observeLifetime = function () { 332 | }; 333 | 334 | engine.beginEventRecording = 335 | engine.endEventRecording = 336 | engine.saveEventRecord = function() { 337 | console.warning("Event recording will not work in the browser!"); 338 | }; 339 | 340 | engine._mocks = {}; 341 | engine._mockImpl = function (name, mock, isCppCall, isEvent) { 342 | if (mock) { 343 | this._mocks[name] = mock; 344 | } 345 | // Extract the name of the arguments from Function.prototype.toString 346 | var functionStripped = mock.toString().replace("function " + mock.name + "(", ""); 347 | var rightParanthesis = functionStripped.indexOf(")"); 348 | var args = functionStripped.substr(0, rightParanthesis); 349 | if (this.browserCallbackMock) { 350 | this.browserCallbackMock(name, 351 | args, 352 | isCppCall, 353 | Boolean(isEvent)); 354 | } 355 | } 356 | engine.mock = function (name, mock, isEvent) { 357 | this._mockImpl(name, mock, true, isEvent); 358 | }; 359 | } 360 | 361 | engine.events = {}; 362 | for (var property in Emitter.prototype) { 363 | engine[property] = Emitter.prototype[property]; 364 | } 365 | 366 | if (engine.isAttached) { 367 | engine.on = function (name, callback, context) { 368 | var handlers = this.events[name]; 369 | 370 | if (handlers === undefined && engine.AddOrRemoveOnHandler !== undefined) { 371 | // Check where to cache the handler 372 | var prevEvent = engine.AddOrRemoveOnHandler(name, callback, context || engine); 373 | 374 | // handler cached in C++ 375 | if(prevEvent === undefined) { 376 | return { clear: this._createClear(this, name, undefined) }; 377 | } 378 | 379 | handlers = this.events[name] = []; 380 | 381 | // Add the previous handler 382 | var prevHandler = new Handler(prevEvent[0], prevEvent[1] || this); 383 | prevHandler.wasInCPP = true; 384 | handlers.push(prevHandler); 385 | } else if (handlers === undefined) { 386 | handlers = this.events[name] = []; 387 | } 388 | 389 | var handler = new Handler(callback, context || this); 390 | handlers.push(handler); 391 | return { clear: this._createClear(this, name, handler) }; 392 | } 393 | } 394 | 395 | /// @function engine.on 396 | /// Register handler for and event 397 | /// @param {String} name name of the event 398 | /// @param {Function} callback callback function to be executed when the event has been triggered 399 | /// @param context *this* context for the function, by default the engine object 400 | 401 | /// @function engine.beginEventRecording 402 | /// Begins recording all events triggered using View::TriggerEvent from the game 403 | 404 | /// @function engine.endEventRecording 405 | /// Ends event recording 406 | 407 | /// @function engine.saveEventRecord 408 | /// Saves the events recorded in between the last calls to engine.beginEventRecording and engine.endEventRecording to a file 409 | /// @param {String} path The path to the file where to save the recorded events. Optional. Defaults to "eventRecord.json" 410 | 411 | /// @function engine.replayEvents 412 | /// Replays the events previously recorded and stored in path. If you need to be notified when all events 413 | /// are replayed, assign a callback to engine.onEventsReplayed 414 | /// @param {Number} timeScale The speed at which to replay the events (e.g. pass 2 to double the speed). Optional. Defaults to 1. 415 | /// @param {String} path The path to the file the recorded events are stored. Optional. Defaults to "eventRecord.json" 416 | 417 | /// @function engine.off 418 | /// Remove handler for an event 419 | /// @param {String} name name of the event, by default removes all events 420 | /// @param {Function} callback the callback function to be removed, by default removes all callbacks for a given event 421 | /// @param context *this* context for the function, by default all removes all callbacks, regardless of context 422 | /// @warning Removing all handlers for `engine` will remove some *Coherent UI* internal events, breaking some functionality. 423 | 424 | /// @function engine.trigger 425 | /// Trigger an event 426 | /// This function will trigger any C++ handler registered for this event with `Coherent::UI::View::RegisterForEvent` 427 | /// @param {String} name name of the event 428 | /// @param ... any extra arguments to be passed to the event handlers 429 | 430 | engine._trigger = Emitter.prototype.trigger; 431 | var concatArguments = Array.prototype.concat; 432 | engine.trigger = function (name) { 433 | this._trigger.apply(this, arguments); 434 | this.TriggerEvent.apply(this, arguments); 435 | 436 | if (this.events['all'] !== undefined) { 437 | var allArguments = concatArguments.apply(['all'], arguments); 438 | this._trigger.apply(this, allArguments); 439 | } 440 | }; 441 | /// @function engine.showOverlay 442 | /// Shows the debugging overlay in the browser. 443 | /// Only works in the browser. Attempts to use it in Coherent UI will do nothing. 444 | engine.showOverlay = function () {}; 445 | 446 | 447 | /// @function engine.hideOverlay 448 | /// Hides the debugging overlay in the browser. 449 | /// Only works in the browser. Attempts to use it in Coherent UI will do nothing. 450 | engine.hideOverlay = function () {}; 451 | 452 | /// @function engine.mock 453 | /// Mocks a C++ function call with the specified function. 454 | /// Only works in the browser. Attempts to use it in Coherent UI will do nothing. 455 | /// @param {String} name name of the event 456 | /// @param {Function} mock a function to be called in-place of your native binding 457 | /// @param {Boolean} isEvent whether you are mocking an event or function call 458 | if (engine.isAttached) { 459 | engine.mock = function (name, mock, isEvent) { }; 460 | } 461 | 462 | engine._BindingsReady = false; 463 | engine._WindowLoaded = false; 464 | engine._RequestId = 0; 465 | engine._ActiveRequests = {}; 466 | 467 | /// @function engine.createDeferred 468 | /// Create a new deferred object. 469 | /// Use this to create deferred / promises that can be used together with `engine.call`. 470 | /// @return {Deferred} a new deferred object 471 | /// @see @ref CustomizingPromises 472 | engine.createDeferred = (global.engineCreateDeferred === undefined) ? 473 | function () { return new Promise(); } 474 | : global.engineCreateDeferred; 475 | 476 | /// @function engine.call 477 | /// Call asynchronously a C++ handler and retrieve the result 478 | /// The C++ handler must have been registered with `Coherent::UI::View::BindCall` 479 | /// @param {String} name name of the C++ handler to be called 480 | /// @param ... any extra parameters to be passed to the C++ handler 481 | /// @return {Deferred} deferred object whose promise is resolved with the result of the C++ handler 482 | engine.call = function () { 483 | engine._RequestId++; 484 | var id = engine._RequestId; 485 | 486 | var deferred = engine.createDeferred(); 487 | engine._ActiveRequests[id] = deferred; 488 | var messageArguments = Array.prototype.slice.call(arguments); 489 | messageArguments.splice(1, 0, id); 490 | engine.SendMessage.apply(this, messageArguments); 491 | return deferred; 492 | }; 493 | 494 | engine._Result = function (requestId) { 495 | var deferred = engine._ActiveRequests[requestId]; 496 | if (deferred !== undefined) 497 | { 498 | delete engine._ActiveRequests[requestId]; 499 | 500 | var resultArguments = Array.prototype.slice.call(arguments); 501 | resultArguments.shift(); 502 | deferred.resolve.apply(deferred, resultArguments); 503 | } 504 | }; 505 | 506 | engine._Errors = [ 'Success', 'ArgumentType', 'NoSuchMethod', 'NoResult' ]; 507 | 508 | engine._ForEachError = function (errors, callback) { 509 | var length = errors.length; 510 | 511 | for (var i = 0; i < length; ++i) { 512 | callback(errors[i].first, errors[i].second); 513 | } 514 | }; 515 | 516 | engine._MapErrors = function (errors) { 517 | var length = errors.length; 518 | 519 | for (var i = 0; i < length; ++i) { 520 | errors[i].first = engine._Errors[errors[i].first]; 521 | } 522 | }; 523 | 524 | engine._TriggerError = function (type, message) { 525 | engine.trigger('Error', type, message); 526 | }; 527 | 528 | engine._OnError = function (requestId, errors) { 529 | engine._MapErrors(errors); 530 | 531 | if (requestId === null || requestId === 0) { 532 | engine._ForEachError(errors, engine._TriggerError); 533 | } 534 | else { 535 | var deferred = engine._ActiveRequests[requestId]; 536 | 537 | delete engine._ActiveRequests[requestId]; 538 | 539 | deferred.reject(errors); 540 | } 541 | }; 542 | 543 | engine._eventHandles = {}; 544 | 545 | engine._Register = function (eventName) { 546 | var trigger = (function (name, engine) { 547 | return function () { 548 | var eventArguments = [name]; 549 | eventArguments.push.apply(eventArguments, arguments); 550 | engine.TriggerEvent.apply(this, eventArguments); 551 | }; 552 | }(eventName, engine)); 553 | 554 | engine._eventHandles[eventName] = engine.on(eventName, trigger); 555 | }; 556 | 557 | engine._removeEventThunk = function (name) { 558 | var handle = engine._eventHandles[name]; 559 | handle.clear(); 560 | delete engine._eventHandles[name]; 561 | }; 562 | 563 | engine._Unregister = function (name) { 564 | if (typeof name === 'string') { 565 | engine._removeEventThunk(name); 566 | } else { 567 | name.forEach(engine._removeEventThunk, engine); 568 | } 569 | }; 570 | 571 | function createMethodStub(name) { 572 | var stub = function() { 573 | var args = Array.prototype.slice.call(arguments); 574 | args.splice(0, 0, name, this._id); 575 | return engine.call.apply(engine, args); 576 | }; 577 | return stub; 578 | } 579 | 580 | engine._boundTypes = {}; 581 | 582 | engine._createInstance = function (args) { 583 | var type = args[0], 584 | id = args[1], 585 | methods = args[2], 586 | constructor = engine._boundTypes[type]; 587 | 588 | if (constructor === undefined) { 589 | constructor = function (id) { 590 | this._id = id; 591 | }; 592 | constructor.prototype.__Type = type; 593 | methods.forEach(function (name) { 594 | constructor.prototype[name] = createMethodStub(type + '_' + name); 595 | }); 596 | engine._boundTypes[type] = constructor; 597 | } 598 | 599 | var instance = new constructor(id); 600 | engine.__observeLifetime(instance); 601 | return instance; 602 | } 603 | 604 | engine._OnReady = function () { 605 | engine._BindingsReady = true; 606 | if (engine._WindowLoaded) { 607 | engine.trigger('Ready'); 608 | } 609 | }; 610 | 611 | engine._OnWindowLoaded = function () { 612 | engine._WindowLoaded = true; 613 | if (engine._BindingsReady) { 614 | engine.trigger('Ready'); 615 | } 616 | }; 617 | 618 | engine._ThrowError = function (error) { 619 | var prependTab = function (s) { return "\t" + s; }; 620 | var errorString = error.name + ": " + error.message + "\n" + 621 | error.stack.split("\n").map(prependTab).join("\n"); 622 | console.error(errorString); 623 | }; 624 | 625 | if (hasOnLoad) { 626 | global.onload = (function (originalWindowLoaded) { 627 | return function () { 628 | if (originalWindowLoaded) { 629 | originalWindowLoaded(); 630 | } 631 | engine._OnWindowLoaded(); 632 | }; 633 | }(global.onload)); 634 | } else { 635 | engine._WindowLoaded = true; 636 | } 637 | 638 | engine.on('_Result', engine._Result, engine); 639 | engine.on('_Register', engine._Register, engine); 640 | engine.on('_Unregister', engine._Unregister, engine); 641 | engine.on('_OnReady', engine._OnReady, engine); 642 | engine.on('_OnError', engine._OnError, engine); 643 | 644 | engine.on('__OnReplayRecordCompleted', function(jsonRecords) { 645 | if (engine.onEventsReplayed) { 646 | engine.onEventsReplayed(); 647 | } 648 | }); 649 | 650 | engine.BindingsReady(VERSION[0], VERSION[1], VERSION[2], VERSION[3]); 651 | 652 | return engine; 653 | }); 654 | -------------------------------------------------------------------------------- /packs/behaviors/scripts/client/client.js: -------------------------------------------------------------------------------- 1 | import '../plugin/index.js'; 2 | import {systemInstance as system, Coordinate, Position, BlockType, Direction, Block } from 'norma-core'; 3 | 4 | 5 | import { utils } from '../utils.js' 6 | 7 | const platform = { 8 | use: function (system) { 9 | var clientSystem = client.registerSystem(0, 0); 10 | this.init(clientSystem, system) 11 | }, 12 | init: function (clientSystem, system) { 13 | system.inject(platform); 14 | let coordinatePlayerLookingAt = undefined 15 | let playerID = undefined 16 | let tick = 0 17 | let buildInstructionsQuery = [] 18 | 19 | function setServerSideOption(key, value) { 20 | let setServerSideOptionEventData = clientSystem.createEventData("NormaConstructor:setServerSideOption") 21 | setServerSideOptionEventData.data.playerID = playerID 22 | setServerSideOptionEventData.data.option.key = key 23 | setServerSideOptionEventData.data.option.value = value 24 | clientSystem.broadcastEvent("NormaConstructor:setServerSideOption", setServerSideOptionEventData) 25 | } 26 | function loggerFactory(user) { 27 | return { 28 | displayChat, displayObject, 29 | log: function (level, message) { 30 | const colorMap = new Map([ 31 | ["verbose", { num: 0, color: "§a" }], 32 | ["debug", { num: 1, color: "§6" }], 33 | ["info", { num: 2, color: "§b" }], 34 | ["warning", { num: 3, color: "§e" }], 35 | ["error", { num: 4, color: "§c" }], 36 | ["fatal", { num: 5, color: "§4" }] 37 | ]) 38 | if (colorMap.get(level).num >= colorMap.get(user.session["__logLevel"]).num) 39 | this.displayChat(colorMap.get(level).color + "[" + level + "]" + message) 40 | }, 41 | logObject: function (level, object) { 42 | this.log(level, JSON.stringify(object, null, ' ')) 43 | } 44 | } 45 | } 46 | this._loggerFactory = loggerFactory; 47 | 48 | 49 | 50 | 51 | clientSystem.initialize = function () { 52 | clientSystem.registerEventData("NormaConstructor:ExecutionResponse", { playerID: undefined, buildInstructions: undefined }) 53 | clientSystem.registerEventData("NormaConstructor:setServerSideOption", { playerID: undefined, option: { key: undefined, value: undefined } }) 54 | clientSystem.registerEventData("NormaConstructor:queryBlockType", { 55 | playerID: undefined, 56 | position: undefined 57 | }) 58 | //TODO:Incorporate the following with the event above. 59 | clientSystem.registerEventData("NZConstructor:blockFetchRequest", { 60 | playerID: undefined, 61 | position: undefined, 62 | requestID: undefined 63 | }) 64 | 65 | clientSystem.registerEventData("NZConstructor:setBlock", { 66 | x: undefined, 67 | y: undefined, 68 | z: undefined, 69 | blockIdentifier: undefined, 70 | blockState: undefined, 71 | playerID: undefined 72 | }) 73 | 74 | clientSystem.listenForEvent("minecraft:hit_result_continuous", (eventData) => { coordinatePlayerLookingAt = eventData.data.position }) 75 | clientSystem.listenForEvent("minecraft:client_entered_world", (eventData) => { 76 | 77 | playerID = utils.misc.generatePlayerIDFromUniqueID(eventData.data.player.__unique_id__) 78 | let user = system.createUser(playerID); 79 | 80 | let logger = loggerFactory(user); 81 | user.session.__logLevel = "verbose"; 82 | user.session.__on = true; 83 | logger.logObject("debug", eventData.data.player) 84 | //Logging: 85 | const scriptLoggerConfig = clientSystem.createEventData("minecraft:script_logger_config"); 86 | scriptLoggerConfig.data.log_errors = true; 87 | scriptLoggerConfig.data.log_information = true; 88 | scriptLoggerConfig.data.log_warnings = true; 89 | clientSystem.broadcastEvent("minecraft:script_logger_config", scriptLoggerConfig); 90 | 91 | //Set default setServerSideOption:(Yes I hate it too) 92 | setServerSideOption("__requestAdditionalPosition", false) 93 | setServerSideOption("__requestAdditionalBlockType", false) 94 | setServerSideOption("__requestAdditionalDirection", false) 95 | 96 | //Wait until the mobile version officially supports scripting API. 97 | 98 | // let loadUIEventData = clientSystem.createEventData("minecraft:load_ui") 99 | // loadUIEventData.data.path = "HUD.html" 100 | // loadUIEventData.data.options = { 101 | // absorbs_input: false, 102 | // always_accepts_input: false, 103 | // force_render_below: true, 104 | // is_showing_menu: false, 105 | // render_game_behind: true, 106 | // render_only_when_topmost: false, 107 | // should_steal_mouse: true 108 | // } 109 | // clientSystem.broadcastEvent("minecraft:load_ui", loadUIEventData) 110 | 111 | //Need to enable "Enable Content Log File" in "General"-"Profile"-"Content Log Settings" 112 | client.log("Logging started. NZ IS JULAO!") 113 | 114 | 115 | }) 116 | 117 | 118 | 119 | clientSystem.listenForEvent("NormaConstructor:displayChatToClient", (eventData) => { 120 | if (playerID == eventData.data.playerID) 121 | displayChat(eventData.data.message) 122 | }) 123 | clientSystem.listenForEvent("NormaConstructor:command", (eventData) => { 124 | let user = system.getUser(playerID); 125 | let logger = loggerFactory(user); 126 | if (playerID == eventData.data.playerID && (user.session["__on"] || eventData.data.command == "show_menu")) { 127 | switch (eventData.data.command) { 128 | case "get_data": { 129 | logger.logObject("debug", eventData.data.additionalData) 130 | 131 | let serveData = { blockType: undefined, position: undefined, direction: undefined } 132 | 133 | let direction = eventData.data.additionalData.direction 134 | if (eventData.data.additionalData.playerRequest["direction"]) serveData.direction = direction 135 | 136 | if (eventData.data.additionalData.isGetAir) serveData.blockType = new BlockType("minecraft:air", null) 137 | 138 | if (eventData.data.additionalData.playerRequest["position"] || eventData.data.additionalData.playerRequest["blockType"]) { 139 | let rawCoordinate = coordinatePlayerLookingAt 140 | if (rawCoordinate == null) { 141 | logger.log("error", "Unable to get the block position. Please retry.") 142 | } 143 | else { 144 | let coordinate = rawCoordinate 145 | function isCoordinatePlaneFacing(num) { 146 | return Math.floor(num) == num 147 | } 148 | if (isCoordinatePlaneFacing(rawCoordinate.x)) coordinate.x -= ((-180 <= direction.y && direction.y < 0) ? 0 : 1) 149 | if (isCoordinatePlaneFacing(rawCoordinate.y)) coordinate.y -= ((-90 <= direction.x && direction.x < 0) ? 0 : 1) 150 | if (isCoordinatePlaneFacing(rawCoordinate.z)) coordinate.z -= ((-90 <= direction.y && direction.y < 90) ? 0 : 1) 151 | coordinate.x = Math.floor(coordinate.x) 152 | coordinate.y = Math.floor(coordinate.y) 153 | coordinate.z = Math.floor(coordinate.z) 154 | 155 | let position = new Position(coordinate, eventData.data.additionalData.tickingArea) 156 | 157 | if (eventData.data.additionalData.playerRequest["position"]) serveData.position = position 158 | if (eventData.data.additionalData.playerRequest["blockType"]) { 159 | let queryBlockTypeEventData = clientSystem.createEventData("NormaConstructor:queryBlockType") 160 | queryBlockTypeEventData.data.position = position 161 | queryBlockTypeEventData.data.playerID = playerID 162 | clientSystem.broadcastEvent("NormaConstructor:queryBlockType", queryBlockTypeEventData) 163 | } 164 | } 165 | } 166 | storeData(user, serveData.blockType, serveData.position, serveData.direction) 167 | break; 168 | } 169 | case "remove_last_position": { 170 | logger.log("info", "Removing the last position...") 171 | user.removePosition() 172 | break; 173 | } 174 | case "remove_last_blocktype": { 175 | logger.log("info", "Removing the last blockType...") 176 | user.removeBlockType() 177 | break; 178 | } 179 | case "remove_last_direction": { 180 | logger.log("info", "Removing the last direction...") 181 | user.removeDirection() 182 | break; 183 | } 184 | case "choose_next_generator": { 185 | logger.log("info", "Choosing next generator...") 186 | user.nextGenerator() 187 | logger.log("debug", "Current generator:") 188 | logger.logObject("debug", user.getCurrentGeneratorName()) 189 | break; 190 | } 191 | case "show_saved_data": { 192 | //logger.log("info", "Current positionArray:") 193 | //logger.logObject("info", generatorArray[generatorIndex].positionArray) 194 | //logger.log("info", "Current blockTypeArray:") 195 | //logger.logObject("info", generatorArray[generatorIndex].blockTypeArray) 196 | //logger.log("info", "Current directionArray:") 197 | //logger.logObject("info", generatorArray[generatorIndex].directionArray) 198 | logger.log("info", "Current generator state:") 199 | logger.logObject("info", user.getCurrentState()) 200 | logger.log("info", "Current session:") 201 | logger.logObject("info", user.session) 202 | break; 203 | } 204 | case "execute": { 205 | execute(user); 206 | break; 207 | } 208 | case "show_menu": { 209 | let loadUIEventData = clientSystem.createEventData("minecraft:load_ui") 210 | loadUIEventData.data.path = "menu/menu.html" 211 | clientSystem.broadcastEvent("minecraft:load_ui", loadUIEventData) 212 | break; 213 | } 214 | case "read_tag": { 215 | function parseTag(tag) { 216 | user.runNOS(tag, undefined); 217 | } 218 | eventData.data.additionalData.forEach((tag) => { 219 | if (tag) parseTag(tag) 220 | }) 221 | break; 222 | } 223 | } 224 | } 225 | }) 226 | clientSystem.listenForEvent("NormaConstructor:serveData", (eventData) => { 227 | let user = system.getUser(playerID); 228 | let logger = loggerFactory(user); 229 | 230 | if (playerID == eventData.data.playerID && user.session["__on"]) { 231 | logger.log("debug", "RECEIVE:") 232 | logger.logObject("debug", eventData) 233 | storeData(user, eventData.data.blockType, eventData.data.position, eventData.data.direction) 234 | 235 | } 236 | }) 237 | 238 | clientSystem.listenForEvent("minecraft:ui_event", (eventData) => { 239 | let user = system.getUser(playerID); 240 | if (eventData.data.slice(0, eventData.data.indexOf(":")) == "NormaConstructor") { 241 | let uiData = JSON.parse(eventData.data.slice(eventData.data.indexOf(":") + 1)) 242 | 243 | switch (uiData.type) { 244 | //Must wait until the UI is loaded 245 | 246 | case "get": { 247 | let sendUIEventData = clientSystem.createEventData("minecraft:send_ui_event") 248 | sendUIEventData.data.eventIdentifier = "NormaConstructor:get" 249 | sendUIEventData.data.data = JSON.stringify(user.getCurrentState()[uiData.data], null, ' ') 250 | clientSystem.broadcastEvent("minecraft:send_ui_event", sendUIEventData) 251 | break; 252 | } 253 | case "set": { 254 | user.getCurrentState()[uiData.data.key] = uiData.data.value 255 | break; 256 | } 257 | case "callUIHandler": { 258 | user.UIHandler(uiData.data) 259 | break; 260 | } 261 | case "command": { 262 | switch (uiData.data) { 263 | case "reload": { 264 | let sendUIEventData = clientSystem.createEventData("minecraft:send_ui_event") 265 | sendUIEventData.data.eventIdentifier = "NormaConstructor:reload" 266 | sendUIEventData.data.data = JSON.stringify({ 267 | description: { 268 | name: user.getCurrentGeneratorName(), 269 | usage: { 270 | positionUsage: [], 271 | blockTypeUsage: [], 272 | directionUsage: [], 273 | optionUsage: user.getCurrentUI() 274 | }, 275 | }, 276 | option: user.getCurrentState() 277 | }, null, ' ') 278 | clientSystem.broadcastEvent("minecraft:send_ui_event", sendUIEventData) 279 | break; 280 | } 281 | case "execute": { 282 | execute(user); 283 | break; 284 | } 285 | case "closeMenu": { 286 | let closeMenuEventData = clientSystem.createEventData("minecraft:unload_ui") 287 | closeMenuEventData.data.path = "menu/menu.html" 288 | clientSystem.broadcastEvent("minecraft:unload_ui", closeMenuEventData) 289 | break; 290 | } 291 | case "chooseNextGenerator": { 292 | user.nextGenerator(); 293 | break; 294 | } 295 | case "chooseLastGenerator": { 296 | user.perviousGenerator() 297 | } 298 | } 299 | break; 300 | } 301 | case "setServerSideOption": { 302 | setServerSideOption(uiData.data.key, uiData.data.value) 303 | break; 304 | } 305 | case "setLocalOption": { 306 | setSession(user, uiData.data.key, uiData.data.value) 307 | break; 308 | } 309 | case "displayChat": { 310 | displayChat(uiData.data) 311 | break; 312 | } 313 | } 314 | } 315 | }) 316 | } 317 | 318 | 319 | 320 | 321 | clientSystem.update = function () { 322 | 323 | if ((++tick) % 5 == 0 && buildInstructionsQuery.length > 0) { 324 | 325 | let executionResponseEventData = clientSystem.createEventData("NormaConstructor:ExecutionResponse") 326 | executionResponseEventData.data.playerID = playerID 327 | executionResponseEventData.data.buildInstructions = buildInstructionsQuery.splice(0, 100) 328 | clientSystem.broadcastEvent("NormaConstructor:ExecutionResponse", executionResponseEventData) 329 | } 330 | }; 331 | 332 | clientSystem.shutdown = function () { 333 | let user = system.getUser(playerID); 334 | user.exit(); 335 | //TODO:Ask the server to delete the profile.(Maybe...not necessary.) 336 | }; 337 | 338 | function storeData(user, blockType, position, direction) { 339 | if (blockType != undefined) user.addBlockType(blockType) 340 | if (position != undefined) user.addPosition(position) 341 | if (direction != undefined) user.addDirection(direction) 342 | if (user.getCurrentState()["__executeOnAllSatisfied"]) execute(user) 343 | } 344 | async function execute(user) { 345 | let logger = loggerFactory(user); 346 | logger.log("info", "Start validating parameters..."); 347 | let isVaild = await user.isValidParameter(); 348 | if (isVaild) { 349 | logger.log("info", "Now Execution started."); 350 | 351 | //The "buildInstructions" was named "blockArray" as it only consisted of blocks that are to be placed. 352 | let buildInstructions = await user.generate(); 353 | if(buildInstructions === undefined) return; 354 | 355 | logger.logObject("verbose", buildInstructions) 356 | 357 | buildInstructionsQuery = buildInstructionsQuery.concat(buildInstructions) 358 | //The following line is the original code which append the array to the query. Sadly, it will throw an error when there's too many blocks. 359 | //I...am not even sure if it is fixed. 360 | //Array.prototype.push.apply(buildInstructionsQuery, buildInstructions); 361 | 362 | //generatorArray[generatorIndex].postGenerate(); 363 | } 364 | } 365 | function setSession(user, key, value) { 366 | user.session[key] = value 367 | } 368 | 369 | function displayObject(object) { 370 | displayChat(JSON.stringify(object, null, ' ')) 371 | } 372 | function displayChat(message) { 373 | let eventData = clientSystem.createEventData("minecraft:display_chat_event"); 374 | eventData.data.message = message; 375 | clientSystem.broadcastEvent("minecraft:display_chat_event", eventData); 376 | 377 | } 378 | 379 | class BlockFetch { 380 | constructor() { 381 | this.idToResolve = new Map() 382 | clientSystem.listenForEvent("NZConstructor:blockFetchResponse", function (eventData) { 383 | if (eventData.data.playerID == playerID) { 384 | let resolve = this.idToResolve.get(eventData.data.requestID) 385 | resolve(eventData.data.blockType) 386 | this.idToResolve.delete(eventData.data.requestID) 387 | } 388 | }.bind(this)) 389 | } 390 | registerRequest(id, resolve) { 391 | this.idToResolve.set(id, resolve) 392 | } 393 | get(tickingArea, x, y, z) { 394 | let position = new Position(new Coordinate(x, y, z), tickingArea) 395 | let blockFetchRequestEventData = clientSystem.createEventData("NZConstructor:blockFetchRequest") 396 | blockFetchRequestEventData.data.position = position 397 | blockFetchRequestEventData.data.playerID = playerID 398 | let requestID 399 | do { 400 | requestID = Math.random() 401 | } 402 | while (this.idToResolve.has(requestID)) 403 | blockFetchRequestEventData.data.requestID = requestID 404 | clientSystem.broadcastEvent("NZConstructor:blockFetchRequest", blockFetchRequestEventData) 405 | return new Promise((resolve, reject) => { 406 | this.registerRequest(requestID, resolve) 407 | }) 408 | } 409 | } 410 | 411 | const blockFetch = new BlockFetch() 412 | async function getBlock(tickingArea, x, y, z) { 413 | let blockType = await blockFetch.get(tickingArea, x, y, z) 414 | return blockType 415 | } 416 | function setBlock(user, x, y, z, blockIdentifier, blockState) { 417 | let logger = loggerFactory(user); 418 | logger.log("verbose", "NZ is JULAO") 419 | let setBlockEventData = clientSystem.createEventData("NZConstructor:setBlock") 420 | setBlockEventData.data = { x: x, y: y, z: z, blockIdentifier: blockIdentifier, blockState: blockState, playerID: playerID } 421 | clientSystem.broadcastEvent("NZConstructor:setBlock", setBlockEventData) 422 | logger.logObject("verbose", setBlockEventData) 423 | } 424 | }, 425 | createRuntime(id) { 426 | let user = system.getUser(id); 427 | let loggerFactory = this._loggerFactory; 428 | return { 429 | logger: loggerFactory(user), 430 | }; 431 | } 432 | } 433 | 434 | platform.use(system) -------------------------------------------------------------------------------- /packs/behaviors/scripts/plugin/nc/utils.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-unused-vars 2 | import { Coordinate, BlockType, Direction, Generator } from "norma-core"; 3 | const blockDirectionTable = { 4 | "huge_mushroom_bits": { 5 | "default": { 6 | "none": 0, 7 | "-x+y-z": 1, 8 | "+y-z": 2, 9 | "+x+y-z": 3, 10 | "-x+y": 4, 11 | "+y": 5, 12 | "+x+y": 6, 13 | "-x+y+z": 7, 14 | "+y+z": 8, 15 | "+x+y+z": 9, 16 | "+y-y": 10, 17 | "null": 11, 18 | "nil": 12, 19 | "NaN": 13, 20 | "all": 14, 21 | "stem": 15 22 | } 23 | }, 24 | "pillar_axis": { 25 | "default": { 26 | "+x": "x", 27 | "-x": "x", 28 | "+y": "y", 29 | "-y": "y", 30 | "+z": "z", 31 | "-z": "z" 32 | } 33 | }, 34 | "axis": { 35 | "default": { 36 | "+x": "x", 37 | "-x": "x", 38 | "+z": "z", 39 | "-z": "z" 40 | } 41 | }, 42 | "facing_direction": { 43 | "default": { 44 | "+x": 5, 45 | "-x": 4, 46 | "+y": 1, 47 | "-y": 0, 48 | "+z": 3, 49 | "-z": 2 50 | } 51 | }, 52 | "direction": { 53 | "minecraft:bed": { 54 | "+x": 3, 55 | "-x": 1, 56 | "+z": 0, 57 | "-z": 2 58 | }, 59 | "minecraft:wooden_door": { 60 | "+x": 0, 61 | "-x": 1, 62 | "+z": 2, 63 | "-z": 3 64 | }, 65 | "minecraft:iron_door": { 66 | "+x": 0, 67 | "-x": 1, 68 | "+z": 2, 69 | "-z": 3 70 | }, 71 | "minecraft:lit_pumpkin": { 72 | "+x": 3, 73 | "-x": 1, 74 | "+z": 0, 75 | "-z": 2 76 | }, 77 | "minecraft:trapdoor": { 78 | "+x": 0, 79 | "-x": 1, 80 | "+z": 2, 81 | "-z": 3 82 | }, 83 | "minecraft:fence_gate": { 84 | "+x": 3, 85 | "-x": 1, 86 | "+z": 0, 87 | "-z": 2 88 | }, 89 | "minecraft:end_portal_frame": { 90 | "+x": 3, 91 | "-x": 1, 92 | "+z": 0, 93 | "-z": 2 94 | }, 95 | "minecraft:cocoa": { 96 | "+x": 3, 97 | "-x": 1, 98 | "+z": 0, 99 | "-z": 2 100 | }, 101 | "minecraft:tripwire_hook": { 102 | "+x": 3, 103 | "-x": 1, 104 | "+z": 0, 105 | "-z": 2 106 | }, 107 | "minecraft:anvil": { 108 | "+x": 2, 109 | "-x": 0, 110 | "+z": 3, 111 | "-z": 1 112 | }, 113 | "minecraft:unpowered_repeater": { 114 | "+x": 3, 115 | "-x": 1, 116 | "+z": 0, 117 | "-z": 2 118 | }, 119 | "minecraft:powered_repeater": { 120 | "+x": 3, 121 | "-x": 1, 122 | "+z": 0, 123 | "-z": 2 124 | }, 125 | "minecraft:unpowered_comparator": { 126 | "+x": 3, 127 | "-x": 1, 128 | "+z": 0, 129 | "-z": 2 130 | }, 131 | "minecraft:powered_comparator": { 132 | "+x": 3, 133 | "-x": 1, 134 | "+z": 0, 135 | "-z": 2 136 | }, 137 | "minecraft:iron_trapdoor": { 138 | "+x": 0, 139 | "-x": 1, 140 | "+z": 2, 141 | "-z": 3 142 | }, 143 | "minecraft:spruce_fence_gate": { 144 | "+x": 3, 145 | "-x": 1, 146 | "+z": 0, 147 | "-z": 2 148 | }, 149 | "minecraft:birch_fence_gate": { 150 | "+x": 3, 151 | "-x": 1, 152 | "+z": 0, 153 | "-z": 2 154 | }, 155 | "minecraft:jungle_fence_gate": { 156 | "+x": 3, 157 | "-x": 1, 158 | "+z": 0, 159 | "-z": 2 160 | }, 161 | "minecraft:dark_oak_fence_gate": { 162 | "+x": 3, 163 | "-x": 1, 164 | "+z": 0, 165 | "-z": 2 166 | }, 167 | "minecraft:acacia_fence_gate": { 168 | "+x": 3, 169 | "-x": 1, 170 | "+z": 0, 171 | "-z": 2 172 | }, 173 | "minecraft:spruce_door": { 174 | "+x": 0, 175 | "-x": 1, 176 | "+z": 2, 177 | "-z": 3 178 | }, 179 | "minecraft:birch_door": { 180 | "+x": 0, 181 | "-x": 1, 182 | "+z": 2, 183 | "-z": 3 184 | }, 185 | "minecraft:jungle_door": { 186 | "+x": 0, 187 | "-x": 1, 188 | "+z": 2, 189 | "-z": 3 190 | }, 191 | "minecraft:acacia_door": { 192 | "+x": 0, 193 | "-x": 1, 194 | "+z": 2, 195 | "-z": 3 196 | }, 197 | "minecraft:dark_oak_door": { 198 | "+x": 0, 199 | "-x": 1, 200 | "+z": 2, 201 | "-z": 3 202 | }, 203 | "minecraft:acacia_trapdoor": { 204 | "+x": 0, 205 | "-x": 1, 206 | "+z": 2, 207 | "-z": 3 208 | }, 209 | "minecraft:birch_trapdoor": { 210 | "+x": 0, 211 | "-x": 1, 212 | "+z": 2, 213 | "-z": 3 214 | }, 215 | "minecraft:dark_oak_trapdoor": { 216 | "+x": 0, 217 | "-x": 1, 218 | "+z": 2, 219 | "-z": 3 220 | }, 221 | "minecraft:jungle_trapdoor": { 222 | "+x": 0, 223 | "-x": 1, 224 | "+z": 2, 225 | "-z": 3 226 | }, 227 | "minecraft:spruce_trapdoor": { 228 | "+x": 0, 229 | "-x": 1, 230 | "+z": 2, 231 | "-z": 3 232 | }, 233 | "minecraft:carved_pumpkin": { 234 | "+x": 3, 235 | "-x": 1, 236 | "+z": 0, 237 | "-z": 2 238 | }, 239 | "minecraft:pumpkin": { 240 | "+x": 3, 241 | "-x": 1, 242 | "+z": 0, 243 | "-z": 2 244 | }, 245 | "minecraft:lectern": { 246 | "+x": 3, 247 | "-x": 1, 248 | "+z": 0, 249 | "-z": 2 250 | }, 251 | "minecraft:grindstone": { 252 | "+x": 3, 253 | "-x": 1, 254 | "+z": 0, 255 | "-z": 2 256 | }, 257 | "minecraft:loom": { 258 | "+x": 3, 259 | "-x": 1, 260 | "+z": 0, 261 | "-z": 2 262 | }, 263 | "minecraft:bell": { 264 | "+x": 3, 265 | "-x": 1, 266 | "+z": 0, 267 | "-z": 2 268 | }, 269 | "minecraft:campfire": { 270 | "+x": 3, 271 | "-x": 1, 272 | "+z": 0, 273 | "-z": 2 274 | }, 275 | "default": { 276 | "+x": 3, 277 | "-x": 1, 278 | "+z": 0, 279 | "-z": 2 280 | } 281 | }, 282 | "ground_sign_direction": { 283 | "default": { 284 | "0": 0, 285 | "22.5": 1, 286 | "45": 2, 287 | "67.5": 3, 288 | "90": 4, 289 | "112.5": 5, 290 | "135": 6, 291 | "157.5": 7, 292 | "180": 8, 293 | "-157.5": 9, 294 | "-135": 10, 295 | "-112.5": 11, 296 | "-90": 12, 297 | "-67.5": 13, 298 | "-45": 14, 299 | "-22.5": 15 300 | } 301 | }, 302 | "rail_direction": { 303 | "default": { 304 | "x": 0, 305 | "z": 1, 306 | "+x": 2, 307 | "-x": 3, 308 | "+z": 5, 309 | "-z": 4 310 | } 311 | }, 312 | "torch_facing_direction": { 313 | "default": { 314 | "-x": "west", 315 | "+x": "east", 316 | "-z": "north", 317 | "+z": "south", 318 | "y": "top" 319 | } 320 | }, 321 | "weirdo_direction": { 322 | "default": { 323 | "+x": 0, 324 | "-x": 1, 325 | "+z": 2, 326 | "-z": 3 327 | } 328 | }, 329 | "lever_direction": { 330 | "default": { 331 | "x-y": "down_east_west", 332 | "+x": "east", 333 | "-x": "west", 334 | "+z": "south", 335 | "-z": "north", 336 | "z+y": "up_north_south", 337 | "x+y": "up_east_west", 338 | "z-y": "down_north_south" 339 | } 340 | }, 341 | "portal_axis": { 342 | "default": { 343 | "+x": "x", 344 | "-x": "x", 345 | "+z": "z", 346 | "-z": "z" 347 | } 348 | }, 349 | "vine_direction_bits": { 350 | "default": { 351 | "NZ IS JULAO": 0, 352 | "+z": 1, 353 | "-x": 2, 354 | "-x+z": 3, 355 | "-z": 4, 356 | "+z-z": 5, 357 | "-x-z": 6, 358 | "-x+z-z": 7, 359 | "+x": 8, 360 | "+x+z": 9, 361 | "+x-x": 10, 362 | "+x-x+z": 11, 363 | "+x-z": 12, 364 | "+x+z-z": 13, 365 | "+x-x-z": 14, 366 | "+x-x+z-z": 15 367 | } 368 | } 369 | }; 370 | let translator = { 371 | directionMarkToDirection: function (directionMark) { 372 | switch (directionMark) { 373 | case "+x": return new Direction(0, -90); 374 | case "-x": return new Direction(0, 90); 375 | case "+y": return new Direction(-90, 0); 376 | case "-y": return new Direction(90, 0); 377 | case "+z": return new Direction(0, 0); 378 | case "-z": return new Direction(0, 180); 379 | 380 | case "x": return new Direction(0, -90); 381 | case "y": return new Direction(90, 0); 382 | case "z": return new Direction(0, 0); 383 | default: { 384 | return "Ahhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"; 385 | } 386 | } 387 | } 388 | }; 389 | let utils = { 390 | setter: { 391 | setLogger: function (logger) { 392 | utils.logger = logger 393 | } 394 | }, 395 | misc: { 396 | generatePlayerIDFromUniqueID: function (uniqueID) { 397 | let low = uniqueID["64bit_low"]%10000 398 | let high = uniqueID["64bit_high"]%10000 399 | //hash function: 400 | 401 | return (low + high) * (low + high + 1) / 2 + high; 402 | } 403 | }, 404 | generators: { 405 | canonical: { 406 | addFunction: function (type, data, target) { 407 | let indexOfVacancy = target.indexOf(undefined) 408 | if (indexOfVacancy == -1) utils.logger.log("warning", `Too many ${type}s!New one is ignored`) 409 | else { 410 | target[indexOfVacancy] = data 411 | utils.logger.log("info", `New ${type} accepted.`) 412 | } 413 | }, 414 | removeFunction: function (index, target) { 415 | if (index === undefined) 416 | for (index = target.length - 1; index >= 0 && target[index] == undefined; index--); 417 | if (index >= 0) target[index] = undefined 418 | utils.logger.logObject("info", target) 419 | }, 420 | validateParameter: function () { 421 | let result = new String() 422 | if (this.blockTypeArray.indexOf(undefined) != -1) 423 | result += "Too few blockTypes!Refusing to execute.\n" 424 | if (this.positionArray.indexOf(undefined) != -1) 425 | result += "Too few positions!Refusing to execute.\n" 426 | if (this.directionArray.indexOf(undefined) != -1) 427 | result += "Too few directions!Refusing to execute." 428 | if (result == "") result = "success" 429 | else utils.logger.log("error", result) 430 | 431 | return result; 432 | }, 433 | postGenerate: function () { 434 | this.positionArray.fill(undefined) 435 | this.blockTypeArray.fill(undefined) 436 | this.directionArray.fill(undefined) 437 | }, 438 | //A generator that is canonical must : 439 | //1.have finite fixed(?) numbers of parameters, in which the arrays are initially filled with undefined. 440 | //2.don't need to verifiy options. 441 | //3.after the generation, the generator only need to reset the array. 442 | generatorConstrctor: function ({ 443 | description, 444 | criteria: { 445 | positionArrayLength, 446 | blockTypeArrayLength, 447 | directionArrayLength 448 | }, 449 | option, 450 | method: { 451 | generate, UIHandler 452 | } 453 | }) { 454 | return new Generator( 455 | description, 456 | new Array(positionArrayLength).fill(undefined), 457 | new Array(blockTypeArrayLength).fill(undefined), 458 | new Array(directionArrayLength).fill(undefined), 459 | option, 460 | function (position) { utils.generators.canonical.addFunction("position", position, this.positionArray) }, 461 | function (blockType) { utils.generators.canonical.addFunction("block type", blockType, this.blockTypeArray) }, 462 | function (direction) { utils.generators.canonical.addFunction("direction", direction, this.directionArray) }, 463 | function (index) { utils.generators.canonical.removeFunction(index, this.positionArray) }, 464 | function (index) { utils.generators.canonical.removeFunction(index, this.blockTypeArray) }, 465 | function (index) { utils.generators.canonical.removeFunction(index, this.directionArray) }, 466 | function () { return utils.generators.canonical.validateParameter.call(this) }, 467 | generate, 468 | function () { utils.generators.canonical.postGenerate.call(this) }, 469 | UIHandler 470 | ) 471 | } 472 | } 473 | }, 474 | geometry: { 475 | getDirectionMark: { 476 | horizontal: function (theta) { 477 | if (-45 <= theta && theta <= 45) return "+z" 478 | else if (-135 <= theta && theta <= -45) return "+x" 479 | else if (45 <= theta && theta <= 135) return "-x" 480 | else return "-z" 481 | } 482 | }, 483 | }, 484 | coordinateGeometry: { 485 | transform: function (f, g, h) { 486 | return (coordinate) => { 487 | return new Coordinate( 488 | f(coordinate.x, coordinate.y, coordinate.z), 489 | g(coordinate.x, coordinate.y, coordinate.z), 490 | h(coordinate.x, coordinate.y, coordinate.z), 491 | ); 492 | }; 493 | }, 494 | 495 | generateLine: function (x, y, z, t_span, constraint, t_step) { 496 | //TODO: t_step<0?t_span[0]>t_span[1]? 497 | let coordinateArray = []; 498 | 499 | function isRedundant(coordinateArray, newCoordinate) { 500 | if (coordinateArray.length == 0) return false; 501 | return ( 502 | coordinateArray[coordinateArray.length - 1].x == newCoordinate.x && 503 | coordinateArray[coordinateArray.length - 1].y == newCoordinate.y && 504 | coordinateArray[coordinateArray.length - 1].z == newCoordinate.z 505 | ) 506 | } 507 | 508 | if (t_step == undefined || t_step < 0.0001/* Prevent performance issue. */) t_step = 0.0001 509 | for (let t = t_span[0]; t <= t_span[1]; t += t_step) { 510 | let newCoordinate = new Coordinate(Math.round(x(t)), Math.round(y(t)), Math.round(z(t))); 511 | if (!isRedundant(coordinateArray, newCoordinate) && constraint(newCoordinate.x, newCoordinate.y, newCoordinate.z, t)) { 512 | 513 | coordinateArray.push(newCoordinate); 514 | } 515 | } 516 | return coordinateArray; 517 | }, 518 | generateLineWithTwoPoints: function (x_start, y_start, z_start, x_end, y_end, z_end) { 519 | let t_span = [0, 1]; 520 | let x_coefficient = (x_end - x_start) / (t_span[1] - t_span[0]); 521 | let y_coefficient = (y_end - y_start) / (t_span[1] - t_span[0]); 522 | let z_coefficient = (z_end - z_start) / (t_span[1] - t_span[0]); 523 | return this.generateLine( 524 | (t) => { return ((t - t_span[0]) * x_coefficient + x_start); }, 525 | (t) => { return ((t - t_span[0]) * y_coefficient + y_start); }, 526 | (t) => { return ((t - t_span[0]) * z_coefficient + z_start); }, 527 | t_span, (x, y, z, t) => { return true }, Math.min(x_coefficient == 0 ? t_span[1] - t_span[0] : 1 / x_coefficient, y_coefficient == 0 ? t_span[1] - t_span[0] : 1 / y_coefficient, z_coefficient == 0 ? t_span[1] - t_span[0] : 1 / z_coefficient)); 528 | }, 529 | generateTriangle: function (x1, y1, z1, x2, y2, z2, x3, y3, z3) { 530 | let coordinateArray = []; 531 | coordinateArray = coordinateArray.concat(this.generateLineWithTwoPoints(x1, y1, z1, x2, y2, z2)) 532 | coordinateArray = coordinateArray.concat(this.generateLineWithTwoPoints(x2, y2, z2, x3, y3, z3)) 533 | coordinateArray = coordinateArray.concat(this.generateLineWithTwoPoints(x3, y3, z3, x1, y1, z1)) 534 | 535 | return coordinateArray 536 | }, 537 | generateFilledPlanarTriangle: function (x1, y1, z1, x2, y2, z2, x3, y3, z3) { 538 | const A = (y2 - y1) * (z3 - z1) - (y3 - y1) * (z2 - z1) 539 | const B = -((x2 - x1) * (z3 - z1) - (x3 - x1) * (z2 - z1)) 540 | const C = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1) 541 | const G = new Coordinate((x1 + x2 + x3) / 3, (y1 + y2 + y3) / 3, (z1 + z2 + z3) / 3) 542 | let x_span = [Math.min(x1, x2, x3), Math.max(x1, x2, x3)] 543 | let y_span = [Math.min(y1, y2, y3), Math.max(y1, y2, y3)] 544 | let z_span = [Math.min(z1, z2, z3), Math.max(z1, z2, z3)] 545 | 546 | function signedDistance(x_start, y_start, x_end, y_end) { 547 | return (x, y) => { return (y_end - y_start) * x - (x_end - x_start) * y + x_end * y_start - x_start * y_end } 548 | } 549 | 550 | return this.generateWithConstraint(x_span, y_span, z_span, (x, y, z) => { 551 | return (Math.abs(A * (x - x1) + B * (y - y1) + C * (z - z1)) < Math.sqrt(A * A + B * B + C * C) / 2) 552 | && 553 | ( 554 | signedDistance(x1, y1, x2, y2)(x, y) * signedDistance(x1, y1, x2, y2)(G.x, G.y) >= 0 && 555 | signedDistance(x1, y1, x3, y3)(x, y) * signedDistance(x1, y1, x3, y3)(G.x, G.y) >= 0 && 556 | signedDistance(x2, y2, x3, y3)(x, y) * signedDistance(x2, y2, x3, y3)(G.x, G.y) >= 0 && 557 | 558 | signedDistance(x1, z1, x2, z2)(x, z) * signedDistance(x1, z1, x2, z2)(G.x, G.z) >= 0 && 559 | signedDistance(x1, z1, x3, z3)(x, z) * signedDistance(x1, z1, x3, z3)(G.x, G.z) >= 0 && 560 | signedDistance(x2, z2, x3, z3)(x, z) * signedDistance(x2, z2, x3, z3)(G.x, G.z) >= 0 && 561 | 562 | signedDistance(y1, z1, y2, z2)(y, z) * signedDistance(y1, z1, y2, z2)(G.y, G.z) >= 0 && 563 | signedDistance(y1, z1, y3, z3)(y, z) * signedDistance(y1, z1, y3, z3)(G.y, G.z) >= 0 && 564 | signedDistance(y2, z2, y3, z3)(y, z) * signedDistance(y2, z2, y3, z3)(G.y, G.z) >= 0 565 | ) 566 | }) 567 | }, 568 | generateSphere: function (x, y, z, r) { 569 | return this.generateWithConstraint([x - r, x + r], [y - r, y + r], [z - r, z + r], (_x, _y, _z) => { return (_x - x) * (_x - x) + (_y - y) * (_y - y) + (_z - z) * (_z - z) < r * r }) 570 | }, 571 | generateHollowSphere: function (x, y, z, r) { 572 | return this.generateWithConstraint([x - r, x + r], [y - r, y + r], [z - r, z + r], (_x, _y, _z) => { return (_x - x) * (_x - x) + (_y - y) * (_y - y) + (_z - z) * (_z - z) >= (r - 1) * (r - 1) && (_x - x) * (_x - x) + (_y - y) * (_y - y) + (_z - z) * (_z - z) < r * r }) 573 | }, 574 | generateWithConstraint: function (x_span, y_span, z_span, constraint) { 575 | let coordinateArray = []; 576 | 577 | 578 | 579 | const x_step = 1 / 3; 580 | const y_step = 1 / 3; 581 | const z_step = 1 / 3; 582 | 583 | 584 | if (x_span[0] >= x_span[1]) 585 | [x_span[0], x_span[1]] = [x_span[1], x_span[0]] 586 | 587 | if (y_span[0] >= y_span[1]) 588 | [y_span[0], y_span[1]] = [y_span[1], y_span[0]] 589 | 590 | if (z_span[0] >= z_span[1]) 591 | [z_span[0], z_span[1]] = [z_span[1], z_span[0]] 592 | 593 | 594 | function verifier(x, y, z) { 595 | for (let _x = Math.max(x - x_step, x_span[0]); _x <= Math.min(x + x_step, x_span[1]); _x += x_step) 596 | for (let _z = Math.max(z - z_step, z_span[0]); _z <= Math.min(z + z_step, z_span[1]); _z += z_step) 597 | for (let _y = Math.max(y - y_step, y_span[0]); _y <= Math.min(y + y_step, y_span[1]); _y += y_step) 598 | if (constraint(_x, _y, _z)) return true 599 | return false 600 | } 601 | 602 | for (let x = x_span[0]; x <= x_span[1]; x += 1) 603 | for (let z = z_span[0]; z <= z_span[1]; z += 1) 604 | for (let y = y_span[0]; y <= y_span[1]; y += 1) 605 | if (verifier(x, y, z)) 606 | coordinateArray.push(new Coordinate(x, y, z)) 607 | // function isRedundant(coordinateArray, newCoordinate) { 608 | // if (coordinateArray.length == 0) return false; 609 | // return ( 610 | // coordinateArray[coordinateArray.length - 1].x == newCoordinate.x && 611 | // coordinateArray[coordinateArray.length - 1].y == newCoordinate.y && 612 | // coordinateArray[coordinateArray.length - 1].z == newCoordinate.z 613 | // ) 614 | // } 615 | // for (let x = x_span[0]; x <= x_span[1]; x += x_step) 616 | // for (let z = z_span[0]; z <= z_span[1]; z += z_step) 617 | // for (let y = y_span[0]; y <= y_span[1]; y += y_step) 618 | // if (constraint(x, y, z)) { 619 | // let newCoordinate = new Coordinate(Math.round(x), Math.round(y), Math.round(z)) 620 | // if (!isRedundant(coordinateArray, newCoordinate)) 621 | // coordinateArray.push(newCoordinate) 622 | // } 623 | 624 | 625 | 626 | return coordinateArray 627 | 628 | }, 629 | withBresenhamAlgorithm: { 630 | //Shamelessly adopted from http://members.chello.at/~easyfilter/bresenham.html ( 631 | generateLineWithTwoPoints: function (x0, y0, z0, x1, y1, z1) { 632 | x0 = Math.round(x0) 633 | y0 = Math.round(y0) 634 | z0 = Math.round(z0) 635 | x1 = Math.round(x1) 636 | y1 = Math.round(y1) 637 | z1 = Math.round(z1) 638 | let coordinateArray = [] 639 | let dx = Math.abs(x1 - x0), sx = x0 < x1 ? 1 : -1; 640 | let dy = Math.abs(y1 - y0), sy = y0 < y1 ? 1 : -1; 641 | let dz = Math.abs(z1 - z0), sz = z0 < z1 ? 1 : -1; 642 | let dm = Math.max(dx, dy, dz), i = dm; 643 | x1 = y1 = z1 = Math.floor(dm / 2); 644 | 645 | for (; ;) { 646 | coordinateArray.push(new Coordinate(x0, y0, z0)); 647 | if (i-- == 0) break; 648 | x1 -= dx; if (x1 < 0) { x1 += dm; x0 += sx; } 649 | y1 -= dy; if (y1 < 0) { y1 += dm; y0 += sy; } 650 | z1 -= dz; if (z1 < 0) { z1 += dm; z0 += sz; } 651 | } 652 | return coordinateArray 653 | }, 654 | generate2DEllipse: function (xm, ym, a, b) { 655 | let coordinateArray = [] 656 | function setPixel(x, y) { 657 | coordinateArray.push(new Coordinate(x, y, 0)) 658 | } 659 | var x = -a, y = 0; /* II. quadrant from bottom left to top right */ 660 | var e2, dx = (1 + 2 * x) * b * b; /* error increment */ 661 | var dy = x * x, err = dx + dy; /* error of 1.step */ 662 | 663 | do { 664 | setPixel(xm - x, ym + y); /* I. Quadrant */ 665 | setPixel(xm + x, ym + y); /* II. Quadrant */ 666 | setPixel(xm + x, ym - y); /* III. Quadrant */ 667 | setPixel(xm - x, ym - y); /* IV. Quadrant */ 668 | e2 = 2 * err; 669 | if (e2 >= dx) { x++; err += dx += 2 * b * b; } /* x step */ 670 | if (e2 <= dy) { y++; err += dy += 2 * a * a; } /* y step */ 671 | } while (x <= 0); 672 | 673 | while (y++ < b) { /* too early stop for flat ellipses with a=1, */ 674 | setPixel(xm, ym + y); /* -> finish tip of ellipse */ 675 | setPixel(xm, ym - y); 676 | } 677 | return coordinateArray 678 | }, 679 | 680 | generate2DCircle: function (xm, ym, r) { 681 | let coordinateArray = [] 682 | function setPixel(x, y) { 683 | coordinateArray.push(new Coordinate(x, y, 0)) 684 | } 685 | var x = -r, y = 0, err = 2 - 2 * r; /* bottom left to top right */ 686 | do { 687 | setPixel(xm - x, ym + y); /* I. Quadrant +x +y */ 688 | setPixel(xm - y, ym - x); /* II. Quadrant -x +y */ 689 | setPixel(xm + x, ym - y); /* III. Quadrant -x -y */ 690 | setPixel(xm + y, ym + x); /* IV. Quadrant +x -y */ 691 | r = err; 692 | if (r <= y) err += ++y * 2 + 1; /* y step */ 693 | if (r > x || err > y) err += ++x * 2 + 1; /* x step */ 694 | } while (x < 0); 695 | return coordinateArray 696 | }, 697 | 698 | //Unsatisfactory. Will cause holes. 699 | generateFilledPlanarTriangle: function (x1, y1, z1, x2, y2, z2, x3, y3, z3) { 700 | let coordinateSet = new Set() 701 | let generateLine = this.generateLine 702 | generateLine(x2, y2, z2, x3, y3, z3).forEach(({ x, y, z }) => { generateLine(x1, y1, z1, x, y, z).forEach((coordinate) => { coordinateSet.add(coordinate) }) }) 703 | return coordinateSet.values() 704 | }, 705 | generateEllipseRect: function (x0, y0, x1, y1) { /* rectangular parameter enclosing the ellipse */ 706 | var a = Math.abs(x1 - x0), b = Math.abs(y1 - y0), b1 = b & 1; /* diameter */ 707 | var dx = 4 * (1.0 - a) * b * b, dy = 4 * (b1 + 1) * a * a; /* error increment */ 708 | var err = dx + dy + b1 * a * a, e2; /* error of 1.step */ 709 | 710 | if (x0 > x1) { x0 = x1; x1 += a; } /* if called with swapped points */ 711 | if (y0 > y1) y0 = y1; /* .. exchange them */ 712 | y0 += (b + 1) >> 1; y1 = y0 - b1; /* starting pixel */ 713 | a = 8 * a * a; b1 = 8 * b * b; 714 | 715 | do { 716 | setPixel(x1, y0); /* I. Quadrant */ 717 | setPixel(x0, y0); /* II. Quadrant */ 718 | setPixel(x0, y1); /* III. Quadrant */ 719 | setPixel(x1, y1); /* IV. Quadrant */ 720 | e2 = 2 * err; 721 | if (e2 <= dy) { y0++; y1--; err += dy += a; } /* y step */ 722 | if (e2 >= dx || 2 * err > dy) { x0++; x1--; err += dx += b1; } /* x */ 723 | } while (x0 <= x1); 724 | 725 | while (y0 - y1 <= b) { /* too early stop of flat ellipses a=1 */ 726 | setPixel(x0 - 1, y0); /* -> finish tip of ellipse */ 727 | setPixel(x1 + 1, y0++); 728 | setPixel(x0 - 1, y1); 729 | setPixel(x1 + 1, y1--); 730 | } 731 | } 732 | 733 | } 734 | 735 | }, 736 | blockGeometry: { 737 | getBlockDirection: function (blockType) { 738 | let directionRelatedBlockStateKey = (function () { 739 | //The following function decides which specific key controls how the block rotates, if it exists. 740 | //It is based on the fact that, only one blockState will decide how. 741 | //Hope it won't change. 742 | for (let blockStateKey in blockType.blockState) 743 | if (blockDirectionTable[blockStateKey] != undefined) return blockStateKey; 744 | return ""; 745 | }()); 746 | let directionMap = (function () { 747 | if (blockDirectionTable[directionRelatedBlockStateKey][blockType.blockIdentifier] == undefined) 748 | return blockDirectionTable[directionRelatedBlockStateKey]["default"]; 749 | else 750 | return blockDirectionTable[directionRelatedBlockStateKey][blockType.blockIdentifier]; 751 | }()); 752 | let directionMark = (function () { 753 | for (let mark in directionMap) 754 | if (directionMap[mark] == blockType.blockState[directionRelatedBlockStateKey]) return mark; 755 | return "error"; 756 | }()); 757 | return translator.directionMarkToDirection(directionMark); 758 | }, 759 | //The degree is absolute degree. 760 | setBlockDirection: function (blockType, directionMark) { 761 | //Ignoring special block that doesn't use "+x" etc for now. 762 | let directionRelatedBlockStateKey = (function () { 763 | //The following function decides which specific key controls how the block rotates, if it exists. 764 | //It is based on the fact that, only one blockState will decide how. 765 | //Hope it won't change. 766 | for (let blockStateKey in blockType.blockState) 767 | if (blockDirectionTable[blockStateKey] != undefined) return blockStateKey; 768 | return ""; 769 | }()); 770 | let directionMap = (function () { 771 | if (blockDirectionTable[directionRelatedBlockStateKey][blockType.blockIdentifier] == undefined) 772 | return blockDirectionTable[directionRelatedBlockStateKey]["default"]; 773 | else 774 | return blockDirectionTable[directionRelatedBlockStateKey][blockType.blockIdentifier]; 775 | }()); 776 | blockType.blockState[directionRelatedBlockStateKey] = directionMap[directionMark]; 777 | return blockType; 778 | }, 779 | 780 | }, 781 | }; 782 | 783 | export { utils }; -------------------------------------------------------------------------------- /packs/behaviors/scripts/plugin/zaofu/index.js: -------------------------------------------------------------------------------- 1 | import { systemInstance as system, Description, Usage, Block, Coordinate, Position, BlockType, BuildInstruction, canonicalGeneratorFactory } from 'norma-core'; 2 | import { mcfont } from "./font.js" 3 | system.registerCanonicalGenerator({ 4 | description: 5 | new Description("铁路生成器(DrZaofu版)", 6 | new Usage( 7 | [], 8 | [], 9 | [], 10 | [ 11 | { 12 | viewtype: "edittext", 13 | text: "长度", 14 | key: "length", 15 | }, 16 | { 17 | viewtype: "button", 18 | text: "类型", 19 | key: "Type", 20 | data: [ 21 | { value: "OG", text: "地上铁" }, 22 | { value: "OR", text: "高架铁" }, 23 | { value: "UG", text: "地下铁" } 24 | ] 25 | }, 26 | { 27 | viewtype: "edittext", 28 | text: "高架铁的柱子向下多少格", 29 | key: "ORpillar" 30 | }, 31 | { 32 | viewtype: "edittext", 33 | text: "地上铁与高架铁的桥墩间隔", 34 | key: "gap" 35 | }, 36 | { 37 | viewtype: "checkbox", 38 | text: "照明", 39 | key: "light", 40 | data: [ 41 | { value: true, text: "是" }, 42 | { value: false, text: "否" } 43 | ] 44 | }, 45 | { 46 | viewtype: "edittext", 47 | text: "轨道数", 48 | key: "numberOfTrack", 49 | }, 50 | { 51 | viewtype: "button", 52 | text: "主题", 53 | key: "style", 54 | data: [ 55 | { value: "Q", text: "石英" }, 56 | { value: "S", text: "石砖" }, 57 | { value: "G", text: "玻璃" } 58 | ] 59 | } 60 | ]) 61 | ), 62 | criteria: { 63 | positionArrayLength: 1, 64 | blockTypeArrayLength: 0, 65 | directionArrayLength: 1 66 | }, 67 | option: { 68 | "length": 50, 69 | "Type": "UG", 70 | "ORpillar": 20, 71 | "gap": 15, 72 | "light": true, 73 | "numberOfTrack": 1, 74 | "style": "S" 75 | }, 76 | method: { 77 | generate: function (e) { 78 | 79 | let { logger } = e.runtime 80 | 81 | let blockArray = [] 82 | 83 | 84 | let positionArray = e.state.positions 85 | let blockTypeArray = e.state.blockTypes 86 | let directionArray = e.state.directions 87 | let option = e.state 88 | 89 | let directionMark = (function () { 90 | if (-45 <= directionArray[0].y && directionArray[0].y <= 45) return "+z" 91 | else if (-135 <= directionArray[0].y && directionArray[0].y <= -45) return "+x" 92 | else if (45 <= directionArray[0].y && directionArray[0].y <= 135) return "-x" 93 | else return "-z" 94 | }()) 95 | 96 | 97 | 98 | let sections = { 99 | "UG": [//地下铁 100 | [ 101 | [1, 2, 1], 102 | [1, 3, 0], 103 | [1, 0, 0], 104 | [1, 0, 0], 105 | [1, 4, 0], 106 | [1, 2, 1] 107 | ], 108 | [ 109 | [1], 110 | [11], 111 | [0], 112 | [0], 113 | [9], 114 | [10] 115 | ], 116 | [ 117 | [1, 2, 1], 118 | [0, 7, 0], 119 | [0, 0, 0], 120 | [0, 0, 0], 121 | [0, 8, 0], 122 | [1, 2, 1] 123 | ], 124 | [ 125 | [1, 2, 1], 126 | [0, 5, 1], 127 | [0, 0, 1], 128 | [0, 0, 1], 129 | [0, 6, 1], 130 | [1, 2, 1] 131 | ] 132 | ], 133 | "OR": [//高架铁 134 | [ 135 | [0, 0], 136 | [0, 0], 137 | [0, 0], 138 | [0, 0], 139 | [0, 0], 140 | [12, 0], 141 | [2, 1], 142 | [1, 1], 143 | [1, 1], 144 | [5, 1], 145 | ], 146 | [ 147 | [11], 148 | [0], 149 | [0], 150 | [0], 151 | [0], 152 | [9], 153 | [10], 154 | [1], 155 | [1], 156 | [1] 157 | ], 158 | [ 159 | [0, 0, 0], 160 | [0, 0, 0], 161 | [0, 0, 0], 162 | [0, 0, 0], 163 | [0, 0, 0], 164 | [0, 8, 0], 165 | [1, 2, 1], 166 | [1, 1, 1], 167 | [1, 1, 1], 168 | [1, 1, 1] 169 | ], 170 | [ 171 | [0, 0], 172 | [0, 0], 173 | [0, 0], 174 | [0, 0], 175 | [0, 0], 176 | [0, 12], 177 | [1, 2], 178 | [1, 1], 179 | [1, 1], 180 | [1, 3] 181 | ], 182 | [ 183 | option.gap,//间隔长度 184 | [0, 0 - option.ORpillar, 0],//相对坐标 后面格式跟this一样 185 | [ 186 | [11, 11], 187 | [11, 0], 188 | [11, 0], 189 | [11, 0], 190 | [11, 0], 191 | [12, 0], 192 | [2, 1], 193 | [1, 1], 194 | [1, 1], 195 | [5, 1] 196 | ].concat(JSON.parse(("[" + (JSON.stringify([-1, -1]) + ",").repeat(option.ORpillar) + "]").replace(",]", "]"))), 197 | [ 198 | [11], 199 | [0], 200 | [0], 201 | [0], 202 | [0], 203 | [9], 204 | [10], 205 | [1], 206 | [1], 207 | [1] 208 | ].concat(JSON.parse(("[" + (JSON.stringify([1]) + ",").repeat(option.ORpillar) + "]").replace(",]", "]"))), 209 | [ 210 | [11, 11, 11], 211 | [0, 13, 0], 212 | [0, 0, 0], 213 | [0, 0, 0], 214 | [0, 0, 0], 215 | [0, 8, 0], 216 | [1, 2, 1], 217 | [1, 1, 1], 218 | [1, 1, 1], 219 | [1, 1, 1] 220 | ].concat(JSON.parse(("[" + (JSON.stringify([-1, -1]) + ",").repeat(option.ORpillar) + "]").replace(",]", "]"))), 221 | [ 222 | [11, 11], 223 | [0, 11], 224 | [0, 11], 225 | [0, 11], 226 | [0, 11], 227 | [0, 12], 228 | [1, 2], 229 | [1, 1], 230 | [1, 1], 231 | [1, 3] 232 | ].concat(JSON.parse(("[" + (JSON.stringify([-1, -1]) + ",").repeat(option.ORpillar) + "]").replace(",]", "]"))) 233 | ] 234 | ], 235 | "OG": [//地上铁 236 | [ 237 | [0, 0], 238 | [0, 0], 239 | [0, 0], 240 | [0, 0], 241 | [11, 0], 242 | [11, 0], 243 | [11, 0], 244 | [2, 1] 245 | ], 246 | [ 247 | [0], 248 | [11], 249 | [0], 250 | [0], 251 | [0], 252 | [0], 253 | [9], 254 | [10], 255 | ], 256 | [ 257 | [0, 0, 0], 258 | [0, 0, 0], 259 | [0, 0, 0], 260 | [0, 0, 0], 261 | [0, 0, 0], 262 | [0, 0, 0], 263 | [0, 11, 0], 264 | [1, 2, 1] 265 | ], 266 | [ 267 | [0, 0], 268 | [0, 0], 269 | [0, 0], 270 | [0, 0], 271 | [0, 11], 272 | [0, 11], 273 | [0, 11], 274 | [1, 2] 275 | ], 276 | [ 277 | option.gap,//间隔长度 278 | [0, 0, 0],//相对坐标 后面格式跟this一样 279 | [ 280 | [12, 12], 281 | [12, 0], 282 | [12, 0], 283 | [12, 0], 284 | [12, 0], 285 | [12, 0], 286 | [12, 0], 287 | [2, 1] 288 | ], 289 | [ 290 | [12], 291 | [11], 292 | [0], 293 | [0], 294 | [0], 295 | [0], 296 | [9], 297 | [10] 298 | ], 299 | [ 300 | [12, 12, 12], 301 | [0, 13, 0], 302 | [0, 0, 0], 303 | [0, 0, 0], 304 | [0, 0, 0], 305 | [0, 0, 0], 306 | [0, 11, 0], 307 | [1, 2, 1] 308 | ], 309 | [ 310 | [12, 12], 311 | [0, 12], 312 | [0, 12], 313 | [0, 12], 314 | [0, 12], 315 | [0, 12], 316 | [0, 12], 317 | [1, 2] 318 | ] 319 | ] 320 | ] 321 | } 322 | 323 | let style = { 324 | "Q": [ 325 | new BlockType("minecraft:air", {}), 326 | new BlockType("minecraft:quartz_block", { "chisel_type": "default", "pillar_axis": "y" }), 327 | option.light ? new BlockType("minecraft:glowstone", {}) : new BlockType("minecraft:quartz_block", { "chisel_type": "default", "pillar_axis": "y" }), 328 | new BlockType("minecraft:quartz_stairs", { "weirdo_direction": directionMark == "-x" ? 2 : directionMark == "-z" ? 1 : directionMark == "+x" ? 3 : 0, "upside_down_bit": true }), 329 | new BlockType("minecraft:quartz_stairs", { "weirdo_direction": directionMark == "-x" ? 2 : directionMark == "-z" ? 1 : directionMark == "+x" ? 3 : 0, "upside_down_bit": false }), 330 | new BlockType("minecraft:quartz_stairs", { "weirdo_direction": directionMark == "+x" ? 2 : directionMark == "+z" ? 1 : directionMark == "-x" ? 3 : 0, "upside_down_bit": true }), 331 | new BlockType("minecraft:quartz_stairs", { "weirdo_direction": directionMark == "+x" ? 2 : directionMark == "+z" ? 1 : directionMark == "-x" ? 3 : 0, "upside_down_bit": false }), 332 | new BlockType("minecraft:stone_slab", { "stone_slab_type": "quartz", "top_slot_bit": true }), 333 | new BlockType("minecraft:stone_slab", { "stone_slab_type": "quartz", "top_slot_bit": false }), 334 | new BlockType("minecraft:golden_rail", { "rail_data_bit": true, "rail_direction": directionMark == "-x" || directionMark == "+x" ? 1 : 0 }), 335 | new BlockType("minecraft:redstone_block", {}), 336 | new BlockType("minecraft:glass_pane", {}), 337 | new BlockType("minecraft:quartz_block", { "chisel_type": "lines", "pillar_axis": "y" }), 338 | new BlockType("minecraft:lantern", { "hanging": true }) 339 | ], 340 | "S": [ 341 | new BlockType("minecraft:air", {}), 342 | new BlockType("minecraft:stonebrick", { "stone_brick_type": "default" }), 343 | option.light ? new BlockType("minecraft:glowstone", {}) : new BlockType("minecraft:stonebrick", { "stone_brick_type": "default" }), 344 | new BlockType("minecraft:stone_brick_stairs", { "weirdo_direction": directionMark == "-x" ? 2 : directionMark == "-z" ? 1 : directionMark == "+x" ? 3 : 0, "upside_down_bit": true }), 345 | new BlockType("minecraft:stone_brick_stairs", { "weirdo_direction": directionMark == "-x" ? 2 : directionMark == "-z" ? 1 : directionMark == "+x" ? 3 : 0, "upside_down_bit": false }), 346 | new BlockType("minecraft:stone_brick_stairs", { "weirdo_direction": directionMark == "+x" ? 2 : directionMark == "+z" ? 1 : directionMark == "-x" ? 3 : 0, "upside_down_bit": true }), 347 | new BlockType("minecraft:stone_brick_stairs", { "weirdo_direction": directionMark == "+x" ? 2 : directionMark == "+z" ? 1 : directionMark == "-x" ? 3 : 0, "upside_down_bit": false }), 348 | new BlockType("minecraft:stone_slab", { "stone_slab_type": "stone_brick", "top_slot_bit": true }), 349 | new BlockType("minecraft:stone_slab", { "stone_slab_type": "stone_brick", "top_slot_bit": false }), 350 | new BlockType("minecraft:golden_rail", { "rail_data_bit": true, "rail_direction": directionMark == "-x" || directionMark == "+x" ? 1 : 0 }), 351 | new BlockType("minecraft:redstone_block", {}), 352 | new BlockType("minecraft:iron_bars", {}), 353 | new BlockType("minecraft:cobblestone_wall", { "wall_block_type": "stone_brick" }), 354 | new BlockType("minecraft:lantern", { "hanging": true }) 355 | ], 356 | "G": [ 357 | new BlockType("minecraft:air", {}), 358 | new BlockType("minecraft:glass", {}), 359 | option.light ? new BlockType("minecraft:sealantern", {}) : new BlockType("minecraft:glass", {}), 360 | new BlockType("minecraft:iron_trapdoor", { "direction": 0, "upside_down_bit": true, "open_bit": false }), 361 | new BlockType("minecraft:iron_trapdoor", { "direction": 0, "upside_down_bit": false, "open_bit": false }), 362 | new BlockType("minecraft:iron_trapdoor", { "direction": 0, "upside_down_bit": true, "open_bit": false }), 363 | new BlockType("minecraft:iron_trapdoor", { "direction": 0, "upside_down_bit": false, "open_bit": false }), 364 | new BlockType("minecraft:iron_trapdoor", { "direction": 0, "upside_down_bit": true, "open_bit": false }), 365 | new BlockType("minecraft:iron_trapdoor", { "direction": 0, "upside_down_bit": false, "open_bit": false }), 366 | new BlockType("minecraft:golden_rail", { "rail_data_bit": true, "rail_direction": directionMark == "-x" || directionMark == "+x" ? 1 : 0 }), 367 | new BlockType("minecraft:redstone_block", {}), 368 | new BlockType("minecraft:glass_pane", {}), 369 | new BlockType("minecraft:sealantern", {}), 370 | new BlockType("minecraft:air", {}) 371 | ] 372 | } 373 | let section = [sections[option.Type][0], sections[option.Type][3]] 374 | for (let i = 0; i < option.numberOfTrack; i++) { 375 | section.splice(1, 0, sections[option.Type][1]) 376 | if ((i + 1) < option.numberOfTrack) { 377 | section.splice(1, 0, sections[option.Type][2]) 378 | } 379 | } 380 | 381 | 382 | 383 | let running_position = [0, section[0].length - 1, 0] 384 | section.forEach( 385 | (tmp_big_array) => { 386 | tmp_big_array.forEach( 387 | (tmp_small_array) => { 388 | tmp_small_array.forEach( 389 | (tmp_point) => { 390 | if (tmp_point != -1) { 391 | directionMark == "-z" ? blockArray.push({ "type": "fill", "data": { blockType: style[option.style][tmp_point], startCoordinate: { x: positionArray[0].coordinate.x + running_position[0], y: positionArray[0].coordinate.y + running_position[1], z: positionArray[0].coordinate.z - running_position[2] }, endCoordinate: { x: positionArray[0].coordinate.x + running_position[0], y: positionArray[0].coordinate.y + running_position[1], z: positionArray[0].coordinate.z - running_position[2] - option.length } } }) 392 | : directionMark == "+x" ? blockArray.push({ "type": "fill", "data": { blockType: style[option.style][tmp_point], startCoordinate: { x: positionArray[0].coordinate.x + running_position[2], y: positionArray[0].coordinate.y + running_position[1], z: positionArray[0].coordinate.z + running_position[0] }, endCoordinate: { x: positionArray[0].coordinate.x + running_position[2] + option.length, y: positionArray[0].coordinate.y + running_position[1], z: positionArray[0].coordinate.z + running_position[0] } } }) 393 | : directionMark == "+z" ? blockArray.push({ "type": "fill", "data": { blockType: style[option.style][tmp_point], startCoordinate: { x: positionArray[0].coordinate.x - running_position[0], y: positionArray[0].coordinate.y + running_position[1], z: positionArray[0].coordinate.z + running_position[2] }, endCoordinate: { x: positionArray[0].coordinate.x - running_position[0], y: positionArray[0].coordinate.y + running_position[1], z: positionArray[0].coordinate.z + running_position[2] + option.length } } }) 394 | : blockArray.push({ "type": "fill", "data": { blockType: style[option.style][tmp_point], startCoordinate: { x: positionArray[0].coordinate.x - running_position[2], y: positionArray[0].coordinate.y + running_position[1], z: positionArray[0].coordinate.z - running_position[0] }, endCoordinate: { x: positionArray[0].coordinate.x - running_position[2] - option.length, y: positionArray[0].coordinate.y + running_position[1], z: positionArray[0].coordinate.z - running_position[0] } } }) 395 | } 396 | running_position[0] += 1 397 | } 398 | ) 399 | running_position[0] -= tmp_small_array.length 400 | running_position[1] -= 1 401 | } 402 | ) 403 | running_position[0] += tmp_big_array[0].length 404 | running_position[1] += tmp_big_array.length 405 | } 406 | ) 407 | blockArray.splice(0, 0, { "type": "fill", "data": { blockType: style[option.style][0], startCoordinate: blockArray[0].data.startCoordinate, endCoordinate: blockArray[blockArray.length - 1].data.endCoordinate } }) 408 | // logger.debug(blockArray[0]) 409 | // logger.debug(blockArray[1]) 410 | if (sections[option.Type][4]) { 411 | let gaps = [sections[option.Type][4][2], sections[option.Type][4][5]] 412 | for (let i = 0; i < option.numberOfTrack; i++) { 413 | gaps.splice(1, 0, sections[option.Type][4][3]) 414 | if ((i + 1) < option.numberOfTrack) { 415 | gaps.splice(1, 0, sections[option.Type][4][4]) 416 | } 417 | } 418 | let running_position_gap 419 | for (let gap = sections[option.Type][4][0]; gap < option.length; gap += option.gap) { 420 | running_position_gap = [0 + sections[option.Type][4][1][0], gaps[0].length - 1 + sections[option.Type][4][1][1], 0 + sections[option.Type][4][1][2]] 421 | gaps.forEach( 422 | (tmp_big_array_gap) => { 423 | tmp_big_array_gap.forEach( 424 | (tmp_small_array_gap) => { 425 | tmp_small_array_gap.forEach( 426 | (tmp_point_gap) => { 427 | if (tmp_point_gap != -1) { 428 | directionMark == "-z" ? blockArray.push({ "blockType": style[option.style][tmp_point_gap], "position": { "coordinate": { x: positionArray[0].coordinate.x + running_position_gap[0], y: positionArray[0].coordinate.y + running_position_gap[1], z: positionArray[0].coordinate.z - running_position_gap[2] - gap }, "tickingArea": positionArray[0].tickingArea } }) 429 | : directionMark == "+x" ? blockArray.push({ "blockType": style[option.style][tmp_point_gap], "position": { "coordinate": { x: positionArray[0].coordinate.x + running_position_gap[2] + gap, y: positionArray[0].coordinate.y + running_position_gap[1], z: positionArray[0].coordinate.z + running_position_gap[0] }, "tickingArea": positionArray[0].tickingArea } }) 430 | : directionMark == "+z" ? blockArray.push({ "blockType": style[option.style][tmp_point_gap], "position": { "coordinate": { x: positionArray[0].coordinate.x - running_position_gap[0], y: positionArray[0].coordinate.y + running_position_gap[1], z: positionArray[0].coordinate.z + running_position_gap[2] + gap }, "tickingArea": positionArray[0].tickingArea } }) 431 | : blockArray.push({ "blockType": style[option.style][tmp_point_gap], "position": { "coordinate": { x: positionArray[0].coordinate.x - running_position_gap[2] - gap, y: positionArray[0].coordinate.y + running_position_gap[1], z: positionArray[0].coordinate.z - running_position_gap[0] }, "tickingArea": positionArray[0].tickingArea } }) 432 | } 433 | running_position_gap[0] += 1 434 | } 435 | ) 436 | running_position_gap[0] -= tmp_small_array_gap.length 437 | running_position_gap[1] -= 1 438 | } 439 | ) 440 | running_position_gap[0] += tmp_big_array_gap[0].length 441 | running_position_gap[1] += tmp_big_array_gap.length 442 | } 443 | ) 444 | } 445 | } 446 | return blockArray 447 | } 448 | }, 449 | UIHandler: function (e) { 450 | } 451 | }); 452 | 453 | system.registerCanonicalGenerator({ 454 | description: new Description("创建像素字", new Usage([], [], [], [ 455 | { 456 | viewtype: "edittext", 457 | text: "内容", 458 | key: "keyText" 459 | }, 460 | { 461 | viewtype: "checkbox", 462 | text: "垂直(向下延伸)", 463 | key: "isVertical", 464 | data: [ 465 | { value: true, text: "是" }, 466 | { value: false, text: "否" } 467 | ] 468 | }, 469 | { 470 | viewtype: "checkbox", 471 | text: "平面", 472 | key: "isFlat", 473 | data: [ 474 | { value: true, text: "是" }, 475 | { value: false, text: "否" } 476 | ] 477 | }])), 478 | criteria: { positionArrayLength: 1, blockTypeArrayLength: 1, directionArrayLength: 1 }, 479 | option: { 480 | "keyText": "NZ IS JULAO", 481 | "isFlat": false, 482 | "isVertical": false 483 | }, 484 | method: { 485 | generate: function (e) { 486 | 487 | let blockArray = [] 488 | let { logger } = e.runtime 489 | 490 | let positionArray = e.state.positions 491 | let blockTypeArray = e.state.blockTypes 492 | let directionArray = e.state.directions 493 | let option = e.state 494 | 495 | let directionMark = (function () { 496 | if (-45 <= directionArray[0].y && directionArray[0].y <= 45) return "+z" 497 | else if (-135 <= directionArray[0].y && directionArray[0].y <= -45) return "+x" 498 | else if (45 <= directionArray[0].y && directionArray[0].y <= 135) return "-x" 499 | else return "-z" 500 | }()) 501 | 502 | let rawText = (function (text, mcfont) {//新版mcfont的解码 503 | let rawTextArray = [] 504 | for (let i = 0; i < text.length; i++) {//i 每个字 505 | rawTextArray.push((function (text, mcfont) { 506 | if (text == " ") {//空格return 0 507 | return 0 508 | } 509 | let cnm = mcfont.substring(text.charCodeAt() * 16, text.charCodeAt() * 16 + 16) 510 | let wdnmd = [] 511 | let p 512 | let u 513 | for (let d = 0; d < 16; d++) {//d 16个Unicode 514 | p = cnm.charCodeAt(d) 515 | u = 65536 516 | for (let m = 0; m < 16; m++) {// m 每次减少 517 | u /= 2 518 | if (p - u >= 0) { 519 | p -= u 520 | wdnmd.push(1) 521 | } 522 | else { 523 | wdnmd.push(0) 524 | } 525 | } 526 | } 527 | return wdnmd 528 | } 529 | )(text[i], mcfont)) 530 | } 531 | return rawTextArray 532 | })(option["keyText"], mcfont) 533 | 534 | /*let rawText = (function (text,mcfont) { 535 | let l 536 | l = [] 537 | for (let i = 0; i < text.length; i++) { 538 | if (text[i] == " ") { 539 | l.push(0) 540 | } else { 541 | l.push(mcfont[text.charCodeAt(i)]) 542 | } 543 | } 544 | return(l) 545 | })(option["keyText"], presetBuildings.mcfont)*/ //旧版mcfont的解码 546 | let tempPosition = [0, 15, 0] 547 | if (option["isVertical"]) { 548 | tempPosition[1] = 0 549 | } 550 | //t = 每个字 551 | //i = 每列 552 | //z = 每行 553 | 554 | let u 555 | for (let t = 0; t < rawText.length; t++) { 556 | for (let i = 0; i < 16; i++) { 557 | for (let z = 0; z < 16; z++) { 558 | if (rawText[t][i * 16 + z]) { 559 | if (option["isFlat"]) { 560 | if (directionMark == "-z") { 561 | blockArray.push({ "position": { "coordinate": { "x": positionArray[0].coordinate.x + tempPosition[0], "y": positionArray[0].coordinate.y + tempPosition[2], "z": positionArray[0].coordinate.z - tempPosition[1] }, "tickingArea": positionArray[0].tickingArea }, "blockType": blockTypeArray[0] }) 562 | } else 563 | if (directionMark == "+x") { 564 | blockArray.push({ "position": { "coordinate": { "x": positionArray[0].coordinate.x + tempPosition[1], "y": positionArray[0].coordinate.y + tempPosition[2], "z": positionArray[0].coordinate.z + tempPosition[0] }, "tickingArea": positionArray[0].tickingArea }, "blockType": blockTypeArray[0] }) 565 | } else 566 | if (directionMark == "+z") { 567 | blockArray.push({ "position": { "coordinate": { "x": positionArray[0].coordinate.x - tempPosition[0], "y": positionArray[0].coordinate.y + tempPosition[2], "z": positionArray[0].coordinate.z + tempPosition[1] }, "tickingArea": positionArray[0].tickingArea }, "blockType": blockTypeArray[0] }) 568 | } else 569 | if (directionMark == "-x") { 570 | blockArray.push({ "position": { "coordinate": { "x": positionArray[0].coordinate.x - tempPosition[1], "y": positionArray[0].coordinate.y + tempPosition[2], "z": positionArray[0].coordinate.z - tempPosition[0] }, "tickingArea": positionArray[0].tickingArea }, "blockType": blockTypeArray[0] }) 571 | } 572 | } else { 573 | if (directionMark == "-z") { 574 | blockArray.push({ "position": { "coordinate": { "x": positionArray[0].coordinate.x + tempPosition[0], "y": positionArray[0].coordinate.y + tempPosition[1], "z": positionArray[0].coordinate.z + tempPosition[2] }, "tickingArea": positionArray[0].tickingArea }, "blockType": blockTypeArray[0] }) 575 | } else 576 | if (directionMark == "+x") { 577 | blockArray.push({ "position": { "coordinate": { "x": positionArray[0].coordinate.x + tempPosition[2], "y": positionArray[0].coordinate.y + tempPosition[1], "z": positionArray[0].coordinate.z + tempPosition[0] }, "tickingArea": positionArray[0].tickingArea }, "blockType": blockTypeArray[0] }) 578 | } else 579 | if (directionMark == "+z") { 580 | blockArray.push({ "position": { "coordinate": { "x": positionArray[0].coordinate.x - tempPosition[0], "y": positionArray[0].coordinate.y + tempPosition[1], "z": positionArray[0].coordinate.z + tempPosition[2] }, "tickingArea": positionArray[0].tickingArea }, "blockType": blockTypeArray[0] }) 581 | } else 582 | if (directionMark == "-x") { 583 | blockArray.push({ "position": { "coordinate": { "x": positionArray[0].coordinate.x + tempPosition[2], "y": positionArray[0].coordinate.y + tempPosition[1], "z": positionArray[0].coordinate.z - tempPosition[0] }, "tickingArea": positionArray[0].tickingArea }, "blockType": blockTypeArray[0] }) 584 | } 585 | } 586 | } 587 | tempPosition[0] += 1 588 | } 589 | tempPosition[1] += -1 590 | tempPosition[0] += -16 591 | } 592 | if (t + 2 > rawText.length) { 593 | break 594 | } 595 | if (option["isVertical"]) { 596 | for (let d = 0; d < 16; d++) { 597 | u = 0 598 | for (let q = 0; q < 16; q++) { 599 | if (rawText[t + 1][d * 16 + 15 - q] != 1) { 600 | u++ 601 | } 602 | } 603 | if (u == 16) { 604 | tempPosition[1] += 1 605 | } else { 606 | break 607 | } 608 | } 609 | if (rawText[t] == 0) { 610 | tempPosition[1] += -8 611 | } 612 | } else { 613 | tempPosition[1] += 16 614 | for (let d = 0; d < 16; d++) { 615 | u = 0 616 | for (let q = 0; q < 16; q++) { 617 | if (rawText[t][q * 16 + 15 - d] != 1) { 618 | u++ 619 | } 620 | } 621 | if (u == 16) { 622 | tempPosition[0] += -1 623 | } else { 624 | break 625 | } 626 | } 627 | if (rawText[t] == 0) { 628 | tempPosition[0] += 8 629 | } 630 | tempPosition[0] += 17 631 | } 632 | } 633 | return blockArray 634 | 635 | } 636 | } 637 | }); --------------------------------------------------------------------------------