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",