Merge branch 'easyPlace' into dev

This commit is contained in:
ForestOfLight
2025-07-10 19:31:10 -07:00
Unverified
5 changed files with 3701 additions and 28 deletions
+2 -1
View File
@@ -19,7 +19,8 @@ function giveActionItem(playerId) {
const player = world.getEntity(playerId);
const container = player.getComponent(EntityComponentTypes.Inventory)?.container;
const itemStack = new ItemStack('construct:easy_place');
if (!container.contains(itemStack)) {
const offhandItemStack = player.getComponent(EntityComponentTypes.Equippable).getEquipment(EquipmentSlot.Offhand);
if (!container.contains(itemStack) && offhandItemStack?.typeId !== 'construct:easy_place') {
const remainingItemStack = container.addItem(itemStack);
if (remainingItemStack)
player.dimension.spawnItem(remainingItemStack, player.location);
+25 -19
View File
@@ -1,12 +1,14 @@
import { BuilderOption } from '../classes/Builder/BuilderOption';
import { BlockPermutation, EntityComponentTypes, EquipmentSlot, GameMode, InputMode, ItemStack, system, world } from '@minecraft/server';
import { BlockPermutation, EntityComponentTypes, EquipmentSlot, GameMode, ItemStack, system, world } from '@minecraft/server';
import { bannedBlocks, bannedToValidBlockMap, whitelistedBlockStates, resetToBlockStates, bannedDimensionBlocks,
blockIdToItemStackMap } from '../data';
import { placeBlock } from '../utils';
import { placeBlock, fetchMatchingItemSlot } from '../utils';
import { Raycaster } from '../classes/Raycaster';
import { Builders } from '../classes/Builder/Builders';
import { Vector } from '../lib/Vector';
const PROCESS_INTERVAL = 2; // Fast Easy Place will attempt to place twice when at an interval of 1.
const locationsPlacedLastTick = new Set();
const PLAYER_COLLISION_BOX = { width: 0.6, height: 1.8 };
const builderOption = new BuilderOption({
identifier: 'fastEasyPlace',
@@ -21,7 +23,8 @@ function giveActionItem(playerId) {
const player = world.getEntity(playerId);
const container = player.getComponent(EntityComponentTypes.Inventory)?.container;
const itemStack = new ItemStack('construct:easy_place');
if (!container.contains(itemStack)) {
const offhandItemStack = player.getComponent(EntityComponentTypes.Equippable).getEquipment(EquipmentSlot.Offhand);
if (!container.contains(itemStack) && offhandItemStack?.typeId !== 'construct:easy_place') {
const remainingItemStack = container.addItem(itemStack);
if (remainingItemStack)
player.dimension.spawnItem(remainingItemStack, player.location);
@@ -46,7 +49,7 @@ function removeActionItem(playerId) {
}
}
system.runInterval(onTick, PROCESS_INTERVAL);
system.runInterval(onTick);
world.beforeEvents.playerInteractWithBlock.subscribe(onPlayerInteractWithBlock);
function onTick() {
@@ -68,6 +71,12 @@ function processEasyPlace(player) {
if (!structureBlock)
return;
const worldBlock = player.dimension.getBlock(structureBlock.location);
if (locationsPlacedLastTick.has(JSON.stringify(worldBlock.location)))
return;
locationsPlacedLastTick.add(JSON.stringify(worldBlock.location));
system.runTimeout(() => {
locationsPlacedLastTick.delete(JSON.stringify(worldBlock.location));
}, 2);
tryPlaceBlock(player, worldBlock, structureBlock.permutation);
}
@@ -86,7 +95,7 @@ function isHoldingActionItem(player) {
}
function tryPlaceBlock(player, worldBlock, structureBlock) {
if (isBannedBlock(player, structureBlock) || !locationIsPlaceable(worldBlock)) return;
if (isBannedBlock(player, structureBlock) || !locationIsPlaceable(player, worldBlock)) return;
structureBlock = tryConvertBannedToValidBlock(structureBlock);
if (player.getGameMode() === GameMode.Creative) {
placeBlock(player, worldBlock, structureBlock);
@@ -96,8 +105,8 @@ function tryPlaceBlock(player, worldBlock, structureBlock) {
}
}
function locationIsPlaceable(worldBlock) {
return worldBlock.isAir || worldBlock.isLiquid;
function locationIsPlaceable(player, worldBlock) {
return (worldBlock.isAir || worldBlock.isLiquid) && !isBlockInsidePlayer(player, worldBlock);
}
function isBannedBlock(player, structureBlock) {
@@ -149,15 +158,12 @@ function getPlaceableItemStack(structureBlock) {
return newItemId ? new ItemStack(newItemId) : structureBlock.getItemStack();
}
function fetchMatchingItemSlot(player, itemToMatchId) {
if (!itemToMatchId)
return void 0;
const inventory = player.getComponent(EntityComponentTypes.Inventory)?.container;
if (!inventory)
return void 0;
for (let index = 0; index < inventory.size; index++) {
const itemSlot = inventory.getSlot(index);
if (itemSlot.hasItem() && itemSlot?.typeId === itemToMatchId)
return itemSlot;
}
function isBlockInsidePlayer(player, worldBlock) {
const playerLocation = Vector.from(player.location);
const blockLocation = Vector.from(worldBlock.location);
const playerMin = playerLocation.subtract({ x: PLAYER_COLLISION_BOX.width / 2, y: -0.1, z: PLAYER_COLLISION_BOX.width / 2 });
const playerMax = playerLocation.add({ x: PLAYER_COLLISION_BOX.width / 2, y: PLAYER_COLLISION_BOX.height, z: PLAYER_COLLISION_BOX.width / 2 });
const blockMin = blockLocation;
const blockMax = blockLocation.add({ x: 1, y: 1, z: 1 });
return Vector.intersect(playerMax, playerMin, blockMax, blockMin);
}