From 594b5e1c0dbf519c77f8e110fbfbcbfad2a3d679 Mon Sep 17 00:00:00 2001 From: Christian Knaapen Date: Sun, 11 Jun 2023 17:23:01 +0200 Subject: [PATCH] Decreasing itemstacks in survival. Disabled replacing blocks in survival. Expanded config options for survival. Added keybinds to switch to previous build mode, and to switch between disabled and previous. Updated RandomizerBags to use new placement method in vanilla mode. Removed SurvivalHelper placement methods. --- .../effortlessbuilding/ClientEvents.java | 14 +- .../effortlessbuilding/CommonConfig.java | 113 +++++--- .../EffortlessBuilding.java | 6 + .../effortlessbuilding/ServerConfig.java | 2 +- .../buildmode/BuildModes.java | 26 +- .../buildmode/ModeOptions.java | 8 +- .../foundation/utility/BlockHelper.java | 5 +- .../gui/buildmode/RadialMenu.java | 18 +- .../item/AbstractRandomizerBagItem.java | 32 +-- .../item/ReachUpgrade1Item.java | 2 +- .../item/ReachUpgrade2Item.java | 2 +- .../item/ReachUpgrade3Item.java | 2 +- .../systems/BuildSettings.java | 18 +- .../systems/BuilderChain.java | 6 +- .../systems/ItemUsageTracker.java | 15 +- .../systems/ServerBlockPlacer.java | 57 ++-- .../systems/ServerBuildState.java | 1 + .../effortlessbuilding/systems/UndoRedo.java | 5 +- .../utilities/BlockEntry.java | 6 + .../utilities/BlockUtilities.java | 12 - .../utilities/InventoryHelper.java | 52 ++++ .../utilities/SurvivalHelper.java | 252 +----------------- .../assets/effortlessbuilding/lang/en_us.json | 2 + 23 files changed, 271 insertions(+), 385 deletions(-) diff --git a/src/main/java/nl/requios/effortlessbuilding/ClientEvents.java b/src/main/java/nl/requios/effortlessbuilding/ClientEvents.java index 13fad4e..f893319 100644 --- a/src/main/java/nl/requios/effortlessbuilding/ClientEvents.java +++ b/src/main/java/nl/requios/effortlessbuilding/ClientEvents.java @@ -40,13 +40,15 @@ public class ClientEvents { EffortlessBuilding.log("Registering KeyMappings!"); // register key bindings - keyBindings = new KeyMapping[4]; + keyBindings = new KeyMapping[6]; // instantiate the key bindings keyBindings[0] = new KeyMapping("key.effortlessbuilding.mode.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_LEFT_ALT, 0), "key.effortlessbuilding.category"); keyBindings[1] = new KeyMapping("key.effortlessbuilding.hud.desc", KeyConflictContext.IN_GAME, InputConstants.getKey(GLFW.GLFW_KEY_KP_ADD, 0), "key.effortlessbuilding.category"); keyBindings[2] = new KeyMapping("key.effortlessbuilding.undo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, InputConstants.getKey(GLFW.GLFW_KEY_Z, 0), "key.effortlessbuilding.category"); keyBindings[3] = new KeyMapping("key.effortlessbuilding.redo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, InputConstants.getKey(GLFW.GLFW_KEY_Y, 0), "key.effortlessbuilding.category"); + keyBindings[4] = new KeyMapping("key.effortlessbuilding.previous_build_mode.desc", KeyConflictContext.IN_GAME, InputConstants.UNKNOWN, "key.effortlessbuilding.category"); + keyBindings[5] = new KeyMapping("key.effortlessbuilding.disable_build_mode_toggle.desc", KeyConflictContext.IN_GAME, InputConstants.UNKNOWN, "key.effortlessbuilding.category"); for (KeyMapping keyBinding : keyBindings) { event.register(keyBinding); @@ -158,6 +160,16 @@ public class ClientEvents { if (keyBindings[3].consumeClick()) { ModeOptions.performAction(player, ModeOptions.ActionEnum.REDO); } + + //Previous build mode + if (keyBindings[4].consumeClick()) { + ModeOptions.performAction(player, ModeOptions.ActionEnum.PREVIOUS_BUILD_MODE); + } + + //Disable build mode toggle + if (keyBindings[5].consumeClick()) { + ModeOptions.performAction(player, ModeOptions.ActionEnum.DISABLE_BUILD_MODE_TOGGLE); + } } public static void openModifierSettings() { diff --git a/src/main/java/nl/requios/effortlessbuilding/CommonConfig.java b/src/main/java/nl/requios/effortlessbuilding/CommonConfig.java index f641391..552a988 100644 --- a/src/main/java/nl/requios/effortlessbuilding/CommonConfig.java +++ b/src/main/java/nl/requios/effortlessbuilding/CommonConfig.java @@ -8,67 +8,100 @@ public class CommonConfig { private static final Builder builder = new Builder(); public static final Reach reach = new Reach(builder); - public static final SurvivalBalancers survivalBalancers = new SurvivalBalancers(builder); + public static final MaxBlocksPlacedAtOnce maxBlocksPlacedAtOnce = new MaxBlocksPlacedAtOnce(builder); + public static final MaxBlocksPerAxis maxBlocksPerAxis = new MaxBlocksPerAxis(builder); public static final ForgeConfigSpec spec = builder.build(); public static class Reach { - public final BooleanValue enableReachUpgrades; - public final IntValue maxReachCreative; - public final IntValue maxReachLevel0; - public final IntValue maxReachLevel1; - public final IntValue maxReachLevel2; - public final IntValue maxReachLevel3; + public final IntValue reachCreative; + public final IntValue reachLevel0; + public final IntValue reachLevel1; + public final IntValue reachLevel2; + public final IntValue reachLevel3; public Reach(Builder builder) { builder.push("Reach"); - enableReachUpgrades = builder - .comment("Reach: how far away the player can place blocks using mirror/array etc.", - "Enable the crafting of reach upgrades to increase reach.", - "If disabled, reach is set to level 3 for survival players.") - .define("enableReachUpgrades", true); - maxReachCreative = builder - .comment("Maximum reach in creative", - "Keep in mind that chunks need to be loaded to be able to place blocks inside.") - .defineInRange("maxReachCreative", 200, 0, 1000); + reachCreative = builder + .comment("How far away the player can place and break blocks.") + .defineInRange("maxReachCreative", 200, 0, 10000); - maxReachLevel0 = builder + reachLevel0 = builder .comment("Maximum reach in survival without upgrades", "Reach upgrades are craftable consumables that permanently increase reach.", "Set to 0 to disable Effortless Building until the player has consumed a reach upgrade.") - .defineInRange("maxReachLevel0", 20, 0, 1000); + .defineInRange("reachLevel0", 20, 0, 10000); - maxReachLevel1 = builder - .comment("Maximum reach in survival with one upgrade") - .defineInRange("maxReachLevel1", 50, 0, 1000); + reachLevel1 = builder + .defineInRange("reachLevel1", 50, 0, 10000); - maxReachLevel2 = builder - .comment("Maximum reach in survival with two upgrades") - .defineInRange("maxReachLevel2", 100, 0, 1000); + reachLevel2 = builder + .defineInRange("reachLevel2", 100, 0, 10000); - maxReachLevel3 = builder - .comment("Maximum reach in survival with three upgrades") - .defineInRange("maxReachLevel3", 200, 0, 1000); + reachLevel3 = builder + .defineInRange("reachLevel3", 200, 0, 10000); builder.pop(); } } - public static class SurvivalBalancers { - public final IntValue quickReplaceMiningLevel; + public static class MaxBlocksPlacedAtOnce { + public final IntValue creative; + public final IntValue level0; + public final IntValue level1; + public final IntValue level2; + public final IntValue level3; - public SurvivalBalancers(Builder builder) { - builder.push("SurvivalBalancers"); + public MaxBlocksPlacedAtOnce(Builder builder) { + builder.push("MaxBlocksPlacedAtOnce"); - quickReplaceMiningLevel = builder - .comment("Determines what blocks can be replaced in survival.", - "-1: only blocks that can be harvested by hand (default)", - "0: blocks that can be harvested with wooden or gold tools", - "1: blocks that can be harvested with stone tools", - "2: blocks that can be harvested with iron tools", - "3: blocks that can be harvested with diamond tools", - "4: blocks that can be harvested with netherite tools") - .defineInRange("quickReplaceMiningLevel", -1, -1, 3); + creative = builder + .comment("How many blocks can be placed in one click.") + .defineInRange("maxBlocksPlacedAtOnceCreative", 10000, 0, 10000); + + level0 = builder + .comment("Maximum blocks placed at once in survival without upgrades") + .defineInRange("maxBlocksPlacedAtOnceLevel0", 100, 0, 10000); + + level1 = builder + .defineInRange("maxBlocksPlacedAtOnceLevel1", 200, 0, 10000); + + level2 = builder + .defineInRange("maxBlocksPlacedAtOnceLevel2", 500, 0, 10000); + + level3 = builder + .defineInRange("maxBlocksPlacedAtOnceLevel3", 1000, 0, 10000); + + builder.pop(); + } + } + + public static class MaxBlocksPerAxis { + public final IntValue creative; + public final IntValue level0; + public final IntValue level1; + public final IntValue level2; + public final IntValue level3; + + public MaxBlocksPerAxis(Builder builder) { + builder.push("MaxBlocksPerAxis"); + + creative = builder + .comment("How many blocks can be placed at once per axis.") + .defineInRange("maxBlocksPerAxisCreative", 10000, 0, 10000); + + level0 = builder + .comment("Maximum blocks placed at once in survival without upgrades") + .defineInRange("maxBlocksPerAxisLevel0", 100, 0, 10000); + + level1 = builder + .defineInRange("maxBlocksPerAxisLevel1", 200, 0, 10000); + + level2 = builder + .defineInRange("maxBlocksPerAxisLevel2", 500, 0, 10000); + + level3 = builder + .defineInRange("maxBlocksPerAxisLevel3", 1000, 0, 10000); builder.pop(); } diff --git a/src/main/java/nl/requios/effortlessbuilding/EffortlessBuilding.java b/src/main/java/nl/requios/effortlessbuilding/EffortlessBuilding.java index c3a7c85..464eaf7 100644 --- a/src/main/java/nl/requios/effortlessbuilding/EffortlessBuilding.java +++ b/src/main/java/nl/requios/effortlessbuilding/EffortlessBuilding.java @@ -27,6 +27,7 @@ import nl.requios.effortlessbuilding.network.PacketHandler; import nl.requios.effortlessbuilding.proxy.ClientProxy; import nl.requios.effortlessbuilding.proxy.IProxy; import nl.requios.effortlessbuilding.proxy.ServerProxy; +import nl.requios.effortlessbuilding.systems.ItemUsageTracker; import nl.requios.effortlessbuilding.systems.ServerBlockPlacer; import nl.requios.effortlessbuilding.systems.UndoRedo; import org.apache.logging.log4j.LogManager; @@ -43,6 +44,7 @@ public class EffortlessBuilding { public static final ServerBlockPlacer SERVER_BLOCK_PLACER = new ServerBlockPlacer(); public static final UndoRedo UNDO_REDO = new UndoRedo(); + public static final ItemUsageTracker ITEM_USAGE_TRACKER = new ItemUsageTracker(); //Registration private static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MODID); @@ -107,4 +109,8 @@ public class EffortlessBuilding { proxy.logTranslate(player, prefix, translationKey, suffix, actionBar); } + public static void logError(String msg) { + logger.error(msg); + } + } diff --git a/src/main/java/nl/requios/effortlessbuilding/ServerConfig.java b/src/main/java/nl/requios/effortlessbuilding/ServerConfig.java index eb013e4..fb71917 100644 --- a/src/main/java/nl/requios/effortlessbuilding/ServerConfig.java +++ b/src/main/java/nl/requios/effortlessbuilding/ServerConfig.java @@ -35,7 +35,7 @@ public class ServerConfig { .defineList("whitelist", Arrays.asList("Player1", "Player2"), o -> true); maxBlocksPlacedAtOnce = builder - .comment("Maximum number of blocks that can be placed at once.") + .comment("Maximum number of blocks that can be placed at once. This is a last check. If you want the player to receive visual feedback instead of an error message, change values in the common config.") .defineInRange("maxBlocksPlacedAtOnce", 10000, 1, 100000); builder.pop(); diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java index 6c1b175..ba4a60f 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java @@ -1,22 +1,23 @@ package nl.requios.effortlessbuilding.buildmode; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.language.I18n; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.ClipContext; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.network.IsUsingBuildModePacket; import nl.requios.effortlessbuilding.network.PacketHandler; -import nl.requios.effortlessbuilding.utilities.BlockEntry; import nl.requios.effortlessbuilding.utilities.BlockSet; -import nl.requios.effortlessbuilding.utilities.ReachHelper; - -import java.util.*; @OnlyIn(Dist.CLIENT) public class BuildModes { private BuildModeEnum buildMode = BuildModeEnum.DISABLED; + private BuildModeEnum previousBuildMode = BuildModeEnum.DISABLED; + private BuildModeEnum beforeDisabledBuildMode = BuildModeEnum.SINGLE; public void findCoordinates(BlockSet blocks, Player player) { buildMode.instance.findCoordinates(blocks); @@ -30,6 +31,23 @@ public class BuildModes { this.buildMode = buildMode; PacketHandler.INSTANCE.sendToServer(new IsUsingBuildModePacket(this.buildMode != BuildModeEnum.DISABLED)); + + EffortlessBuilding.log(Minecraft.getInstance().player, I18n.get(buildMode.getNameKey()), true); + } + + public void activatePreviousBuildMode() { + var temp = buildMode; + setBuildMode(previousBuildMode); + previousBuildMode = temp; + } + + public void activateDisableBuildModeToggle(){ + if (buildMode == BuildModeEnum.DISABLED) { + setBuildMode(beforeDisabledBuildMode); + } else { + beforeDisabledBuildMode = buildMode; + setBuildMode(BuildModeEnum.DISABLED); + } } public void onCancel() { diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeOptions.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeOptions.java index 298c351..3f4849c 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeOptions.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeOptions.java @@ -73,6 +73,8 @@ public class ModeOptions { case REDO -> PacketHandler.INSTANCE.sendToServer(new PerformRedoPacket()); case OPEN_MODIFIER_SETTINGS -> ClientEvents.openModifierSettings(); case OPEN_PLAYER_SETTINGS -> ClientEvents.openPlayerSettings(); + case PREVIOUS_BUILD_MODE -> EffortlessBuildingClient.BUILD_MODES.activatePreviousBuildMode(); + case DISABLE_BUILD_MODE_TOGGLE -> EffortlessBuildingClient.BUILD_MODES.activateDisableBuildModeToggle(); case REPLACE_ONLY_AIR -> EffortlessBuildingClient.BUILD_SETTINGS.setReplaceMode(BuildSettings.ReplaceMode.ONLY_AIR); case REPLACE_BLOCKS_AND_AIR -> EffortlessBuildingClient.BUILD_SETTINGS.setReplaceMode(BuildSettings.ReplaceMode.BLOCKS_AND_AIR); @@ -103,7 +105,9 @@ public class ModeOptions { if (player.level.isClientSide && action != ActionEnum.OPEN_MODIFIER_SETTINGS && - action != ActionEnum.OPEN_PLAYER_SETTINGS) { + action != ActionEnum.OPEN_PLAYER_SETTINGS && + action != ActionEnum.PREVIOUS_BUILD_MODE && + action != ActionEnum.DISABLE_BUILD_MODE_TOGGLE) { EffortlessBuilding.logTranslate(player, "", action.getNameKey(), "", true); } @@ -114,6 +118,8 @@ public class ModeOptions { REDO("redo", AllIcons.I_REDO), OPEN_MODIFIER_SETTINGS("open_modifier_settings", AllIcons.I_SETTINGS), OPEN_PLAYER_SETTINGS("open_player_settings", AllIcons.I_SETTINGS), + PREVIOUS_BUILD_MODE("previous_build_mode", AllIcons.I_SINGLE), + DISABLE_BUILD_MODE_TOGGLE("disable_build_mode_toggle", AllIcons.I_DISABLE), REPLACE_ONLY_AIR("replace_only_air", AllIcons.I_REPLACE_AIR), REPLACE_BLOCKS_AND_AIR("replace_blocks_and_air", AllIcons.I_REPLACE_BLOCKS_AND_AIR), diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/BlockHelper.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/BlockHelper.java index 48836e0..44df777 100644 --- a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/BlockHelper.java +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/BlockHelper.java @@ -285,9 +285,8 @@ public class BlockHelper { } try { - state.getBlock() - .setPlacedBy(world, target, state, null, stack); - } catch (Exception e) { + state.getBlock().setPlacedBy(world, target, state, null, stack); + } catch (Exception ignored) { } return true; } diff --git a/src/main/java/nl/requios/effortlessbuilding/gui/buildmode/RadialMenu.java b/src/main/java/nl/requios/effortlessbuilding/gui/buildmode/RadialMenu.java index 27b71c3..2be32d4 100644 --- a/src/main/java/nl/requios/effortlessbuilding/gui/buildmode/RadialMenu.java +++ b/src/main/java/nl/requios/effortlessbuilding/gui/buildmode/RadialMenu.java @@ -3,7 +3,6 @@ package nl.requios.effortlessbuilding.gui.buildmode; import com.mojang.blaze3d.vertex.*; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.math.Vector4f; -import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.player.LocalPlayer; @@ -14,23 +13,20 @@ import net.minecraft.client.resources.sounds.SimpleSoundInstance; import net.minecraft.core.Direction; import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.FormattedText; import net.minecraft.network.chat.MutableComponent; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.util.RandomSource; import nl.requios.effortlessbuilding.ClientEvents; -import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuildingClient; import nl.requios.effortlessbuilding.buildmode.ModeOptions; import nl.requios.effortlessbuilding.create.foundation.item.ItemDescription; import nl.requios.effortlessbuilding.create.foundation.item.TooltipHelper; import nl.requios.effortlessbuilding.create.foundation.utility.Components; import nl.requios.effortlessbuilding.create.foundation.utility.Lang; -import org.apache.commons.lang3.text.WordUtils; +import nl.requios.effortlessbuilding.systems.PowerLevel; import org.lwjgl.opengl.GL11; -import javax.annotation.ParametersAreNonnullByDefault; import java.util.ArrayList; import static nl.requios.effortlessbuilding.buildmode.ModeOptions.*; @@ -154,10 +150,12 @@ public class RadialMenu extends Screen { buttons.add(new MenuButton(ActionEnum.UNDO, -buttonDistance - 26, -13, Direction.UP)); buttons.add(new MenuButton(ActionEnum.REDO, -buttonDistance, -13, Direction.UP)); - buttons.add(new MenuButton(ActionEnum.REPLACE_ONLY_AIR, -buttonDistance - 78, 13, Direction.DOWN)); - buttons.add(new MenuButton(ActionEnum.REPLACE_BLOCKS_AND_AIR, -buttonDistance - 52, 13, Direction.DOWN)); - buttons.add(new MenuButton(ActionEnum.REPLACE_ONLY_BLOCKS, -buttonDistance - 26, 13, Direction.DOWN)); - buttons.add(new MenuButton(ActionEnum.REPLACE_FILTERED_BY_OFFHAND, -buttonDistance, 13, Direction.DOWN)); + if (Minecraft.getInstance().player != null && PowerLevel.canReplaceBlocks(Minecraft.getInstance().player)) { + buttons.add(new MenuButton(ActionEnum.REPLACE_ONLY_AIR, -buttonDistance - 78, 13, Direction.DOWN)); + buttons.add(new MenuButton(ActionEnum.REPLACE_BLOCKS_AND_AIR, -buttonDistance - 52, 13, Direction.DOWN)); + buttons.add(new MenuButton(ActionEnum.REPLACE_ONLY_BLOCKS, -buttonDistance - 26, 13, Direction.DOWN)); + buttons.add(new MenuButton(ActionEnum.REPLACE_FILTERED_BY_OFFHAND, -buttonDistance, 13, Direction.DOWN)); + } //Add buildmode dependent options OptionEnum[] options = currentBuildMode.options; @@ -426,8 +424,6 @@ public class RadialMenu extends Screen { EffortlessBuildingClient.BUILD_MODES.setBuildMode(switchTo); - EffortlessBuilding.log(player, I18n.get(switchTo.getNameKey()), true); - if (fromMouseClick) performedActionUsingMouse = true; } diff --git a/src/main/java/nl/requios/effortlessbuilding/item/AbstractRandomizerBagItem.java b/src/main/java/nl/requios/effortlessbuilding/item/AbstractRandomizerBagItem.java index a9432c3..c647cde 100644 --- a/src/main/java/nl/requios/effortlessbuilding/item/AbstractRandomizerBagItem.java +++ b/src/main/java/nl/requios/effortlessbuilding/item/AbstractRandomizerBagItem.java @@ -25,15 +25,16 @@ import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.network.NetworkHooks; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; +import nl.requios.effortlessbuilding.EffortlessBuilding; +import nl.requios.effortlessbuilding.network.PacketHandler; import nl.requios.effortlessbuilding.systems.ServerBuildState; +import nl.requios.effortlessbuilding.utilities.BlockEntry; +import nl.requios.effortlessbuilding.utilities.BlockSet; import nl.requios.effortlessbuilding.utilities.SurvivalHelper; import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.List; -import java.util.Random; +import java.util.*; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.Item; @@ -132,15 +133,14 @@ public abstract class AbstractRandomizerBagItem extends Item { } else { if (world.isClientSide) return InteractionResult.SUCCESS; - //Only place manually if in normal vanilla mode + //---Only place manually if in normal vanilla mode--- if (!ServerBuildState.isLikeVanilla(player)) { return InteractionResult.FAIL; } //Use item //Get bag inventory - //TODO offhand support - ItemStack bag = player.getItemInHand(InteractionHand.MAIN_HAND); + ItemStack bag = ctx.getItemInHand(); IItemHandler bagInventory = getBagInventory(bag); if (bagInventory == null) return InteractionResult.FAIL; @@ -148,26 +148,16 @@ public abstract class AbstractRandomizerBagItem extends Item { ItemStack toPlace = pickRandomStack(bagInventory); if (toPlace.isEmpty()) return InteractionResult.FAIL; - //Previously: use onItemUse to place block (no synergy) - //bag.setItemDamage(toPlace.getMetadata()); - //toPlace.onItemUse(player, world, pos, hand, facing, hitX, hitY, hitZ); - - //TODO replaceable if (!world.getBlockState(pos).getBlock().canBeReplaced(world.getBlockState(pos), Fluids.EMPTY)) { pos = pos.relative(facing); } - BlockPlaceContext blockItemUseContext = new BlockPlaceContext(new UseOnContext(player, InteractionHand.MAIN_HAND, new BlockHitResult(hitVec, facing, pos, false))); + BlockPlaceContext blockItemUseContext = new BlockPlaceContext(new UseOnContext(player, ctx.getHand(), new BlockHitResult(hitVec, facing, pos, false))); BlockState blockState = Block.byItem(toPlace.getItem()).getStateForPlacement(blockItemUseContext); - SurvivalHelper.placeBlock(world, player, pos, blockState, toPlace, false, false, true); - - //Synergy - //Works without calling -// BlockSnapshot blockSnapshot = new BlockSnapshot(player.world, pos, blockState); -// BlockEvent.PlaceEvent placeEvent = new BlockEvent.PlaceEvent(blockSnapshot, blockState, player, hand); -// Mirror.onBlockPlaced(placeEvent); -// Array.onBlockPlaced(placeEvent); + var blockEntry = new BlockEntry(pos, blockState, toPlace.getItem()); + var blockSet = new BlockSet(List.of(blockEntry), pos, pos, false); + EffortlessBuilding.SERVER_BLOCK_PLACER.applyBlockSet(player, blockSet); } return InteractionResult.SUCCESS; } diff --git a/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade1Item.java b/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade1Item.java index 515cde0..f4224a4 100644 --- a/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade1Item.java +++ b/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade1Item.java @@ -61,7 +61,7 @@ public class ReachUpgrade1Item extends Item { @Override public void appendHoverText(ItemStack stack, @Nullable Level world, List tooltip, TooltipFlag flag) { - tooltip.add(Component.literal(ChatFormatting.GRAY + "Consume to increase reach to " + ChatFormatting.BLUE + CommonConfig.reach.maxReachLevel1.get())); + tooltip.add(Component.literal(ChatFormatting.GRAY + "Consume to increase reach to " + ChatFormatting.BLUE + CommonConfig.reach.reachLevel1.get())); } } diff --git a/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade2Item.java b/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade2Item.java index 4a6f03a..19ff227 100644 --- a/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade2Item.java +++ b/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade2Item.java @@ -66,7 +66,7 @@ public class ReachUpgrade2Item extends Item { @Override public void appendHoverText(ItemStack stack, @Nullable Level world, List tooltip, TooltipFlag flag) { - tooltip.add(Component.literal(ChatFormatting.GRAY + "Consume to increase reach to " + ChatFormatting.BLUE + CommonConfig.reach.maxReachLevel2.get())); + tooltip.add(Component.literal(ChatFormatting.GRAY + "Consume to increase reach to " + ChatFormatting.BLUE + CommonConfig.reach.reachLevel2.get())); tooltip.add(Component.literal(ChatFormatting.GRAY + "Previous upgrades need to be consumed first")); } } diff --git a/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade3Item.java b/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade3Item.java index be10cb2..b0d6315 100644 --- a/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade3Item.java +++ b/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade3Item.java @@ -69,7 +69,7 @@ public class ReachUpgrade3Item extends Item { @Override public void appendHoverText(ItemStack stack, @Nullable Level world, List tooltip, TooltipFlag flag) { - tooltip.add(Component.literal(ChatFormatting.GRAY + "Consume to increase reach to " + ChatFormatting.BLUE + CommonConfig.reach.maxReachLevel3.get())); + tooltip.add(Component.literal(ChatFormatting.GRAY + "Consume to increase reach to " + ChatFormatting.BLUE + CommonConfig.reach.reachLevel3.get())); tooltip.add(Component.literal(ChatFormatting.GRAY + "Previous upgrades need to be consumed first")); } diff --git a/src/main/java/nl/requios/effortlessbuilding/systems/BuildSettings.java b/src/main/java/nl/requios/effortlessbuilding/systems/BuildSettings.java index eee2918..31b52dd 100644 --- a/src/main/java/nl/requios/effortlessbuilding/systems/BuildSettings.java +++ b/src/main/java/nl/requios/effortlessbuilding/systems/BuildSettings.java @@ -1,5 +1,6 @@ package nl.requios.effortlessbuilding.systems; +import net.minecraft.client.Minecraft; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import nl.requios.effortlessbuilding.buildmode.ModeOptions; @@ -19,7 +20,7 @@ public class BuildSettings { private boolean protectTileEntities = true; public boolean isQuickReplacing() { - return replaceMode != ReplaceMode.ONLY_AIR; + return getReplaceMode() != ReplaceMode.ONLY_AIR; } public void setReplaceMode(ReplaceMode replaceMode) { @@ -28,11 +29,12 @@ public class BuildSettings { } public ReplaceMode getReplaceMode() { + if (!canReplaceBlocks()) return ReplaceMode.ONLY_AIR; return replaceMode; } public ModeOptions.ActionEnum getReplaceModeActionEnum() { - return switch (replaceMode) { + return switch (getReplaceMode()) { case ONLY_AIR -> ModeOptions.ActionEnum.REPLACE_ONLY_AIR; case BLOCKS_AND_AIR -> ModeOptions.ActionEnum.REPLACE_BLOCKS_AND_AIR; case ONLY_BLOCKS -> ModeOptions.ActionEnum.REPLACE_ONLY_BLOCKS; @@ -45,15 +47,15 @@ public class BuildSettings { } public boolean shouldReplaceAir() { - return replaceMode == ReplaceMode.ONLY_AIR || replaceMode == ReplaceMode.BLOCKS_AND_AIR; + return getReplaceMode() == ReplaceMode.ONLY_AIR || getReplaceMode() == ReplaceMode.BLOCKS_AND_AIR; } public boolean shouldReplaceBlocks() { - return replaceMode == ReplaceMode.ONLY_BLOCKS || replaceMode == ReplaceMode.BLOCKS_AND_AIR; + return getReplaceMode() == ReplaceMode.ONLY_BLOCKS || getReplaceMode() == ReplaceMode.BLOCKS_AND_AIR; } public boolean shouldReplaceFiltered() { - return replaceMode == ReplaceMode.FILTERED_BY_OFFHAND; + return getReplaceMode() == ReplaceMode.FILTERED_BY_OFFHAND; } public boolean shouldProtectTileEntities() { @@ -61,6 +63,10 @@ public class BuildSettings { } public boolean shouldOffsetStartPosition() { - return replaceMode != ReplaceMode.ONLY_AIR; + return getReplaceMode() != ReplaceMode.ONLY_AIR; + } + + public boolean canReplaceBlocks(){ + return Minecraft.getInstance().player != null && PowerLevel.canReplaceBlocks(Minecraft.getInstance().player); } } diff --git a/src/main/java/nl/requios/effortlessbuilding/systems/BuilderChain.java b/src/main/java/nl/requios/effortlessbuilding/systems/BuilderChain.java index 9c75079..19a3089 100644 --- a/src/main/java/nl/requios/effortlessbuilding/systems/BuilderChain.java +++ b/src/main/java/nl/requios/effortlessbuilding/systems/BuilderChain.java @@ -262,7 +262,11 @@ public class BuilderChain { Vec3 relativeHitVec = lookingAt.getLocation().subtract(Vec3.atLowerCornerOf(lookingAt.getBlockPos())); //Keep track of itemstack usage - EffortlessBuildingClient.ITEM_USAGE_TRACKER.initialize(player, heldItem); + EffortlessBuildingClient.ITEM_USAGE_TRACKER.initialize(); + + if (CompatHelper.isItemBlockProxy(heldItem, false)) { + AbstractRandomizerBagItem.resetRandomness(); + } var iter = blocks.entrySet().iterator(); while (iter.hasNext()) { diff --git a/src/main/java/nl/requios/effortlessbuilding/systems/ItemUsageTracker.java b/src/main/java/nl/requios/effortlessbuilding/systems/ItemUsageTracker.java index d8b64e5..b7f84a8 100644 --- a/src/main/java/nl/requios/effortlessbuilding/systems/ItemUsageTracker.java +++ b/src/main/java/nl/requios/effortlessbuilding/systems/ItemUsageTracker.java @@ -3,8 +3,6 @@ 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; @@ -12,7 +10,7 @@ import nl.requios.effortlessbuilding.utilities.InventoryHelper; import java.util.HashMap; import java.util.Map; -@OnlyIn(Dist.CLIENT) +//Common, both client and server have an instance of this public class ItemUsageTracker { //How many blocks we want to place @@ -21,17 +19,17 @@ public class ItemUsageTracker { //How many blocks we have in inventory in total public Map inInventory = new HashMap<>(); + //How many blocks we can place or have placed + public Map placed = new HashMap<>(); + //How many blocks are missing from our inventory public Map missing = new HashMap<>(); - public void initialize(Player player, ItemStack heldItem) { + public void initialize() { total.clear(); inInventory.clear(); + placed.clear(); missing.clear(); - - if (CompatHelper.isItemBlockProxy(heldItem, false)) { - AbstractRandomizerBagItem.resetRandomness(); - } } //returns if we have enough items in inventory to use count more @@ -57,6 +55,7 @@ public class ItemUsageTracker { for (Item item : total.keySet()) { int used = total.get(item); int have = inInventory.getOrDefault(item, 0); + placed.put(item, Math.min(used, have)); if (used > have) { missing.put(item, used - have); } diff --git a/src/main/java/nl/requios/effortlessbuilding/systems/ServerBlockPlacer.java b/src/main/java/nl/requios/effortlessbuilding/systems/ServerBlockPlacer.java index 2b52ccf..c4190cc 100644 --- a/src/main/java/nl/requios/effortlessbuilding/systems/ServerBlockPlacer.java +++ b/src/main/java/nl/requios/effortlessbuilding/systems/ServerBlockPlacer.java @@ -9,10 +9,7 @@ import net.minecraftforge.items.ItemHandlerHelper; import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.ServerConfig; import nl.requios.effortlessbuilding.create.foundation.utility.BlockHelper; -import nl.requios.effortlessbuilding.utilities.BlockEntry; -import nl.requios.effortlessbuilding.utilities.BlockPlacerHelper; -import nl.requios.effortlessbuilding.utilities.BlockSet; -import nl.requios.effortlessbuilding.utilities.BlockUtilities; +import nl.requios.effortlessbuilding.utilities.*; import java.util.*; @@ -61,6 +58,7 @@ public class ServerBlockPlacer { if (!checkAndNotifyAllowedToUseMod(player)) return; if (!validateBlockSet(player, blocks)) return; + EffortlessBuilding.ITEM_USAGE_TRACKER.initialize(); var undoSet = new BlockSet(); for (BlockEntry block : blocks) { if (blocks.skipFirst && block.blockPos == blocks.firstPos) continue; @@ -69,14 +67,22 @@ public class ServerBlockPlacer { undoSet.add(block); } } - if (isAllowedToUndo(player, false)) - EffortlessBuilding.UNDO_REDO.addUndo(player, undoSet); + + //Remove items from inventory + //(Adding items is done during BlockPlacerHelper.breakBlock) + EffortlessBuilding.ITEM_USAGE_TRACKER.calculateMissingItems(player); + if (!player.isCreative()) { + InventoryHelper.removeFromInventory(player, EffortlessBuilding.ITEM_USAGE_TRACKER.placed); + } + + EffortlessBuilding.UNDO_REDO.addUndo(player, undoSet); } public void undoBlockSet(Player player, BlockSet blocks) { - if (!isAllowedToUndo(player, true)) return; + if (!EffortlessBuilding.UNDO_REDO.isAllowedToUndo(player)) return; + EffortlessBuilding.ITEM_USAGE_TRACKER.initialize(); var redoSet = new BlockSet(); for (BlockEntry block : blocks) { if (blocks.skipFirst && block.blockPos == blocks.firstPos) continue; @@ -85,6 +91,14 @@ public class ServerBlockPlacer { redoSet.add(block); } } + + //Remove items from inventory + //(Adding items is done during BlockPlacerHelper.breakBlock) + EffortlessBuilding.ITEM_USAGE_TRACKER.calculateMissingItems(player); + if (!player.isCreative()) { + InventoryHelper.removeFromInventory(player, EffortlessBuilding.ITEM_USAGE_TRACKER.placed); + } + EffortlessBuilding.UNDO_REDO.addRedo(player, redoSet); } @@ -99,7 +113,15 @@ public class ServerBlockPlacer { if (breaking) { success = BlockPlacerHelper.breakBlock(player, block); } else { - success = BlockPlacerHelper.placeBlock(player, block); + //If we have the item in our inventory, place it + if (EffortlessBuilding.ITEM_USAGE_TRACKER.increaseUsageCount(block.item, 1, player)) { + success = BlockPlacerHelper.placeBlock(player, block); + } else { + success = false; + //Not having the item at this point would be a bit weird, so we notify the player + //It could mean the client/server are out of sync, or the inventory changed during the short delay period + EffortlessBuilding.log(player, ChatFormatting.RED + block.item.toString() + " not found in inventory."); + } } isPlacingOrBreakingBlocks = false; return success; @@ -124,7 +146,14 @@ public class ServerBlockPlacer { if (breaking) { success = BlockPlacerHelper.breakBlock(player, tempBlockEntry); } else { - success = BlockPlacerHelper.placeBlock(player, tempBlockEntry); + //If we have the item in our inventory, place it + if (EffortlessBuilding.ITEM_USAGE_TRACKER.increaseUsageCount(tempBlockEntry.item, 1, player)) { + success = BlockPlacerHelper.placeBlock(player, tempBlockEntry); + } else { + success = false; + //Not having the item at this point would be a bit weird, so we notify the player + EffortlessBuilding.log(player, ChatFormatting.RED + tempBlockEntry.item.toString() + " not found in inventory."); + } } isPlacingOrBreakingBlocks = false; @@ -156,16 +185,6 @@ public class ServerBlockPlacer { return true; } - private boolean isAllowedToUndo(Player player, boolean log) { - - if (!player.isCreative()) { - if (log) EffortlessBuilding.log(player, ChatFormatting.RED + "Undo is not available in survival mode."); - return false; - } - - return true; - } - private boolean validateBlockSet(Player player, BlockSet blocks) { if (blocks.isEmpty()) { diff --git a/src/main/java/nl/requios/effortlessbuilding/systems/ServerBuildState.java b/src/main/java/nl/requios/effortlessbuilding/systems/ServerBuildState.java index 1bd2b88..fd71db2 100644 --- a/src/main/java/nl/requios/effortlessbuilding/systems/ServerBuildState.java +++ b/src/main/java/nl/requios/effortlessbuilding/systems/ServerBuildState.java @@ -25,6 +25,7 @@ public class ServerBuildState { } public static boolean isQuickReplacing(Player player) { + if (!PowerLevel.canReplaceBlocks(player)) return false; return player.getPersistentData().contains(IS_QUICK_REPLACING_KEY); } diff --git a/src/main/java/nl/requios/effortlessbuilding/systems/UndoRedo.java b/src/main/java/nl/requios/effortlessbuilding/systems/UndoRedo.java index 1bba987..604e38b 100644 --- a/src/main/java/nl/requios/effortlessbuilding/systems/UndoRedo.java +++ b/src/main/java/nl/requios/effortlessbuilding/systems/UndoRedo.java @@ -30,10 +30,7 @@ public class UndoRedo { public final Map> undoStacks = new HashMap<>(); public final Map> redoStacks = new HashMap<>(); - private boolean isAllowedToUndo(Player player) { - if (!player.isCreative()) { - return false; - } + public boolean isAllowedToUndo(Player player) { return true; } diff --git a/src/main/java/nl/requios/effortlessbuilding/utilities/BlockEntry.java b/src/main/java/nl/requios/effortlessbuilding/utilities/BlockEntry.java index c69d628..1cb70d5 100644 --- a/src/main/java/nl/requios/effortlessbuilding/utilities/BlockEntry.java +++ b/src/main/java/nl/requios/effortlessbuilding/utilities/BlockEntry.java @@ -31,6 +31,12 @@ public class BlockEntry { this.blockPos = blockPos; } + public BlockEntry(BlockPos blockPos, BlockState blockState, Item item) { + this.blockPos = blockPos; + this.newBlockState = blockState; + this.item = item; + } + public void copyRotationSettingsFrom(BlockEntry blockEntry) { mirrorX = blockEntry.mirrorX; mirrorY = blockEntry.mirrorY; diff --git a/src/main/java/nl/requios/effortlessbuilding/utilities/BlockUtilities.java b/src/main/java/nl/requios/effortlessbuilding/utilities/BlockUtilities.java index 1827a7c..addf8bc 100644 --- a/src/main/java/nl/requios/effortlessbuilding/utilities/BlockUtilities.java +++ b/src/main/java/nl/requios/effortlessbuilding/utilities/BlockUtilities.java @@ -1,35 +1,23 @@ package nl.requios.effortlessbuilding.utilities; -import com.google.common.collect.Lists; import net.minecraft.client.Minecraft; import net.minecraft.core.Direction; -import net.minecraft.core.Registry; -import net.minecraft.nbt.CompoundTag; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundSource; -import net.minecraft.stats.Stats; import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.BucketItem; -import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.pattern.BlockInWorld; import net.minecraft.world.level.block.state.properties.Half; import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.util.BlockSnapshot; -import net.minecraftforge.event.ForgeEventFactory; -import nl.requios.effortlessbuilding.create.foundation.utility.BlockHelper; - -import java.util.List; //Common public class BlockUtilities { diff --git a/src/main/java/nl/requios/effortlessbuilding/utilities/InventoryHelper.java b/src/main/java/nl/requios/effortlessbuilding/utilities/InventoryHelper.java index f6fff27..debf471 100644 --- a/src/main/java/nl/requios/effortlessbuilding/utilities/InventoryHelper.java +++ b/src/main/java/nl/requios/effortlessbuilding/utilities/InventoryHelper.java @@ -5,6 +5,9 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.ItemStack; +import nl.requios.effortlessbuilding.EffortlessBuilding; + +import java.util.Map; public class InventoryHelper { @@ -39,4 +42,53 @@ public class InventoryHelper { } return total; } + + public static void removeFromInventory(Player player, Map items) { + for (Item item : items.keySet()) { + int count = items.get(item); + removeFromInventory(player, item, count); + } + } + + public static void removeFromInventory(Player player, Item item, int amount) { + if (player.isCreative()) return; + + //From BlockHelper.findAndRemoveInInventory + int amountFound = 0; + + { + // Try held Item first + int preferredSlot = player.getInventory().selected; + ItemStack itemstack = player.getInventory() + .getItem(preferredSlot); + int count = itemstack.getCount(); + if (itemstack.getItem() == item && count > 0) { + int taken = Math.min(count, amount - amountFound); + player.getInventory() + .setItem(preferredSlot, new ItemStack(itemstack.getItem(), count - taken)); + amountFound += taken; + } + } + + // Search inventory + for (int i = 0; i < player.getInventory() + .getContainerSize(); ++i) { + if (amountFound == amount) + break; + + ItemStack itemstack = player.getInventory() + .getItem(i); + int count = itemstack.getCount(); + if (itemstack.getItem() == item && count > 0) { + int taken = Math.min(count, amount - amountFound); + player.getInventory() + .setItem(i, new ItemStack(itemstack.getItem(), count - taken)); + amountFound += taken; + } + } + + if (amountFound != amount) { + EffortlessBuilding.logError(player.getDisplayName().getString() + " tried to remove " + amount + " " + item + " from inventory but only removed " + amountFound); + } + } } diff --git a/src/main/java/nl/requios/effortlessbuilding/utilities/SurvivalHelper.java b/src/main/java/nl/requios/effortlessbuilding/utilities/SurvivalHelper.java index 7e74ef5..ce9332e 100644 --- a/src/main/java/nl/requios/effortlessbuilding/utilities/SurvivalHelper.java +++ b/src/main/java/nl/requios/effortlessbuilding/utilities/SurvivalHelper.java @@ -30,258 +30,9 @@ import javax.annotation.Nullable; public class SurvivalHelper { - //Used for all placing of blocks in this mod. - //Checks if area is loaded, if player has the right permissions, if existing block can be replaced (drops it if so) and consumes an item from the stack. - //Based on ItemBlock#onItemUse - public static boolean placeBlock(Level world, Player player, BlockPos pos, BlockState blockState, - ItemStack origstack, boolean skipPlaceCheck, - boolean skipCollisionCheck, boolean playSound) { - if (!world.isLoaded(pos)) return false; - ItemStack itemstack = origstack; - - if (blockState.isAir() || itemstack.isEmpty()) { - dropBlock(world, player, pos); - world.removeBlock(pos, false); - return true; - } - - //Randomizer bag, other proxy item synergy - //Preliminary compatibility code for other items that hold blocks - if (CompatHelper.isItemBlockProxy(itemstack)) - itemstack = CompatHelper.getItemBlockByState(itemstack, blockState); - - if (!(itemstack.getItem() instanceof BlockItem)) - return false; - Block block = ((BlockItem) itemstack.getItem()).getBlock(); - - - //More manual with ItemBlock#placeBlockAt - if (skipPlaceCheck || canPlace(world, player, pos, blockState, itemstack, skipCollisionCheck)) { - //Drop existing block - dropBlock(world, player, pos); - - //TryPlace sets block with offset and reduces itemstack count in creative, so we copy only parts of it -// BlockItemUseContext blockItemUseContext = new BlockItemUseContext(world, player, itemstack, pos, facing, (float) hitVec.x, (float) hitVec.y, (float) hitVec.z); -// EnumActionResult result = ((ItemBlock) itemstack.getItem()).tryPlace(blockItemUseContext); - if (!world.setBlock(pos, blockState, 3)) return false; - BlockItem.updateCustomBlockEntityTag(world, player, pos, itemstack); //Actually BlockItem::onBlockPlaced but that is protected - block.setPlacedBy(world, pos, blockState, player, itemstack); - if (player instanceof ServerPlayer) { - CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer) player, pos, itemstack); - } - - BlockState afterState = world.getBlockState(pos); - - if (playSound) { - SoundType soundtype = afterState.getBlock().getSoundType(afterState, world, pos, player); - world.playSound(null, pos, soundtype.getPlaceSound(), SoundSource.BLOCKS, (soundtype.getVolume() + 1.0F) / 2.0F, soundtype.getPitch() * 0.8F); - } - - if (!player.isCreative() && Block.byItem(itemstack.getItem()) == block) { - itemstack.shrink(1); - } - - return true; - } - return false; - - //Using ItemBlock#onItemUse -// EnumActionResult result; -// PlayerInteractEvent.RightClickBlock event = ForgeHooks.onRightClickBlock(player, EnumHand.MAIN_HAND, pos, facing, net.minecraftforge.common.ForgeHooks.rayTraceEyeHitVec(player, ReachHelper.getPlacementReach(player))); -// if (player.isCreative()) -// { -// int i = itemstack.getMetadata(); -// int j = itemstack.getCount(); -// if (event.getUseItem() != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY) { -// EnumActionResult enumactionresult = itemstack.getItem().onItemUse(player, world, pos, EnumHand.MAIN_HAND, facing, (float) hitVec.x, (float) hitVec.y, (float) hitVec.z); -// itemstack.setItemDamage(i); -// itemstack.setCount(j); -// return enumactionresult == EnumActionResult.SUCCESS; -// } else return false; -// } -// else -// { -// ItemStack copyForUse = itemstack.copy(); -// if (event.getUseItem() != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY) -// result = itemstack.getItem().onItemUse(player, world, pos, EnumHand.MAIN_HAND, facing, (float) hitVec.x, (float) hitVec.y, (float) hitVec.z); -// if (itemstack.isEmpty()) net.minecraftforge.event.ForgeEventFactory.onPlayerDestroyItem(player, copyForUse, EnumHand.MAIN_HAND); -// return false; -// } - - } - - //Used for all breaking of blocks in this mod. - //Checks if area is loaded, if appropriate tool is used in survival mode, and drops the block directly into the players inventory - public static boolean breakBlock(Level world, Player player, BlockPos pos, boolean skipChecks) { - if (!world.isLoaded(pos) && !world.isEmptyBlock(pos)) return false; - - //Check if can break - if (skipChecks || canBreak(world, player, pos)) { -// player.addStat(StatList.getBlockStats(world.getNewBlockState(pos).getBlock())); -// player.addExhaustion(0.005F); - - //Drop existing block - dropBlock(world, player, pos); - - //Damage tool - player.getMainHandItem().mineBlock(world, world.getBlockState(pos), pos, player); - - world.removeBlock(pos, false); - return true; - } - return false; - } - - //Gives items directly to player - public static void dropBlock(Level world, Player player, BlockPos pos) { - if (player.isCreative()) return; - - BlockState blockState = world.getBlockState(pos); - Block block = blockState.getBlock(); - - block.playerDestroy(world, player, pos, blockState, world.getBlockEntity(pos), player.getMainHandItem()); - - //TODO drop items in inventory instead of world - -// List drops = new ArrayList<>(); -// -// //From Block#harvestBlock -// int silktouch = EnchantmentHelper.getEnchantmentLevel(Enchantments.SILK_TOUCH, player.getHeldItemMainhand()); -// if (block.canSilkHarvest(world, pos, blockState, player) && silktouch > 0) { -// -// //From Block#getSilkTouchDrop (protected) -// Item item = Item.getItemFromBlock(block); -// int i = 0; -// -// if (item.getHasSubtypes()) -// { -// i = block.getMetaFromState(blockState); -// } -// -// drops.add(new ItemStack(item, 1, i)); -// -// net.minecraftforge.event.ForgeEventFactory.fireBlockHarvesting(drops, world, pos, blockState, 0, 1.0f, true, player); -// } -// -// int fortune = EnchantmentHelper.getEnchantmentLevel(Enchantments.FORTUNE, player.getHeldItemMainhand()); -// drops.addAll(block.getDrops(world, pos, blockState, fortune)); -// for (ItemStack drop : drops) -// { -// ItemHandlerHelper.giveItemToPlayer(player, drop); -// } - } - - /** - * Check if player can place a block. - * Turn randomizer bag into itemstack inside before. - * - * @param world - * @param player - * @param pos - * @param newBlockState the blockstate that is going to be placed - * @param itemStack the itemstack used for placing - * @param skipCollisionCheck skips collision check with entities - * @return Whether the player may place the block at pos with itemstack - */ - public static boolean canPlace(Level world, Player player, BlockPos pos, BlockState newBlockState, ItemStack itemStack, boolean skipCollisionCheck) { - - if (!player.isCreative()) { - //Check if itemstack is correct - if (itemStack.isEmpty() || !(itemStack.getItem() instanceof BlockItem) || - Block.byItem(itemStack.getItem()) != newBlockState.getBlock()) { - return false; - } - } - - Block block = null; - if (itemStack != null && !itemStack.isEmpty() && itemStack.getItem() instanceof BlockItem) - block = ((BlockItem) itemStack.getItem()).getBlock(); - else //In creative we might not have an itemstack - block = newBlockState.getBlock(); - - return canPlayerEdit(player, world, pos, itemStack) && - mayPlace(world, block, newBlockState, pos, skipCollisionCheck, player) && - canReplace(world, player, pos); - } - - //Can be harvested with hand? (or in creative) - private static boolean canReplace(Level world, Player player, BlockPos pos) { - if (player.isCreative()) return true; - - BlockState state = world.getBlockState(pos); - - int miningLevel = CommonConfig.survivalBalancers.quickReplaceMiningLevel.get(); - switch (miningLevel) { - case -1: - return !state.requiresCorrectToolForDrops(); - case 0: - return !state.is(BlockTags.NEEDS_STONE_TOOL) && - !state.is(BlockTags.NEEDS_IRON_TOOL) && - !state.is(BlockTags.NEEDS_DIAMOND_TOOL); - case 1: - return !state.is(BlockTags.NEEDS_IRON_TOOL) && - !state.is(BlockTags.NEEDS_DIAMOND_TOOL); - case 2: - return !state.is(BlockTags.NEEDS_DIAMOND_TOOL); - case 3: - case 4: - return true; - } - - return false; - } - - //From Player#mayUseItemAt - private static boolean canPlayerEdit(Player player, Level world, BlockPos pos, ItemStack stack) { - if (!world.mayInteract(player, pos)) return false; - - if (player.getAbilities().mayBuild) { - //True in creative and survival mode - return true; - } else { - //Adventure mode - BlockInWorld blockinworld = new BlockInWorld(world, pos, false); - return stack.hasAdventureModePlaceTagForBlock(world.registryAccess().registryOrThrow(Registry.BLOCK_REGISTRY), blockinworld); - } - } - - //From World#mayPlace - private static boolean mayPlace(Level world, Block blockIn, BlockState newBlockState, BlockPos pos, boolean skipCollisionCheck, @Nullable Entity placer) { - BlockState currentBlockState = world.getBlockState(pos); - VoxelShape voxelShape = skipCollisionCheck ? null : blockIn.defaultBlockState().getCollisionShape(world, pos); - - if (voxelShape != null && !world.isUnobstructed(placer, voxelShape)) { - return false; - } - - //Check if double slab - if (placer != null && doesBecomeDoubleSlab(((Player) placer), pos)) { - return true; - } - - //Check if same block - //Necessary otherwise extra items will be dropped - if (currentBlockState == newBlockState) { - return false; - } - - if (currentBlockState.getMaterial() == Material.BUILDABLE_GLASS && blockIn == Blocks.ANVIL) { - return true; - } - - //Check quickreplace - if (placer instanceof Player player) { - boolean isQuickReplacing = world.isClientSide ? EffortlessBuildingClient.BUILD_SETTINGS.isQuickReplacing() - : ServerBuildState.isQuickReplacing(player); - if (isQuickReplacing) return true; - } - - return currentBlockState.getMaterial().isReplaceable() /*&& canPlaceBlockOnSide(world, pos, sidePlacedOn)*/; - } - - //Can break using held tool? (or in creative) public static boolean canBreak(Level world, Player player, BlockPos pos) { + BlockState blockState = world.getBlockState(pos); if (!world.getFluidState(pos).isEmpty()) return false; @@ -291,6 +42,7 @@ public class SurvivalHelper { } public static boolean doesBecomeDoubleSlab(Player player, BlockPos pos) { + BlockState placedBlockState = player.level.getBlockState(pos); ItemStack itemstack = player.getItemInHand(InteractionHand.MAIN_HAND); diff --git a/src/main/resources/assets/effortlessbuilding/lang/en_us.json b/src/main/resources/assets/effortlessbuilding/lang/en_us.json index 4da0f70..9f34dc2 100644 --- a/src/main/resources/assets/effortlessbuilding/lang/en_us.json +++ b/src/main/resources/assets/effortlessbuilding/lang/en_us.json @@ -10,6 +10,8 @@ "key.effortlessbuilding.undo.desc": "Undo", "key.effortlessbuilding.redo.desc": "Redo", "key.effortlessbuilding.altplacement.desc": "Alternative placement", + "key.effortlessbuilding.previous_build_mode.desc": "Activate Previous Build Mode", + "key.effortlessbuilding.disable_build_mode_toggle.desc": "Toggle Disabled <> Previous Build Mode", "item.effortlessbuilding.randomizer_bag": "Leather Randomizer Bag", "item.effortlessbuilding.golden_randomizer_bag": "Golden Randomizer Bag",