You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
56 lines
3.7 KiB
JavaScript
56 lines
3.7 KiB
JavaScript
// 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 {}
|
|
});
|