diff --git a/plugins/BlockRotationV2/README.md b/plugins/BlockRotationV2/README.md new file mode 100644 index 000000000..40adaa745 --- /dev/null +++ b/plugins/BlockRotationV2/README.md @@ -0,0 +1,11 @@ +# Simple Block Rotation + +Simple Block Rotation automates common behaviour for rotating blocks. + +## Installation + +Simply install the extension to your project from bridge.'s extension library. + +## Usage + +Add either the `bridge:log_rotate_on_place`, `bridge:rotate_on_place`, or `bridge:rotate_y_on_place` block components to your block. diff --git a/plugins/BlockRotationV2/components/block/logRotate.js b/plugins/BlockRotationV2/components/block/logRotate.js index 8b185e7a6..9c41ad1c3 100644 --- a/plugins/BlockRotationV2/components/block/logRotate.js +++ b/plugins/BlockRotationV2/components/block/logRotate.js @@ -10,52 +10,49 @@ export default function defineComponent({ name, template, schema }) { }) template(({ rotation_from = 'player' }, { create }) => { - const rotationLookup = [ - [0.0, 0.0, 0.0], - [90.0, 0.0, 0.0], - [0.0, 90.0, -90.0], - ] - create( - { - 'bridge:block_rotation': [0, 1, 2], - }, - 'minecraft:block/description/properties' - ) + const state = rotation_from === 'player' + ? 'cardinal_facing' + : 'block_face'; create( { - permutations: rotationLookup.map((rotation, i) => ({ - condition: `query.block_property('bridge:block_rotation') == ${i}`, - components: { - 'minecraft:rotation': rotation, - }, - })), - }, - 'minecraft:block' - ) - - create( - { - 'minecraft:on_player_placing': { - event: 'bridge:update_rotation', + 'minecraft:placement_direction': { + enabled_states: [ + `minecraft:${state}` + ], + ...(state === 'cardinal_direction' ? { y_rotation_offset: 180 } : {}) }, }, - 'minecraft:block/components' - ) + 'minecraft:block/description/traits' + ); create( { - 'bridge:update_rotation': { - set_block_property: { - 'bridge:block_rotation': `math.floor(${ - rotation_from === 'player' - ? 'query.cardinal_facing' - : 'query.block_face' - } / 2.0)`, + permutations: [ + // X axis + { + condition: `q.block_state('minecraft:${state}') == 'west' || q.block_state('minecraft:${state}') == 'east'`, + components: { + "minecraft:transformation": { rotation: [0, 0, 90] } + } }, - }, + // Y axis + { + condition: `q.block_state('minecraft:${state}') == 'down' || q.block_state('minecraft:${state}') == 'up'`, + components: { + "minecraft:transformation": { rotation: [0, 0, 0] } + } + }, + // Z axis + { + condition: `q.block_state('minecraft:${state}') == 'north' || q.block_state('minecraft:${state}') == 'south'`, + components: { + "minecraft:transformation": { rotation: [90, 0, 0] } + } + } + ] }, - 'minecraft:block/events' + 'minecraft:block' ) }) } diff --git a/plugins/BlockRotationV2/components/block/rotate.js b/plugins/BlockRotationV2/components/block/rotate.js index 673d0cd9f..bf7538188 100644 --- a/plugins/BlockRotationV2/components/block/rotate.js +++ b/plugins/BlockRotationV2/components/block/rotate.js @@ -1,3 +1,11 @@ +const rotationLookup = new Map([ + ['down', [-90.0, 0.0, 0.0]], + ['up', [90.0, 0.0, 0.0]], + ['north', [0.0, 0.0, 0.0]], + ['west', [0.0, 90.0, 0.0]], + ['south', [0.0, 180.0, 0.0]], + ['east', [0.0, -90.0, 0.0]], +]); export default function defineComponent({ name, template, schema }) { name('bridge:rotate_on_place') schema({ @@ -10,53 +18,34 @@ export default function defineComponent({ name, template, schema }) { }) template(({ rotation_from = 'player' }, { create }) => { - const rotationLookup = [ - [0.0, 0.0, 0.0], - [0.0, 0.0, 180.0], - [90.0, 0.0, 0.0], - [-90.0, 0.0, 0.0], - [0.0, 0.0, -90.0], - ] + const state = rotation_from === 'player' + ? 'cardinal_direction' + : 'block_face'; + create( { - 'bridge:block_rotation': [0, 1, 2, 3, 4, 5], + 'minecraft:placement_direction': { + enabled_states: [ + `minecraft:${state}` + ], + ...(state === 'cardinal_direction' ? { y_rotation_offset: 180 } : {}) + }, }, - 'minecraft:block/description/properties' - ) + 'minecraft:block/description/traits' + ); create( { - permutations: rotationLookup.map((rotation, i) => ({ - condition: `query.block_property('bridge:block_rotation') == ${i}`, + permutations: Array.from(rotationLookup.entries()).map(([name, rotation]) => ({ + condition: `q.block_state('minecraft:${state}') == '${name}'`, components: { - 'minecraft:rotation': rotation, + 'minecraft:transformation': { + rotation, + }, }, })), }, 'minecraft:block' - ) - - create( - { - 'minecraft:on_player_placing': { - event: 'bridge:update_rotation', - }, - }, - 'minecraft:block/components' - ) - - create( - { - 'bridge:update_rotation': { - set_block_property: { - 'bridge:block_rotation': - rotation_from === 'player' - ? 'query.cardinal_facing' - : 'query.block_face', - }, - }, - }, - 'minecraft:block/events' - ) + ); }) } diff --git a/plugins/BlockRotationV2/components/block/rotateY.js b/plugins/BlockRotationV2/components/block/rotateY.js index 222c6c0ae..c4afd00e9 100644 --- a/plugins/BlockRotationV2/components/block/rotateY.js +++ b/plugins/BlockRotationV2/components/block/rotateY.js @@ -1,3 +1,15 @@ +const rotationLookup = new Map([ + ['north', [0.0, 0.0, 0.0]], + ['south', [0.0, 180.0, 0.0]], + ['west', [0.0, 90.0, 0.0]], + ['east', [0.0, -90.0, 0.0]], +]); +const rotationLookupFlipped = new Map([ + ['north', [0.0, 180.0, 0.0]], + ['south', [0.0, 0.0, 0.0]], + ['west', [0.0, -90.0, 0.0]], + ['east', [0.0, 90.0, 0.0]], +]); export default function defineComponent({ name, template, schema }) { name('bridge:rotate_y_on_place') schema({ @@ -9,58 +21,33 @@ export default function defineComponent({ name, template, schema }) { }) template(({ flip = false }, { create }) => { - const rotationLookup = [ - [0.0, 0.0, 0.0], - [0.0, 180.0, 0.0], - [0.0, 90.0, 0.0], - [0.0, 270.0, 0.0], - ] - const rotationLookupFlipped = [ - [0.0, 180.0, 0.0], - [0.0, 0.0, 0.0], - [0.0, 270.0, 0.0], - [0.0, 90.0, 0.0], - ] create( { - 'bridge:block_rotation': [2, 3, 4, 5], + 'minecraft:placement_direction': { + enabled_states: [ + 'minecraft:cardinal_direction' + ], + y_rotation_offset: 180 // Face towards player + }, }, - 'minecraft:block/description/properties' - ) + 'minecraft:block/description/traits' + ); create( { - permutations: (flip + permutations: Array.from((flip ? rotationLookupFlipped : rotationLookup - ).map((rotation, i) => ({ - condition: `query.block_property('bridge:block_rotation') == ${i + 2}`, + ).entries).map(([name, rotation]) => ({ + condition: `q.block_state('minecraft:cardinal_direction') == '${name}'`, components: { - 'minecraft:rotation': rotation, + 'minecraft:transformation': { + rotation + } }, })), }, 'minecraft:block' ) - - create( - { - 'minecraft:on_player_placing': { - event: 'bridge:update_rotation', - }, - }, - 'minecraft:block/components' - ) - - create( - { - 'bridge:update_rotation': { - set_block_property: { - 'bridge:block_rotation': 'query.cardinal_facing_2d', - }, - }, - }, - 'minecraft:block/events' - ) }) } diff --git a/plugins/BlockRotationV2/manifest.json b/plugins/BlockRotationV2/manifest.json index b842045a9..0f97c5b16 100644 --- a/plugins/BlockRotationV2/manifest.json +++ b/plugins/BlockRotationV2/manifest.json @@ -1,9 +1,9 @@ { "author": "Joel ant 05", "name": "Simple Block Rotation", - "version": "1.0.3", + "version": "1.0.4", "id": "b05592ed-cc3e-437c-ae7c-3f51353051bd", - "description": "Adding rotation to blocks is as easy as it should be: Adding a single component! (Deprecated in MC 1.21.20)", + "description": "Adding rotation to blocks is as easy as it should be: Adding a single component!", "api_version": 2, "target": "v2", "tags": [ diff --git a/plugins/BlockRotationV2/plugin.zip b/plugins/BlockRotationV2/plugin.zip index 4cb73a146..bba423e9c 100644 Binary files a/plugins/BlockRotationV2/plugin.zip and b/plugins/BlockRotationV2/plugin.zip differ diff --git a/plugins/ConnectableBlock/README.md b/plugins/ConnectableBlock/README.md new file mode 100644 index 000000000..8871b55fe --- /dev/null +++ b/plugins/ConnectableBlock/README.md @@ -0,0 +1,15 @@ +# Connectable Block + +Connectable Block automates common behaviour for connectable blocks. + +## Installation + +After installing the plugin from bridge.'s extension store, import the script to your main scripting entry point: + +```js +import * as Connectable from 'scripts/connectable.js' +``` + +## Usage + +Add the `bridge:connectable` block component to a block. Specify settings within the component. Your block should now connect. diff --git a/plugins/ConnectableBlock/components/block/connectable.ts b/plugins/ConnectableBlock/components/block/connectable.ts index ff6d8ce31..080b8f7b8 100644 --- a/plugins/ConnectableBlock/components/block/connectable.ts +++ b/plugins/ConnectableBlock/components/block/connectable.ts @@ -1,199 +1,261 @@ -const directions = ['north', 'east', 'south', 'west', 'up', 'down', 'north_up', 'east_up', 'south_up', 'west_up', 'north_down', 'east_down', 'south_down', 'west_down']; +const directions = [ + 'north', + 'east', + 'south', + 'west', + 'up', + 'down', + 'north_up', + 'east_up', + 'south_up', + 'west_up', + 'north_down', + 'east_down', + 'south_down', + 'west_down', +] export default defineComponent(({ name, template, schema }) => { name('bridge:connectable') schema({ - description: 'Allows the block to connect to neighboring blocks. Note: Requires format_version to be 1.20.60!', + description: + 'Allows the block to connect to neighboring blocks. You must import the connectable script into your main scripting entry point!', type: 'object', anyOf: [ { required: ['tag', 'directions', 'parts'] }, - { required: ['tag', 'directions', 'geometries'] } + { required: ['tag', 'directions', 'geometries'] }, ], properties: { tag: { - description: 'The neighbor block tag which the component will test.', - type: 'string' + description: + 'The neighbor block tag which the component will test.', + type: 'string', }, directions: { - description: 'Specifies which direction the component will use & create block properties for.', + description: + 'Specifies which direction the component will use & create block properties for.', type: 'array', items: { type: 'string', - enum: directions - } + enum: directions, + }, }, parts: { - description: 'The part_visiblity method | Defines when to hide specific parts of the geometry. Not compatible with the "geometries" method.', + description: + 'The part_visiblity method | Defines when to hide specific parts of the geometry. Not compatible with the "geometries" method.', type: 'array', items: { type: 'object', anyOf: [ { required: ['name', 'directions'] }, - { required: ['name', 'direction_combinations'] } + { required: ['name', 'direction_combinations'] }, ], properties: { name: { description: 'Name of the bone.', - type: 'string' + type: 'string', }, directions: { - description: 'Specifies when to show the part. Multiple directions can be passed.', + description: + 'Specifies when to show the part. Multiple directions can be passed.', type: 'array', items: { type: 'string', - enum: directions - } + enum: directions, + }, }, direction_combinations: { - description: 'Specifies when to show the part. Multiple directions combinations can be passed. Does an AND between the directions in inside of the array and an OR between the arrays', + description: + 'Specifies when to show the part. Multiple directions combinations can be passed. Does an AND between the directions in inside of the array and an OR between the arrays', type: 'array', items: { type: 'array', items: { type: 'string', - enum: directions - } - } + enum: directions, + }, + }, }, inverted: { description: 'Specifies to invert the check', - type: 'boolean' - } - } - } + type: 'boolean', + }, + }, + }, }, geometries: { - description: 'The geometries method | Defines a list of geometries and when to hide each one. Not compatible with the "part_visiblity" method.', + description: + 'The geometries method | Defines a list of geometries and when to hide each one. Not compatible with the "part_visiblity" method.', type: 'array', items: { type: 'object', anyOf: [ - { required: ['name', 'directions', 'material_instances'] }, - { required: ['name', 'direction_combinations', 'material_instances'] } + { + required: [ + 'name', + 'directions', + 'material_instances', + ], + }, + { + required: [ + 'name', + 'direction_combinations', + 'material_instances', + ], + }, ], properties: { name: { description: 'Definition name of the geometry.', - type: 'string' + type: 'string', }, directions: { - description: 'Specifies when to show the geometry. Multiple directions can be passed.', + description: + 'Specifies when to show the geometry. Multiple directions can be passed.', type: 'array', items: { type: 'string', - enum: directions - } + enum: directions, + }, }, direction_combinations: { - description: 'Specifies when to show the geometry. Multiple directions can be passed. Does an AND between the directions in inside of the array and an OR between the arrays', + description: + 'Specifies when to show the geometry. Multiple directions can be passed. Does an AND between the directions in inside of the array and an OR between the arrays', type: 'array', items: { type: 'string', - enum: directions - } + enum: directions, + }, }, material_instances: { - $ref: '/data/packages/minecraftBedrock/schema/block/v1.16.100/components/material_instances.json' + $ref: '/data/packages/minecraftBedrock/schema/block/v1.16.100/components/material_instances.json', }, inverted: { description: 'Specifies to invert the check', - type: 'boolean' - } - } - } - } - } + type: 'boolean', + }, + }, + }, + }, + }, }) - template(({ tag, directions, parts = [], geometries = [] }: { tag: string, directions: string[], parts: any, geometries: any }, { create, sourceBlock }) => { - const positions = new Map([ - ['north', [0, 0, -1]], - ['east', [1, 0, 0]], - ['south', [0, 0, 1]], - ['west', [-1, 0, 0]], - ['up', [0, 1, 0]], - ['down', [0, -1, 0]], - ['north_up', [0, 1, -1]], - ['east_up', [1, 1, 0]], - ['south_up', [0, 1, 1]], - ['west_up', [-1, 1, 0]], - ['north_down', [0, -1, -1]], - ['east_down', [1, -1, 0]], - ['south_down', [0, -1, 1]], - ['west_down', [-1, -1, 0]], - ]) - - directions.map((dir: string) => { + template( + ( + { + tag, + directions, + parts = [], + geometries = [], + }: { + tag: string + directions: string[] + parts: any + geometries: any + }, + { create, sourceBlock } + ) => { create( { - [`bridge:${dir}_neighbor`]: [false, true] + ...Object.fromEntries( + directions.map((dir: string) => [ + `bridge:${dir}_neighbor`, + [false, true], + ]) + ), + 'bridge:connectable': [tag, 'empty'], }, 'minecraft:block/description/states' ) - }) - function getQueryStringForPartOrGeometry(part_or_geo: { directions: string[] | undefined, direction_combinations: string[][] | undefined, inverted: boolean | undefined }) { - return (part_or_geo.inverted ? "!(" : "") + ( - part_or_geo.directions ? ( - part_or_geo.directions.length === 1 ? - `q.block_state('bridge:${part_or_geo.directions}_neighbor')==true` - : - `${part_or_geo.directions.map((dir: string) => `q.block_state('bridge:${dir}_neighbor')==true`).join('&&')}` + function getQueryStringForPartOrGeometry(part_or_geo: { + directions: string[] | undefined + direction_combinations: string[][] | undefined + inverted: boolean | undefined + }) { + return ( + (part_or_geo.inverted ? '!(' : '') + + (part_or_geo.directions + ? part_or_geo.directions.length === 1 + ? `q.block_state('bridge:${part_or_geo.directions}_neighbor')==true` + : `${part_or_geo.directions + .map( + (dir: string) => + `q.block_state('bridge:${dir}_neighbor')==true` + ) + .join('&&')}` + : part_or_geo.direction_combinations.length === 1 + ? `${part_or_geo.direction_combinations[0].map( + (dir: string) => + `q.block_state('bridge:${dir}_neighbor')==true` + )}` + : `${part_or_geo.direction_combinations + .map((dirs: string[]) => + dirs + .map( + (dir: string) => + `q.block_state('bridge:${dir}_neighbor')==true` + ) + .join('&&') + ) + .join('||')}`) + + (part_or_geo.inverted ? ')' : '') ) - : - ( - part_or_geo.direction_combinations.length === 1 ? - `${part_or_geo.direction_combinations[0].map((dir: string) => `q.block_state('bridge:${dir}_neighbor')==true`)}` - : - `${part_or_geo.direction_combinations.map((dirs: string[]) => dirs.map((dir: string) => `q.block_state('bridge:${dir}_neighbor')==true`).join('&&')).join('||')}` - ) - ) + (part_or_geo.inverted ? ")" : "") - } - if (parts) { - parts.map((part: { name: string, directions: string[] | undefined, direction_combinations: string[][] | undefined, inverted: boolean | undefined }) => { + } + + if (parts) { + create( + Object.fromEntries( + parts.map( + (part: { + name: string + directions: string[] | undefined + direction_combinations: string[][] | undefined + inverted: boolean | undefined + }) => [ + part.name, + getQueryStringForPartOrGeometry(part), + ] + ) + ), + 'minecraft:block/components/minecraft:geometry/bone_visibility' + ) + } + + if (geometries) { create( { - [part.name]: getQueryStringForPartOrGeometry(part) + permutations: geometries.map( + (geo: { + name: string + directions: string[] | undefined + direction_combinations: string[][] | undefined + material_instances: any + inverted: boolean | undefined + }) => ({ + condition: getQueryStringForPartOrGeometry(geo), + components: { + 'minecraft:geometry': geo.name, + 'minecraft:material_instances': + geo.material_instances, + }, + }) + ), }, - 'minecraft:block/components/minecraft:geometry/bone_visibility' + 'minecraft:block' ) - }) - } + } - if (geometries) { create( { - permutations: geometries.map((geo: { name: string, directions: string[] | undefined, direction_combinations: string[][] | undefined, material_instances: any, inverted: boolean | undefined }) => ({ - condition: getQueryStringForPartOrGeometry(geo), - components: { - 'minecraft:geometry': geo.name, - 'minecraft:material_instances': geo.material_instances - } - })) + 'minecraft:tick': { + looping: true, + interval_range: [0, 0], + }, + 'minecraft:custom_components': ['bridge:connectable'], }, - 'minecraft:block' + 'minecraft:block/components' ) } - - create( - { - 'minecraft:queued_ticking': { - looping: true, - interval_range: [0, 0], - on_tick: { - event: 'e:update.neighbors' - } - } - }, - 'minecraft:block/components' - ) - - directions.map((dir: string) => { - create( - { - [`bridge:${dir}_neighbor`]: `q.block_neighbor_has_any_tag(${positions.get(dir)}, '${tag}') ? true : false` - }, - 'minecraft:block/events/e:update.neighbors/set_block_state' - ) - }) - }) + ) }) diff --git a/plugins/ConnectableBlock/manifest.json b/plugins/ConnectableBlock/manifest.json index edc49d12d..07eea8962 100644 --- a/plugins/ConnectableBlock/manifest.json +++ b/plugins/ConnectableBlock/manifest.json @@ -2,9 +2,9 @@ "icon": "mdi-cube-outline", "author": "Arexon", "name": "Connectable Block", - "version": "1.1.3", + "version": "1.2.0", "id": "8e362b9e-7c63-4495-b0ab-111fd31de00d", - "description": "Easily make your block connect with neighboring blocks by using part_visibity or geometries. (Deprecated in MC 1.21.20)", + "description": "Easily make your block connect with neighboring blocks by using part_visibity or geometries.\nSince 1.2.0 it requires scripting, so DON'T forget to import the connectable.js file into your scripting main.js! No need for beta api's", "api_version": 2, "target": "v2", "tags": [ @@ -14,6 +14,10 @@ "components/block": { "pack": "behaviorPack", "path": "components/block/bridge/" + }, + "scripts": { + "pack": "behaviorPack", + "path": "scripts" } }, "releaseTimestamp": 1632821021507 diff --git a/plugins/ConnectableBlock/plugin.zip b/plugins/ConnectableBlock/plugin.zip index d98a690b4..7847835ae 100644 Binary files a/plugins/ConnectableBlock/plugin.zip and b/plugins/ConnectableBlock/plugin.zip differ diff --git a/plugins/ConnectableBlock/scripts/connectable.js b/plugins/ConnectableBlock/scripts/connectable.js new file mode 100644 index 000000000..0c3305f84 --- /dev/null +++ b/plugins/ConnectableBlock/scripts/connectable.js @@ -0,0 +1,43 @@ +import { world } from "@minecraft/server"; + +const positions = new Map([ + ['north', [0, 0, -1]], + ['east', [1, 0, 0]], + ['south', [0, 0, 1]], + ['west', [-1, 0, 0]], + ['up', [0, 1, 0]], + ['down', [0, -1, 0]], + ['north_up', [0, 1, -1]], + ['east_up', [1, 1, 0]], + ['south_up', [0, 1, 1]], + ['west_up', [-1, 1, 0]], + ['north_down', [0, -1, -1]], + ['east_down', [1, -1, 0]], + ['south_down', [0, -1, 1]], + ['west_down', [-1, -1, 0]], +]); + +world.beforeEvents.worldInitialize.subscribe(({ blockComponentRegistry }) => { + blockComponentRegistry.registerCustomComponent( + "bridge:connectable", + /** @type {import("@minecraft/server").BlockCustomComponent} */ + { + onTick({ block }) { + const tag = block.permutation.getState("bridge:connectable"); + if (!tag) return; + for (const [dir, pos] of positions) { + try { + block.setPermutation( + block.permutation.withState( + `bridge:${dir}_neighbor`, + block.offset({ x: pos[0], y: pos[1], z: pos[2] })?.hasTag(tag) + ) + ); + } catch { + // user can remove directions, so then it will give an error + } + } + }, + } + ); +});