Enabled for survival. Calculating missing items. Showing itemstacks at cursor. Showing preview blocks in red.
Increased max blocks placed at once. Filtering coordinates that are not loaded or outside of world border. Sending items instead of itemstacks to server.
This commit is contained in:
@@ -2,14 +2,10 @@ package nl.requios.effortlessbuilding;
|
|||||||
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.BlockItem;
|
import net.minecraft.world.item.BlockItem;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
|
|
||||||
import net.minecraftforge.common.util.FakePlayer;
|
import net.minecraftforge.common.util.FakePlayer;
|
||||||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
|
||||||
import net.minecraftforge.event.TickEvent;
|
import net.minecraftforge.event.TickEvent;
|
||||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||||
import net.minecraftforge.event.level.BlockEvent;
|
import net.minecraftforge.event.level.BlockEvent;
|
||||||
@@ -17,10 +13,9 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
|
|||||||
import net.minecraftforge.fml.LogicalSide;
|
import net.minecraftforge.fml.LogicalSide;
|
||||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||||
import net.minecraftforge.network.PacketDistributor;
|
import net.minecraftforge.network.PacketDistributor;
|
||||||
|
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
||||||
import nl.requios.effortlessbuilding.network.ModifierSettingsPacket;
|
import nl.requios.effortlessbuilding.network.ModifierSettingsPacket;
|
||||||
import nl.requios.effortlessbuilding.network.PacketHandler;
|
import nl.requios.effortlessbuilding.network.PacketHandler;
|
||||||
import nl.requios.effortlessbuilding.systems.UndoRedo;
|
|
||||||
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
|
||||||
import nl.requios.effortlessbuilding.systems.ServerBuildState;
|
import nl.requios.effortlessbuilding.systems.ServerBuildState;
|
||||||
import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
import nl.requios.effortlessbuilding.utilities.ReachHelper;
|
||||||
|
|
||||||
@@ -58,6 +53,7 @@ public class CommonEvents {
|
|||||||
//Fixed issue with e.g. Create Wrench shift-rightclick disassembling being cancelled.
|
//Fixed issue with e.g. Create Wrench shift-rightclick disassembling being cancelled.
|
||||||
if (isPlayerHoldingBlock(player)) {
|
if (isPlayerHoldingBlock(player)) {
|
||||||
event.setCanceled(true);
|
event.setCanceled(true);
|
||||||
|
//TODO Notify client to not decrease itemstack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import nl.requios.effortlessbuilding.gui.RandomizerBagScreen;
|
|||||||
import nl.requios.effortlessbuilding.render.BlockPreviews;
|
import nl.requios.effortlessbuilding.render.BlockPreviews;
|
||||||
import nl.requios.effortlessbuilding.systems.BuilderChain;
|
import nl.requios.effortlessbuilding.systems.BuilderChain;
|
||||||
import nl.requios.effortlessbuilding.systems.BuildSettings;
|
import nl.requios.effortlessbuilding.systems.BuildSettings;
|
||||||
|
import nl.requios.effortlessbuilding.systems.BuilderFilter;
|
||||||
|
import nl.requios.effortlessbuilding.systems.ItemUsageTracker;
|
||||||
|
|
||||||
public class EffortlessBuildingClient {
|
public class EffortlessBuildingClient {
|
||||||
|
|
||||||
@@ -19,6 +21,8 @@ public class EffortlessBuildingClient {
|
|||||||
public static final BuildModifiers BUILD_MODIFIERS = new BuildModifiers();
|
public static final BuildModifiers BUILD_MODIFIERS = new BuildModifiers();
|
||||||
public static final BuildSettings BUILD_SETTINGS = new BuildSettings();
|
public static final BuildSettings BUILD_SETTINGS = new BuildSettings();
|
||||||
public static final BlockPreviews BLOCK_PREVIEWS = new BlockPreviews();
|
public static final BlockPreviews BLOCK_PREVIEWS = new BlockPreviews();
|
||||||
|
public static final BuilderFilter BUILDER_FILTER = new BuilderFilter();
|
||||||
|
public static final ItemUsageTracker ITEM_USAGE_TRACKER = new ItemUsageTracker();
|
||||||
|
|
||||||
public static void onConstructorClient(IEventBus modEventBus, IEventBus forgeEventBus) {
|
public static void onConstructorClient(IEventBus modEventBus, IEventBus forgeEventBus) {
|
||||||
modEventBus.addListener(EffortlessBuildingClient::clientSetup);
|
modEventBus.addListener(EffortlessBuildingClient::clientSetup);
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public class ServerConfig {
|
|||||||
|
|
||||||
maxBlocksPlacedAtOnce = builder
|
maxBlocksPlacedAtOnce = builder
|
||||||
.comment("Maximum number of blocks that can be placed at once.")
|
.comment("Maximum number of blocks that can be placed at once.")
|
||||||
.defineInRange("maxBlocksPlacedAtOnce", 1000, 1, 10000);
|
.defineInRange("maxBlocksPlacedAtOnce", 10000, 1, 100000);
|
||||||
|
|
||||||
builder.pop();
|
builder.pop();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -211,7 +211,8 @@ public class BlockPreviews {
|
|||||||
CreateClient.GHOST_BLOCKS.showGhostState(blockPos.toShortString(), blockState)
|
CreateClient.GHOST_BLOCKS.showGhostState(blockPos.toShortString(), blockState)
|
||||||
.at(blockPos)
|
.at(blockPos)
|
||||||
.alpha(alpha)
|
.alpha(alpha)
|
||||||
.scale(scale);
|
.scale(scale)
|
||||||
|
.colored(blockEntry.invalid ? Color.RED : Color.WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
//k=1 is the identity curve, k<1 produces the classic gain() shape, and k>1 produces "s" shaped curves. The curves are symmetric (and inverse) for k=a and k=1/a.
|
//k=1 is the identity curve, k<1 produces the classic gain() shape, and k>1 produces "s" shaped curves. The curves are symmetric (and inverse) for k=a and k=1/a.
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ import com.mojang.blaze3d.vertex.Tesselator;
|
|||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
import net.minecraft.ChatFormatting;
|
import net.minecraft.ChatFormatting;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.Font;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
import net.minecraftforge.client.event.RenderGuiEvent;
|
import net.minecraftforge.client.event.RenderGuiEvent;
|
||||||
@@ -16,6 +18,7 @@ import net.minecraftforge.client.event.RenderLevelStageEvent;
|
|||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||||
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
||||||
|
import nl.requios.effortlessbuilding.create.foundation.utility.Color;
|
||||||
import nl.requios.effortlessbuilding.systems.BuilderChain;
|
import nl.requios.effortlessbuilding.systems.BuilderChain;
|
||||||
|
|
||||||
/***
|
/***
|
||||||
@@ -47,6 +50,8 @@ public class RenderHandler {
|
|||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void onRenderGuiEvent(RenderGuiEvent event) {
|
public static void onRenderGuiEvent(RenderGuiEvent event) {
|
||||||
renderSubText(event.getPoseStack());
|
renderSubText(event.getPoseStack());
|
||||||
|
|
||||||
|
drawStacks(event.getPoseStack());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final ChatFormatting highlightColor = ChatFormatting.DARK_AQUA;
|
private static final ChatFormatting highlightColor = ChatFormatting.DARK_AQUA;
|
||||||
@@ -70,7 +75,7 @@ public class RenderHandler {
|
|||||||
var font = Minecraft.getInstance().font;
|
var font = Minecraft.getInstance().font;
|
||||||
|
|
||||||
ms.pushPose();
|
ms.pushPose();
|
||||||
ms.translate((double)(screenWidth / 2), (double)(screenHeight - 54), 0.0D);
|
ms.translate(screenWidth / 2.0, screenHeight - 54, 0.0D);
|
||||||
RenderSystem.enableBlend();
|
RenderSystem.enableBlend();
|
||||||
RenderSystem.defaultBlendFunc();
|
RenderSystem.defaultBlendFunc();
|
||||||
int l = font.width(text);
|
int l = font.width(text);
|
||||||
@@ -79,6 +84,56 @@ public class RenderHandler {
|
|||||||
ms.popPose();
|
ms.popPose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Draw item stacks at cursor, showing what will be used and what is missing
|
||||||
|
private static void drawStacks(PoseStack ms) {
|
||||||
|
var state = EffortlessBuildingClient.BUILDER_CHAIN.getBuildingState();
|
||||||
|
if (state != BuilderChain.BuildingState.PLACING) return;
|
||||||
|
|
||||||
|
var stacks = EffortlessBuildingClient.ITEM_USAGE_TRACKER.total;
|
||||||
|
//Show if we are in survival or we are using multiple types of items
|
||||||
|
if (Minecraft.getInstance().player == null || (Minecraft.getInstance().player.isCreative() && stacks.size() <= 1)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int screenWidth = Minecraft.getInstance().getWindow().getGuiScaledWidth();
|
||||||
|
int screenHeight = Minecraft.getInstance().getWindow().getGuiScaledHeight();
|
||||||
|
|
||||||
|
int x = screenWidth / 2 + 10;
|
||||||
|
int y = screenHeight / 2 - 8;
|
||||||
|
|
||||||
|
//Draw item texture with count
|
||||||
|
int i = 0;
|
||||||
|
for (var stack : stacks.entrySet()) {
|
||||||
|
int total = stack.getValue();
|
||||||
|
int missing = EffortlessBuildingClient.ITEM_USAGE_TRACKER.getMissingCount(stack.getKey());
|
||||||
|
|
||||||
|
if (total - missing > 0) {
|
||||||
|
drawItemStack(ms, new ItemStack(stack.getKey(), total - missing), x + i * 20, y, false);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missing > 0) {
|
||||||
|
drawItemStack(ms, new ItemStack(stack.getKey(), missing), x + i * 20, y, true);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawItemStack(PoseStack ms, ItemStack stack, int x, int y, boolean missing) {
|
||||||
|
Minecraft.getInstance().getItemRenderer().renderGuiItem(stack, x, y);
|
||||||
|
|
||||||
|
//draw count text, red if missing
|
||||||
|
//from ItemRenderer#renderGuiItemDecorations
|
||||||
|
ms.pushPose();
|
||||||
|
Font font = Minecraft.getInstance().font;
|
||||||
|
String text = String.valueOf(stack.getCount());
|
||||||
|
ms.translate(0.0D, 0.0D, (double)(Minecraft.getInstance().getItemRenderer().blitOffset + 200.0F));
|
||||||
|
MultiBufferSource.BufferSource multibuffersource$buffersource = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder());
|
||||||
|
font.drawInBatch(text, (float)(x + 19 - 2 - font.width(text)), (float)(y + 6 + 3), missing ? ChatFormatting.RED.getColor() : ChatFormatting.WHITE.getColor(), true, ms.last().pose(), multibuffersource$buffersource, false, 0, 15728880);
|
||||||
|
multibuffersource$buffersource.endBatch();
|
||||||
|
ms.popPose();
|
||||||
|
}
|
||||||
|
|
||||||
protected static VertexConsumer beginLines(MultiBufferSource.BufferSource renderTypeBuffer) {
|
protected static VertexConsumer beginLines(MultiBufferSource.BufferSource renderTypeBuffer) {
|
||||||
return renderTypeBuffer.getBuffer(BuildRenderTypes.LINES);
|
return renderTypeBuffer.getBuffer(BuildRenderTypes.LINES);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ public class BuilderChain {
|
|||||||
private AbilitiesState abilitiesState = AbilitiesState.CAN_PLACE_AND_BREAK;
|
private AbilitiesState abilitiesState = AbilitiesState.CAN_PLACE_AND_BREAK;
|
||||||
|
|
||||||
public void onRightClick() {
|
public void onRightClick() {
|
||||||
|
|
||||||
if (abilitiesState != AbilitiesState.CAN_PLACE_AND_BREAK || buildingState == BuildingState.BREAKING) {
|
if (abilitiesState != AbilitiesState.CAN_PLACE_AND_BREAK || buildingState == BuildingState.BREAKING) {
|
||||||
cancel();
|
cancel();
|
||||||
return;
|
return;
|
||||||
@@ -95,6 +96,7 @@ public class BuilderChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onLeftClick() {
|
public void onLeftClick() {
|
||||||
|
|
||||||
if (abilitiesState == AbilitiesState.NONE || buildingState == BuildingState.PLACING) {
|
if (abilitiesState == AbilitiesState.NONE || buildingState == BuildingState.PLACING) {
|
||||||
cancel();
|
cancel();
|
||||||
return;
|
return;
|
||||||
@@ -109,9 +111,9 @@ public class BuilderChain {
|
|||||||
//Use new start position for breaking, because we assumed the player was gonna place
|
//Use new start position for breaking, because we assumed the player was gonna place
|
||||||
blocks.setStartPos(new BlockEntry(startPosForBreaking));
|
blocks.setStartPos(new BlockEntry(startPosForBreaking));
|
||||||
EffortlessBuildingClient.BUILD_MODIFIERS.findCoordinates(blocks, player);
|
EffortlessBuildingClient.BUILD_MODIFIERS.findCoordinates(blocks, player);
|
||||||
BuilderFilter.filterOnCoordinates(blocks, player);
|
EffortlessBuildingClient.BUILDER_FILTER.filterOnCoordinates(blocks, player);
|
||||||
findExistingBlockStates(player.level);
|
findExistingBlockStates(player.level);
|
||||||
BuilderFilter.filterOnExistingBlockStates(blocks, player);
|
EffortlessBuildingClient.BUILDER_FILTER.filterOnExistingBlockStates(blocks, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
var buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode();
|
var buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode();
|
||||||
@@ -131,6 +133,7 @@ public class BuilderChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onTick() {
|
public void onTick() {
|
||||||
|
|
||||||
var previousCoordinates = new HashSet<>(blocks.getCoordinates());
|
var previousCoordinates = new HashSet<>(blocks.getCoordinates());
|
||||||
blocks.clear();
|
blocks.clear();
|
||||||
startPosForPlacing = null;
|
startPosForPlacing = null;
|
||||||
@@ -160,7 +163,7 @@ public class BuilderChain {
|
|||||||
|
|
||||||
EffortlessBuildingClient.BUILD_MODES.findCoordinates(blocks, player);
|
EffortlessBuildingClient.BUILD_MODES.findCoordinates(blocks, player);
|
||||||
EffortlessBuildingClient.BUILD_MODIFIERS.findCoordinates(blocks, player);
|
EffortlessBuildingClient.BUILD_MODIFIERS.findCoordinates(blocks, player);
|
||||||
BuilderFilter.filterOnCoordinates(blocks, player);
|
EffortlessBuildingClient.BUILDER_FILTER.filterOnCoordinates(blocks, player);
|
||||||
|
|
||||||
if (buildMode == BuildModeEnum.DISABLED && blocks.size() <= 1) {
|
if (buildMode == BuildModeEnum.DISABLED && blocks.size() <= 1) {
|
||||||
abilitiesState = AbilitiesState.NONE;
|
abilitiesState = AbilitiesState.NONE;
|
||||||
@@ -168,18 +171,17 @@ public class BuilderChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
findExistingBlockStates(world);
|
findExistingBlockStates(world);
|
||||||
BuilderFilter.filterOnExistingBlockStates(blocks, player);
|
EffortlessBuildingClient.BUILDER_FILTER.filterOnExistingBlockStates(blocks, player);
|
||||||
|
|
||||||
var itemStack = player.getItemInHand(InteractionHand.MAIN_HAND);
|
var heldItem = player.getItemInHand(InteractionHand.MAIN_HAND);
|
||||||
findNewBlockStates(player, itemStack);
|
findNewBlockStates(player, heldItem); //includes filtering on new blockstates
|
||||||
BuilderFilter.filterOnNewBlockStates(blocks, player);
|
|
||||||
|
|
||||||
//Check if any changes are made
|
//Check if any changes are made
|
||||||
if (previousHeldItem != itemStack.getItem() || !previousCoordinates.equals(blocks.getCoordinates())) {
|
if (previousHeldItem != heldItem.getItem() || !previousCoordinates.equals(blocks.getCoordinates())) {
|
||||||
onBlocksChanged(player);
|
onBlocksChanged(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
previousHeldItem = itemStack.getItem();
|
previousHeldItem = heldItem.getItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Whether we can place or break blocks, determined by what we are looking at and what we are holding
|
//Whether we can place or break blocks, determined by what we are looking at and what we are holding
|
||||||
@@ -222,9 +224,6 @@ public class BuilderChain {
|
|||||||
if (player.blockPosition().distSqr(startPos) > maxReach * maxReach) return null;
|
if (player.blockPosition().distSqr(startPos) > maxReach * maxReach) return null;
|
||||||
|
|
||||||
startPosForBreaking = startPos;
|
startPosForBreaking = startPos;
|
||||||
if (!shouldLookAtNear && !ReachHelper.canBreakFar(player)) {
|
|
||||||
startPosForBreaking = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (abilitiesState == AbilitiesState.CAN_PLACE_AND_BREAK) {
|
if (abilitiesState == AbilitiesState.CAN_PLACE_AND_BREAK) {
|
||||||
//Calculate start position for placing
|
//Calculate start position for placing
|
||||||
@@ -241,7 +240,7 @@ public class BuilderChain {
|
|||||||
//We can only break
|
//We can only break
|
||||||
|
|
||||||
//Do not break far if we are not allowed to
|
//Do not break far if we are not allowed to
|
||||||
if (startPosForBreaking == null) return null;
|
if (!shouldLookAtNear && !ReachHelper.canBreakFar(player)) return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var blockEntry = new BlockEntry(startPos);
|
var blockEntry = new BlockEntry(startPos);
|
||||||
@@ -255,29 +254,54 @@ public class BuilderChain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void findNewBlockStates(Player player, ItemStack itemStack) {
|
private void findNewBlockStates(Player player, ItemStack heldItem) {
|
||||||
if (buildingState == BuildingState.BREAKING) return;
|
if (buildingState == BuildingState.BREAKING) return;
|
||||||
|
|
||||||
var originalDirection = player.getDirection();
|
var originalDirection = player.getDirection();
|
||||||
var clickedFace = lookingAt.getDirection();
|
var clickedFace = lookingAt.getDirection();
|
||||||
Vec3 relativeHitVec = lookingAt.getLocation().subtract(Vec3.atLowerCornerOf(lookingAt.getBlockPos()));
|
Vec3 relativeHitVec = lookingAt.getLocation().subtract(Vec3.atLowerCornerOf(lookingAt.getBlockPos()));
|
||||||
|
|
||||||
//TODO keep track of count and find different itemstack if necessary
|
//Keep track of itemstack usage
|
||||||
if (itemStack.getItem() instanceof BlockItem) {
|
EffortlessBuildingClient.ITEM_USAGE_TRACKER.initialize(player, heldItem);
|
||||||
|
|
||||||
for (BlockEntry blockEntry : blocks) {
|
var iter = blocks.entrySet().iterator();
|
||||||
blockEntry.setItemStackAndFindNewBlockState(itemStack, player.level, originalDirection, clickedFace, relativeHitVec);
|
while (iter.hasNext()) {
|
||||||
|
var blockEntry = iter.next().getValue();
|
||||||
|
|
||||||
|
//Determine itemstack
|
||||||
|
ItemStack itemStack = determineItemStack(player, heldItem);
|
||||||
|
if (itemStack == null || itemStack.isEmpty()) {
|
||||||
|
iter.remove();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (CompatHelper.isItemBlockProxy(itemStack, false)) {
|
//Find new blockstate
|
||||||
|
blockEntry.setItemAndFindNewBlockState(itemStack, player.level, originalDirection, clickedFace, relativeHitVec);
|
||||||
|
|
||||||
AbstractRandomizerBagItem.resetRandomness();
|
//Filter on new blockstate
|
||||||
for (BlockEntry blockEntry : blocks) {
|
if (EffortlessBuildingClient.BUILDER_FILTER.filterOnNewBlockState(blockEntry, player)) {
|
||||||
ItemStack itemBlockStack = CompatHelper.getItemBlockFromStack(itemStack);
|
iter.remove();
|
||||||
if (itemBlockStack == null || itemBlockStack.isEmpty()) continue;
|
continue;
|
||||||
blockEntry.setItemStackAndFindNewBlockState(itemBlockStack, player.level, originalDirection, clickedFace, relativeHitVec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Increase itemstack usage if not filtered out
|
||||||
|
//Mark invalid if the player does not have enough of that item
|
||||||
|
blockEntry.invalid = !EffortlessBuildingClient.ITEM_USAGE_TRACKER.increaseUsageCount(itemStack.getItem(), 1, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EffortlessBuildingClient.ITEM_USAGE_TRACKER.calculateMissingItems(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemStack determineItemStack(Player player, ItemStack heldItem) {
|
||||||
|
if (heldItem.getItem() instanceof BlockItem) {
|
||||||
|
return heldItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CompatHelper.isItemBlockProxy(heldItem, false)) {
|
||||||
|
return CompatHelper.getItemBlockFromStack(heldItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onBlocksChanged(Player player) {
|
private void onBlocksChanged(Player player) {
|
||||||
|
|||||||
@@ -6,17 +6,28 @@ import net.minecraftforge.api.distmarker.Dist;
|
|||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
||||||
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
||||||
|
import nl.requios.effortlessbuilding.utilities.BlockEntry;
|
||||||
import nl.requios.effortlessbuilding.utilities.BlockSet;
|
import nl.requios.effortlessbuilding.utilities.BlockSet;
|
||||||
import nl.requios.effortlessbuilding.utilities.PlaceChecker;
|
import nl.requios.effortlessbuilding.utilities.PlaceChecker;
|
||||||
import nl.requios.effortlessbuilding.utilities.SurvivalHelper;
|
import nl.requios.effortlessbuilding.utilities.SurvivalHelper;
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
@OnlyIn(Dist.CLIENT)
|
||||||
public class BuilderFilter {
|
public class BuilderFilter {
|
||||||
public static void filterOnCoordinates(BlockSet blocks, Player player) {
|
public void filterOnCoordinates(BlockSet blocks, Player player) {
|
||||||
|
var world = player.level;
|
||||||
|
var iter = blocks.entrySet().iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
var pos = iter.next().getValue().blockPos;
|
||||||
|
boolean remove = false;
|
||||||
|
|
||||||
|
if (!world.isLoaded(pos)) remove = true;
|
||||||
|
if (!world.getWorldBorder().isWithinBounds(pos)) remove = true;
|
||||||
|
|
||||||
|
if (remove) iter.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void filterOnExistingBlockStates(BlockSet blocks, Player player) {
|
public void filterOnExistingBlockStates(BlockSet blocks, Player player) {
|
||||||
var buildSettings = EffortlessBuildingClient.BUILD_SETTINGS;
|
var buildSettings = EffortlessBuildingClient.BUILD_SETTINGS;
|
||||||
var buildingState = EffortlessBuildingClient.BUILDER_CHAIN.getPretendBuildingState();
|
var buildingState = EffortlessBuildingClient.BUILDER_CHAIN.getPretendBuildingState();
|
||||||
boolean placing = buildingState == BuilderChain.BuildingState.PLACING;
|
boolean placing = buildingState == BuilderChain.BuildingState.PLACING;
|
||||||
@@ -60,19 +71,15 @@ public class BuilderFilter {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void filterOnNewBlockStates(BlockSet blocks, Player player) {
|
//Returns true if we should remove the entry
|
||||||
var buildSettings = EffortlessBuildingClient.BUILD_SETTINGS;
|
public boolean filterOnNewBlockState(BlockEntry blockEntry, Player player) {
|
||||||
var buildingState = EffortlessBuildingClient.BUILDER_CHAIN.getPretendBuildingState();
|
var buildingState = EffortlessBuildingClient.BUILDER_CHAIN.getPretendBuildingState();
|
||||||
boolean placing = buildingState == BuilderChain.BuildingState.PLACING;
|
boolean placing = buildingState == BuilderChain.BuildingState.PLACING;
|
||||||
|
|
||||||
var iter = blocks.entrySet().iterator();
|
boolean remove = false;
|
||||||
while (iter.hasNext()) {
|
|
||||||
var blockEntry = iter.next().getValue();
|
|
||||||
boolean remove = false;
|
|
||||||
|
|
||||||
if (placing && !PlaceChecker.shouldPlaceBlock(player.level, blockEntry)) remove = true;
|
if (placing && !PlaceChecker.shouldPlaceBlock(player.level, blockEntry)) remove = true;
|
||||||
|
|
||||||
if (remove) iter.remove();
|
return remove;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package nl.requios.effortlessbuilding.systems;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
|
||||||
|
import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem;
|
||||||
|
import nl.requios.effortlessbuilding.utilities.InventoryHelper;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public class ItemUsageTracker {
|
||||||
|
|
||||||
|
//How many blocks we want to place
|
||||||
|
public Map<Item, Integer> total = new HashMap<>();
|
||||||
|
|
||||||
|
//How many blocks we have in inventory in total
|
||||||
|
public Map<Item, Integer> inInventory = new HashMap<>();
|
||||||
|
|
||||||
|
//How many blocks are missing from our inventory
|
||||||
|
public Map<Item, Integer> missing = new HashMap<>();
|
||||||
|
|
||||||
|
public void initialize(Player player, ItemStack heldItem) {
|
||||||
|
total.clear();
|
||||||
|
inInventory.clear();
|
||||||
|
missing.clear();
|
||||||
|
|
||||||
|
if (CompatHelper.isItemBlockProxy(heldItem, false)) {
|
||||||
|
AbstractRandomizerBagItem.resetRandomness();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//returns if we have enough items in inventory to use count more
|
||||||
|
public boolean increaseUsageCount(Item item, int count, Player player) {
|
||||||
|
if (item == null) return true;
|
||||||
|
int newValue = total.getOrDefault(item, 0) + count;
|
||||||
|
total.put(item, newValue);
|
||||||
|
|
||||||
|
if (player.isCreative()) return true;
|
||||||
|
int have = 0;
|
||||||
|
if (inInventory.containsKey(item)) {
|
||||||
|
have = inInventory.get(item);
|
||||||
|
} else {
|
||||||
|
have = InventoryHelper.findTotalItemsInInventory(player, item);
|
||||||
|
inInventory.put(item, have);
|
||||||
|
}
|
||||||
|
|
||||||
|
return have >= newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void calculateMissingItems(Player player) {
|
||||||
|
if (player.isCreative()) return;
|
||||||
|
for (Item item : total.keySet()) {
|
||||||
|
int used = total.get(item);
|
||||||
|
int have = inInventory.getOrDefault(item, 0);
|
||||||
|
if (used > have) {
|
||||||
|
missing.put(item, used - have);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValidCount(Item item) {
|
||||||
|
return total.getOrDefault(item, 0) - missing.getOrDefault(item, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMissingCount(Item item) {
|
||||||
|
return missing.getOrDefault(item, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ public class ServerBlockPlacer {
|
|||||||
private final Set<DelayedEntry> delayedEntriesView = Collections.unmodifiableSet(delayedEntries);
|
private final Set<DelayedEntry> delayedEntriesView = Collections.unmodifiableSet(delayedEntries);
|
||||||
|
|
||||||
public void placeBlocksDelayed(Player player, BlockSet blocks, long placeTime) {
|
public void placeBlocksDelayed(Player player, BlockSet blocks, long placeTime) {
|
||||||
|
|
||||||
if (!checkAndNotifyAllowedToUseMod(player)) return;
|
if (!checkAndNotifyAllowedToUseMod(player)) return;
|
||||||
if (!validateBlockSet(player, blocks)) return;
|
if (!validateBlockSet(player, blocks)) return;
|
||||||
|
|
||||||
@@ -32,6 +33,7 @@ public class ServerBlockPlacer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void tick() {
|
public void tick() {
|
||||||
|
|
||||||
//Iterator to prevent concurrent modification exception
|
//Iterator to prevent concurrent modification exception
|
||||||
for (var iterator = delayedEntries.iterator(); iterator.hasNext(); ) {
|
for (var iterator = delayedEntries.iterator(); iterator.hasNext(); ) {
|
||||||
DelayedEntry entry = iterator.next();
|
DelayedEntry entry = iterator.next();
|
||||||
@@ -55,6 +57,7 @@ public class ServerBlockPlacer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void applyBlockSet(Player player, BlockSet blocks) {
|
public void applyBlockSet(Player player, BlockSet blocks) {
|
||||||
|
|
||||||
if (!checkAndNotifyAllowedToUseMod(player)) return;
|
if (!checkAndNotifyAllowedToUseMod(player)) return;
|
||||||
if (!validateBlockSet(player, blocks)) return;
|
if (!validateBlockSet(player, blocks)) return;
|
||||||
|
|
||||||
@@ -71,6 +74,7 @@ public class ServerBlockPlacer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void undoBlockSet(Player player, BlockSet blocks) {
|
public void undoBlockSet(Player player, BlockSet blocks) {
|
||||||
|
|
||||||
if (!isAllowedToUndo(player, true)) return;
|
if (!isAllowedToUndo(player, true)) return;
|
||||||
|
|
||||||
var redoSet = new BlockSet();
|
var redoSet = new BlockSet();
|
||||||
@@ -85,6 +89,7 @@ public class ServerBlockPlacer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean applyBlockEntry(Player player, BlockEntry block) {
|
private boolean applyBlockEntry(Player player, BlockEntry block) {
|
||||||
|
|
||||||
block.existingBlockState = player.level.getBlockState(block.blockPos);
|
block.existingBlockState = player.level.getBlockState(block.blockPos);
|
||||||
boolean breaking = BlockUtilities.isNullOrAir(block.newBlockState);
|
boolean breaking = BlockUtilities.isNullOrAir(block.newBlockState);
|
||||||
if (!validateBlockEntry(player, block, breaking)) return false;
|
if (!validateBlockEntry(player, block, breaking)) return false;
|
||||||
@@ -101,6 +106,7 @@ public class ServerBlockPlacer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean undoBlockEntry(Player player, BlockEntry block) {
|
private boolean undoBlockEntry(Player player, BlockEntry block) {
|
||||||
|
|
||||||
boolean breaking = BlockUtilities.isNullOrAir(block.existingBlockState);
|
boolean breaking = BlockUtilities.isNullOrAir(block.existingBlockState);
|
||||||
|
|
||||||
var tempBlockEntry = new BlockEntry(block.blockPos);
|
var tempBlockEntry = new BlockEntry(block.blockPos);
|
||||||
@@ -126,11 +132,6 @@ public class ServerBlockPlacer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkAndNotifyAllowedToUseMod(Player player) {
|
private boolean checkAndNotifyAllowedToUseMod(Player player) {
|
||||||
//TODO temp no survival allowed
|
|
||||||
if (!player.isCreative()) {
|
|
||||||
EffortlessBuilding.log(player, ChatFormatting.RED + "Effortless Building is not yet supported in survival mode.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!player.getAbilities().mayBuild) {
|
if (!player.getAbilities().mayBuild) {
|
||||||
EffortlessBuilding.log(player, ChatFormatting.RED + "You are not allowed to build.");
|
EffortlessBuilding.log(player, ChatFormatting.RED + "You are not allowed to build.");
|
||||||
@@ -145,6 +146,7 @@ public class ServerBlockPlacer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAllowedToUseMod(Player player) {
|
private boolean isAllowedToUseMod(Player player) {
|
||||||
|
|
||||||
if (!ServerConfig.validation.allowInSurvival.get() && !player.isCreative()) return false;
|
if (!ServerConfig.validation.allowInSurvival.get() && !player.isCreative()) return false;
|
||||||
|
|
||||||
if (ServerConfig.validation.useWhitelist.get()) {
|
if (ServerConfig.validation.useWhitelist.get()) {
|
||||||
@@ -155,8 +157,9 @@ public class ServerBlockPlacer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAllowedToUndo(Player player, boolean log) {
|
private boolean isAllowedToUndo(Player player, boolean log) {
|
||||||
|
|
||||||
if (!player.isCreative()) {
|
if (!player.isCreative()) {
|
||||||
if (log) EffortlessBuilding.log(player, ChatFormatting.RED + "Undo is not supported in survival mode.");
|
if (log) EffortlessBuilding.log(player, ChatFormatting.RED + "Undo is not available in survival mode.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,6 +167,7 @@ public class ServerBlockPlacer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean validateBlockSet(Player player, BlockSet blocks) {
|
private boolean validateBlockSet(Player player, BlockSet blocks) {
|
||||||
|
|
||||||
if (blocks.isEmpty()) {
|
if (blocks.isEmpty()) {
|
||||||
EffortlessBuilding.log(player, ChatFormatting.RED + "No blocks to place.");
|
EffortlessBuilding.log(player, ChatFormatting.RED + "No blocks to place.");
|
||||||
return false;
|
return false;
|
||||||
@@ -178,34 +182,41 @@ public class ServerBlockPlacer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Dont allow mixing breaking and placing blocks
|
//Dont allow mixing breaking and placing blocks
|
||||||
//First determine if we are breaking or placing
|
if (isMixedPlacingAndBreaking(player, blocks)) {
|
||||||
var iterator = blocks.iterator();
|
EffortlessBuilding.log(player, ChatFormatting.RED + "Cannot mix breaking and placing blocks.");
|
||||||
//Get any block from the set, skip first if we have to
|
return false;
|
||||||
var anyBlock = iterator.next();
|
|
||||||
if (blocks.skipFirst && anyBlock.blockPos == blocks.firstPos) {
|
|
||||||
anyBlock = iterator.next();
|
|
||||||
}
|
|
||||||
boolean breaking = anyBlock.newBlockState == null || anyBlock.newBlockState.isAir();
|
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
var block = iterator.next();
|
|
||||||
if (block.newBlockState == null || block.newBlockState.isAir()) {
|
|
||||||
if (!breaking) {
|
|
||||||
EffortlessBuilding.log(player, ChatFormatting.RED + "Cannot mix breaking and placing blocks.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (breaking) {
|
|
||||||
EffortlessBuilding.log(player, ChatFormatting.RED + "Cannot mix breaking and placing blocks.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isMixedPlacingAndBreaking(Player player, BlockSet blocks) {
|
||||||
|
|
||||||
|
//First determine if we are breaking or placing
|
||||||
|
var iterator = blocks.iterator();
|
||||||
|
|
||||||
|
//Get any block from the set, skip first if we have to
|
||||||
|
var anyBlock = iterator.next();
|
||||||
|
if (blocks.skipFirst && anyBlock.blockPos == blocks.firstPos) {
|
||||||
|
anyBlock = iterator.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean breaking = anyBlock.newBlockState == null || anyBlock.newBlockState.isAir();
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
var block = iterator.next();
|
||||||
|
if (block.newBlockState == null || block.newBlockState.isAir()) {
|
||||||
|
if (!breaking) return true;
|
||||||
|
} else {
|
||||||
|
if (breaking) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean validateBlockEntry(Player player, BlockEntry block, boolean breaking) {
|
private boolean validateBlockEntry(Player player, BlockEntry block, boolean breaking) {
|
||||||
|
|
||||||
if (!player.level.isLoaded(block.blockPos)) return false;
|
if (!player.level.isLoaded(block.blockPos)) return false;
|
||||||
|
|
||||||
if (breaking && BlockUtilities.isNullOrAir(block.existingBlockState)) return false;
|
if (breaking && BlockUtilities.isNullOrAir(block.existingBlockState)) return false;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import net.minecraft.core.BlockPos;
|
|||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.nbt.NbtUtils;
|
import net.minecraft.nbt.NbtUtils;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
@@ -22,7 +23,9 @@ public class BlockEntry {
|
|||||||
//BlockState that is currently in the world
|
//BlockState that is currently in the world
|
||||||
public BlockState existingBlockState;
|
public BlockState existingBlockState;
|
||||||
public BlockState newBlockState;
|
public BlockState newBlockState;
|
||||||
public ItemStack itemStack = ItemStack.EMPTY;
|
public Item item;
|
||||||
|
//Invalid block entries will be marked red and won't be sent to server
|
||||||
|
public boolean invalid = false;
|
||||||
|
|
||||||
public BlockEntry(BlockPos blockPos) {
|
public BlockEntry(BlockPos blockPos) {
|
||||||
this.blockPos = blockPos;
|
this.blockPos = blockPos;
|
||||||
@@ -35,10 +38,11 @@ public class BlockEntry {
|
|||||||
rotation = blockEntry.rotation;
|
rotation = blockEntry.rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setItemStackAndFindNewBlockState(ItemStack itemStack, Level world, Direction originalDirection, Direction clickedFace, Vec3 relativeHitVec) {
|
public void setItemAndFindNewBlockState(ItemStack itemStack, Level world, Direction originalDirection, Direction clickedFace, Vec3 relativeHitVec) {
|
||||||
this.itemStack = itemStack;
|
this.item = itemStack.getItem();
|
||||||
|
|
||||||
Block block = Block.byItem(itemStack.getItem());
|
//Find new blockstate with right direction
|
||||||
|
Block block = Block.byItem(this.item);
|
||||||
var direction = originalDirection;
|
var direction = originalDirection;
|
||||||
if (rotation != null) direction = rotation.rotate(direction);
|
if (rotation != null) direction = rotation.rotate(direction);
|
||||||
direction = applyMirror(direction);
|
direction = applyMirror(direction);
|
||||||
@@ -62,7 +66,7 @@ public class BlockEntry {
|
|||||||
public static void encode(FriendlyByteBuf buf, BlockEntry block) {
|
public static void encode(FriendlyByteBuf buf, BlockEntry block) {
|
||||||
buf.writeBlockPos(block.blockPos);
|
buf.writeBlockPos(block.blockPos);
|
||||||
buf.writeNullable(block.newBlockState, (buffer, blockState) -> buffer.writeNbt(NbtUtils.writeBlockState(blockState)));
|
buf.writeNullable(block.newBlockState, (buffer, blockState) -> buffer.writeNbt(NbtUtils.writeBlockState(blockState)));
|
||||||
buf.writeItem(block.itemStack);
|
buf.writeInt(Item.getId(block.item));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlockEntry decode(FriendlyByteBuf buf) {
|
public static BlockEntry decode(FriendlyByteBuf buf) {
|
||||||
@@ -72,7 +76,7 @@ public class BlockEntry {
|
|||||||
if (nbt == null) return null;
|
if (nbt == null) return null;
|
||||||
return NbtUtils.readBlockState(nbt);
|
return NbtUtils.readBlockState(nbt);
|
||||||
});
|
});
|
||||||
block.itemStack = buf.readItem();
|
block.item = Item.byId(buf.readInt());
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import java.util.List;
|
|||||||
public class BlockPlacerHelper {
|
public class BlockPlacerHelper {
|
||||||
|
|
||||||
public static boolean breakBlock(Player player, BlockEntry blockEntry) {
|
public static boolean breakBlock(Player player, BlockEntry blockEntry) {
|
||||||
|
|
||||||
ItemStack usedTool = player.getMainHandItem();
|
ItemStack usedTool = player.getMainHandItem();
|
||||||
if (usedTool.isEmpty() || !(usedTool.getItem() instanceof DiggerItem)) {
|
if (usedTool.isEmpty() || !(usedTool.getItem() instanceof DiggerItem)) {
|
||||||
ItemStack offhand = player.getOffhandItem();
|
ItemStack offhand = player.getOffhandItem();
|
||||||
@@ -42,20 +43,14 @@ public class BlockPlacerHelper {
|
|||||||
return brokeBlock;
|
return brokeBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ForgeHooks::onPlaceItemIntoWorld, removed itemstack usage
|
||||||
public static boolean placeBlock(Player player, BlockEntry blockEntry) {
|
public static boolean placeBlock(Player player, BlockEntry blockEntry) {
|
||||||
if (blockEntry.itemStack == null) {
|
|
||||||
return placeBlockWithoutItem(player, blockEntry);
|
|
||||||
} else {
|
|
||||||
var interactionResult = placeItem(player, blockEntry);
|
|
||||||
return interactionResult == InteractionResult.SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean placeBlockWithoutItem(Player player, BlockEntry blockEntry) {
|
|
||||||
Level level = player.level;
|
Level level = player.level;
|
||||||
|
var itemStack = new ItemStack(blockEntry.item);
|
||||||
|
|
||||||
level.captureBlockSnapshots = true;
|
level.captureBlockSnapshots = true;
|
||||||
BlockHelper.placeSchematicBlock(level, player, blockEntry.newBlockState, blockEntry.blockPos, blockEntry.itemStack, null);
|
BlockHelper.placeSchematicBlock(level, player, blockEntry.newBlockState, blockEntry.blockPos, itemStack, null);
|
||||||
level.captureBlockSnapshots = false;
|
level.captureBlockSnapshots = false;
|
||||||
|
|
||||||
//Find out if we get to keep the placed block by sending a forge event
|
//Find out if we get to keep the placed block by sending a forge event
|
||||||
@@ -99,96 +94,4 @@ public class BlockPlacerHelper {
|
|||||||
level.capturedBlockSnapshots.clear();
|
level.capturedBlockSnapshots.clear();
|
||||||
return !eventResult;
|
return !eventResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
//ForgeHooks::onPlaceItemIntoWorld
|
|
||||||
private static InteractionResult placeItem(Player player, BlockEntry block) {
|
|
||||||
ItemStack itemstack = block.itemStack;
|
|
||||||
Level level = player.level;
|
|
||||||
|
|
||||||
if (player != null && !player.getAbilities().mayBuild && !itemstack.hasAdventureModePlaceTagForBlock(level.registryAccess().registryOrThrow(Registry.BLOCK_REGISTRY), new BlockInWorld(level, block.blockPos, false)))
|
|
||||||
return InteractionResult.PASS;
|
|
||||||
|
|
||||||
// handle all placement events here
|
|
||||||
Item item = itemstack.getItem();
|
|
||||||
int size = itemstack.getCount();
|
|
||||||
CompoundTag nbt = null;
|
|
||||||
if (itemstack.getTag() != null)
|
|
||||||
nbt = itemstack.getTag().copy();
|
|
||||||
|
|
||||||
if (!(itemstack.getItem() instanceof BucketItem)) // if not bucket
|
|
||||||
level.captureBlockSnapshots = true;
|
|
||||||
|
|
||||||
ItemStack copy = itemstack.copy();
|
|
||||||
////
|
|
||||||
BlockHelper.placeSchematicBlock(level, player, block.newBlockState, block.blockPos, block.itemStack, null);
|
|
||||||
////
|
|
||||||
InteractionResult ret = InteractionResult.SUCCESS;
|
|
||||||
if (itemstack.isEmpty())
|
|
||||||
ForgeEventFactory.onPlayerDestroyItem(player, copy, InteractionHand.MAIN_HAND);
|
|
||||||
|
|
||||||
level.captureBlockSnapshots = false;
|
|
||||||
|
|
||||||
if (ret.consumesAction())
|
|
||||||
{
|
|
||||||
// save new item data
|
|
||||||
int newSize = itemstack.getCount();
|
|
||||||
CompoundTag newNBT = null;
|
|
||||||
if (itemstack.getTag() != null)
|
|
||||||
{
|
|
||||||
newNBT = itemstack.getTag().copy();
|
|
||||||
}
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
List<BlockSnapshot> blockSnapshots = (List<BlockSnapshot>)level.capturedBlockSnapshots.clone();
|
|
||||||
level.capturedBlockSnapshots.clear();
|
|
||||||
|
|
||||||
// make sure to set pre-placement item data for event
|
|
||||||
itemstack.setCount(size);
|
|
||||||
itemstack.setTag(nbt);
|
|
||||||
|
|
||||||
Direction side = Direction.UP;
|
|
||||||
|
|
||||||
boolean eventResult = false;
|
|
||||||
if (blockSnapshots.size() > 1)
|
|
||||||
{
|
|
||||||
eventResult = ForgeEventFactory.onMultiBlockPlace(player, blockSnapshots, side);
|
|
||||||
}
|
|
||||||
else if (blockSnapshots.size() == 1)
|
|
||||||
{
|
|
||||||
eventResult = ForgeEventFactory.onBlockPlace(player, blockSnapshots.get(0), side);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventResult)
|
|
||||||
{
|
|
||||||
ret = InteractionResult.FAIL; // cancel placement
|
|
||||||
// revert back all captured blocks
|
|
||||||
for (BlockSnapshot blocksnapshot : Lists.reverse(blockSnapshots))
|
|
||||||
{
|
|
||||||
level.restoringBlockSnapshots = true;
|
|
||||||
blocksnapshot.restore(true, false);
|
|
||||||
level.restoringBlockSnapshots = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Change the stack to its new content
|
|
||||||
itemstack.setCount(newSize);
|
|
||||||
itemstack.setTag(newNBT);
|
|
||||||
|
|
||||||
for (BlockSnapshot snap : blockSnapshots)
|
|
||||||
{
|
|
||||||
int updateFlag = snap.getFlag();
|
|
||||||
BlockState oldBlock = snap.getReplacedBlock();
|
|
||||||
BlockState newBlock = level.getBlockState(snap.getPos());
|
|
||||||
newBlock.onPlace(level, snap.getPos(), oldBlock, false);
|
|
||||||
|
|
||||||
level.markAndNotifyBlock(snap.getPos(), level.getChunkAt(snap.getPos()), oldBlock, newBlock, updateFlag, 512);
|
|
||||||
}
|
|
||||||
if (player != null)
|
|
||||||
player.awardStat(Stats.ITEM_USED.get(item));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
level.capturedBlockSnapshots.clear();
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ public class BlockSet extends HashMap<BlockPos, BlockEntry> implements Iterable<
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void encode(FriendlyByteBuf buf, BlockSet block) {
|
public static void encode(FriendlyByteBuf buf, BlockSet block) {
|
||||||
buf.writeCollection(block.values(), BlockEntry::encode);
|
buf.writeCollection(block.values().stream().filter(be -> !be.invalid).toList(), BlockEntry::encode);
|
||||||
buf.writeBlockPos(block.firstPos);
|
buf.writeBlockPos(block.firstPos);
|
||||||
buf.writeBlockPos(block.lastPos);
|
buf.writeBlockPos(block.lastPos);
|
||||||
buf.writeBoolean(block.skipFirst);
|
buf.writeBoolean(block.skipFirst);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package nl.requios.effortlessbuilding.utilities;
|
package nl.requios.effortlessbuilding.utilities;
|
||||||
|
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.BlockItem;
|
import net.minecraft.world.item.BlockItem;
|
||||||
@@ -28,4 +29,14 @@ public class InventoryHelper {
|
|||||||
}
|
}
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int findTotalItemsInInventory(Player player, Item item) {
|
||||||
|
int total = 0;
|
||||||
|
for (ItemStack invStack : player.getInventory().items) {
|
||||||
|
if (!invStack.isEmpty() && invStack.getItem().equals(item)) {
|
||||||
|
total += invStack.getCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
|||||||
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
|
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import nl.requios.effortlessbuilding.EffortlessBuildingClient;
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
@OnlyIn(Dist.CLIENT)
|
||||||
public class PlaceChecker {
|
public class PlaceChecker {
|
||||||
@@ -38,15 +39,17 @@ public class PlaceChecker {
|
|||||||
&& state.getValue(BlockStateProperties.DOUBLE_BLOCK_HALF) == DoubleBlockHalf.LOWER)
|
&& state.getValue(BlockStateProperties.DOUBLE_BLOCK_HALF) == DoubleBlockHalf.LOWER)
|
||||||
toReplaceOther = world.getBlockState(pos.above());
|
toReplaceOther = world.getBlockState(pos.above());
|
||||||
|
|
||||||
if (!world.isLoaded(pos))
|
// if (!world.isLoaded(pos))
|
||||||
return false;
|
// return false;
|
||||||
if (!world.getWorldBorder().isWithinBounds(pos))
|
// if (!world.getWorldBorder().isWithinBounds(pos))
|
||||||
return false;
|
// return false;
|
||||||
if (toReplace == state)
|
if (toReplace == state)
|
||||||
return false;
|
return false;
|
||||||
if (toReplace.getDestroySpeed(world, pos) == -1
|
if (toReplace.getDestroySpeed(world, pos) == -1
|
||||||
|| (toReplaceOther != null && toReplaceOther.getDestroySpeed(world, pos) == -1))
|
|| (toReplaceOther != null && toReplaceOther.getDestroySpeed(world, pos) == -1))
|
||||||
return false;
|
return false;
|
||||||
|
if (EffortlessBuildingClient.BUILD_SETTINGS.shouldProtectTileEntities() && toReplaceOther != null && toReplaceOther.hasBlockEntity())
|
||||||
|
return false;
|
||||||
|
|
||||||
boolean isNormalCube = state.isRedstoneConductor(world, pos);
|
boolean isNormalCube = state.isRedstoneConductor(world, pos);
|
||||||
return shouldPlace(world, pos, state, tileEntity, toReplace, toReplaceOther, isNormalCube);
|
return shouldPlace(world, pos, state, tileEntity, toReplace, toReplaceOther, isNormalCube);
|
||||||
@@ -55,14 +58,13 @@ public class PlaceChecker {
|
|||||||
//SchematicannonTileEntity::shouldPlace
|
//SchematicannonTileEntity::shouldPlace
|
||||||
private static boolean shouldPlace(Level level, BlockPos pos, BlockState state, BlockEntity tileEntity, BlockState toReplace,
|
private static boolean shouldPlace(Level level, BlockPos pos, BlockState state, BlockEntity tileEntity, BlockState toReplace,
|
||||||
BlockState toReplaceOther, boolean isNormalCube) {
|
BlockState toReplaceOther, boolean isNormalCube) {
|
||||||
return true;
|
|
||||||
// if (!replaceTileEntities
|
// if (!replaceTileEntities
|
||||||
// && (toReplace.hasBlockEntity() || (toReplaceOther != null && toReplaceOther.hasBlockEntity())))
|
// && (toReplace.hasBlockEntity() || (toReplaceOther != null && toReplaceOther.hasBlockEntity())))
|
||||||
// return false;
|
// return false;
|
||||||
//
|
|
||||||
// if (shouldIgnoreBlockState(state))
|
if (shouldIgnoreBlockState(state))
|
||||||
// return false;
|
return false;
|
||||||
//
|
|
||||||
// boolean placingAir = state.isAir();
|
// boolean placingAir = state.isAir();
|
||||||
//
|
//
|
||||||
// if (replaceMode == 3)
|
// if (replaceMode == 3)
|
||||||
@@ -76,7 +78,7 @@ public class PlaceChecker {
|
|||||||
// && (toReplaceOther == null || !toReplaceOther.isRedstoneConductor(level, pos)) && !placingAir)
|
// && (toReplaceOther == null || !toReplaceOther.isRedstoneConductor(level, pos)) && !placingAir)
|
||||||
// return true;
|
// return true;
|
||||||
//
|
//
|
||||||
// return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//SchematicannonTileEntity::shouldIgnoreBlockState
|
//SchematicannonTileEntity::shouldIgnoreBlockState
|
||||||
|
|||||||
Reference in New Issue
Block a user