added decobench assets added backend logic to best of my ability
This commit is contained in:
@@ -1 +1,32 @@
|
|||||||
{"format_version":"1.21.100","minecraft:block":{"description":{"identifier":"rzb_dcs:invisible_block"},"components":{"minecraft:selection_box":{"origin":[-7.95,0,-7.95],"size":[15.9,15.9,15.9]},"minecraft:collision_box":{"origin":[-7.95,0,-7.95],"size":[15.9,15.9,15.9]},"minecraft:destructible_by_mining":false,"minecraft:destructible_by_explosion":false,"minecraft:movable":{"movement_type":"immovable"},"tag:rzb_dcs:inv_block_little":{},"minecraft:liquid_detection":{"can_contain_liquid":true,"detection_rules":[{"liquid_type":"water","on_liquid_touches":"no_reaction"}]},"minecraft:geometry":"geometry.rzb_dcs.none","minecraft:material_instances":{"*":{"texture":"rzb_dcs_none","render_method":"alpha_test"}},"rzb_dcs:breakblock_particle":{}}}}
|
{
|
||||||
|
"format_version": "1.21.60",
|
||||||
|
"minecraft:block": {
|
||||||
|
"description": {
|
||||||
|
"identifier": "rzb_dcs:invisible_block"
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"minecraft:material_instances": {
|
||||||
|
"*": {
|
||||||
|
"texture": "rzb_dcs_none",
|
||||||
|
"render_method": "alpha_test"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minecraft:collision_box": {
|
||||||
|
"origin": [
|
||||||
|
-7.95,
|
||||||
|
0,
|
||||||
|
-7.95
|
||||||
|
],
|
||||||
|
"size": [
|
||||||
|
15.9,
|
||||||
|
15.9,
|
||||||
|
15.9
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"minecraft:selection_box": false,
|
||||||
|
"minecraft:destructible_by_mining": false,
|
||||||
|
"minecraft:destructible_by_explosion": false,
|
||||||
|
"minecraft:light_dampening": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,208 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.21.60",
|
||||||
|
"minecraft:entity": {
|
||||||
|
"description": {
|
||||||
|
"identifier": "rzb_dcs:decobench",
|
||||||
|
"is_spawnable": true,
|
||||||
|
"is_summonable": true,
|
||||||
|
"is_experimental": false
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"minecraft:type_family": {
|
||||||
|
"family": [
|
||||||
|
"decobench",
|
||||||
|
"inanimate"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"minecraft:health": {
|
||||||
|
"value": 10,
|
||||||
|
"max": 10
|
||||||
|
},
|
||||||
|
"minecraft:physics": {
|
||||||
|
"has_gravity": false,
|
||||||
|
"has_collision": false
|
||||||
|
},
|
||||||
|
"minecraft:collision_box": {
|
||||||
|
"width": 1,
|
||||||
|
"height": 1
|
||||||
|
},
|
||||||
|
"minecraft:custom_hit_test": {
|
||||||
|
"hitboxes": [
|
||||||
|
{
|
||||||
|
"width": 1,
|
||||||
|
"height": 1,
|
||||||
|
"pivot": [
|
||||||
|
0,
|
||||||
|
0.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"minecraft:pushable": {
|
||||||
|
"is_pushable": false,
|
||||||
|
"is_pushable_by_piston": false
|
||||||
|
},
|
||||||
|
"minecraft:knockback_resistance": {
|
||||||
|
"value": 1
|
||||||
|
},
|
||||||
|
"minecraft:persistent": {},
|
||||||
|
"minecraft:fire_immune": true,
|
||||||
|
"minecraft:nameable": {
|
||||||
|
"allow_name_tag_renaming": false
|
||||||
|
},
|
||||||
|
"minecraft:damage_sensor": {
|
||||||
|
"triggers": [
|
||||||
|
{
|
||||||
|
"cause": "all",
|
||||||
|
"deals_damage": "no"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"minecraft:interact": {
|
||||||
|
"interactions": [
|
||||||
|
{
|
||||||
|
"on_interact": {
|
||||||
|
"filters": {
|
||||||
|
"test": "is_family",
|
||||||
|
"subject": "other",
|
||||||
|
"value": "player"
|
||||||
|
},
|
||||||
|
"event": "rzb_dcs:open"
|
||||||
|
},
|
||||||
|
"swing": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"events": {
|
||||||
|
"rzb_dcs:open": {},
|
||||||
|
"rzb_dcs:ht_0": {
|
||||||
|
"add": {
|
||||||
|
"component_groups": [
|
||||||
|
"rzb_dcs:ht_0"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rzb_dcs:ht_90": {
|
||||||
|
"add": {
|
||||||
|
"component_groups": [
|
||||||
|
"rzb_dcs:ht_90"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rzb_dcs:ht_180": {
|
||||||
|
"add": {
|
||||||
|
"component_groups": [
|
||||||
|
"rzb_dcs:ht_180"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rzb_dcs:ht_270": {
|
||||||
|
"add": {
|
||||||
|
"component_groups": [
|
||||||
|
"rzb_dcs:ht_270"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"component_groups": {
|
||||||
|
"rzb_dcs:ht_0": {
|
||||||
|
"minecraft:custom_hit_test": {
|
||||||
|
"hitboxes": [
|
||||||
|
{
|
||||||
|
"width": 1,
|
||||||
|
"height": 1,
|
||||||
|
"pivot": [
|
||||||
|
0,
|
||||||
|
0.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"width": 1,
|
||||||
|
"height": 1,
|
||||||
|
"pivot": [
|
||||||
|
1,
|
||||||
|
0.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rzb_dcs:ht_90": {
|
||||||
|
"minecraft:custom_hit_test": {
|
||||||
|
"hitboxes": [
|
||||||
|
{
|
||||||
|
"width": 1,
|
||||||
|
"height": 1,
|
||||||
|
"pivot": [
|
||||||
|
0,
|
||||||
|
0.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"width": 1,
|
||||||
|
"height": 1,
|
||||||
|
"pivot": [
|
||||||
|
0,
|
||||||
|
0.5,
|
||||||
|
1
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rzb_dcs:ht_180": {
|
||||||
|
"minecraft:custom_hit_test": {
|
||||||
|
"hitboxes": [
|
||||||
|
{
|
||||||
|
"width": 1,
|
||||||
|
"height": 1,
|
||||||
|
"pivot": [
|
||||||
|
0,
|
||||||
|
0.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"width": 1,
|
||||||
|
"height": 1,
|
||||||
|
"pivot": [
|
||||||
|
-1,
|
||||||
|
0.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rzb_dcs:ht_270": {
|
||||||
|
"minecraft:custom_hit_test": {
|
||||||
|
"hitboxes": [
|
||||||
|
{
|
||||||
|
"width": 1,
|
||||||
|
"height": 1,
|
||||||
|
"pivot": [
|
||||||
|
0,
|
||||||
|
0.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"width": 1,
|
||||||
|
"height": 1,
|
||||||
|
"pivot": [
|
||||||
|
0,
|
||||||
|
0.5,
|
||||||
|
-1
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.21.60",
|
||||||
|
"minecraft:entity": {
|
||||||
|
"description": {
|
||||||
|
"identifier": "rzb_dcs:decobench_init",
|
||||||
|
"is_spawnable": true,
|
||||||
|
"is_summonable": true,
|
||||||
|
"is_experimental": false
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"minecraft:physics": {
|
||||||
|
"has_gravity": false,
|
||||||
|
"has_collision": false
|
||||||
|
},
|
||||||
|
"minecraft:collision_box": {
|
||||||
|
"width": 0.1,
|
||||||
|
"height": 0.1
|
||||||
|
},
|
||||||
|
"minecraft:damage_sensor": {
|
||||||
|
"triggers": [
|
||||||
|
{
|
||||||
|
"cause": "all",
|
||||||
|
"deals_damage": "no"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"minecraft:nameable": {
|
||||||
|
"allow_name_tag_renaming": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.21.60",
|
||||||
|
"minecraft:entity": {
|
||||||
|
"description": {
|
||||||
|
"identifier": "rzb_dcs:decomposer",
|
||||||
|
"is_spawnable": true,
|
||||||
|
"is_summonable": true,
|
||||||
|
"is_experimental": false
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"minecraft:type_family": {
|
||||||
|
"family": [
|
||||||
|
"decomposer",
|
||||||
|
"inanimate"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"minecraft:health": {
|
||||||
|
"value": 10,
|
||||||
|
"max": 10
|
||||||
|
},
|
||||||
|
"minecraft:physics": {
|
||||||
|
"has_gravity": false,
|
||||||
|
"has_collision": false
|
||||||
|
},
|
||||||
|
"minecraft:collision_box": {
|
||||||
|
"width": 1,
|
||||||
|
"height": 1
|
||||||
|
},
|
||||||
|
"minecraft:custom_hit_test": {
|
||||||
|
"hitboxes": [
|
||||||
|
{
|
||||||
|
"width": 1,
|
||||||
|
"height": 1,
|
||||||
|
"pivot": [
|
||||||
|
0,
|
||||||
|
0.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"minecraft:pushable": {
|
||||||
|
"is_pushable": false,
|
||||||
|
"is_pushable_by_piston": false
|
||||||
|
},
|
||||||
|
"minecraft:knockback_resistance": {
|
||||||
|
"value": 1
|
||||||
|
},
|
||||||
|
"minecraft:persistent": {},
|
||||||
|
"minecraft:fire_immune": true,
|
||||||
|
"minecraft:nameable": {
|
||||||
|
"allow_name_tag_renaming": false
|
||||||
|
},
|
||||||
|
"minecraft:damage_sensor": {
|
||||||
|
"triggers": [
|
||||||
|
{
|
||||||
|
"cause": "all",
|
||||||
|
"deals_damage": "no"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"minecraft:interact": {
|
||||||
|
"interactions": [
|
||||||
|
{
|
||||||
|
"on_interact": {
|
||||||
|
"filters": {
|
||||||
|
"test": "is_family",
|
||||||
|
"subject": "other",
|
||||||
|
"value": "player"
|
||||||
|
},
|
||||||
|
"event": "rzb_dcs:open"
|
||||||
|
},
|
||||||
|
"swing": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"events": {
|
||||||
|
"rzb_dcs:open": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.21.60",
|
||||||
|
"minecraft:entity": {
|
||||||
|
"description": {
|
||||||
|
"identifier": "rzb_dcs:decomposer_init",
|
||||||
|
"is_spawnable": true,
|
||||||
|
"is_summonable": true,
|
||||||
|
"is_experimental": false
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"minecraft:physics": {
|
||||||
|
"has_gravity": false,
|
||||||
|
"has_collision": false
|
||||||
|
},
|
||||||
|
"minecraft:collision_box": {
|
||||||
|
"width": 0.1,
|
||||||
|
"height": 0.1
|
||||||
|
},
|
||||||
|
"minecraft:damage_sensor": {
|
||||||
|
"triggers": [
|
||||||
|
{
|
||||||
|
"cause": "all",
|
||||||
|
"deals_damage": "no"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"minecraft:nameable": {
|
||||||
|
"allow_name_tag_renaming": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.21.60",
|
||||||
|
"minecraft:item": {
|
||||||
|
"description": {
|
||||||
|
"identifier": "rzb_dcs:deco_seasons_decomp",
|
||||||
|
"menu_category": {
|
||||||
|
"category": "items",
|
||||||
|
"group": "rzb_dcs:group_decostation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"minecraft:icon": {
|
||||||
|
"textures": {
|
||||||
|
"default": "rzb_dcs_deco_seasons_decomp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minecraft:max_stack_size": 16,
|
||||||
|
"minecraft:hand_equipped": true,
|
||||||
|
"minecraft:entity_placer": {
|
||||||
|
"entity": "rzb_dcs:decomposer_init"
|
||||||
|
},
|
||||||
|
"minecraft:display_name": {
|
||||||
|
"value": "item.rzb_dcs:deco_seasons_decomp.name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.21.60",
|
||||||
|
"minecraft:item": {
|
||||||
|
"description": {
|
||||||
|
"identifier": "rzb_dcs:seasons_bench",
|
||||||
|
"menu_category": {
|
||||||
|
"category": "items",
|
||||||
|
"group": "rzb_dcs:group_decostation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"minecraft:icon": {
|
||||||
|
"textures": {
|
||||||
|
"default": "rzb_dcs_seasons_bench"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minecraft:max_stack_size": 16,
|
||||||
|
"minecraft:hand_equipped": true,
|
||||||
|
"minecraft:entity_placer": {
|
||||||
|
"entity": "rzb_dcs:decobench_init"
|
||||||
|
},
|
||||||
|
"minecraft:display_name": {
|
||||||
|
"value": "item.rzb_dcs:seasons_bench.name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
|||||||
// features/break_particle.js — custom block break particle
|
// features/break_particle.js custom block break particle
|
||||||
|
|
||||||
import { system } from "../core/mc.js";
|
import { system } from "../core/mc.js";
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// features/brush.js — the Color Brush recolour
|
// features/brush.js the Color Brush recolour
|
||||||
import { world, system, BlockPermutation, getDir, safeGetBlock } from "../core/mc.js";
|
import { world, system, BlockPermutation, getDir, safeGetBlock } from "../core/mc.js";
|
||||||
import { VARIANT_SEQ } from "../core/variants.js";
|
import { VARIANT_SEQ } from "../core/variants.js";
|
||||||
import { particleFor, brushFx, debounced } from "../core/fx.js";
|
import { particleFor, brushFx, debounced } from "../core/fx.js";
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
|
|
||||||
// features/decor.js — standalone brush recolorable decoration blocks.
|
// features/decor.js standalone brush recolorable decoration blocks.
|
||||||
|
|
||||||
import { registerVariants } from "../core/variants.js";
|
import { registerVariants } from "../core/variants.js";
|
||||||
|
|
||||||
registerVariants(["rzb_dcs:sp22_white", "rzb_dcs:sp22_yellow", "rzb_dcs:sp22_pink", "rzb_dcs:sp22_purple", "rzb_dcs:sp22_red", "rzb_dcs:sp22_salmon"]); // rose vase
|
registerVariants(["rzb_dcs:sp22_white", "rzb_dcs:sp22_yellow", "rzb_dcs:sp22_pink", "rzb_dcs:sp22_purple", "rzb_dcs:sp22_red", "rzb_dcs:sp22_salmon"]); // rose vase
|
||||||
registerVariants(["rzb_dcs:sp25_pink", "rzb_dcs:sp25_red"]); // valentine card
|
registerVariants(["rzb_dcs:sp25_pink", "rzb_dcs:sp25_red"]); // valentine card
|
||||||
registerVariants(["rzb_dcs:sp21_white", "rzb_dcs:sp21_yellow", "rzb_dcs:sp21_pink", "rzb_dcs:sp21_red"]); // potted cherry branch
|
registerVariants(["rzb_dcs:sp21_white", "rzb_dcs:sp21_yellow", "rzb_dcs:sp21_pink", "rzb_dcs:sp21_red"]); // potted cherry branch
|
||||||
registerVariants(["rzb_dcs:sp12_silver", "rzb_dcs:sp12_gold", "rzb_dcs:sp12_rosegold"]); // engagement ring (metals — natural order)
|
registerVariants(["rzb_dcs:sp12_silver", "rzb_dcs:sp12_gold", "rzb_dcs:sp12_rosegold"]); // engagement ring (metals natural order)
|
||||||
registerVariants(["rzb_dcs:sp11_yellow", "rzb_dcs:sp11_pink", "rzb_dcs:sp11_white"]); // easter basket
|
registerVariants(["rzb_dcs:sp11_yellow", "rzb_dcs:sp11_pink", "rzb_dcs:sp11_white"]); // easter basket
|
||||||
registerVariants(["rzb_dcs:sp26_tulips", "rzb_dcs:sp26_flowers1", "rzb_dcs:sp26_flowers2"]); // watering can (flower types — natural order)
|
registerVariants(["rzb_dcs:sp26_tulips", "rzb_dcs:sp26_flowers1", "rzb_dcs:sp26_flowers2"]); // watering can (flower types natural order)
|
||||||
registerVariants(["rzb_dcs:sp27_plain", "rzb_dcs:sp27_spring"]); // welcome mat (styles — natural order)
|
registerVariants(["rzb_dcs:sp27_plain", "rzb_dcs:sp27_spring"]); // welcome mat (styles natural order)
|
||||||
registerVariants(["rzb_dcs:sp37_white", "rzb_dcs:sp37_red"]); // spider lily bouquet
|
registerVariants(["rzb_dcs:sp37_white", "rzb_dcs:sp37_red"]); // spider lily bouquet
|
||||||
registerVariants(["rzb_dcs:sp39_yellow", "rzb_dcs:sp39_pink", "rzb_dcs:sp39_purple", "rzb_dcs:sp39_blue", "rzb_dcs:sp39_green"]); // spring armchair (canonical cycle order)
|
registerVariants(["rzb_dcs:sp39_yellow", "rzb_dcs:sp39_pink", "rzb_dcs:sp39_purple", "rzb_dcs:sp39_blue", "rzb_dcs:sp39_green"]); // spring armchair (canonical cycle order)
|
||||||
registerVariants(["rzb_dcs:sp40_yellow", "rzb_dcs:sp40_pink", "rzb_dcs:sp40_purple", "rzb_dcs:sp40_blue", "rzb_dcs:sp40_green"]); // spring couch left
|
registerVariants(["rzb_dcs:sp40_yellow", "rzb_dcs:sp40_pink", "rzb_dcs:sp40_purple", "rzb_dcs:sp40_blue", "rzb_dcs:sp40_green"]); // spring couch left
|
||||||
@@ -28,7 +28,7 @@ registerVariants(["rzb_dcs:su37_yellow", "rzb_dcs:su37_green"]); // potted bambo
|
|||||||
registerVariants(["rzb_dcs:sp44_blue_and_purple", "rzb_dcs:sp44_pink_and_green"]); // candle lanterns (spring, 3-frame flipbook)
|
registerVariants(["rzb_dcs:sp44_blue_and_purple", "rzb_dcs:sp44_pink_and_green"]); // candle lanterns (spring, 3-frame flipbook)
|
||||||
registerVariants(["rzb_dcs:wi49_blue", "rzb_dcs:wi49_green", "rzb_dcs:wi49_red", "rzb_dcs:wi49_white"]); // candle holder / advent candlestick (winter, 3-frame flipbook)
|
registerVariants(["rzb_dcs:wi49_blue", "rzb_dcs:wi49_green", "rzb_dcs:wi49_red", "rzb_dcs:wi49_white"]); // candle holder / advent candlestick (winter, 3-frame flipbook)
|
||||||
registerVariants(["rzb_dcs:sp45", "rzb_dcs:sp45_rainbow"]); // wind chime 2 (spring) OFF-block form; brushing the animated entity recolours via toggles.js
|
registerVariants(["rzb_dcs:sp45", "rzb_dcs:sp45_rainbow"]); // wind chime 2 (spring) OFF-block form; brushing the animated entity recolours via toggles.js
|
||||||
// rose vine wall (spring) — 3 shape pieces for building vine chains, each brush-cyclable through its 11 colours
|
// rose vine wall (spring) 3 shape pieces for building vine chains, each brush-cyclable through its 11 colours
|
||||||
registerVariants(["rzb_dcs:sp47_red", "rzb_dcs:sp47_pink", "rzb_dcs:sp47_pink_alt", "rzb_dcs:sp47_orange", "rzb_dcs:sp47_yellow", "rzb_dcs:sp47_yellow_alt", "rzb_dcs:sp47_green", "rzb_dcs:sp47_blue", "rzb_dcs:sp47_purple", "rzb_dcs:sp47_white", "rzb_dcs:sp47_black"]); // middle
|
registerVariants(["rzb_dcs:sp47_red", "rzb_dcs:sp47_pink", "rzb_dcs:sp47_pink_alt", "rzb_dcs:sp47_orange", "rzb_dcs:sp47_yellow", "rzb_dcs:sp47_yellow_alt", "rzb_dcs:sp47_green", "rzb_dcs:sp47_blue", "rzb_dcs:sp47_purple", "rzb_dcs:sp47_white", "rzb_dcs:sp47_black"]); // middle
|
||||||
registerVariants(["rzb_dcs:sp48_red", "rzb_dcs:sp48_pink", "rzb_dcs:sp48_pink_alt", "rzb_dcs:sp48_orange", "rzb_dcs:sp48_yellow", "rzb_dcs:sp48_yellow_alt", "rzb_dcs:sp48_green", "rzb_dcs:sp48_blue", "rzb_dcs:sp48_purple", "rzb_dcs:sp48_white", "rzb_dcs:sp48_black"]); // diagonal left
|
registerVariants(["rzb_dcs:sp48_red", "rzb_dcs:sp48_pink", "rzb_dcs:sp48_pink_alt", "rzb_dcs:sp48_orange", "rzb_dcs:sp48_yellow", "rzb_dcs:sp48_yellow_alt", "rzb_dcs:sp48_green", "rzb_dcs:sp48_blue", "rzb_dcs:sp48_purple", "rzb_dcs:sp48_white", "rzb_dcs:sp48_black"]); // diagonal left
|
||||||
registerVariants(["rzb_dcs:sp49_red", "rzb_dcs:sp49_pink", "rzb_dcs:sp49_pink_alt", "rzb_dcs:sp49_orange", "rzb_dcs:sp49_yellow", "rzb_dcs:sp49_yellow_alt", "rzb_dcs:sp49_green", "rzb_dcs:sp49_blue", "rzb_dcs:sp49_purple", "rzb_dcs:sp49_white", "rzb_dcs:sp49_black"]); // diagonal right
|
registerVariants(["rzb_dcs:sp49_red", "rzb_dcs:sp49_pink", "rzb_dcs:sp49_pink_alt", "rzb_dcs:sp49_orange", "rzb_dcs:sp49_yellow", "rzb_dcs:sp49_yellow_alt", "rzb_dcs:sp49_green", "rzb_dcs:sp49_blue", "rzb_dcs:sp49_purple", "rzb_dcs:sp49_white", "rzb_dcs:sp49_black"]); // diagonal right
|
||||||
@@ -74,6 +74,6 @@ registerVariants(["rzb_dcs:bl_p_orange", "rzb_dcs:bl_p_yellow", "rzb_dcs:bl_p_li
|
|||||||
registerVariants(["rzb_dcs:bl_heart_white", "rzb_dcs:bl_heart_orange", "rzb_dcs:bl_heart_yellow", "rzb_dcs:bl_heart_pink", "rzb_dcs:bl_heart_cyan", "rzb_dcs:bl_heart_purple", "rzb_dcs:bl_heart_blue", "rzb_dcs:bl_heart_green", "rzb_dcs:bl_heart_red", "rzb_dcs:bl_heart_berry", "rzb_dcs:bl_heart_rainbow"]); // heart balloons (regular)
|
registerVariants(["rzb_dcs:bl_heart_white", "rzb_dcs:bl_heart_orange", "rzb_dcs:bl_heart_yellow", "rzb_dcs:bl_heart_pink", "rzb_dcs:bl_heart_cyan", "rzb_dcs:bl_heart_purple", "rzb_dcs:bl_heart_blue", "rzb_dcs:bl_heart_green", "rzb_dcs:bl_heart_red", "rzb_dcs:bl_heart_berry", "rzb_dcs:bl_heart_rainbow"]); // heart balloons (regular)
|
||||||
registerVariants(["rzb_dcs:bl_heart_p_orange", "rzb_dcs:bl_heart_p_yellow", "rzb_dcs:bl_heart_p_lime", "rzb_dcs:bl_heart_p_pink", "rzb_dcs:bl_heart_p_cyan", "rzb_dcs:bl_heart_p_purple", "rzb_dcs:bl_heart_p_blue", "rzb_dcs:bl_heart_p_green", "rzb_dcs:bl_heart_p_red"]); // heart balloons (pastel)
|
registerVariants(["rzb_dcs:bl_heart_p_orange", "rzb_dcs:bl_heart_p_yellow", "rzb_dcs:bl_heart_p_lime", "rzb_dcs:bl_heart_p_pink", "rzb_dcs:bl_heart_p_cyan", "rzb_dcs:bl_heart_p_purple", "rzb_dcs:bl_heart_p_blue", "rzb_dcs:bl_heart_p_green", "rzb_dcs:bl_heart_p_red"]); // heart balloons (pastel)
|
||||||
// (balloons_small is a 2-cell multiblock -> brush-cycled via a both-cells branch in brush.js, NOT registerVariants.)
|
// (balloons_small is a 2-cell multiblock -> brush-cycled via a both-cells branch in brush.js, NOT registerVariants.)
|
||||||
// jack 'o lantern carvings — two groups so brushing keeps the on/off state (off cycles off, lit cycles lit); facing preserved
|
// jack 'o lantern carvings two groups so brushing keeps the on/off state (off cycles off, lit cycles lit); facing preserved
|
||||||
registerVariants(["rzb_dcs:fa33_1", "rzb_dcs:fa33_2", "rzb_dcs:fa33_3", "rzb_dcs:fa33_4"]); // carvings (off)
|
registerVariants(["rzb_dcs:fa33_1", "rzb_dcs:fa33_2", "rzb_dcs:fa33_3", "rzb_dcs:fa33_4"]); // carvings (off)
|
||||||
registerVariants(["rzb_dcs:fa33_1_on", "rzb_dcs:fa33_2_on", "rzb_dcs:fa33_3_on", "rzb_dcs:fa33_4_on"]); // carvings (lit)
|
registerVariants(["rzb_dcs:fa33_1_on", "rzb_dcs:fa33_2_on", "rzb_dcs:fa33_3_on", "rzb_dcs:fa33_4_on"]); // carvings (lit)
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ const STATIONS = new Set(["rzb_dcs:decobench", "rzb_dcs:decomposer"]);
|
|||||||
const OBJ = { m: "rzb_dcs_deco_mat", r: "rzb_dcs_deco_red", g: "rzb_dcs_deco_green", b: "rzb_dcs_deco_blue" };
|
const OBJ = { m: "rzb_dcs_deco_mat", r: "rzb_dcs_deco_red", g: "rzb_dcs_deco_green", b: "rzb_dcs_deco_blue" };
|
||||||
const FEED_ITEM = { m: "rzb_dcs:raw_material", r: "minecraft:red_dye", g: "minecraft:green_dye", b: "minecraft:blue_dye" };
|
const FEED_ITEM = { m: "rzb_dcs:raw_material", r: "minecraft:red_dye", g: "minecraft:green_dye", b: "minecraft:blue_dye" };
|
||||||
const CHANNELS = ["m", "r", "g", "b"];
|
const CHANNELS = ["m", "r", "g", "b"];
|
||||||
|
// decomposer fuel (DecoCraft): coal only, +4 per coal up to 32, -4 consumed per block-decompose
|
||||||
|
const FUEL = { obj: "rzb_dcs_decomp_fuel", max: 32, perCoal: 4, perDecomp: 4 };
|
||||||
|
const FUEL_ITEMS = ["minecraft:coal", "minecraft:charcoal"];
|
||||||
|
|
||||||
// block -> how many make 1 raw_material (DecoCraft rates). dirt 8, cobblestone 4, every log/wood 2.
|
// block -> how many make 1 raw_material (DecoCraft rates). dirt 8, cobblestone 4, every log/wood 2.
|
||||||
const DECOMP = { "minecraft:dirt": 8, "minecraft:cobblestone": 4 };
|
const DECOMP = { "minecraft:dirt": 8, "minecraft:cobblestone": 4 };
|
||||||
@@ -44,6 +47,10 @@ const get = (station, key) => { try { return objective(key).getScore(station) ??
|
|||||||
const setRaw = (station, key, v) => { try { objective(key).setScore(station, Math.max(0, Math.min(CAP[key], v))); } catch {} };
|
const setRaw = (station, key, v) => { try { objective(key).setScore(station, Math.max(0, Math.min(CAP[key], v))); } catch {} };
|
||||||
const addUnits = (station, key, delta) => setRaw(station, key, get(station, key) + delta);
|
const addUnits = (station, key, delta) => setRaw(station, key, get(station, key) + delta);
|
||||||
const balance = (station) => ({ m: get(station, "m"), r: get(station, "r"), g: get(station, "g"), b: get(station, "b") });
|
const balance = (station) => ({ m: get(station, "m"), r: get(station, "r"), g: get(station, "g"), b: get(station, "b") });
|
||||||
|
// decomposer fuel scoreboard (participant = the decomposer entity)
|
||||||
|
const fuelObj = () => { let o = world.scoreboard.getObjective(FUEL.obj); if (!o) { try { o = world.scoreboard.addObjective(FUEL.obj, FUEL.obj); } catch { o = world.scoreboard.getObjective(FUEL.obj); } } return o; };
|
||||||
|
const fuelGet = (st) => { try { return fuelObj().getScore(st) ?? 0; } catch { return 0; } };
|
||||||
|
const fuelSet = (st, v) => { try { fuelObj().setScore(st, Math.max(0, Math.min(FUEL.max, v))); } catch {} };
|
||||||
|
|
||||||
// mirror the balance onto the station's meter_* props so the model can show fill
|
// mirror the balance onto the station's meter_* props so the model can show fill
|
||||||
function syncMeters(station) {
|
function syncMeters(station) {
|
||||||
@@ -72,6 +79,15 @@ function takeFromPlayer(player, itemId, count) {
|
|||||||
}
|
}
|
||||||
return count - need;
|
return count - need;
|
||||||
}
|
}
|
||||||
|
// pull up to `count` of itemId from the player's MAINHAND stack only (DecoCraft consumes the held stack, not the inventory)
|
||||||
|
function takeFromHand(player, itemId, count) {
|
||||||
|
const inv = player?.getComponent("minecraft:inventory")?.container; if (!inv) return 0;
|
||||||
|
const i = player.selectedSlotIndex ?? 0, it = inv.getItem(i);
|
||||||
|
if (it?.typeId !== itemId) return 0;
|
||||||
|
const take = Math.min(it.amount, count);
|
||||||
|
if (it.amount - take <= 0) inv.setItem(i, undefined); else { it.amount -= take; inv.setItem(i, it); }
|
||||||
|
return take;
|
||||||
|
}
|
||||||
function givePlayer(player, itemId, count) {
|
function givePlayer(player, itemId, count) {
|
||||||
const inv = player?.getComponent("minecraft:inventory")?.container;
|
const inv = player?.getComponent("minecraft:inventory")?.container;
|
||||||
const stack = new ItemStack(itemId, Math.max(1, Math.min(64, count)));
|
const stack = new ItemStack(itemId, Math.max(1, Math.min(64, count)));
|
||||||
@@ -106,11 +122,21 @@ function decompose(station, slot) {
|
|||||||
const d = slotDeco(slot); if (!d || !d.cost) return;
|
const d = slotDeco(slot); if (!d || !d.cost) return;
|
||||||
const player = nearestPlayer(station); if (!player) return;
|
const player = nearestPlayer(station); if (!player) return;
|
||||||
if (takeFromPlayer(player, d.id, 1) < 1) return; // must hold the decoration to break it
|
if (takeFromPlayer(player, d.id, 1) < 1) return; // must hold the decoration to break it
|
||||||
for (const k of CHANNELS) if (d.cost[k]) givePlayer(player, FEED_ITEM[k], d.cost[k]); // hand its materials back as items
|
if (d.cost.m) givePlayer(player, FEED_ITEM.m, d.cost.m); // raw_material is 1 unit/item -> give m items
|
||||||
|
for (const k of ["r", "g", "b"]) { const items = Math.floor((d.cost[k] || 0) / UNITS[k]); if (items) givePlayer(player, FEED_ITEM[k], items); } // dye cost is in UNITS -> convert to items (/8), no 8x inflation
|
||||||
try { world.scoreboard.getObjective("rzb_dcs_logs_decomposed")?.addScore(station, 1); } catch {}
|
try { world.scoreboard.getObjective("rzb_dcs_logs_decomposed")?.addScore(station, 1); } catch {}
|
||||||
}
|
}
|
||||||
// blocks -> raw_material, from the player's held stack (floor by rate, leftover stays), like DecoCraft
|
// coal -> fuel (DecoCraft: +4 per coal up to 32, from the held stack)
|
||||||
|
function feedFuel(station) {
|
||||||
|
const player = nearestPlayer(station); if (!player) return;
|
||||||
|
const space = FUEL.max - fuelGet(station); if (space < FUEL.perCoal) return;
|
||||||
|
const maxCoal = Math.floor(space / FUEL.perCoal);
|
||||||
|
let took = 0; for (const it of FUEL_ITEMS) { took = takeFromHand(player, it, maxCoal); if (took) break; }
|
||||||
|
if (took) fuelSet(station, fuelGet(station) + took * FUEL.perCoal);
|
||||||
|
}
|
||||||
|
// blocks -> raw_material, from the player's held stack (floor by rate, leftover stays). Requires + consumes coal fuel (DecoCraft)
|
||||||
function decompBlock(station) {
|
function decompBlock(station) {
|
||||||
|
if (fuelGet(station) < FUEL.perDecomp) { try { nearestPlayer(station)?.playSound("note.bass", { volume: 0.6 }); } catch {} return; } // out of fuel
|
||||||
const player = nearestPlayer(station); if (!player) return;
|
const player = nearestPlayer(station); if (!player) return;
|
||||||
const inv = player.getComponent("minecraft:inventory")?.container; if (!inv) return;
|
const inv = player.getComponent("minecraft:inventory")?.container; if (!inv) return;
|
||||||
const idx = player.selectedSlotIndex ?? 0, held = inv.getItem(idx);
|
const idx = player.selectedSlotIndex ?? 0, held = inv.getItem(idx);
|
||||||
@@ -120,13 +146,14 @@ function decompBlock(station) {
|
|||||||
if (held.amount - used <= 0) inv.setItem(idx, undefined);
|
if (held.amount - used <= 0) inv.setItem(idx, undefined);
|
||||||
else { held.amount -= used; inv.setItem(idx, held); }
|
else { held.amount -= used; inv.setItem(idx, held); }
|
||||||
givePlayer(player, FEED_ITEM.m, toraw);
|
givePlayer(player, FEED_ITEM.m, toraw);
|
||||||
|
fuelSet(station, fuelGet(station) - FUEL.perDecomp); // remove_fuel per process
|
||||||
}
|
}
|
||||||
function feed(station, key) {
|
function feed(station, key) {
|
||||||
const player = nearestPlayer(station); if (!player) return;
|
const player = nearestPlayer(station); if (!player) return;
|
||||||
const space = CAP[key] - get(station, key); if (space <= 0) return;
|
const space = CAP[key] - get(station, key); if (space <= 0) return;
|
||||||
const per = UNITS[key];
|
const per = UNITS[key];
|
||||||
const maxItems = Math.floor(space / per) + (space % per ? 1 : 0); // last item may partly fill
|
const maxItems = Math.floor(space / per) + (space % per ? 1 : 0); // last item may partly fill
|
||||||
const took = takeFromPlayer(player, FEED_ITEM[key], maxItems); if (!took) return;
|
const took = takeFromHand(player, FEED_ITEM[key], maxItems); if (!took) return;
|
||||||
addUnits(station, key, Math.min(space, took * per));
|
addUnits(station, key, Math.min(space, took * per));
|
||||||
syncMeters(station);
|
syncMeters(station);
|
||||||
}
|
}
|
||||||
@@ -134,10 +161,9 @@ function feed(station, key) {
|
|||||||
function feedCompound(station, itemId, kA, kB) {
|
function feedCompound(station, itemId, kA, kB) {
|
||||||
const player = nearestPlayer(station); if (!player) return;
|
const player = nearestPlayer(station); if (!player) return;
|
||||||
const per = 4, spaceA = CAP[kA] - get(station, kA), spaceB = CAP[kB] - get(station, kB);
|
const per = 4, spaceA = CAP[kA] - get(station, kA), spaceB = CAP[kB] - get(station, kB);
|
||||||
const room = Math.max(spaceA, spaceB); if (room <= 0) return;
|
const maxItems = Math.min(Math.floor(spaceA / per), Math.floor(spaceB / per)); if (maxItems <= 0) return; // both channels must accept the full 4 (no dye wasted)
|
||||||
const took = takeFromPlayer(player, itemId, Math.ceil(room / per)); if (!took) return;
|
const took = takeFromHand(player, itemId, maxItems); if (!took) return;
|
||||||
addUnits(station, kA, Math.min(spaceA, took * per));
|
addUnits(station, kA, took * per); addUnits(station, kB, took * per);
|
||||||
addUnits(station, kB, Math.min(spaceB, took * per));
|
|
||||||
syncMeters(station);
|
syncMeters(station);
|
||||||
}
|
}
|
||||||
function drop(station, key) {
|
function drop(station, key) {
|
||||||
@@ -147,6 +173,11 @@ function drop(station, key) {
|
|||||||
dropAt(station.dimension, station.location, FEED_ITEM[key], items);
|
dropAt(station.dimension, station.location, FEED_ITEM[key], items);
|
||||||
syncMeters(station);
|
syncMeters(station);
|
||||||
}
|
}
|
||||||
|
// return ALL stored materials as items (DecoCraft returns these when a bench is broken)
|
||||||
|
export function dropAll(station) { for (const k of CHANNELS) drop(station, k); }
|
||||||
|
function dropFuel(station) { const coal = Math.floor(fuelGet(station) / FUEL.perCoal); if (coal > 0) dropAt(station.dimension, station.location, "minecraft:coal", coal); fuelSet(station, 0); }
|
||||||
|
// on break: the bench returns its stored materials, the decomposer returns its stored fuel as coal
|
||||||
|
export function dropStored(station) { if (station?.typeId === "rzb_dcs:decomposer") dropFuel(station); else dropAll(station); }
|
||||||
function refresh(station, slot) { const d = slotDeco(slot); if (d?.cost) writeSlotState(slot, station, d.cost); }
|
function refresh(station, slot) { const d = slotDeco(slot); if (d?.cost) writeSlotState(slot, station, d.cost); }
|
||||||
|
|
||||||
// the /scriptevent router; the UI drives everything through here
|
// the /scriptevent router; the UI drives everything through here
|
||||||
@@ -154,6 +185,7 @@ const HANDLERS = {
|
|||||||
"rzb_dcs:deco_craft": (st, src) => craft(st, src),
|
"rzb_dcs:deco_craft": (st, src) => craft(st, src),
|
||||||
"rzb_dcs:deco_decompose": (st, src) => decompose(st, src),
|
"rzb_dcs:deco_decompose": (st, src) => decompose(st, src),
|
||||||
"rzb_dcs:decomp_block": (st) => decompBlock(st),
|
"rzb_dcs:decomp_block": (st) => decompBlock(st),
|
||||||
|
"rzb_dcs:feed_fuel": (st) => feedFuel(st),
|
||||||
"rzb_dcs:deco_refresh": (st, src) => refresh(st, src),
|
"rzb_dcs:deco_refresh": (st, src) => refresh(st, src),
|
||||||
"rzb_dcs:feed_mat": (st) => feed(st, "m"),
|
"rzb_dcs:feed_mat": (st) => feed(st, "m"),
|
||||||
"rzb_dcs:feed_red": (st) => feed(st, "r"),
|
"rzb_dcs:feed_red": (st) => feed(st, "r"),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
// features/display.js — animated display pieces (place a block -> spawn an entity).
|
// features/display.js animated display pieces (place a block -> spawn an entity).
|
||||||
import { DISPLAY_DIR_YAW } from "../core/grid.js";
|
import { DISPLAY_DIR_YAW } from "../core/grid.js";
|
||||||
import { summonDisplay, breakFx, particleFor } from "../core/fx.js";
|
import { summonDisplay, breakFx, particleFor } from "../core/fx.js";
|
||||||
import { onPlace, onBreak } from "../core/events.js";
|
import { onPlace, onBreak } from "../core/events.js";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
// features/interact.js — right-click lids/toggles + the interact fall-through dispatcher.
|
// features/interact.js right-click lids/toggles + the interact fall-through dispatcher.
|
||||||
|
|
||||||
import { world, system, BlockPermutation, getDir, safeGetBlock } from "../core/mc.js";
|
import { world, system, BlockPermutation, getDir, safeGetBlock } from "../core/mc.js";
|
||||||
import { tubeOverWater } from "../core/grid.js";
|
import { tubeOverWater } from "../core/grid.js";
|
||||||
@@ -110,7 +110,7 @@ world.afterEvents.playerInteractWithBlock?.subscribe((ev) => {
|
|||||||
if (emberToggle(ev.block)) return;
|
if (emberToggle(ev.block)) return;
|
||||||
if (lanternToggle(ev.block)) return;
|
if (lanternToggle(ev.block)) return;
|
||||||
if (jolToggle(ev.block)) return;
|
if (jolToggle(ev.block)) return;
|
||||||
// su02 tube / su03 lounger over water are boats (ride_* component boards them) — don't also sit.
|
// su02 tube / su03 lounger over water are boats (ride_* component boards them) don't also sit.
|
||||||
const id = ev.block?.typeId;
|
const id = ev.block?.typeId;
|
||||||
if ((id?.startsWith("rzb_dcs:su02_") || id?.startsWith("rzb_dcs:su03_")) && tubeOverWater(ev.block)) return;
|
if ((id?.startsWith("rzb_dcs:su02_") || id?.startsWith("rzb_dcs:su03_")) && tubeOverWater(ev.block)) return;
|
||||||
sit(ev.player, ev.block);
|
sit(ev.player, ev.block);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// features/maintenance.js — pick-block anchor redirect + firepit embers.
|
// features/maintenance.js pick-block anchor redirect + firepit embers.
|
||||||
import { world, system, ItemStack, safeGetBlock, isCreative } from "../core/mc.js";
|
import { world, system, ItemStack, safeGetBlock, isCreative } from "../core/mc.js";
|
||||||
import { onPlace, onBreak } from "../core/events.js";
|
import { onPlace, onBreak } from "../core/events.js";
|
||||||
import { UMBRELLA_BAMBOO, UMBRELLA_BEACH, BAMBOO_TABLE } from "./mb_grid.js";
|
import { UMBRELLA_BAMBOO, UMBRELLA_BEACH, BAMBOO_TABLE } from "./mb_grid.js";
|
||||||
@@ -87,7 +87,7 @@ export const EMBER_BLOCKS = {
|
|||||||
"rzb_dcs:su13_green": { y: 0.85, ent: TORCH_ENT },
|
"rzb_dcs:su13_green": { y: 0.85, ent: TORCH_ENT },
|
||||||
"rzb_dcs:su13_yellow": { y: 0.85, ent: TORCH_ENT },
|
"rzb_dcs:su13_yellow": { y: 0.85, ent: TORCH_ENT },
|
||||||
"rzb_dcs:fa37": { y: 0.7, ent: CAULDRON_ENT },
|
"rzb_dcs:fa37": { y: 0.7, ent: CAULDRON_ENT },
|
||||||
"rzb_dcs:fa08": { y: 0.4, ent: SPARKLE_ENT }, // crystal ball — always-on twinkling sparkle ring around the orb (no lit state)
|
"rzb_dcs:fa08": { y: 0.4, ent: SPARKLE_ENT }, // crystal ball always-on twinkling sparkle ring around the orb (no lit state)
|
||||||
// open grill = smoke; the CLOSED grill ids aren't here, so the sweep removes the emitter when it's shut (no lit state)
|
// open grill = smoke; the CLOSED grill ids aren't here, so the sweep removes the emitter when it's shut (no lit state)
|
||||||
"rzb_dcs:su19_black": { y: 0.9, ent: GRILL_ENT },
|
"rzb_dcs:su19_black": { y: 0.9, ent: GRILL_ENT },
|
||||||
"rzb_dcs:su19_blue": { y: 0.9, ent: GRILL_ENT },
|
"rzb_dcs:su19_blue": { y: 0.9, ent: GRILL_ENT },
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// features/mb_grid.js — grid & canopy multiblocks, defined as data.
|
// features/mb_grid.js grid & canopy multiblocks, defined as data.
|
||||||
|
|
||||||
import { defineGridMultiblock } from "../core/multiblock.js";
|
import { defineGridMultiblock } from "../core/multiblock.js";
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// features/mb_pairs.js — partner / vertical / 2x2 multiblocks.
|
// features/mb_pairs.js partner / vertical / 2x2 multiblocks.
|
||||||
import { world, system, BlockPermutation, ItemStack, isCreative, getDir, safeGetBlock } from "../core/mc.js";
|
import { world, system, BlockPermutation, ItemStack, isCreative, getDir, safeGetBlock } from "../core/mc.js";
|
||||||
import { fcCanReplace } from "../core/grid.js";
|
import { fcCanReplace } from "../core/grid.js";
|
||||||
import { undoPlace, breakAir } from "../core/fx.js";
|
import { undoPlace, breakAir } from "../core/fx.js";
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
// features/mb_trees.js — christmas / light / potted trees as multiblocks.
|
// features/mb_trees.js christmas / light / potted trees as multiblocks.
|
||||||
|
|
||||||
import { BlockPermutation, ItemStack, isCreative, getDir, safeGetBlock } from "../core/mc.js";
|
import { BlockPermutation, ItemStack, isCreative, getDir, safeGetBlock } from "../core/mc.js";
|
||||||
import { grid, fcCanReplace } from "../core/grid.js";
|
import { grid, fcCanReplace } from "../core/grid.js";
|
||||||
import { undoPlace, breakAir } from "../core/fx.js";
|
import { undoPlace, breakAir } from "../core/fx.js";
|
||||||
import { onPlace, onBreak } from "../core/events.js";
|
import { onPlace, onBreak } from "../core/events.js";
|
||||||
|
|
||||||
// Rainbow and white are INDEPENDENT block sets (white id = rainbow id + "_w"), each registered as a plain multiblock — no
|
// Rainbow and white are INDEPENDENT block sets (white id = rainbow id + "_w"), each registered as a plain multiblock no
|
||||||
// rzb_dcs:tc state. Pick-block therefore returns the correct item (and name) natively; brush.js converts between the two.
|
// rzb_dcs:tc state. Pick-block therefore returns the correct item (and name) natively; brush.js converts between the two.
|
||||||
|
|
||||||
// --- grid trees (christmas / light): a 3D cell grid placed from the anchor cell ---
|
// --- grid trees (christmas / light): a 3D cell grid placed from the anchor cell ---
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// features/rideables.js — block <-> rideable-entity vehicles (tube, flamingo, lounger, bike, surfboard, basket bike, sled).
|
// features/rideables.js block <-> rideable-entity vehicles (tube, flamingo, lounger, bike, surfboard, basket bike, sled).
|
||||||
|
|
||||||
// Parks as a block; a ride_* interact spawns a steerable entity; riderless it reverts (color + heading kept).
|
// Parks as a block; a ride_* interact spawns a steerable entity; riderless it reverts (color + heading kept).
|
||||||
// Water craft steer via applyImpulse + no-Y setRotation (engine keeps float); land bikes velocity-drive with gravity.
|
// Water craft steer via applyImpulse + no-Y setRotation (engine keeps float); land bikes velocity-drive with gravity.
|
||||||
@@ -135,7 +135,7 @@ function steerForward(p, ent, yawOff = 0) {
|
|||||||
|
|
||||||
// Every buoyant water craft (tube, flamingo, lounger, surfboard) steers identically: impulse horizontal velocity toward
|
// Every buoyant water craft (tube, flamingo, lounger, surfboard) steers identically: impulse horizontal velocity toward
|
||||||
// look+WASD * speed (coast when idle), face the travel heading. Only the pose anim, speed, yaw offset, and turn style
|
// look+WASD * speed (coast when idle), face the travel heading. Only the pose anim, speed, yaw offset, and turn style
|
||||||
// vary — smoothTurn>0 lerps the body toward heading (the round tube), 0 snaps instantly (directional lounger/surfboard).
|
// vary smoothTurn>0 lerps the body toward heading (the round tube), 0 snaps instantly (directional lounger/surfboard).
|
||||||
function driveWaterCraft(p, boat, anim, speed, yawOff = 0, smoothTurn = 0) {
|
function driveWaterCraft(p, boat, anim, speed, yawOff = 0, smoothTurn = 0) {
|
||||||
try { p.playAnimation(anim, { blendOutTime: 0, stopExpression: "!q.is_riding" }); } catch {}
|
try { p.playAnimation(anim, { blendOutTime: 0, stopExpression: "!q.is_riding" }); } catch {}
|
||||||
let cur; try { cur = boat.getVelocity(); } catch { cur = { x: 0, y: 0, z: 0 }; }
|
let cur; try { cur = boat.getVelocity(); } catch { cur = { x: 0, y: 0, z: 0 }; }
|
||||||
@@ -263,7 +263,7 @@ function landImpulse(veh, dim, loc, fx, fz, rx, rz, ix, spd, strafe, breakFn) {
|
|||||||
return { nearGround, gspd: Math.hypot(vel.x, vel.z) * sg, broke };
|
return { nearGround, gspd: Math.hypot(vel.x, vel.z) * sg, broke };
|
||||||
}
|
}
|
||||||
// VELOCITY DRIVE: engine owns Y (gravity), collision, and carries the rider. We steer only horizontal velocity via
|
// VELOCITY DRIVE: engine owns Y (gravity), collision, and carries the rider. We steer only horizontal velocity via
|
||||||
// applyImpulse + face with setRotation — NO teleport (teleport pins position and kills gravity).
|
// applyImpulse + face with setRotation NO teleport (teleport pins position and kills gravity).
|
||||||
function driveBike(p, bike) {
|
function driveBike(p, bike) {
|
||||||
const dim = bike.dimension, loc = bike.location;
|
const dim = bike.dimension, loc = bike.location;
|
||||||
let spd0 = 0; try { spd0 = bike.getDynamicProperty("spd") ?? 0; } catch {}
|
let spd0 = 0; try { spd0 = bike.getDynamicProperty("spd") ?? 0; } catch {}
|
||||||
@@ -398,14 +398,14 @@ const revertBasketBike = (t, dim) => revert2Cell(t, dim, BB_RIG);
|
|||||||
|
|
||||||
const SLED_ENTITY = "rzb_dcs:sled";
|
const SLED_ENTITY = "rzb_dcs:sled";
|
||||||
export const SLED_B = "rzb_dcs:wi41_b_", SLED_FR = "rzb_dcs:wi41_fr_";
|
export const SLED_B = "rzb_dcs:wi41_b_", SLED_FR = "rzb_dcs:wi41_fr_";
|
||||||
const SLED_COLORS = ["red", "green", "blue", "yellow"]; // entity color index — do NOT reorder
|
const SLED_COLORS = ["red", "green", "blue", "yellow"]; // entity color index do NOT reorder
|
||||||
export const SLED_ORDER = ["yellow", "blue", "green", "red"]; // brush cycle order (canonical); decoupled from the index map
|
export const SLED_ORDER = ["yellow", "blue", "green", "red"]; // brush cycle order (canonical); decoupled from the index map
|
||||||
export const SLED_CELLS = { "0_0_0": [0, 0, 0], "0_0_1": [0, 0, 1] }; // anchor(back) + front, one block forward (+FWD)
|
export const SLED_CELLS = { "0_0_0": [0, 0, 0], "0_0_1": [0, 0, 1] }; // anchor(back) + front, one block forward (+FWD)
|
||||||
export const SLED_PREFIX = { "0_0_0": SLED_B, "0_0_1": SLED_FR };
|
export const SLED_PREFIX = { "0_0_0": SLED_B, "0_0_1": SLED_FR };
|
||||||
const SLED_MAX_SNOW = 0.5, SLED_MAX_SLOW = 0.16, SLED_ACCEL = 0.03, SLED_DECEL = 0.03, SLED_STRAFE = 0.1, SLED_STEP = 1.05;
|
const SLED_MAX_SNOW = 0.5, SLED_MAX_SLOW = 0.16, SLED_ACCEL = 0.03, SLED_DECEL = 0.03, SLED_STRAFE = 0.1, SLED_STEP = 1.05;
|
||||||
const SLED_YAW_OFF = 180; // sled drives "backwards" -> flip the model 180 so its front points the way of travel
|
const SLED_YAW_OFF = 180; // sled drives "backwards" -> flip the model 180 so its front points the way of travel
|
||||||
const isSnow = (id) => !!id && /snow|ice|powder_snow/.test(id);
|
const isSnow = (id) => !!id && /snow|ice|powder_snow/.test(id);
|
||||||
const isSand = (id) => !!id && /sand|gravel/.test(id); // loose ground — bikes bog down like on snow
|
const isSand = (id) => !!id && /sand|gravel/.test(id); // loose ground bikes bog down like on snow
|
||||||
registerVariants([...SLED_COLORS.map((c) => SLED_B + c), ...SLED_COLORS.map((c) => SLED_FR + c)]); // brush gate; cycling uses SLED_ORDER
|
registerVariants([...SLED_COLORS.map((c) => SLED_B + c), ...SLED_COLORS.map((c) => SLED_FR + c)]); // brush gate; cycling uses SLED_ORDER
|
||||||
const _slH = makeCellHelpers(SLED_CELLS, SLED_PREFIX);
|
const _slH = makeCellHelpers(SLED_CELLS, SLED_PREFIX);
|
||||||
export const sledCellWorld = _slH.cellWorld, sledAnchorFrom = _slH.anchorFrom, sledParse = _slH.parse;
|
export const sledCellWorld = _slH.cellWorld, sledAnchorFrom = _slH.anchorFrom, sledParse = _slH.parse;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// features/seating.js — the sit system (seat entity + per-furniture config).
|
// features/seating.js the sit system (seat entity + per-furniture config).
|
||||||
import { world, system, isCreative, getDir, safeGetBlock } from "../core/mc.js";
|
import { world, system, isCreative, getDir, safeGetBlock } from "../core/mc.js";
|
||||||
import { DIR_YAW, DIR_TROT, FWD } from "../core/grid.js";
|
import { DIR_YAW, DIR_TROT, FWD } from "../core/grid.js";
|
||||||
import { FLOWER_CART, LOUNGER } from "./mb_grid.js";
|
import { FLOWER_CART, LOUNGER } from "./mb_grid.js";
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
// features/stations.js crafting stations placement + removal (1-to-1 with DecoCraft).
|
||||||
|
// Placer item -> minecraft:entity_placer spawns an INVISIBLE _init; on its spawn we grid-align, check clearance + the
|
||||||
|
// 8-block duplicate guard, then summon the real station PRE-ROTATED to the player's look cardinal (one step, no visible
|
||||||
|
// rotation) and remove the init. A blocked placement refunds the item + plays the reject sound. The station is non-solid;
|
||||||
|
// its footprint is invisible full-collision blocks (bench = 2 cells, decomposer = 1). Hitting a station returns the stored
|
||||||
|
// materials + the item (no item in creative, like DecoCraft) and clears the footprint blocks.
|
||||||
|
import { world, ItemStack, isCreative, safeGetBlock } from "../core/mc.js";
|
||||||
|
import { fcCanReplace } from "../core/grid.js";
|
||||||
|
import { dropStored } from "./decostation.js";
|
||||||
|
|
||||||
|
const INIT_TO_STATION = { "rzb_dcs:decobench_init": "rzb_dcs:decobench", "rzb_dcs:decomposer_init": "rzb_dcs:decomposer" };
|
||||||
|
const STATIONS = new Set(["rzb_dcs:decobench", "rzb_dcs:decomposer"]);
|
||||||
|
const ITEM_FOR = { "rzb_dcs:decobench": "rzb_dcs:seasons_bench", "rzb_dcs:decomposer": "rzb_dcs:deco_seasons_decomp" };
|
||||||
|
const FILL = { "rzb_dcs:decobench": "^ ^ ^ ^1 ^ ^", "rzb_dcs:decomposer": "^ ^ ^ ^ ^ ^" }; // 2-cell bench, 1-cell decomposer
|
||||||
|
const TWO_CELL = new Set(["rzb_dcs:decobench"]);
|
||||||
|
|
||||||
|
const leftCell = (yaw) => { const r = yaw * Math.PI / 180; return [Math.round(Math.cos(r)), Math.round(Math.sin(r))]; }; // world offset of the local-left cell (^1)
|
||||||
|
const replaceable = (dim, cx, cy, cz) => { const b = safeGetBlock(dim, { x: cx, y: cy, z: cz }); return !!b && (b.isAir || fcCanReplace(b)); };
|
||||||
|
|
||||||
|
world.afterEvents.entitySpawn?.subscribe((ev) => {
|
||||||
|
const e = ev.entity;
|
||||||
|
const station = INIT_TO_STATION[e?.typeId];
|
||||||
|
if (station) {
|
||||||
|
const dim = e.dimension, l = e.location;
|
||||||
|
const bx = Math.floor(l.x), by = Math.floor(l.y), bz = Math.floor(l.z);
|
||||||
|
let yaw = 180, player; try { player = dim.getPlayers({ location: l, closest: 1, maxDistance: 6 })[0]; if (player) yaw = Math.round(player.getRotation().y / 90) * 90 + 180; } catch {}
|
||||||
|
const cells = [[bx, by, bz]];
|
||||||
|
if (TWO_CELL.has(station)) { const [lx, lz] = leftCell(yaw); cells.push([bx + lx, by, bz + lz]); }
|
||||||
|
const clear = cells.every(([cx, cy, cz]) => replaceable(dim, cx, cy, cz));
|
||||||
|
let dup = false; try { dup = dim.getEntities({ location: l, type: station, maxDistance: 8 }).length > 0; } catch {}
|
||||||
|
if (!clear || dup) { // DecoCraft: refuse -> refund the item + reject sound
|
||||||
|
try { dim.spawnItem(new ItemStack(ITEM_FOR[station], 1), { x: bx + 0.5, y: by + 0.5, z: bz + 0.5 }); } catch {}
|
||||||
|
try { player?.playSound("note.didgeridoo", { volume: 0.8 }); } catch {}
|
||||||
|
try { e.remove(); } catch {}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ht = TWO_CELL.has(station) ? ` rzb_dcs:ht_${((yaw % 360) + 360) % 360}` : ""; // facing-oriented 2-cell hit box (bench only)
|
||||||
|
try { dim.runCommand(`summon ${station} ${bx + 0.5} ${by} ${bz + 0.5} ${yaw} 0${ht}`); } catch {} // pre-rotated
|
||||||
|
try { e.remove(); } catch {}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (STATIONS.has(e?.typeId) && ev.cause !== "Loaded") { // real station placed -> fill its invisible collision footprint
|
||||||
|
try { e.runCommand(`fill ${FILL[e.typeId]} rzb_dcs:invisible_block`); } catch {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// hit to break -> clear footprint, return stored materials + the item (no item in creative), remove
|
||||||
|
world.afterEvents.entityHitEntity?.subscribe((ev) => {
|
||||||
|
const t = ev.hitEntity; if (!STATIONS.has(t?.typeId)) return;
|
||||||
|
const dmg = ev.damagingEntity; if (dmg?.typeId !== "minecraft:player") return;
|
||||||
|
try { t.runCommand(`fill ${FILL[t.typeId]} air replace rzb_dcs:invisible_block`); } catch {}
|
||||||
|
try { dropStored(t); } catch {}
|
||||||
|
if (!isCreative(dmg)) { try { t.dimension.spawnItem(new ItemStack(ITEM_FOR[t.typeId], 1), t.location); } catch {} }
|
||||||
|
try { t.remove(); } catch {}
|
||||||
|
});
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
// maintenance pick block anchor redirect + firepit embers
|
// maintenance pick block anchor redirect + firepit embers
|
||||||
// bounce springy blocks that launch a player who lands on them
|
// bounce springy blocks that launch a player who lands on them
|
||||||
// decostation decobench + decomposer economy backend (scoreboards, scriptevent router, block/deco to materials)
|
// decostation decobench + decomposer economy backend (scoreboards, scriptevent router, block/deco to materials)
|
||||||
|
// stations place the decobench/decomposer station entities from a placer item (UI/panel = coworker's to build)
|
||||||
// break_particle custom block break particle
|
// break_particle custom block break particle
|
||||||
//
|
//
|
||||||
// To add a prop: plain recolorable block -> one line in decor.js; rotating/canopy multiblock -> one defineGridMultiblock() in mb_grid.js; anything bespoke -> its own features/ module.
|
// To add a prop: plain recolorable block -> one line in decor.js; rotating/canopy multiblock -> one defineGridMultiblock() in mb_grid.js; anything bespoke -> its own features/ module.
|
||||||
@@ -43,4 +44,5 @@ import "./features/brush.js";
|
|||||||
import "./features/maintenance.js";
|
import "./features/maintenance.js";
|
||||||
import "./features/bounce.js";
|
import "./features/bounce.js";
|
||||||
import "./features/decostation.js";
|
import "./features/decostation.js";
|
||||||
|
import "./features/stations.js";
|
||||||
import "./features/break_particle.js";
|
import "./features/break_particle.js";
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.10.0",
|
||||||
|
"minecraft:client_entity": {
|
||||||
|
"description": {
|
||||||
|
"identifier": "rzb_dcs:decobench",
|
||||||
|
"materials": {
|
||||||
|
"default": "entity_alphatest"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"default": "geometry.rzb_dcs.decobench"
|
||||||
|
},
|
||||||
|
"textures": {
|
||||||
|
"default": "textures/entity/rzb_dcs/decobench"
|
||||||
|
},
|
||||||
|
"render_controllers": [
|
||||||
|
"controller.render.default"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.10.0",
|
||||||
|
"minecraft:client_entity": {
|
||||||
|
"description": {
|
||||||
|
"identifier": "rzb_dcs:decobench_init",
|
||||||
|
"materials": {
|
||||||
|
"default": "entity_alphatest"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"default": "geometry.rzb_dcs.blank"
|
||||||
|
},
|
||||||
|
"textures": {
|
||||||
|
"default": "textures/entity/rzb_dcs/decobench"
|
||||||
|
},
|
||||||
|
"render_controllers": [
|
||||||
|
"controller.render.default"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.10.0",
|
||||||
|
"minecraft:client_entity": {
|
||||||
|
"description": {
|
||||||
|
"identifier": "rzb_dcs:decomposer",
|
||||||
|
"materials": {
|
||||||
|
"default": "entity_alphatest"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"default": "geometry.rzb_dcs.decomposer"
|
||||||
|
},
|
||||||
|
"textures": {
|
||||||
|
"default": "textures/entity/rzb_dcs/decomposer"
|
||||||
|
},
|
||||||
|
"render_controllers": [
|
||||||
|
"controller.render.default"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.10.0",
|
||||||
|
"minecraft:client_entity": {
|
||||||
|
"description": {
|
||||||
|
"identifier": "rzb_dcs:decomposer_init",
|
||||||
|
"materials": {
|
||||||
|
"default": "entity_alphatest"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"default": "geometry.rzb_dcs.blank"
|
||||||
|
},
|
||||||
|
"textures": {
|
||||||
|
"default": "textures/entity/rzb_dcs/decomposer"
|
||||||
|
},
|
||||||
|
"render_controllers": [
|
||||||
|
"controller.render.default"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"format_version":"1.16.0","minecraft:geometry":[{"description":{"identifier":"geometry.rzb_dcs.blank","texture_width":16,"texture_height":16},"bones":[{"name":"root","pivot":[0,0,0]}]}]}
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -3914,3 +3914,10 @@ item.rzb_dcs:fa48=Casket Ground
|
|||||||
tile.rzb_dcs:fa48_b.name=Casket Ground
|
tile.rzb_dcs:fa48_b.name=Casket Ground
|
||||||
item.rzb_dcs:fa48_b.name=Casket Ground
|
item.rzb_dcs:fa48_b.name=Casket Ground
|
||||||
item.rzb_dcs:fa48_b=Casket Ground
|
item.rzb_dcs:fa48_b=Casket Ground
|
||||||
|
item.rzb_dcs:seasons_bench.name=Seasons Bench
|
||||||
|
item.rzb_dcs:seasons_bench=Seasons Bench
|
||||||
|
item.rzb_dcs:deco_seasons_decomp.name=Season Decomposer
|
||||||
|
item.rzb_dcs:deco_seasons_decomp=Season Decomposer
|
||||||
|
entity.rzb_dcs:decobench.name=Seasons Bench
|
||||||
|
entity.rzb_dcs:decomposer.name=Season Decomposer
|
||||||
|
tile.rzb_dcs:invisible_block.name=Invisible Block
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -2125,6 +2125,12 @@
|
|||||||
},
|
},
|
||||||
"rzb_dcs_casket_ground": {
|
"rzb_dcs_casket_ground": {
|
||||||
"textures": "textures/items/rzb_dcs/casket_ground"
|
"textures": "textures/items/rzb_dcs/casket_ground"
|
||||||
|
},
|
||||||
|
"rzb_dcs_seasons_bench": {
|
||||||
|
"textures": "textures/items/rzb_dcs/seasons_bench"
|
||||||
|
},
|
||||||
|
"rzb_dcs_deco_seasons_decomp": {
|
||||||
|
"textures": "textures/items/rzb_dcs/deco_seasons_decomp"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 7.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 9.2 KiB |
Reference in New Issue
Block a user