diff --git a/src/main/java/nl/requios/effortlessbuilding/ClientEvents.java b/src/main/java/nl/requios/effortlessbuilding/ClientEvents.java index 4e0714c..bc3749a 100644 --- a/src/main/java/nl/requios/effortlessbuilding/ClientEvents.java +++ b/src/main/java/nl/requios/effortlessbuilding/ClientEvents.java @@ -25,13 +25,14 @@ import net.minecraftforge.client.settings.KeyModifier; import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; -import nl.requios.effortlessbuilding.buildmode.BuildModes; +import nl.requios.effortlessbuilding.buildmode.BuildModeEnum; import nl.requios.effortlessbuilding.buildmode.ModeOptions; -import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.gui.buildmode.PlayerSettingsGui; import nl.requios.effortlessbuilding.gui.buildmode.RadialMenu; import nl.requios.effortlessbuilding.gui.buildmodifier.ModifierSettingsGui; +import nl.requios.effortlessbuilding.render.BlockPreviews; +import nl.requios.effortlessbuilding.render.RenderHandler; import nl.requios.effortlessbuilding.utilities.ReachHelper; import nl.requios.effortlessbuilding.network.*; import nl.requios.effortlessbuilding.render.BuildRenderTypes; @@ -43,8 +44,6 @@ import java.io.IOException; public class ClientEvents { public static KeyMapping[] keyBindings; - public static HitResult previousLookAt; - public static HitResult currentLookAt; public static int ticksInGame = 0; private static int placeCooldown = 0; private static int breakCooldown = 0; @@ -92,28 +91,8 @@ public class ClientEvents { onMouseInput(); - //Update previousLookAt - HitResult objectMouseOver = Minecraft.getInstance().hitResult; - //Checking for null is necessary! Even in vanilla when looking down ladders it is occasionally null (instead of Type MISS) - if (objectMouseOver == null) return; + EffortlessBuildingClient.BLOCK_PREVIEWS.onTick(); - if (currentLookAt == null) { - currentLookAt = objectMouseOver; - previousLookAt = objectMouseOver; - return; - } - - if (objectMouseOver.getType() == HitResult.Type.BLOCK) { - if (currentLookAt.getType() != HitResult.Type.BLOCK) { - currentLookAt = objectMouseOver; - previousLookAt = objectMouseOver; - } else { - if (((BlockHitResult) currentLookAt).getBlockPos() != ((BlockHitResult) objectMouseOver).getBlockPos()) { - previousLookAt = currentLookAt; - currentLookAt = objectMouseOver; - } - } - } } else if (event.phase == TickEvent.Phase.END) { Screen gui = Minecraft.getInstance().screen; if (gui == null || !gui.isPauseScreen()) { @@ -127,10 +106,10 @@ public class ClientEvents { Minecraft mc = Minecraft.getInstance(); LocalPlayer player = mc.player; if (player == null) return; - BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode(); + BuildModeEnum buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode(); if (mc.screen != null || - buildMode == BuildModes.BuildModeEnum.DISABLED || + buildMode == BuildModeEnum.DISABLED || RadialMenu.instance.isVisible()) { return; } @@ -142,7 +121,7 @@ public class ClientEvents { EffortlessBuildingClient.BUILDER_CHAIN.onRightClick(); - } else if (buildMode == BuildModes.BuildModeEnum.SINGLE) { + } else if (buildMode == BuildModeEnum.SINGLE) { placeCooldown--; if (ModeOptions.getBuildSpeed() == ModeOptions.ActionEnum.FAST_SPEED) placeCooldown = 0; } @@ -158,7 +137,7 @@ public class ClientEvents { EffortlessBuildingClient.BUILDER_CHAIN.onLeftClick(); - } else if (buildMode == BuildModes.BuildModeEnum.SINGLE) { + } else if (buildMode == BuildModeEnum.SINGLE) { breakCooldown--; if (ModeOptions.getBuildSpeed() == ModeOptions.ActionEnum.FAST_SPEED) breakCooldown = 0; } @@ -182,11 +161,7 @@ public class ClientEvents { //QuickReplace toggle if (keyBindings[1].consumeClick()) { - ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); - modifierSettings.setQuickReplace(!modifierSettings.doQuickReplace()); - EffortlessBuilding.log(player, "Set " + ChatFormatting.GOLD + "Quick Replace " + ChatFormatting.RESET + ( - modifierSettings.doQuickReplace() ? "on" : "off")); - PacketHandler.INSTANCE.sendToServer(new ModifierSettingsMessage(modifierSettings)); + EffortlessBuildingClient.QUICK_REPLACE.toggleQuickReplacing(); } //Radial menu @@ -217,7 +192,7 @@ public class ClientEvents { //Change placement mode if (keyBindings[5].consumeClick()) { //Toggle between first two actions of the first option of the current build mode - BuildModes.BuildModeEnum currentBuildMode = ModeSettingsManager.getModeSettings(player).getBuildMode(); + BuildModeEnum currentBuildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode(); if (currentBuildMode.options.length > 0) { ModeOptions.OptionEnum option = currentBuildMode.options[0]; if (option.actions.length >= 2) { diff --git a/src/main/java/nl/requios/effortlessbuilding/CommonEvents.java b/src/main/java/nl/requios/effortlessbuilding/CommonEvents.java index 78114b9..19c0261 100644 --- a/src/main/java/nl/requios/effortlessbuilding/CommonEvents.java +++ b/src/main/java/nl/requios/effortlessbuilding/CommonEvents.java @@ -17,11 +17,9 @@ import net.minecraftforge.event.level.BlockEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.network.PacketDistributor; -import nl.requios.effortlessbuilding.buildmode.BuildModes; -import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; +import nl.requios.effortlessbuilding.buildmode.BuildModeEnum; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.UndoRedo; -import nl.requios.effortlessbuilding.capability.ModeCapabilityManager; import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager; import nl.requios.effortlessbuilding.compatibility.CompatHelper; import nl.requios.effortlessbuilding.utilities.ReachHelper; @@ -39,7 +37,6 @@ public class CommonEvents { @SubscribeEvent public void registerCapabilities(RegisterCapabilitiesEvent event){ event.register(ModifierCapabilityManager.IModifierCapability.class); - event.register(ModeCapabilityManager.IModeCapability.class); } } @@ -48,7 +45,6 @@ public class CommonEvents { if (event.getObject() instanceof FakePlayer) return; if (event.getObject() instanceof Player) { event.addCapability(new ResourceLocation(EffortlessBuilding.MODID, "build_modifier"), new ModifierCapabilityManager.Provider()); - event.addCapability(new ResourceLocation(EffortlessBuilding.MODID, "build_mode"), new ModeCapabilityManager.Provider()); } } @@ -66,10 +62,12 @@ public class CommonEvents { if (!(event.getEntity() instanceof Player player)) return; if (event.getEntity() instanceof FakePlayer) return; - BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode(); - ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); + //Don't cancel event if our custom logic is breaking blocks + if (EffortlessBuilding.SERVER_BLOCK_PLACER.isPlacingOrBreakingBlocks()) return; - if (buildMode != BuildModes.BuildModeEnum.DISABLED || modifierSettings.doQuickReplace()) { + BuildModeEnum buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode(); + + if (buildMode != BuildModeEnum.DISABLED || EffortlessBuildingClient.QUICK_REPLACE.isQuickReplacing()) { //Only cancel if itemblock in hand //Fixed issue with e.g. Create Wrench shift-rightclick disassembling being cancelled. @@ -91,15 +89,19 @@ public class CommonEvents { Player player = event.getPlayer(); if (player instanceof FakePlayer) return; + //Don't cancel event if our custom logic is breaking blocks + if (EffortlessBuilding.SERVER_BLOCK_PLACER.isPlacingOrBreakingBlocks()) return; + //Cancel event if necessary //If cant break far then dont cancel event ever - BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode(); - if (buildMode != BuildModes.BuildModeEnum.DISABLED && ReachHelper.canBreakFar(player)) { + BuildModeEnum buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode(); + if (buildMode != BuildModeEnum.DISABLED && ReachHelper.canBreakFar(player)) { event.setCanceled(true); } else { //NORMAL mode, let vanilla handle block breaking //Add to undo stack in client + //TODO move UndoRedo to serverside only if (player instanceof ServerPlayer && event.getState() != null && event.getPos() != null) { PacketDistributor.PacketTarget packetTarget = PacketDistributor.PLAYER.with(() -> (ServerPlayer) player); if (packetTarget != null) @@ -119,7 +121,6 @@ public class CommonEvents { if (event.getEntity() instanceof FakePlayer) return; Player player = event.getEntity(); ModifierSettingsManager.handleNewPlayer(player); - ModeSettingsManager.handleNewPlayer(player); } @SubscribeEvent @@ -137,7 +138,6 @@ public class CommonEvents { if (event.getEntity() instanceof FakePlayer) return; Player player = event.getEntity(); ModifierSettingsManager.handleNewPlayer(player); - ModeSettingsManager.handleNewPlayer(player); } @SubscribeEvent @@ -146,11 +146,6 @@ public class CommonEvents { Player player = event.getEntity(); if (player.getCommandSenderWorld().isClientSide) return; - //Set build mode to normal - ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); - modeSettings.setBuildMode(BuildModes.BuildModeEnum.DISABLED); - ModeSettingsManager.setModeSettings(player, modeSettings); - //Disable modifiers ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); modifierSettings.getMirrorSettings().enabled = false; @@ -159,7 +154,6 @@ public class CommonEvents { ModifierSettingsManager.setModifierSettings(player, modifierSettings); ModifierSettingsManager.handleNewPlayer(player); - ModeSettingsManager.handleNewPlayer(player); UndoRedo.clear(player); PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new ClearUndoMessage()); @@ -174,7 +168,6 @@ public class CommonEvents { Player newPlayer = event.getEntity(); ModifierSettingsManager.setModifierSettings(newPlayer, ModifierSettingsManager.getModifierSettings(oldPlayer)); - ModeSettingsManager.setModeSettings(newPlayer, ModeSettingsManager.getModeSettings(oldPlayer)); } diff --git a/src/main/java/nl/requios/effortlessbuilding/EffortlessBuilding.java b/src/main/java/nl/requios/effortlessbuilding/EffortlessBuilding.java index 00c11ea..0bc7b3c 100644 --- a/src/main/java/nl/requios/effortlessbuilding/EffortlessBuilding.java +++ b/src/main/java/nl/requios/effortlessbuilding/EffortlessBuilding.java @@ -39,7 +39,7 @@ public class EffortlessBuilding { public static final Logger logger = LogManager.getLogger(); public static EffortlessBuilding instance; - public static IProxy proxy = DistExecutor.safeRunForDist(() -> ClientProxy::new, () -> ServerProxy::new); + public static IProxy proxy = DistExecutor.unsafeRunForDist(() -> ClientProxy::new, () -> ServerProxy::new); public static final ServerBlockPlacer SERVER_BLOCK_PLACER = new ServerBlockPlacer(); public static final DelayedBlockPlacer DELAYED_BLOCK_PLACER = new DelayedBlockPlacer(); diff --git a/src/main/java/nl/requios/effortlessbuilding/EffortlessBuildingClient.java b/src/main/java/nl/requios/effortlessbuilding/EffortlessBuildingClient.java index c820199..91b6b47 100644 --- a/src/main/java/nl/requios/effortlessbuilding/EffortlessBuildingClient.java +++ b/src/main/java/nl/requios/effortlessbuilding/EffortlessBuildingClient.java @@ -8,13 +8,17 @@ import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; import nl.requios.effortlessbuilding.gui.DiamondRandomizerBagScreen; import nl.requios.effortlessbuilding.gui.GoldenRandomizerBagScreen; import nl.requios.effortlessbuilding.gui.RandomizerBagScreen; +import nl.requios.effortlessbuilding.render.BlockPreviews; import nl.requios.effortlessbuilding.systems.BuilderChain; +import nl.requios.effortlessbuilding.systems.QuickReplace; public class EffortlessBuildingClient { public static final BuilderChain BUILDER_CHAIN = new BuilderChain(); public static final BuildModes BUILD_MODES = new BuildModes(); public static final BuildModifiers BUILD_MODIFIERS = new BuildModifiers(); + public static final QuickReplace QUICK_REPLACE = new QuickReplace(); + public static final BlockPreviews BLOCK_PREVIEWS = new BlockPreviews(); public static void onConstructorClient(IEventBus modEventBus, IEventBus forgeEventBus) { modEventBus.addListener(EffortlessBuildingClient::clientSetup); diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModeCategoryEnum.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModeCategoryEnum.java new file mode 100644 index 0000000..f94a55f --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModeCategoryEnum.java @@ -0,0 +1,16 @@ +package nl.requios.effortlessbuilding.buildmode; + +import com.mojang.math.Vector4f; + +public enum BuildModeCategoryEnum { + BASIC(new Vector4f(0f, .5f, 1f, .8f)), + DIAGONAL(new Vector4f(0.56f, 0.28f, 0.87f, .8f)), + CIRCULAR(new Vector4f(0.29f, 0.76f, 0.3f, 1f)), + ROOF(new Vector4f(0.83f, 0.87f, 0.23f, .8f)); + + public final Vector4f color; + + BuildModeCategoryEnum(Vector4f color) { + this.color = color; + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModeEnum.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModeEnum.java new file mode 100644 index 0000000..859f31a --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModeEnum.java @@ -0,0 +1,42 @@ +package nl.requios.effortlessbuilding.buildmode; + +import nl.requios.effortlessbuilding.buildmode.buildmodes.*; + +public enum BuildModeEnum { + DISABLED("normal", new Disabled(), BuildModeCategoryEnum.BASIC), + SINGLE("normal_plus", new Single(), BuildModeCategoryEnum.BASIC, ModeOptions.OptionEnum.BUILD_SPEED), + LINE("line", new Line(), BuildModeCategoryEnum.BASIC /*, OptionEnum.THICKNESS*/), + WALL("wall", new Wall(), BuildModeCategoryEnum.BASIC, ModeOptions.OptionEnum.FILL), + FLOOR("floor", new Floor(), BuildModeCategoryEnum.BASIC, ModeOptions.OptionEnum.FILL), + CUBE("cube", new Cube(), BuildModeCategoryEnum.BASIC, ModeOptions.OptionEnum.CUBE_FILL), + DIAGONAL_LINE("diagonal_line", new DiagonalLine(), BuildModeCategoryEnum.DIAGONAL /*, OptionEnum.THICKNESS*/), + DIAGONAL_WALL("diagonal_wall", new DiagonalWall(), BuildModeCategoryEnum.DIAGONAL /*, OptionEnum.FILL*/), + SLOPE_FLOOR("slope_floor", new SlopeFloor(), BuildModeCategoryEnum.DIAGONAL, ModeOptions.OptionEnum.RAISED_EDGE), + CIRCLE("circle", new Circle(), BuildModeCategoryEnum.CIRCULAR, ModeOptions.OptionEnum.CIRCLE_START, ModeOptions.OptionEnum.FILL), + CYLINDER("cylinder", new Cylinder(), BuildModeCategoryEnum.CIRCULAR, ModeOptions.OptionEnum.CIRCLE_START, ModeOptions.OptionEnum.FILL), + SPHERE("sphere", new Sphere(), BuildModeCategoryEnum.CIRCULAR, ModeOptions.OptionEnum.CIRCLE_START, ModeOptions.OptionEnum.FILL); +// PYRAMID("pyramid", new Pyramid(), BuildModeCategoryEnum.ROOF), +// CONE("cone", new Cone(), BuildModeCategoryEnum.ROOF), +// DOME("dome", new Dome(), BuildModeCategoryEnum.ROOF); + + private final String name; + public final IBuildMode instance; + public final BuildModeCategoryEnum category; + public final ModeOptions.OptionEnum[] options; + + BuildModeEnum(String name, IBuildMode instance, BuildModeCategoryEnum category, ModeOptions.OptionEnum... options) { + this.name = name; + this.instance = instance; + this.category = category; + this.options = options; + } + + public String getNameKey() { + return "effortlessbuilding.mode." + name; + } + + public String getDescriptionKey() { + return "effortlessbuilding.modedescription." + name; + } + +} diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java index cb1bd90..4065451 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java @@ -1,23 +1,21 @@ package nl.requios.effortlessbuilding.buildmode; -import com.mojang.math.Vector4f; import net.minecraft.world.entity.player.Player; -import net.minecraft.core.BlockPos; 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.buildmode.buildmodes.*; +import nl.requios.effortlessbuilding.network.IsUsingBuildModePacket; +import nl.requios.effortlessbuilding.network.PacketHandler; import nl.requios.effortlessbuilding.utilities.BlockEntry; import nl.requios.effortlessbuilding.utilities.ReachHelper; import java.util.*; -import static nl.requios.effortlessbuilding.buildmode.ModeOptions.OptionEnum; - @OnlyIn(Dist.CLIENT) public class BuildModes { + private BuildModeEnum buildMode = BuildModeEnum.DISABLED; public void findCoordinates(List blocks, Player player, BuildModeEnum buildMode) { buildMode.instance.findCoordinates(blocks); @@ -29,12 +27,18 @@ public class BuildModes { } } - public BuildModeEnum getBuildMode(Player player) { - return ModeSettingsManager.getModeSettings(player).getBuildMode(); + public BuildModeEnum getBuildMode() { + return buildMode; } - public void onCancel(Player player) { - getBuildMode(player).instance.initialize(); + public void setBuildMode(BuildModeEnum buildMode) { + this.buildMode = buildMode; + + PacketHandler.INSTANCE.sendToServer(new IsUsingBuildModePacket(this.buildMode != BuildModeEnum.DISABLED)); + } + + public void onCancel() { + getBuildMode().instance.initialize(); } //Find coordinates on a line bound by a plane @@ -102,54 +106,4 @@ public class BuildModes { !intersects; } - public enum BuildModeEnum { - DISABLED("normal", new Disabled(), BuildModeCategoryEnum.BASIC), - SINGLE("normal_plus", new Single(), BuildModeCategoryEnum.BASIC, OptionEnum.BUILD_SPEED), - LINE("line", new Line(), BuildModeCategoryEnum.BASIC /*, OptionEnum.THICKNESS*/), - WALL("wall", new Wall(), BuildModeCategoryEnum.BASIC, OptionEnum.FILL), - FLOOR("floor", new Floor(), BuildModeCategoryEnum.BASIC, OptionEnum.FILL), - CUBE("cube", new Cube(), BuildModeCategoryEnum.BASIC, OptionEnum.CUBE_FILL), - DIAGONAL_LINE("diagonal_line", new DiagonalLine(), BuildModeCategoryEnum.DIAGONAL /*, OptionEnum.THICKNESS*/), - DIAGONAL_WALL("diagonal_wall", new DiagonalWall(), BuildModeCategoryEnum.DIAGONAL /*, OptionEnum.FILL*/), - SLOPE_FLOOR("slope_floor", new SlopeFloor(), BuildModeCategoryEnum.DIAGONAL, OptionEnum.RAISED_EDGE), - CIRCLE("circle", new Circle(), BuildModeCategoryEnum.CIRCULAR, OptionEnum.CIRCLE_START, OptionEnum.FILL), - CYLINDER("cylinder", new Cylinder(), BuildModeCategoryEnum.CIRCULAR, OptionEnum.CIRCLE_START, OptionEnum.FILL), - SPHERE("sphere", new Sphere(), BuildModeCategoryEnum.CIRCULAR, OptionEnum.CIRCLE_START, OptionEnum.FILL); -// PYRAMID("pyramid", new Pyramid(), BuildModeCategoryEnum.ROOF), -// CONE("cone", new Cone(), BuildModeCategoryEnum.ROOF), -// DOME("dome", new Dome(), BuildModeCategoryEnum.ROOF); - - private final String name; - public final IBuildMode instance; - public final BuildModeCategoryEnum category; - public final OptionEnum[] options; - - BuildModeEnum(String name, IBuildMode instance, BuildModeCategoryEnum category, OptionEnum... options) { - this.name = name; - this.instance = instance; - this.category = category; - this.options = options; - } - - public String getNameKey() { - return "effortlessbuilding.mode." + name; - } - - public String getDescriptionKey() { - return "effortlessbuilding.modedescription." + name; - } - } - - public enum BuildModeCategoryEnum { - BASIC(new Vector4f(0f, .5f, 1f, .8f)), - DIAGONAL(new Vector4f(0.56f, 0.28f, 0.87f, .8f)), - CIRCULAR(new Vector4f(0.29f, 0.76f, 0.3f, 1f)), - ROOF(new Vector4f(0.83f, 0.87f, 0.23f, .8f)); - - public final Vector4f color; - - BuildModeCategoryEnum(Vector4f color) { - this.color = color; - } - } } diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeOptions.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeOptions.java index dc75454..c57abab 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeOptions.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeOptions.java @@ -4,9 +4,9 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.ChatFormatting; import nl.requios.effortlessbuilding.ClientEvents; import nl.requios.effortlessbuilding.EffortlessBuilding; +import nl.requios.effortlessbuilding.EffortlessBuildingClient; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.UndoRedo; -import nl.requios.effortlessbuilding.proxy.ClientProxy; public class ModeOptions { @@ -72,10 +72,8 @@ public class ModeOptions { UndoRedo.redo(player); break; case REPLACE: - ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); - modifierSettings.setQuickReplace(!modifierSettings.doQuickReplace()); - EffortlessBuilding.log(player, "Set " + ChatFormatting.GOLD + "Quick Replace " + ChatFormatting.RESET + ( - modifierSettings.doQuickReplace() ? "on" : "off"), true); + if (player.level.isClientSide) + EffortlessBuildingClient.QUICK_REPLACE.toggleQuickReplacing(); break; case OPEN_MODIFIER_SETTINGS: if (player.level.isClientSide) diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeSettingsManager.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeSettingsManager.java deleted file mode 100644 index 3eb5b86..0000000 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeSettingsManager.java +++ /dev/null @@ -1,96 +0,0 @@ -package nl.requios.effortlessbuilding.buildmode; - -import net.minecraft.world.entity.player.Player; -import net.minecraft.server.level.ServerPlayer; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.network.PacketDistributor; -import nl.requios.effortlessbuilding.EffortlessBuilding; -import nl.requios.effortlessbuilding.EffortlessBuildingClient; -import nl.requios.effortlessbuilding.capability.ModeCapabilityManager; -import nl.requios.effortlessbuilding.utilities.ReachHelper; -import nl.requios.effortlessbuilding.network.ModeSettingsMessage; -import nl.requios.effortlessbuilding.network.PacketHandler; - -import javax.annotation.Nonnull; - -@Mod.EventBusSubscriber -public class ModeSettingsManager { - - //Retrieves the buildsettings of a player through the modeCapability capability - //Never returns null - @Nonnull - public static ModeSettings getModeSettings(Player player) { - LazyOptional modeCapability = - player.getCapability(ModeCapabilityManager.MODE_CAPABILITY, null); - - if (modeCapability.isPresent()) { - ModeCapabilityManager.IModeCapability capability = modeCapability.orElse(null); - if (capability.getModeData() == null){ - capability.setModeData(new ModeSettings()); - } - return capability.getModeData(); - } - - EffortlessBuilding.logger.warn("Player does not have modeCapability: " + player); - //Return dummy settings - return new ModeSettings(); - } - - public static void setModeSettings(Player player, ModeSettings modeSettings) { - if (player == null) { - EffortlessBuilding.log("Cannot set buildmode settings, player is null"); - return; - } - LazyOptional modeCapability = - player.getCapability(ModeCapabilityManager.MODE_CAPABILITY, null); - - modeCapability.ifPresent((capability) -> { - capability.setModeData(modeSettings); - - if (player.level.isClientSide) { - EffortlessBuildingClient.BUILDER_CHAIN.cancel(); - } - }); - - if (!modeCapability.isPresent()) { - EffortlessBuilding.log(player, "Saving buildmode settings failed."); - } - } - - public static String sanitize(ModeSettings modeSettings, Player player) { - String error = ""; - return error; - } - - public static void handleNewPlayer(Player player) { - //Makes sure player has mode settings (if it doesnt it will create it) - getModeSettings(player); - - //Only on server - if (!player.level.isClientSide) { - //Send to client - ModeSettingsMessage msg = new ModeSettingsMessage(getModeSettings(player)); - PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), msg); - } - } - - public static class ModeSettings { - private BuildModes.BuildModeEnum buildMode = BuildModes.BuildModeEnum.DISABLED; - - public ModeSettings() { - } - - public ModeSettings(BuildModes.BuildModeEnum buildMode) { - this.buildMode = buildMode; - } - - public BuildModes.BuildModeEnum getBuildMode() { - return this.buildMode; - } - - public void setBuildMode(BuildModes.BuildModeEnum buildMode) { - this.buildMode = buildMode; - } - } -} diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/ThreeClicksBuildMode.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/ThreeClicksBuildMode.java index 7f923b1..c45bc3c 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/ThreeClicksBuildMode.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/ThreeClicksBuildMode.java @@ -1,15 +1,14 @@ package nl.requios.effortlessbuilding.buildmode; import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.world.entity.player.Player; -import net.minecraft.core.Direction; import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.Vec3; import nl.requios.effortlessbuilding.utilities.BlockEntry; import nl.requios.effortlessbuilding.utilities.ReachHelper; -import java.util.*; +import java.util.ArrayList; +import java.util.List; public abstract class ThreeClicksBuildMode extends BaseBuildMode { protected BlockEntry firstBlockEntry; diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/TwoClicksBuildMode.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/TwoClicksBuildMode.java index eab1c81..4f224f4 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/TwoClicksBuildMode.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/TwoClicksBuildMode.java @@ -1,18 +1,12 @@ package nl.requios.effortlessbuilding.buildmode; import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.world.entity.player.Player; -import net.minecraft.core.Direction; import net.minecraft.core.BlockPos; -import net.minecraft.world.phys.Vec3; +import net.minecraft.world.entity.player.Player; import nl.requios.effortlessbuilding.utilities.BlockEntry; import nl.requios.effortlessbuilding.utilities.ReachHelper; -import java.util.ArrayList; -import java.util.Dictionary; import java.util.List; -import java.util.UUID; public abstract class TwoClicksBuildMode extends BaseBuildMode { diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/buildmodes/Disabled.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/buildmodes/Disabled.java index 70cfbc0..bdfca9d 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/buildmodes/Disabled.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/buildmodes/Disabled.java @@ -1,13 +1,8 @@ package nl.requios.effortlessbuilding.buildmode.buildmodes; -import net.minecraft.world.entity.player.Player; -import net.minecraft.core.Direction; -import net.minecraft.core.BlockPos; -import net.minecraft.world.phys.Vec3; import nl.requios.effortlessbuilding.buildmode.IBuildMode; import nl.requios.effortlessbuilding.utilities.BlockEntry; -import java.util.ArrayList; import java.util.List; public class Disabled implements IBuildMode { diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/buildmodes/Single.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/buildmodes/Single.java index 7752bf1..d6ec7d9 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/buildmodes/Single.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/buildmodes/Single.java @@ -1,13 +1,8 @@ package nl.requios.effortlessbuilding.buildmode.buildmodes; -import net.minecraft.world.entity.player.Player; -import net.minecraft.core.Direction; -import net.minecraft.core.BlockPos; -import net.minecraft.world.phys.Vec3; import nl.requios.effortlessbuilding.buildmode.IBuildMode; import nl.requios.effortlessbuilding.utilities.BlockEntry; -import java.util.ArrayList; import java.util.List; public class Single implements IBuildMode { diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BuildModifiers.java b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BuildModifiers.java index 9fbc08b..61ac582 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BuildModifiers.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BuildModifiers.java @@ -52,7 +52,7 @@ public class BuildModifiers { if (world.isClientSide) { - BlockPreviews.onBlocksPlaced(); +// BlockPreviews.onBlocksPlaced(blocks); } else { @@ -79,7 +79,7 @@ public class BuildModifiers { } if (world.isClientSide) { - BlockPreviews.onBlocksBroken(); +// BlockPreviews.onBlocksBroken(blocks); //list of air blockstates for (int i = 0; i < coordinates.size(); i++) { @@ -205,14 +205,6 @@ public class BuildModifiers { return blockStates; } - public static boolean isEnabled(ModifierSettingsManager.ModifierSettings modifierSettings, BlockPos startPos) { - //startPos can be null - return Mirror.isEnabled(modifierSettings.getMirrorSettings(), startPos) || - Array.isEnabled(modifierSettings.getArraySettings()) || - RadialMirror.isEnabled(modifierSettings.getRadialMirrorSettings(), startPos) || - modifierSettings.doQuickReplace(); - } - public static BlockState getBlockStateFromItem(ItemStack itemStack, Player player, BlockPos blockPos, Direction facing, Vec3 hitVec, InteractionHand hand) { return Block.byItem(itemStack.getItem()).getStateForPlacement(new BlockPlaceContext(new UseOnContext(player, hand, new BlockHitResult(hitVec, facing, blockPos, false)))); } diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmodifier/ModifierSettingsManager.java b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/ModifierSettingsManager.java index 9965b48..7acf115 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmodifier/ModifierSettingsManager.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/ModifierSettingsManager.java @@ -99,14 +99,6 @@ public class ModifierSettingsManager { error += "Radial mirror exceeds your maximum reach of " + (maxReach / 2) + ". Radius has been set to " + (maxReach / 2) + ". "; } - //Other - if (modifierSettings.reachUpgrade < 0) { - modifierSettings.reachUpgrade = 0; - } - if (modifierSettings.reachUpgrade > 3) { - modifierSettings.reachUpgrade = 3; - } - return error; } @@ -126,8 +118,6 @@ public class ModifierSettingsManager { private Mirror.MirrorSettings mirrorSettings; private Array.ArraySettings arraySettings; private RadialMirror.RadialMirrorSettings radialMirrorSettings; - private boolean quickReplace = false; - private int reachUpgrade = 0; public ModifierSettings() { mirrorSettings = new Mirror.MirrorSettings(); @@ -136,12 +126,10 @@ public class ModifierSettingsManager { } public ModifierSettings(Mirror.MirrorSettings mirrorSettings, Array.ArraySettings arraySettings, - RadialMirror.RadialMirrorSettings radialMirrorSettings, boolean quickReplace, int reachUpgrade) { + RadialMirror.RadialMirrorSettings radialMirrorSettings) { this.mirrorSettings = mirrorSettings; this.arraySettings = arraySettings; this.radialMirrorSettings = radialMirrorSettings; - this.quickReplace = quickReplace; - this.reachUpgrade = reachUpgrade; } public Mirror.MirrorSettings getMirrorSettings() { @@ -173,43 +161,6 @@ public class ModifierSettingsManager { if (radialMirrorSettings == null) return; this.radialMirrorSettings = radialMirrorSettings; } - - public boolean doQuickReplace() { - return quickReplace; - } - - public void setQuickReplace(boolean quickReplace) { - this.quickReplace = quickReplace; - } - - public int getReachUpgrade() { - return reachUpgrade; - } - - public void setReachUpgrade(int reachUpgrade) { - this.reachUpgrade = reachUpgrade; - //Set mirror radius to max - int reach = 10; - switch (reachUpgrade) { - case 0: - reach = CommonConfig.reach.maxReachLevel0.get(); - break; - case 1: - reach = CommonConfig.reach.maxReachLevel1.get(); - break; - case 2: - reach = CommonConfig.reach.maxReachLevel2.get(); - break; - case 3: - reach = CommonConfig.reach.maxReachLevel3.get(); - break; - } - - if (this.mirrorSettings != null) - this.mirrorSettings.radius = reach / 2; - if (this.radialMirrorSettings != null) - this.radialMirrorSettings.radius = reach / 2; - } } } diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmodifier/UndoRedo.java b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/UndoRedo.java index 76d1faf..81768f2 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmodifier/UndoRedo.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/UndoRedo.java @@ -87,7 +87,7 @@ public class UndoRedo { List itemStacks = findItemStacksInInventory(player, previousBlockStates); if (player.level.isClientSide) { - BlockPreviews.onBlocksBroken(coordinates, itemStacks, newBlockStates, blockSet.getSecondPos(), blockSet.getFirstPos()); +// BlockPreviews.onBlocksBroken(coordinates, itemStacks, newBlockStates, blockSet.getSecondPos(), blockSet.getFirstPos()); } else { //break all those blocks, reset to what they were for (int i = 0; i < coordinates.size(); i++) { @@ -146,7 +146,7 @@ public class UndoRedo { List itemStacks = findItemStacksInInventory(player, newBlockStates); if (player.level.isClientSide) { - BlockPreviews.onBlocksPlaced(coordinates, itemStacks, newBlockStates, blockSet.getFirstPos(), blockSet.getSecondPos()); +// BlockPreviews.onBlocksPlaced(coordinates, itemStacks, newBlockStates, blockSet.getFirstPos(), blockSet.getSecondPos()); } else { //place blocks for (int i = 0; i < coordinates.size(); i++) { diff --git a/src/main/java/nl/requios/effortlessbuilding/capability/ModeCapabilityManager.java b/src/main/java/nl/requios/effortlessbuilding/capability/ModeCapabilityManager.java deleted file mode 100644 index 19afd49..0000000 --- a/src/main/java/nl/requios/effortlessbuilding/capability/ModeCapabilityManager.java +++ /dev/null @@ -1,109 +0,0 @@ -package nl.requios.effortlessbuilding.capability; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.Tag; -import net.minecraft.core.Direction; -import net.minecraftforge.common.capabilities.*; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.event.entity.player.PlayerEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import nl.requios.effortlessbuilding.buildmode.BuildModes; -import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import static nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.ModeSettings; - -@Mod.EventBusSubscriber -public class ModeCapabilityManager { - - public static Capability MODE_CAPABILITY = CapabilityManager.get(new CapabilityToken<>(){}); - - // Allows for the capability to persist after death. - @SubscribeEvent - public static void clonePlayer(PlayerEvent.Clone event) { - LazyOptional original = event.getOriginal().getCapability(MODE_CAPABILITY, null); - LazyOptional clone = event.getEntity().getCapability(MODE_CAPABILITY, null); - clone.ifPresent(cloneModeCapability -> - original.ifPresent(originalModeCapability -> - cloneModeCapability.setModeData(originalModeCapability.getModeData()))); - } - - public interface IModeCapability { - ModeSettings getModeData(); - - void setModeData(ModeSettings modeSettings); - } - - public static class ModeCapability implements IModeCapability { - private ModeSettings modeSettings; - - @Override - public ModeSettings getModeData() { - return modeSettings; - } - - @Override - public void setModeData(ModeSettings modeSettings) { - this.modeSettings = modeSettings; - } - } - - public static class Provider extends CapabilityProvider implements ICapabilitySerializable { - - private IModeCapability instance = new ModeCapability(); - private LazyOptional modeCapabilityOptional = LazyOptional.of(() -> instance); - - public Provider() { - super(Provider.class); - gatherCapabilities(); - } - - @Nonnull - @Override - public LazyOptional getCapability(@Nonnull Capability cap, @Nullable Direction side) { - if (cap == MODE_CAPABILITY) return modeCapabilityOptional.cast(); - return LazyOptional.empty(); - } - - @Override - public void invalidateCaps() { - super.invalidateCaps(); - modeCapabilityOptional.invalidate(); - } - - @Override - public void reviveCaps() { - super.reviveCaps(); - modeCapabilityOptional = LazyOptional.of(() -> instance); - } - - @Override - public Tag serializeNBT() { - CompoundTag compound = new CompoundTag(); - ModeSettings modeSettings = instance.getModeData(); - if (modeSettings == null) modeSettings = new ModeSettingsManager.ModeSettings(); - - //compound.putInteger("buildMode", modeSettings.getBuildMode().ordinal()); - - //TODO add mode settings - - return compound; - } - - @Override - public void deserializeNBT(Tag nbt) { - CompoundTag compound = (CompoundTag) nbt; - - //BuildModes.BuildModeEnum buildMode = BuildModes.BuildModeEnum.values()[compound.getInteger("buildMode")]; - - //TODO add mode settings - - ModeSettings modeSettings = new ModeSettings(BuildModes.BuildModeEnum.DISABLED); - instance.setModeData(modeSettings); - } - - } -} diff --git a/src/main/java/nl/requios/effortlessbuilding/capability/ModifierCapabilityManager.java b/src/main/java/nl/requios/effortlessbuilding/capability/ModifierCapabilityManager.java index 1f69ab0..f2d6b75 100644 --- a/src/main/java/nl/requios/effortlessbuilding/capability/ModifierCapabilityManager.java +++ b/src/main/java/nl/requios/effortlessbuilding/capability/ModifierCapabilityManager.java @@ -113,8 +113,6 @@ public class ModifierCapabilityManager { compound.putInt("arrayOffsetZ", a.offset.getZ()); compound.putInt("arrayCount", a.count); - compound.putInt("reachUpgrade", modifierSettings.getReachUpgrade()); - //compound.putBoolean("quickReplace", buildSettings.doQuickReplace()); dont save quickreplace //RADIAL MIRROR @@ -160,10 +158,6 @@ public class ModifierCapabilityManager { int arrayCount = compound.getInt("arrayCount"); Array.ArraySettings arraySettings = new Array.ArraySettings(arrayEnabled, arrayOffset, arrayCount); - int reachUpgrade = compound.getInt("reachUpgrade"); - - //boolean quickReplace = compound.getBoolean("quickReplace"); //dont load quickreplace - //RADIAL MIRROR boolean radialMirrorEnabled = compound.getBoolean("radialMirrorEnabled"); Vec3 radialMirrorPosition = new Vec3( @@ -178,7 +172,7 @@ public class ModifierCapabilityManager { RadialMirror.RadialMirrorSettings radialMirrorSettings = new RadialMirror.RadialMirrorSettings(radialMirrorEnabled, radialMirrorPosition, radialMirrorSlices, radialMirrorAlternate, radialMirrorRadius, radialMirrorDrawLines, radialMirrorDrawPlanes); - ModifierSettings modifierSettings = new ModifierSettings(mirrorSettings, arraySettings, radialMirrorSettings, false, reachUpgrade); + ModifierSettings modifierSettings = new ModifierSettings(mirrorSettings, arraySettings, radialMirrorSettings); instance.setModifierData(modifierSettings); } diff --git a/src/main/java/nl/requios/effortlessbuilding/create/events/ClientEvents.java b/src/main/java/nl/requios/effortlessbuilding/create/events/ClientEvents.java index c849e88..3b19e20 100644 --- a/src/main/java/nl/requios/effortlessbuilding/create/events/ClientEvents.java +++ b/src/main/java/nl/requios/effortlessbuilding/create/events/ClientEvents.java @@ -10,6 +10,7 @@ import net.minecraft.world.phys.Vec3; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.RenderLevelLastEvent; import net.minecraftforge.client.event.ViewportEvent; +import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.TickEvent.ClientTickEvent; import net.minecraftforge.event.level.LevelEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -29,10 +30,8 @@ public class ClientEvents { @SubscribeEvent public static void onTick(ClientTickEvent event) { - if (!isGameActive()) - return; + if (!isGameActive() || event.phase != TickEvent.Phase.END) return; - Level world = Minecraft.getInstance().level; AnimationTickHolder.tick(); CreateClient.GHOST_BLOCKS.tickGhosts(); diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/ItemDescription.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/ItemDescription.java new file mode 100644 index 0000000..f3be447 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/ItemDescription.java @@ -0,0 +1,182 @@ +package nl.requios.effortlessbuilding.create.foundation.item; + +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import nl.requios.effortlessbuilding.create.foundation.utility.Components; +import nl.requios.effortlessbuilding.create.foundation.utility.Lang; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static net.minecraft.ChatFormatting.*; +import static nl.requios.effortlessbuilding.create.foundation.item.TooltipHelper.cutStringTextComponent; +import static nl.requios.effortlessbuilding.create.foundation.item.TooltipHelper.cutTextComponent; + +public class ItemDescription { + + public static final ItemDescription MISSING = new ItemDescription(null); + public static Component trim = Components.literal(" ").withStyle(WHITE, STRIKETHROUGH); + + public enum Palette { + + Blue(BLUE, AQUA), + Green(DARK_GREEN, GREEN), + Yellow(GOLD, YELLOW), + Red(DARK_RED, RED), + Purple(DARK_PURPLE, LIGHT_PURPLE), + Gray(DARK_GRAY, GRAY), + + ; + + private Palette(ChatFormatting primary, ChatFormatting highlight) { + color = primary; + hColor = highlight; + } + + public ChatFormatting color; + public ChatFormatting hColor; + } + + private List lines; + private List linesOnShift; + private List linesOnCtrl; + private Palette palette; + + public ItemDescription(Palette palette) { + this.palette = palette; + lines = new ArrayList<>(); + linesOnShift = new ArrayList<>(); + linesOnCtrl = new ArrayList<>(); + } + + public ItemDescription withSummary(Component summary) { + addStrings(linesOnShift, cutTextComponent(summary, palette.color, palette.hColor)); + return this; + } + + public static String makeProgressBar(int length, int filledLength) { + String bar = " "; + int emptySpaces = length - filledLength; + for (int i = 0; i < filledLength; i++) + bar += "\u2588"; + for (int i = 0; i < emptySpaces; i++) + bar += "\u2592"; + return bar + " "; + } + + public ItemDescription withBehaviour(String condition, String behaviour) { + add(linesOnShift, Components.literal(condition).withStyle(GRAY)); + addStrings(linesOnShift, cutStringTextComponent(behaviour, palette.color, palette.hColor, 1)); + return this; + } + + public ItemDescription withControl(String condition, String action) { + add(linesOnCtrl, Components.literal(condition).withStyle(GRAY)); + addStrings(linesOnCtrl, cutStringTextComponent(action, palette.color, palette.hColor, 1)); + return this; + } + + public ItemDescription createTabs() { + boolean hasDescription = !linesOnShift.isEmpty(); + boolean hasControls = !linesOnCtrl.isEmpty(); + + if (hasDescription || hasControls) { + String[] holdDesc = Lang.translateDirect("tooltip.holdForDescription", "$") + .getString() + .split("\\$"); + String[] holdCtrl = Lang.translateDirect("tooltip.holdForControls", "$") + .getString() + .split("\\$"); + MutableComponent keyShift = Lang.translateDirect("tooltip.keyShift"); + MutableComponent keyCtrl = Lang.translateDirect("tooltip.keyCtrl"); + for (List list : Arrays.asList(lines, linesOnShift, linesOnCtrl)) { + boolean shift = list == linesOnShift; + boolean ctrl = list == linesOnCtrl; + + if (holdDesc.length != 2 || holdCtrl.length != 2) { + list.add(0, Components.literal("Invalid lang formatting!")); + continue; + } + + if (hasControls) { + MutableComponent tabBuilder = Components.empty(); + tabBuilder.append(Components.literal(holdCtrl[0]).withStyle(DARK_GRAY)); + tabBuilder.append(keyCtrl.plainCopy() + .withStyle(ctrl ? WHITE : GRAY)); + tabBuilder.append(Components.literal(holdCtrl[1]).withStyle(DARK_GRAY)); + list.add(0, tabBuilder); + } + + if (hasDescription) { + MutableComponent tabBuilder = Components.empty(); + tabBuilder.append(Components.literal(holdDesc[0]).withStyle(DARK_GRAY)); + tabBuilder.append(keyShift.plainCopy() + .withStyle(shift ? WHITE : GRAY)); + tabBuilder.append(Components.literal(holdDesc[1]).withStyle(DARK_GRAY)); + list.add(0, tabBuilder); + } + + if (shift || ctrl) + list.add(hasDescription && hasControls ? 2 : 1, Components.immutableEmpty()); + } + } + + if (!hasDescription) + linesOnShift = lines; + if (!hasControls) + linesOnCtrl = lines; + + return this; + } + + public static String hightlight(String s, Palette palette) { + return palette.hColor + s + palette.color; + } + + public static void addStrings(List infoList, List textLines) { + textLines.forEach(s -> add(infoList, s)); + } + + public static void add(List infoList, List textLines) { + infoList.addAll(textLines); + } + + public static void add(List infoList, Component line) { + infoList.add(line); + } + + public Palette getPalette() { + return palette; + } + + public List addInformation(List tooltip) { + if (Screen.hasShiftDown()) { + tooltip.addAll(linesOnShift); + return tooltip; + } + + if (Screen.hasControlDown()) { + tooltip.addAll(linesOnCtrl); + return tooltip; + } + + tooltip.addAll(lines); + return tooltip; + } + + public List getLines() { + return lines; + } + + public List getLinesOnCtrl() { + return linesOnCtrl; + } + + public List getLinesOnShift() { + return linesOnShift; + } + +} diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/ItemHandlerWrapper.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/ItemHandlerWrapper.java new file mode 100644 index 0000000..cdbc5f0 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/ItemHandlerWrapper.java @@ -0,0 +1,49 @@ +package nl.requios.effortlessbuilding.create.foundation.item; + +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.items.IItemHandlerModifiable; + +public class ItemHandlerWrapper implements IItemHandlerModifiable { + + private IItemHandlerModifiable wrapped; + + public ItemHandlerWrapper(IItemHandlerModifiable wrapped) { + this.wrapped = wrapped; + } + + @Override + public int getSlots() { + return wrapped.getSlots(); + } + + @Override + public ItemStack getStackInSlot(int slot) { + return wrapped.getStackInSlot(slot); + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { + return wrapped.insertItem(slot, stack, simulate); + } + + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) { + return wrapped.extractItem(slot, amount, simulate); + } + + @Override + public int getSlotLimit(int slot) { + return wrapped.getSlotLimit(slot); + } + + @Override + public boolean isItemValid(int slot, ItemStack stack) { + return wrapped.isItemValid(slot, stack); + } + + @Override + public void setStackInSlot(int slot, ItemStack stack) { + wrapped.setStackInSlot(slot, stack); + } + +} diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/ItemHelper.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/ItemHelper.java new file mode 100644 index 0000000..74f3d58 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/ItemHelper.java @@ -0,0 +1,276 @@ +package nl.requios.effortlessbuilding.create.foundation.item; + +import nl.requios.effortlessbuilding.create.foundation.utility.Pair; +import net.minecraft.core.BlockPos; +import net.minecraft.core.NonNullList; +import net.minecraft.util.Mth; +import net.minecraft.world.Containers; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.level.Level; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; +import org.apache.commons.lang3.mutable.MutableInt; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import java.util.function.Predicate; + +public class ItemHelper { + + public static void dropContents(Level world, BlockPos pos, IItemHandler inv) { + for (int slot = 0; slot < inv.getSlots(); slot++) + Containers.dropItemStack(world, pos.getX(), pos.getY(), pos.getZ(), inv.getStackInSlot(slot)); + } + + public static List multipliedOutput(ItemStack in, ItemStack out) { + List stacks = new ArrayList<>(); + ItemStack result = out.copy(); + result.setCount(in.getCount() * out.getCount()); + + while (result.getCount() > result.getMaxStackSize()) { + stacks.add(result.split(result.getMaxStackSize())); + } + + stacks.add(result); + return stacks; + } + + public static void addToList(ItemStack stack, List stacks) { + for (ItemStack s : stacks) { + if (!ItemHandlerHelper.canItemStacksStack(stack, s)) + continue; + int transferred = Math.min(s.getMaxStackSize() - s.getCount(), stack.getCount()); + s.grow(transferred); + stack.shrink(transferred); + } + if (stack.getCount() > 0) + stacks.add(stack); + } + + public static boolean isSameInventory(IItemHandler h1, IItemHandler h2) { + if (h1 == null || h2 == null) + return false; + if (h1.getSlots() != h2.getSlots()) + return false; + for (int slot = 0; slot < h1.getSlots(); slot++) { + if (h1.getStackInSlot(slot) != h2.getStackInSlot(slot)) + return false; + } + return true; + } + + public static int calcRedstoneFromInventory(@Nullable IItemHandler inv) { + if (inv == null) + return 0; + int i = 0; + float f = 0.0F; + int totalSlots = inv.getSlots(); + + for (int j = 0; j < inv.getSlots(); ++j) { + int slotLimit = inv.getSlotLimit(j); + if (slotLimit == 0) { + totalSlots--; + continue; + } + ItemStack itemstack = inv.getStackInSlot(j); + if (!itemstack.isEmpty()) { + f += (float) itemstack.getCount() / (float) Math.min(slotLimit, itemstack.getMaxStackSize()); + ++i; + } + } + + if (totalSlots == 0) + return 0; + + f = f / totalSlots; + return Mth.floor(f * 14.0F) + (i > 0 ? 1 : 0); + } + + public static List> condenseIngredients(NonNullList recipeIngredients) { + List> actualIngredients = new ArrayList<>(); + Ingredients: for (Ingredient igd : recipeIngredients) { + for (Pair pair : actualIngredients) { + ItemStack[] stacks1 = pair.getFirst() + .getItems(); + ItemStack[] stacks2 = igd.getItems(); + if (stacks1.length != stacks2.length) + continue; + for (int i = 0; i <= stacks1.length; i++) { + if (i == stacks1.length) { + pair.getSecond() + .increment(); + continue Ingredients; + } + if (!ItemStack.matches(stacks1[i], stacks2[i])) + break; + } + } + actualIngredients.add(Pair.of(igd, new MutableInt(1))); + } + return actualIngredients; + } + + public static boolean matchIngredients(Ingredient i1, Ingredient i2) { + if (i1 == i2) + return true; + ItemStack[] stacks1 = i1.getItems(); + ItemStack[] stacks2 = i2.getItems(); + if (stacks1 == stacks2) + return true; + if (stacks1.length == stacks2.length) { + for (int i = 0; i < stacks1.length; i++) + if (!ItemStack.isSame(stacks1[i], stacks2[i])) + return false; + return true; + } + return false; + } + + public static boolean matchAllIngredients(NonNullList ingredients) { + if (ingredients.size() <= 1) + return true; + Ingredient firstIngredient = ingredients.get(0); + for (int i = 1; i < ingredients.size(); i++) + if (!matchIngredients(firstIngredient, ingredients.get(i))) + return false; + return true; + } + + public static enum ExtractionCountMode { + EXACTLY, UPTO + } + + public static ItemStack extract(IItemHandler inv, Predicate test, boolean simulate) { + return extract(inv, test, ExtractionCountMode.UPTO, 64, simulate); + } + + public static ItemStack extract(IItemHandler inv, Predicate test, int exactAmount, boolean simulate) { + return extract(inv, test, ExtractionCountMode.EXACTLY, exactAmount, simulate); + } + + public static ItemStack extract(IItemHandler inv, Predicate test, ExtractionCountMode mode, int amount, + boolean simulate) { + ItemStack extracting = ItemStack.EMPTY; + boolean amountRequired = mode == ExtractionCountMode.EXACTLY; + boolean checkHasEnoughItems = amountRequired; + boolean hasEnoughItems = !checkHasEnoughItems; + boolean potentialOtherMatch = false; + int maxExtractionCount = amount; + + Extraction: do { + extracting = ItemStack.EMPTY; + + for (int slot = 0; slot < inv.getSlots(); slot++) { + int amountToExtractFromThisSlot = + Math.min(maxExtractionCount - extracting.getCount(), inv.getStackInSlot(slot) + .getMaxStackSize()); + ItemStack stack = inv.extractItem(slot, amountToExtractFromThisSlot, true); + + if (stack.isEmpty()) + continue; + if (!test.test(stack)) + continue; + if (!extracting.isEmpty() && !canItemStackAmountsStack(stack, extracting)) { + potentialOtherMatch = true; + continue; + } + + if (extracting.isEmpty()) + extracting = stack.copy(); + else + extracting.grow(stack.getCount()); + + if (!simulate && hasEnoughItems) + inv.extractItem(slot, stack.getCount(), false); + + if (extracting.getCount() >= maxExtractionCount) { + if (checkHasEnoughItems) { + hasEnoughItems = true; + checkHasEnoughItems = false; + continue Extraction; + } else { + break Extraction; + } + } + } + + if (!extracting.isEmpty() && !hasEnoughItems && potentialOtherMatch) { + ItemStack blackListed = extracting.copy(); + test = test.and(i -> !ItemHandlerHelper.canItemStacksStack(i, blackListed)); + continue; + } + + if (checkHasEnoughItems) + checkHasEnoughItems = false; + else + break Extraction; + + } while (true); + + if (amountRequired && extracting.getCount() < amount) + return ItemStack.EMPTY; + + return extracting; + } + + public static ItemStack extract(IItemHandler inv, Predicate test, + Function amountFunction, boolean simulate) { + ItemStack extracting = ItemStack.EMPTY; + int maxExtractionCount = 64; + + for (int slot = 0; slot < inv.getSlots(); slot++) { + if (extracting.isEmpty()) { + ItemStack stackInSlot = inv.getStackInSlot(slot); + if (stackInSlot.isEmpty() || !test.test(stackInSlot)) + continue; + int maxExtractionCountForItem = amountFunction.apply(stackInSlot); + if (maxExtractionCountForItem == 0) + continue; + maxExtractionCount = Math.min(maxExtractionCount, maxExtractionCountForItem); + } + + ItemStack stack = inv.extractItem(slot, maxExtractionCount - extracting.getCount(), true); + + if (!test.test(stack)) + continue; + if (!extracting.isEmpty() && !canItemStackAmountsStack(stack, extracting)) + continue; + + if (extracting.isEmpty()) + extracting = stack.copy(); + else + extracting.grow(stack.getCount()); + + if (!simulate) + inv.extractItem(slot, stack.getCount(), false); + if (extracting.getCount() >= maxExtractionCount) + break; + } + + return extracting; + } + + public static boolean canItemStackAmountsStack(ItemStack a, ItemStack b) { + return ItemHandlerHelper.canItemStacksStack(a, b) && a.getCount() + b.getCount() <= a.getMaxStackSize(); + } + + public static ItemStack findFirstMatch(IItemHandler inv, Predicate test) { + int slot = findFirstMatchingSlotIndex(inv, test); + if (slot == -1) + return ItemStack.EMPTY; + else + return inv.getStackInSlot(slot); + } + + public static int findFirstMatchingSlotIndex(IItemHandler inv, Predicate test) { + for (int slot = 0; slot < inv.getSlots(); slot++) { + ItemStack toTest = inv.getStackInSlot(slot); + if (test.test(toTest)) + return slot; + } + return -1; + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/TagDependentIngredientItem.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/TagDependentIngredientItem.java new file mode 100644 index 0000000..0e92452 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/TagDependentIngredientItem.java @@ -0,0 +1,31 @@ +package nl.requios.effortlessbuilding.create.foundation.item; + +import net.minecraft.core.NonNullList; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.tags.ITagManager; + +public class TagDependentIngredientItem extends Item { + + private TagKey tag; + + public TagDependentIngredientItem(Properties properties, TagKey tag) { + super(properties); + this.tag = tag; + } + + @Override + public void fillItemCategory(CreativeModeTab tab, NonNullList list) { + if (!shouldHide()) + super.fillItemCategory(tab, list); + } + + public boolean shouldHide() { + ITagManager tagManager = ForgeRegistries.ITEMS.tags(); + return !tagManager.isKnownTagName(tag) || tagManager.getTag(tag).isEmpty(); + } + +} diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/TooltipHelper.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/TooltipHelper.java new file mode 100644 index 0000000..b05958a --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/TooltipHelper.java @@ -0,0 +1,312 @@ +package nl.requios.effortlessbuilding.create.foundation.item; + +import com.google.common.base.Strings; +import com.mojang.bridge.game.Language; +import nl.requios.effortlessbuilding.create.foundation.item.ItemDescription.Palette; +import nl.requios.effortlessbuilding.create.foundation.utility.Components; +import nl.requios.effortlessbuilding.create.foundation.utility.Couple; +import nl.requios.effortlessbuilding.create.foundation.utility.FontHelper; +import nl.requios.effortlessbuilding.create.foundation.utility.Lang; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ItemLike; + +import java.text.BreakIterator; +import java.util.*; +import java.util.function.Supplier; + +public class TooltipHelper { + + public static final int maxWidthPerLine = 200; + public static final Map cachedTooltips = new HashMap<>(); + public static Language cachedLanguage; + private static boolean gogglesMode; + private static final Map> tooltipReferrals = new HashMap<>(); + + public static MutableComponent holdShift(Palette color, boolean highlighted) { + return Lang.translateDirect("tooltip.holdForDescription", Lang.translateDirect("tooltip.keyShift") + .withStyle(ChatFormatting.GRAY)) + .withStyle(ChatFormatting.DARK_GRAY); + } + + public static void addHint(List tooltip, String hintKey, Object... messageParams) { + Component spacing = Components.literal(""); + tooltip.add(spacing.plainCopy() + .append(Lang.translateDirect(hintKey + ".title")) + .withStyle(ChatFormatting.GOLD)); + Component hint = Lang.translateDirect(hintKey); + List cutComponent = TooltipHelper.cutTextComponent(hint, ChatFormatting.GRAY, ChatFormatting.WHITE); + for (Component component : cutComponent) + tooltip.add(spacing.plainCopy() + .append(component)); + } + + public static void referTo(ItemLike item, Supplier itemWithTooltip) { + tooltipReferrals.put(item.asItem(), () -> itemWithTooltip.get() + .asItem() + .getDescriptionId()); + } + + public static void referTo(ItemLike item, String string) { + tooltipReferrals.put(item.asItem(), () -> string); + } + + @Deprecated + public static List cutString(Component s, ChatFormatting defaultColor, ChatFormatting highlightColor) { + return cutString(s.getString(), defaultColor, highlightColor, 0); + } + + @Deprecated + public static List cutString(String s, ChatFormatting defaultColor, ChatFormatting highlightColor, + int indent) { + // Apply markup + String markedUp = s.replaceAll("_([^_]+)_", highlightColor + "$1" + defaultColor); + + // Split words + List words = new LinkedList<>(); + BreakIterator iterator = BreakIterator.getLineInstance(Minecraft.getInstance().getLocale()); + iterator.setText(markedUp); + int start = iterator.first(); + for (int end = iterator.next(); end != BreakIterator.DONE; start = end, end = iterator.next()) { + String word = markedUp.substring(start, end); + words.add(word); + } + + Font font = Minecraft.getInstance().font; + List lines = FontHelper.cutString(font, markedUp, maxWidthPerLine); + + // Format + String lineStart = Strings.repeat(" ", indent); + List formattedLines = new ArrayList<>(lines.size()); + String format = defaultColor.toString(); + for (String line : lines) { + String formattedLine = format + lineStart + line; + formattedLines.add(formattedLine); +// format = TextFormatting.getFormatString(formattedLine); + } + return formattedLines; + } + + public static List cutStringTextComponent(String c, ChatFormatting defaultColor, + ChatFormatting highlightColor) { + return cutTextComponent(Components.literal(c), defaultColor, highlightColor, 0); + } + + public static List cutTextComponent(Component c, ChatFormatting defaultColor, + ChatFormatting highlightColor) { + return cutTextComponent(c, defaultColor, highlightColor, 0); + } + + public static List cutStringTextComponent(String c, ChatFormatting defaultColor, + ChatFormatting highlightColor, int indent) { + return cutTextComponent(Components.literal(c), defaultColor, highlightColor, indent); + } + + public static List cutTextComponent(Component c, ChatFormatting defaultColor, + ChatFormatting highlightColor, int indent) { + String s = c.getString(); + + // Apply markup + String markedUp = s;// .replaceAll("_([^_]+)_", highlightColor + "$1" + defaultColor); + + // Split words + List words = new LinkedList<>(); + BreakIterator iterator = BreakIterator.getLineInstance(Minecraft.getInstance().getLocale()); + iterator.setText(markedUp); + int start = iterator.first(); + for (int end = iterator.next(); end != BreakIterator.DONE; start = end, end = iterator.next()) { + String word = markedUp.substring(start, end); + words.add(word); + } + + // Apply hard wrap + Font font = Minecraft.getInstance().font; + List lines = new LinkedList<>(); + StringBuilder currentLine = new StringBuilder(); + int width = 0; + for (String word : words) { + int newWidth = font.width(word.replaceAll("_", "")); + if (width + newWidth > maxWidthPerLine) { + if (width > 0) { + String line = currentLine.toString(); + lines.add(line); + currentLine = new StringBuilder(); + width = 0; + } else { + lines.add(word); + continue; + } + } + currentLine.append(word); + width += newWidth; + } + if (width > 0) { + lines.add(currentLine.toString()); + } + + // Format + MutableComponent lineStart = Components.literal(Strings.repeat(" ", indent)); + lineStart.withStyle(defaultColor); + List formattedLines = new ArrayList<>(lines.size()); + Couple f = Couple.create(highlightColor, defaultColor); + + boolean currentlyHighlighted = false; + for (String string : lines) { + MutableComponent currentComponent = lineStart.plainCopy(); + String[] split = string.split("_"); + for (String part : split) { + currentComponent.append(Components.literal(part).withStyle(f.get(currentlyHighlighted))); + currentlyHighlighted = !currentlyHighlighted; + } + + formattedLines.add(currentComponent); + currentlyHighlighted = !currentlyHighlighted; + } + + return formattedLines; + } + +// public static List cutTextComponentOld(ITextComponent c, TextFormatting defaultColor, +// TextFormatting highlightColor, int indent) { +// IFormattableTextComponent lineStart = StringTextComponent.EMPTY.copy(); +// for (int i = 0; i < indent; i++) +// lineStart.append(" "); +// lineStart.formatted(defaultColor); +// +// List lines = new ArrayList<>(); +// String rawText = getUnformattedDeepText(c); +// String[] words = rawText.split(" "); +// String word; +// IFormattableTextComponent currentLine = lineStart.copy(); +// +// boolean firstWord = true; +// boolean lastWord; +// +// // Apply hard wrap +// for (int i = 0; i < words.length; i++) { +// word = words[i]; +// lastWord = i == words.length - 1; +// +// if (!lastWord && !firstWord && getComponentLength(currentLine) + word.length() > maxCharsPerLine) { +// lines.add(currentLine); +// currentLine = lineStart.copy(); +// firstWord = true; +// } +// +// currentLine.append(new StringTextComponent((firstWord ? "" : " ") + word.replace("_", "")) +// .formatted(word.matches("_([^_]+)_") ? highlightColor : defaultColor)); +// firstWord = false; +// } +// +// if (!firstWord) { +// lines.add(currentLine); +// } +// +// return lines; +// } + + private static void checkLocale() { + Language currentLanguage = Minecraft.getInstance() + .getLanguageManager() + .getSelected(); + if (cachedLanguage != currentLanguage) { + cachedTooltips.clear(); + cachedLanguage = currentLanguage; + } + } + + public static boolean hasTooltip(ItemStack stack, Player player) { + checkLocale(); + + String key = getTooltipTranslationKey(stack); + if (cachedTooltips.containsKey(key)) + return cachedTooltips.get(key) != ItemDescription.MISSING; + return findTooltip(stack); + } + + public static ItemDescription getTooltip(ItemStack stack) { + checkLocale(); + String key = getTooltipTranslationKey(stack); + if (cachedTooltips.containsKey(key)) { + ItemDescription itemDescription = cachedTooltips.get(key); + if (itemDescription != ItemDescription.MISSING) + return itemDescription; + } + return null; + } + + private static boolean findTooltip(ItemStack stack) { + String key = getTooltipTranslationKey(stack); + if (I18n.exists(key)) { + cachedTooltips.put(key, buildToolTip(key, stack)); + return true; + } + cachedTooltips.put(key, ItemDescription.MISSING); + return false; + } + + private static ItemDescription buildToolTip(String translationKey, ItemStack stack) { + ItemDescription tooltip = new ItemDescription(Palette.Blue); + String summaryKey = translationKey + ".summary"; + + // Summary + if (I18n.exists(summaryKey)) + tooltip = tooltip.withSummary(Components.literal(I18n.get(summaryKey))); + + // Requirements +// if (stack.getItem() instanceof BlockItem) { +// BlockItem item = (BlockItem) stack.getItem(); +// if (item.getBlock() instanceof IRotate || item.getBlock() instanceof EngineBlock) { +// tooltip = tooltip.withKineticStats(item.getBlock()); +// } +// } + + // Behaviours + for (int i = 1; i < 100; i++) { + String conditionKey = translationKey + ".condition" + i; + String behaviourKey = translationKey + ".behaviour" + i; + if (!I18n.exists(conditionKey)) + break; + if (i == 1) + tooltip.getLinesOnShift() + .add(Components.immutableEmpty()); + tooltip.withBehaviour(I18n.get(conditionKey), I18n.get(behaviourKey)); + } + + // Controls + for (int i = 1; i < 100; i++) { + String controlKey = translationKey + ".control" + i; + String actionKey = translationKey + ".action" + i; + if (!I18n.exists(controlKey)) + break; + tooltip.withControl(I18n.get(controlKey), I18n.get(actionKey)); + } + + return tooltip.createTabs(); + } + + public static String getTooltipTranslationKey(ItemStack stack) { + Item item = stack.getItem(); + if (tooltipReferrals.containsKey(item)) + return tooltipReferrals.get(item) + .get() + ".tooltip"; + return item.getDescriptionId(stack) + ".tooltip"; + } + +// private static int getComponentLength(ITextComponent component) { +// AtomicInteger l = new AtomicInteger(); +// TextProcessing.visitFormatted(component, Style.EMPTY, (s, style, charConsumer) -> { +// l.getAndIncrement(); +// return true; +// }); +// return l.get(); +// } + +} diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/UncontainableBlockItem.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/UncontainableBlockItem.java new file mode 100644 index 0000000..6e9a8b6 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/UncontainableBlockItem.java @@ -0,0 +1,15 @@ +package nl.requios.effortlessbuilding.create.foundation.item; + +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.level.block.Block; + +public class UncontainableBlockItem extends BlockItem { + public UncontainableBlockItem(Block block, Properties properties) { + super(block, properties); + } + + @Override + public boolean canFitInsideContainerItems() { + return false; + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/render/CreateCustomRenderedItemModel.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/render/CreateCustomRenderedItemModel.java new file mode 100644 index 0000000..72748e5 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/render/CreateCustomRenderedItemModel.java @@ -0,0 +1,12 @@ +package nl.requios.effortlessbuilding.create.foundation.item.render; + +import nl.requios.effortlessbuilding.create.Create; +import net.minecraft.client.resources.model.BakedModel; + +public abstract class CreateCustomRenderedItemModel extends CustomRenderedItemModel { + + public CreateCustomRenderedItemModel(BakedModel template, String basePath) { + super(template, Create.ID, basePath); + } + +} diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/render/CustomRenderedItemModel.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/render/CustomRenderedItemModel.java new file mode 100644 index 0000000..25191be --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/render/CustomRenderedItemModel.java @@ -0,0 +1,74 @@ +package nl.requios.effortlessbuilding.create.foundation.item.render; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.BlockModelRotation; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.event.ModelEvent; +import net.minecraftforge.client.model.BakedModelWrapper; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public abstract class CustomRenderedItemModel extends BakedModelWrapper { + + protected String namespace; + protected String basePath; + protected Map partials = new HashMap<>(); + + public CustomRenderedItemModel(BakedModel template, String namespace, String basePath) { + super(template); + this.namespace = namespace; + this.basePath = basePath; + } + + @Override + public boolean isCustomRenderer() { + return true; + } + + @Override + public BakedModel applyTransform(ItemTransforms.TransformType cameraTransformType, PoseStack mat, boolean leftHand) { + // Super call returns originalModel, but we want to return this, else ISTER + // won't be used. + super.applyTransform(cameraTransformType, mat, leftHand); + return this; + } + + public final BakedModel getOriginalModel() { + return originalModel; + } + + public BakedModel getPartial(String name) { + return partials.get(name); + } + + public final List getModelLocations() { + return partials.keySet().stream().map(this::getPartialModelLocation).collect(Collectors.toList()); + } + + protected void addPartials(String... partials) { + for (String name : partials) + this.partials.put(name, null); + } + + public void loadPartials(ModelEvent.BakingCompleted event) { + ModelBakery modelLoader = event.getModelBakery(); + for (String name : partials.keySet()) + partials.put(name, loadPartial(modelLoader, name)); + } + + @SuppressWarnings("deprecation") + protected BakedModel loadPartial(ModelBakery modelLoader, String name) { + return modelLoader.bake(getPartialModelLocation(name), BlockModelRotation.X0_Y0); + } + + protected ResourceLocation getPartialModelLocation(String name) { + return new ResourceLocation(namespace, "item/" + basePath + "/" + name); + } + +} diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/render/PartialItemModelRenderer.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/render/PartialItemModelRenderer.java new file mode 100644 index 0000000..5c1c491 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/item/render/PartialItemModelRenderer.java @@ -0,0 +1,95 @@ +package nl.requios.effortlessbuilding.create.foundation.item.render; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import nl.requios.effortlessbuilding.create.foundation.render.RenderTypes; +import nl.requios.effortlessbuilding.create.foundation.utility.Iterate; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.client.extensions.common.IClientItemExtensions; +import net.minecraftforge.client.model.data.ModelData; + +public class PartialItemModelRenderer { + + private static final PartialItemModelRenderer INSTANCE = new PartialItemModelRenderer(); + + private final RandomSource random = RandomSource.create(); + + private ItemStack stack; + private ItemTransforms.TransformType transformType; + private PoseStack ms; + private MultiBufferSource buffer; + private int overlay; + + public static PartialItemModelRenderer of(ItemStack stack, ItemTransforms.TransformType transformType, + PoseStack ms, MultiBufferSource buffer, int overlay) { + PartialItemModelRenderer instance = INSTANCE; + instance.stack = stack; + instance.transformType = transformType; + instance.ms = ms; + instance.buffer = buffer; + instance.overlay = overlay; + return instance; + } + + public void render(BakedModel model, int light) { + render(model, RenderTypes.getItemPartialTranslucent(), light); + } + + public void renderSolid(BakedModel model, int light) { + render(model, RenderTypes.getItemPartialSolid(), light); + } + + public void renderSolidGlowing(BakedModel model, int light) { + render(model, RenderTypes.getGlowingSolid(), light); + } + + public void renderGlowing(BakedModel model, int light) { + render(model, RenderTypes.getGlowingTranslucent(), light); + } + + public void render(BakedModel model, RenderType type, int light) { + if (stack.isEmpty()) + return; + + ms.pushPose(); + ms.translate(-0.5D, -0.5D, -0.5D); + + if (!model.isCustomRenderer()) { + VertexConsumer vc = ItemRenderer.getFoilBufferDirect(buffer, type, true, stack.hasFoil()); + for (BakedModel pass : model.getRenderPasses(stack, false)) { + renderBakedItemModel(pass, light, ms, vc); + } + } else + IClientItemExtensions.of(stack) + .getCustomRenderer() + .renderByItem(stack, transformType, ms, buffer, light, overlay); + + ms.popPose(); + } + + private void renderBakedItemModel(BakedModel model, int light, PoseStack ms, VertexConsumer buffer) { + ItemRenderer ir = Minecraft.getInstance() + .getItemRenderer(); + ModelData data = ModelData.EMPTY; + + for (RenderType renderType : model.getRenderTypes(stack, false)) { + for (Direction direction : Iterate.directions) { + random.setSeed(42L); + ir.renderQuadList(ms, buffer, model.getQuads(null, direction, random, data, renderType), stack, light, + overlay); + } + + random.setSeed(42L); + ir.renderQuadList(ms, buffer, model.getQuads(null, null, random, data, renderType), stack, light, overlay); + } + } + +} diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/networking/ISyncPersistentData.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/networking/ISyncPersistentData.java new file mode 100644 index 0000000..17b0310 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/networking/ISyncPersistentData.java @@ -0,0 +1,57 @@ +package nl.requios.effortlessbuilding.create.foundation.networking; + +import net.minecraft.client.Minecraft; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.Entity; +import net.minecraftforge.network.NetworkEvent.Context; +import net.minecraftforge.network.PacketDistributor; + +import java.util.HashSet; +import java.util.function.Supplier; + +public interface ISyncPersistentData { + + void onPersistentDataUpdated(); + + public static class PersistentDataPacket extends SimplePacketBase { + + private int entityId; + private Entity entity; + private CompoundTag readData; + + public PersistentDataPacket(Entity entity) { + this.entity = entity; + this.entityId = entity.getId(); + } + + public PersistentDataPacket(FriendlyByteBuf buffer) { + entityId = buffer.readInt(); + readData = buffer.readNbt(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(entityId); + buffer.writeNbt(entity.getPersistentData()); + } + + @Override + public void handle(Supplier context) { + context.get() + .enqueueWork(() -> { + Entity entityByID = Minecraft.getInstance().level.getEntity(entityId); + CompoundTag data = entityByID.getPersistentData(); + new HashSet<>(data.getAllKeys()).forEach(data::remove); + data.merge(readData); + if (!(entityByID instanceof ISyncPersistentData)) + return; + ((ISyncPersistentData) entityByID).onPersistentDataUpdated(); + }); + context.get() + .setPacketHandled(true); + } + + } + +} diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/networking/SimplePacketBase.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/networking/SimplePacketBase.java new file mode 100644 index 0000000..3217e84 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/networking/SimplePacketBase.java @@ -0,0 +1,14 @@ +package nl.requios.effortlessbuilding.create.foundation.networking; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.network.NetworkEvent.Context; + +import java.util.function.Supplier; + +public abstract class SimplePacketBase { + + public abstract void write(FriendlyByteBuf buffer); + + public abstract void handle(Supplier context); + +} 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 11e130f..14415e6 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 @@ -233,15 +233,12 @@ public class BlockHelper { if (state.hasProperty(BlockStateProperties.WATERLOGGED)) state = state.setValue(BlockStateProperties.WATERLOGGED, Boolean.FALSE); -// if (AllBlocks.BELT.has(state)) { -// world.setBlock(target, state, 2); -// return; -// } else if (state.getBlock() == Blocks.COMPOSTER) -// state = Blocks.COMPOSTER.defaultBlockState(); -// else if (state.getBlock() != Blocks.SEA_PICKLE && state.getBlock() instanceof IPlantable) -// state = ((IPlantable) state.getBlock()).getPlant(world, target); -// else if (state.is(BlockTags.CAULDRONS)) -// state = Blocks.CAULDRON.defaultBlockState(); + if (state.getBlock() == Blocks.COMPOSTER) + state = Blocks.COMPOSTER.defaultBlockState(); + else if (state.getBlock() != Blocks.SEA_PICKLE && state.getBlock() instanceof IPlantable) + state = ((IPlantable) state.getBlock()).getPlant(world, target); + else if (state.is(BlockTags.CAULDRONS)) + state = Blocks.CAULDRON.defaultBlockState(); if (world.dimensionType() .ultraWarm() && state.getFluidState().is(FluidTags.WATER)) { diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/ghost/GhostBlocks.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/ghost/GhostBlocks.java index 96c2893..6334c95 100644 --- a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/ghost/GhostBlocks.java +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/ghost/GhostBlocks.java @@ -1,6 +1,7 @@ package nl.requios.effortlessbuilding.create.foundation.utility.ghost; import com.mojang.blaze3d.vertex.PoseStack; +import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.create.foundation.render.SuperRenderTypeBuffer; import net.minecraft.util.Mth; import net.minecraft.world.level.block.state.BlockState; 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 3c924c7..01262ab 100644 --- a/src/main/java/nl/requios/effortlessbuilding/gui/buildmode/RadialMenu.java +++ b/src/main/java/nl/requios/effortlessbuilding/gui/buildmode/RadialMenu.java @@ -20,10 +20,9 @@ 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.buildmode.ModeSettingsManager; import nl.requios.effortlessbuilding.network.ModeActionMessage; -import nl.requios.effortlessbuilding.network.ModeSettingsMessage; import nl.requios.effortlessbuilding.network.PacketHandler; import org.apache.commons.lang3.text.WordUtils; import org.lwjgl.opengl.GL11; @@ -33,7 +32,7 @@ import java.util.ArrayList; import static nl.requios.effortlessbuilding.buildmode.ModeOptions.*; -import nl.requios.effortlessbuilding.buildmode.BuildModes.BuildModeEnum; +import nl.requios.effortlessbuilding.buildmode.BuildModeEnum; import nl.requios.effortlessbuilding.buildmode.ModeOptions.ActionEnum; import nl.requios.effortlessbuilding.buildmode.ModeOptions.OptionEnum; @@ -99,7 +98,7 @@ public class RadialMenu extends Screen { @Override public void render(PoseStack ms, final int mouseX, final int mouseY, final float partialTicks) { - BuildModeEnum currentBuildMode = ModeSettingsManager.getModeSettings(minecraft.player).getBuildMode(); + BuildModeEnum currentBuildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode(); ms.pushPose(); ms.translate(0, 0, 200); @@ -450,16 +449,12 @@ public class RadialMenu extends Screen { private void performAction(boolean fromMouseClick) { LocalPlayer player = Minecraft.getInstance().player; - ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); - if (switchTo != null) { playRadialMenuSound(); - modeSettings.setBuildMode(switchTo); - ModeSettingsManager.setModeSettings(player, modeSettings); - PacketHandler.INSTANCE.sendToServer(new ModeSettingsMessage(modeSettings)); + EffortlessBuildingClient.BUILD_MODES.setBuildMode(switchTo); - EffortlessBuilding.log(player, I18n.get(modeSettings.getBuildMode().getNameKey()), true); + 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 d29253d..272f573 100644 --- a/src/main/java/nl/requios/effortlessbuilding/item/AbstractRandomizerBagItem.java +++ b/src/main/java/nl/requios/effortlessbuilding/item/AbstractRandomizerBagItem.java @@ -23,9 +23,8 @@ import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.network.NetworkHooks; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; -import nl.requios.effortlessbuilding.buildmode.BuildModes; -import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; +import nl.requios.effortlessbuilding.systems.ServerBuildState; import nl.requios.effortlessbuilding.capability.ItemHandlerCapabilityProvider; import nl.requios.effortlessbuilding.utilities.SurvivalHelper; @@ -134,9 +133,7 @@ public abstract class AbstractRandomizerBagItem extends Item { if (world.isClientSide) return InteractionResult.SUCCESS; //Only place manually if in normal vanilla mode - BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode(); - ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); - if (buildMode != BuildModes.BuildModeEnum.DISABLED || modifierSettings.doQuickReplace()) { + if (ServerBuildState.isUsingBuildMode(player) || ServerBuildState.isQuickReplacing(player)) { return InteractionResult.FAIL; } diff --git a/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade1Item.java b/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade1Item.java index bd5cf67..4b1868e 100644 --- a/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade1Item.java +++ b/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade1Item.java @@ -40,10 +40,9 @@ public class ReachUpgrade1Item extends Item { return new InteractionResultHolder<>(InteractionResult.PASS, player.getItemInHand(hand)); } - ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); - int currentLevel = modifierSettings.getReachUpgrade(); + int currentLevel = ReachHelper.getReachUpgrade(player); if (currentLevel == 0) { - modifierSettings.setReachUpgrade(1); + ReachHelper.setReachUpgrade(player, 1); if (world.isClientSide) EffortlessBuilding.log(player, "Upgraded reach to " + ReachHelper.getMaxReach(player)); player.setItemInHand(hand, ItemStack.EMPTY); diff --git a/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade2Item.java b/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade2Item.java index 849b64b..8963487 100644 --- a/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade2Item.java +++ b/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade2Item.java @@ -40,10 +40,10 @@ public class ReachUpgrade2Item extends Item { return new InteractionResultHolder<>(InteractionResult.PASS, player.getItemInHand(hand)); } - ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); - int currentLevel = modifierSettings.getReachUpgrade(); + int currentLevel = ReachHelper.getReachUpgrade(player); if (currentLevel == 1) { - modifierSettings.setReachUpgrade(2); + ReachHelper.setReachUpgrade(player, 2); + if (world.isClientSide) EffortlessBuilding.log(player, "Upgraded reach to " + ReachHelper.getMaxReach(player)); player.setItemInHand(hand, ItemStack.EMPTY); diff --git a/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade3Item.java b/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade3Item.java index cb8baed..dd03493 100644 --- a/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade3Item.java +++ b/src/main/java/nl/requios/effortlessbuilding/item/ReachUpgrade3Item.java @@ -40,10 +40,10 @@ public class ReachUpgrade3Item extends Item { return new InteractionResultHolder<>(InteractionResult.PASS, player.getItemInHand(hand)); } - ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); - int currentLevel = modifierSettings.getReachUpgrade(); + int currentLevel = ReachHelper.getReachUpgrade(player); if (currentLevel == 2) { - modifierSettings.setReachUpgrade(3); + ReachHelper.setReachUpgrade(player, 3); + if (world.isClientSide) EffortlessBuilding.log(player, "Upgraded reach to " + ReachHelper.getMaxReach(player)); player.setItemInHand(hand, ItemStack.EMPTY); diff --git a/src/main/java/nl/requios/effortlessbuilding/network/AddUndoMessage.java b/src/main/java/nl/requios/effortlessbuilding/network/AddUndoMessage.java index 21480a1..6e5e21c 100644 --- a/src/main/java/nl/requios/effortlessbuilding/network/AddUndoMessage.java +++ b/src/main/java/nl/requios/effortlessbuilding/network/AddUndoMessage.java @@ -21,6 +21,7 @@ import java.util.function.Supplier; /*** * Sends a message to the client asking to add a block to the undo stack. */ +@Deprecated public class AddUndoMessage { private final BlockPos coordinate; private final BlockState previousBlockState; diff --git a/src/main/java/nl/requios/effortlessbuilding/network/ClearUndoMessage.java b/src/main/java/nl/requios/effortlessbuilding/network/ClearUndoMessage.java index 1358242..c24a00a 100644 --- a/src/main/java/nl/requios/effortlessbuilding/network/ClearUndoMessage.java +++ b/src/main/java/nl/requios/effortlessbuilding/network/ClearUndoMessage.java @@ -15,6 +15,7 @@ import java.util.function.Supplier; /*** * Sends a message to the client asking to clear the undo and redo stacks. */ +@Deprecated public class ClearUndoMessage { public ClearUndoMessage() { diff --git a/src/main/java/nl/requios/effortlessbuilding/network/IsQuickReplacingPacket.java b/src/main/java/nl/requios/effortlessbuilding/network/IsQuickReplacingPacket.java new file mode 100644 index 0000000..a7ee038 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/network/IsQuickReplacingPacket.java @@ -0,0 +1,39 @@ +package nl.requios.effortlessbuilding.network; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.network.NetworkEvent; +import nl.requios.effortlessbuilding.create.foundation.networking.SimplePacketBase; +import nl.requios.effortlessbuilding.systems.ServerBuildState; + +import java.util.function.Supplier; + +/** + * Shares mode settings (see ModeSettingsManager) between server and client + */ +public class IsQuickReplacingPacket { + private boolean isQuickReplacing; + + public IsQuickReplacingPacket() { + } + + public IsQuickReplacingPacket(boolean isQuickReplacing) { + this.isQuickReplacing = isQuickReplacing; + } + + public static void encode(IsQuickReplacingPacket message, FriendlyByteBuf buf) { + buf.writeBoolean(message.isQuickReplacing); + } + + public static IsQuickReplacingPacket decode(FriendlyByteBuf buf) { + return new IsQuickReplacingPacket(buf.readBoolean()); + } + + public static class Handler { + public static void handle(IsQuickReplacingPacket message, Supplier ctx) { + ctx.get().enqueueWork(() -> { + ServerBuildState.setIsQuickReplacing(ctx.get().getSender(), message.isQuickReplacing); + }); + ctx.get().setPacketHandled(true); + } + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/network/IsUsingBuildModePacket.java b/src/main/java/nl/requios/effortlessbuilding/network/IsUsingBuildModePacket.java new file mode 100644 index 0000000..9968cf8 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/network/IsUsingBuildModePacket.java @@ -0,0 +1,39 @@ +package nl.requios.effortlessbuilding.network; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.network.NetworkEvent; + +import java.util.function.Supplier; + +import nl.requios.effortlessbuilding.systems.ServerBuildState; + +/** + * Shares mode settings (see ModeSettingsManager) between server and client + */ +public class IsUsingBuildModePacket { + private boolean isUsingBuildMode; + + public IsUsingBuildModePacket() { + } + + public IsUsingBuildModePacket(boolean isUsingBuildMode) { + this.isUsingBuildMode = isUsingBuildMode; + } + + public static void encode(IsUsingBuildModePacket message, FriendlyByteBuf buf) { + buf.writeBoolean(message.isUsingBuildMode); + } + + public static IsUsingBuildModePacket decode(FriendlyByteBuf buf) { + return new IsUsingBuildModePacket(buf.readBoolean()); + } + + public static class Handler { + public static void handle(IsUsingBuildModePacket message, Supplier ctx) { + ctx.get().enqueueWork(() -> { + ServerBuildState.setIsUsingBuildMode(ctx.get().getSender(), message.isUsingBuildMode); + }); + ctx.get().setPacketHandled(true); + } + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/network/ModeActionMessage.java b/src/main/java/nl/requios/effortlessbuilding/network/ModeActionMessage.java index 41a308f..181ff30 100644 --- a/src/main/java/nl/requios/effortlessbuilding/network/ModeActionMessage.java +++ b/src/main/java/nl/requios/effortlessbuilding/network/ModeActionMessage.java @@ -11,6 +11,7 @@ import java.util.function.Supplier; /** * Shares mode settings (see ModeSettingsManager) between server and client */ +@Deprecated public class ModeActionMessage { private ModeOptions.ActionEnum action; diff --git a/src/main/java/nl/requios/effortlessbuilding/network/ModeSettingsMessage.java b/src/main/java/nl/requios/effortlessbuilding/network/ModeSettingsMessage.java deleted file mode 100644 index a4ae9d2..0000000 --- a/src/main/java/nl/requios/effortlessbuilding/network/ModeSettingsMessage.java +++ /dev/null @@ -1,51 +0,0 @@ -package nl.requios.effortlessbuilding.network; - -import net.minecraft.world.entity.player.Player; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.network.NetworkEvent; -import nl.requios.effortlessbuilding.EffortlessBuilding; -import nl.requios.effortlessbuilding.buildmode.BuildModes; -import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; - -import java.util.function.Supplier; - -import static nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.ModeSettings; - -/** - * Shares mode settings (see ModeSettingsManager) between server and client - */ -public class ModeSettingsMessage { - - private ModeSettings modeSettings; - - public ModeSettingsMessage() { - } - - public ModeSettingsMessage(ModeSettings modeSettings) { - this.modeSettings = modeSettings; - } - - public static void encode(ModeSettingsMessage message, FriendlyByteBuf buf) { - buf.writeInt(message.modeSettings.getBuildMode().ordinal()); - } - - public static ModeSettingsMessage decode(FriendlyByteBuf buf) { - BuildModes.BuildModeEnum buildMode = BuildModes.BuildModeEnum.values()[buf.readInt()]; - - return new ModeSettingsMessage(new ModeSettings(buildMode)); - } - - public static class Handler { - public static void handle(ModeSettingsMessage message, Supplier ctx) { - ctx.get().enqueueWork(() -> { - Player player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx); - - // Sanitize - ModeSettingsManager.sanitize(message.modeSettings, player); - - ModeSettingsManager.setModeSettings(player, message.modeSettings); - }); - ctx.get().setPacketHandled(true); - } - } -} diff --git a/src/main/java/nl/requios/effortlessbuilding/network/ModifierSettingsMessage.java b/src/main/java/nl/requios/effortlessbuilding/network/ModifierSettingsMessage.java index 9aaea50..56ca0c1 100644 --- a/src/main/java/nl/requios/effortlessbuilding/network/ModifierSettingsMessage.java +++ b/src/main/java/nl/requios/effortlessbuilding/network/ModifierSettingsMessage.java @@ -57,10 +57,6 @@ public class ModifierSettingsMessage { buf.writeInt(a.count); } - buf.writeBoolean(message.modifierSettings.doQuickReplace()); - - buf.writeInt(message.modifierSettings.getReachUpgrade()); - //RADIAL MIRROR RadialMirror.RadialMirrorSettings r = message.modifierSettings.getRadialMirrorSettings(); buf.writeBoolean(r != null); @@ -102,10 +98,6 @@ public class ModifierSettingsMessage { a = new Array.ArraySettings(arrayEnabled, arrayOffset, arrayCount); } - boolean quickReplace = buf.readBoolean(); - - int reachUpgrade = buf.readInt(); - //RADIAL MIRROR RadialMirror.RadialMirrorSettings r = new RadialMirror.RadialMirrorSettings(); if (buf.readBoolean()) { @@ -120,7 +112,7 @@ public class ModifierSettingsMessage { radialMirrorAlternate, radialMirrorRadius, radialMirrorDrawLines, radialMirrorDrawPlanes); } - ModifierSettings modifierSettings = new ModifierSettings(m, a, r, quickReplace, reachUpgrade); + ModifierSettings modifierSettings = new ModifierSettings(m, a, r); return new ModifierSettingsMessage(modifierSettings); } diff --git a/src/main/java/nl/requios/effortlessbuilding/network/OnBlockPlacedMessage.java b/src/main/java/nl/requios/effortlessbuilding/network/OnBlockPlacedMessage.java deleted file mode 100644 index 4b83130..0000000 --- a/src/main/java/nl/requios/effortlessbuilding/network/OnBlockPlacedMessage.java +++ /dev/null @@ -1,49 +0,0 @@ -package nl.requios.effortlessbuilding.network; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.fml.LogicalSide; -import net.minecraftforge.network.NetworkEvent; -import nl.requios.effortlessbuilding.EffortlessBuildingClient; - -import java.util.function.Supplier; - -/*** - * Sends a message to the client indicating that a block has been placed. - * Necessary because Forge's onBlockPlaced event is only called on the server. - */ -public class OnBlockPlacedMessage { - - public OnBlockPlacedMessage() { - } - - public static void encode(OnBlockPlacedMessage message, FriendlyByteBuf buf) { - - } - - public static OnBlockPlacedMessage decode(FriendlyByteBuf buf) { - return new OnBlockPlacedMessage(); - } - - public static class Handler { - public static void handle(OnBlockPlacedMessage message, Supplier ctx) { - ctx.get().enqueueWork(() -> { - if (ctx.get().getDirection().getReceptionSide() == LogicalSide.CLIENT) { - //Received clientside - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ClientHandler.handle(message, ctx)); - } - }); - ctx.get().setPacketHandled(true); - } - } - - @OnlyIn(Dist.CLIENT) - public static class ClientHandler { - public static void handle(OnBlockPlacedMessage message, Supplier ctx) { - - EffortlessBuildingClient.BUILDER_CHAIN.onRightClick(); - } - } -} diff --git a/src/main/java/nl/requios/effortlessbuilding/network/PacketHandler.java b/src/main/java/nl/requios/effortlessbuilding/network/PacketHandler.java index 672ae02..9729862 100644 --- a/src/main/java/nl/requios/effortlessbuilding/network/PacketHandler.java +++ b/src/main/java/nl/requios/effortlessbuilding/network/PacketHandler.java @@ -1,10 +1,13 @@ package nl.requios.effortlessbuilding.network; import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.network.NetworkDirection; import net.minecraftforge.network.NetworkRegistry; import net.minecraftforge.network.simple.SimpleChannel; import nl.requios.effortlessbuilding.EffortlessBuilding; +import java.util.Optional; + public class PacketHandler { private static final String PROTOCOL_VERSION = "1"; public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel( @@ -17,14 +20,22 @@ public class PacketHandler { public static void register() { int id = 0; - INSTANCE.registerMessage(id++, ModifierSettingsMessage.class, ModifierSettingsMessage::encode, ModifierSettingsMessage::decode, ModifierSettingsMessage.Handler::handle); - INSTANCE.registerMessage(id++, ModeSettingsMessage.class, ModeSettingsMessage::encode, ModeSettingsMessage::decode, ModeSettingsMessage.Handler::handle); - INSTANCE.registerMessage(id++, ModeActionMessage.class, ModeActionMessage::encode, ModeActionMessage::decode, ModeActionMessage.Handler::handle); - INSTANCE.registerMessage(id++, OnBlockPlacedMessage.class, OnBlockPlacedMessage::encode, OnBlockPlacedMessage::decode, OnBlockPlacedMessage.Handler::handle); - INSTANCE.registerMessage(id++, AddUndoMessage.class, AddUndoMessage::encode, AddUndoMessage::decode, AddUndoMessage.Handler::handle); - INSTANCE.registerMessage(id++, ClearUndoMessage.class, ClearUndoMessage::encode, ClearUndoMessage::decode, ClearUndoMessage.Handler::handle); - INSTANCE.registerMessage(id++, ServerPlaceBlocksMessage.class, ServerPlaceBlocksMessage::encode, ServerPlaceBlocksMessage::decode, ServerPlaceBlocksMessage.Handler::handle); - + INSTANCE.registerMessage(id++, IsUsingBuildModePacket.class, IsUsingBuildModePacket::encode, IsUsingBuildModePacket::decode, + IsUsingBuildModePacket.Handler::handle, Optional.of(NetworkDirection.PLAY_TO_SERVER)); + INSTANCE.registerMessage(id++, IsQuickReplacingPacket.class, IsQuickReplacingPacket::encode, IsQuickReplacingPacket::decode, + IsQuickReplacingPacket.Handler::handle, Optional.of(NetworkDirection.PLAY_TO_SERVER)); + INSTANCE.registerMessage(id++, ModifierSettingsMessage.class, ModifierSettingsMessage::encode, ModifierSettingsMessage::decode, + ModifierSettingsMessage.Handler::handle); + INSTANCE.registerMessage(id++, ModeActionMessage.class, ModeActionMessage::encode, ModeActionMessage::decode, + ModeActionMessage.Handler::handle); + INSTANCE.registerMessage(id++, ServerPlaceBlocksPacket.class, ServerPlaceBlocksPacket::encode, ServerPlaceBlocksPacket::decode, + ServerPlaceBlocksPacket.Handler::handle, Optional.of(NetworkDirection.PLAY_TO_SERVER)); + INSTANCE.registerMessage(id++, ServerBreakBlocksPacket.class, ServerBreakBlocksPacket::encode, ServerBreakBlocksPacket::decode, + ServerBreakBlocksPacket.Handler::handle, Optional.of(NetworkDirection.PLAY_TO_SERVER)); + INSTANCE.registerMessage(id++, AddUndoMessage.class, AddUndoMessage::encode, AddUndoMessage::decode, + AddUndoMessage.Handler::handle); + INSTANCE.registerMessage(id++, ClearUndoMessage.class, ClearUndoMessage::encode, ClearUndoMessage::decode, + ClearUndoMessage.Handler::handle); } } diff --git a/src/main/java/nl/requios/effortlessbuilding/network/ServerBreakBlocksPacket.java b/src/main/java/nl/requios/effortlessbuilding/network/ServerBreakBlocksPacket.java new file mode 100644 index 0000000..25bc353 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/network/ServerBreakBlocksPacket.java @@ -0,0 +1,46 @@ +package nl.requios.effortlessbuilding.network; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Player; +import net.minecraftforge.network.NetworkEvent; +import nl.requios.effortlessbuilding.EffortlessBuilding; +import nl.requios.effortlessbuilding.utilities.BlockEntry; + +import java.util.List; +import java.util.function.Supplier; + +/** + * Sends a message to the server to break multiple blocks + */ +public class ServerBreakBlocksPacket { + + private List blocks; + + public ServerBreakBlocksPacket() {} + + public ServerBreakBlocksPacket(List blocks) { + this.blocks = blocks; + } + + public static void encode(ServerBreakBlocksPacket message, FriendlyByteBuf buf) { + buf.writeCollection(message.blocks, BlockEntry::encode); + } + + public static ServerBreakBlocksPacket decode(FriendlyByteBuf buf) { + ServerBreakBlocksPacket message = new ServerBreakBlocksPacket(); + message.blocks = buf.readList(BlockEntry::decode); + return message; + } + + + public static class Handler { + public static void handle(ServerBreakBlocksPacket message, Supplier ctx) { + ctx.get().enqueueWork(() -> { + Player player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx); + + EffortlessBuilding.SERVER_BLOCK_PLACER.breakBlocks(player, message.blocks); + }); + ctx.get().setPacketHandled(true); + } + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/network/ServerPlaceBlocksMessage.java b/src/main/java/nl/requios/effortlessbuilding/network/ServerPlaceBlocksPacket.java similarity index 64% rename from src/main/java/nl/requios/effortlessbuilding/network/ServerPlaceBlocksMessage.java rename to src/main/java/nl/requios/effortlessbuilding/network/ServerPlaceBlocksPacket.java index c134868..03633c2 100644 --- a/src/main/java/nl/requios/effortlessbuilding/network/ServerPlaceBlocksMessage.java +++ b/src/main/java/nl/requios/effortlessbuilding/network/ServerPlaceBlocksPacket.java @@ -1,6 +1,5 @@ package nl.requios.effortlessbuilding.network; -import net.minecraft.nbt.NbtUtils; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.entity.player.Player; import net.minecraftforge.network.NetworkEvent; @@ -13,29 +12,29 @@ import java.util.function.Supplier; /** * Sends a message to the server to place multiple blocks */ -public class ServerPlaceBlocksMessage { +public class ServerPlaceBlocksPacket { private List blocks; - public ServerPlaceBlocksMessage() {} + public ServerPlaceBlocksPacket() {} - public ServerPlaceBlocksMessage(List blocks) { + public ServerPlaceBlocksPacket(List blocks) { this.blocks = blocks; } - public static void encode(ServerPlaceBlocksMessage message, FriendlyByteBuf buf) { + public static void encode(ServerPlaceBlocksPacket message, FriendlyByteBuf buf) { buf.writeCollection(message.blocks, BlockEntry::encode); } - public static ServerPlaceBlocksMessage decode(FriendlyByteBuf buf) { - ServerPlaceBlocksMessage message = new ServerPlaceBlocksMessage(); + public static ServerPlaceBlocksPacket decode(FriendlyByteBuf buf) { + ServerPlaceBlocksPacket message = new ServerPlaceBlocksPacket(); message.blocks = buf.readList(BlockEntry::decode); return message; } public static class Handler { - public static void handle(ServerPlaceBlocksMessage message, Supplier ctx) { + public static void handle(ServerPlaceBlocksPacket message, Supplier ctx) { ctx.get().enqueueWork(() -> { Player player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx); diff --git a/src/main/java/nl/requios/effortlessbuilding/network/TranslatedLogMessage.java b/src/main/java/nl/requios/effortlessbuilding/network/TranslatedLogPacket.java similarity index 75% rename from src/main/java/nl/requios/effortlessbuilding/network/TranslatedLogMessage.java rename to src/main/java/nl/requios/effortlessbuilding/network/TranslatedLogPacket.java index a127298..e22dcc5 100644 --- a/src/main/java/nl/requios/effortlessbuilding/network/TranslatedLogMessage.java +++ b/src/main/java/nl/requios/effortlessbuilding/network/TranslatedLogPacket.java @@ -11,35 +11,35 @@ import java.util.function.Supplier; /** * Send packet to client to translate and log the containing message */ -public class TranslatedLogMessage { +public class TranslatedLogPacket { private final String prefix; private final String translationKey; private final String suffix; private final boolean actionBar; - public TranslatedLogMessage() { + public TranslatedLogPacket() { prefix = ""; translationKey = ""; suffix = ""; actionBar = false; } - public TranslatedLogMessage(String prefix, String translationKey, String suffix, boolean actionBar) { + public TranslatedLogPacket(String prefix, String translationKey, String suffix, boolean actionBar) { this.prefix = prefix; this.translationKey = translationKey; this.suffix = suffix; this.actionBar = actionBar; } - public static void encode(TranslatedLogMessage message, FriendlyByteBuf buf) { + public static void encode(TranslatedLogPacket message, FriendlyByteBuf buf) { buf.writeUtf(message.prefix); buf.writeUtf(message.translationKey); buf.writeUtf(message.suffix); buf.writeBoolean(message.actionBar); } - public static TranslatedLogMessage decode(FriendlyByteBuf buf) { - return new TranslatedLogMessage(buf.readUtf(), buf.readUtf(), buf.readUtf(), buf.readBoolean()); + public static TranslatedLogPacket decode(FriendlyByteBuf buf) { + return new TranslatedLogPacket(buf.readUtf(), buf.readUtf(), buf.readUtf(), buf.readBoolean()); } public String getPrefix() { @@ -59,7 +59,7 @@ public class TranslatedLogMessage { } public static class Handler { - public static void handle(TranslatedLogMessage message, Supplier ctx) { + public static void handle(TranslatedLogPacket message, Supplier ctx) { ctx.get().enqueueWork(() -> { if (ctx.get().getDirection().getReceptionSide() == LogicalSide.CLIENT) { //Received clientside diff --git a/src/main/java/nl/requios/effortlessbuilding/proxy/ServerProxy.java b/src/main/java/nl/requios/effortlessbuilding/proxy/ServerProxy.java index 71f6024..be21683 100644 --- a/src/main/java/nl/requios/effortlessbuilding/proxy/ServerProxy.java +++ b/src/main/java/nl/requios/effortlessbuilding/proxy/ServerProxy.java @@ -5,7 +5,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraftforge.network.NetworkEvent; import net.minecraftforge.network.PacketDistributor; import nl.requios.effortlessbuilding.network.PacketHandler; -import nl.requios.effortlessbuilding.network.TranslatedLogMessage; +import nl.requios.effortlessbuilding.network.TranslatedLogPacket; import java.util.function.Supplier; @@ -17,6 +17,6 @@ public class ServerProxy implements IProxy { } public void logTranslate(Player player, String prefix, String translationKey, String suffix, boolean actionBar) { - PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new TranslatedLogMessage(prefix, translationKey, suffix, actionBar)); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new TranslatedLogPacket(prefix, translationKey, suffix, actionBar)); } } diff --git a/src/main/java/nl/requios/effortlessbuilding/render/BlockPreviews.java b/src/main/java/nl/requios/effortlessbuilding/render/BlockPreviews.java index 573ab6c..51a3170 100644 --- a/src/main/java/nl/requios/effortlessbuilding/render/BlockPreviews.java +++ b/src/main/java/nl/requios/effortlessbuilding/render/BlockPreviews.java @@ -1,13 +1,12 @@ package nl.requios.effortlessbuilding.render; -import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraft.core.Direction; -import net.minecraft.sounds.SoundSource; import net.minecraft.core.BlockPos; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.util.Mth; @@ -15,208 +14,136 @@ 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.ClientConfig; -import nl.requios.effortlessbuilding.ClientEvents; -import nl.requios.effortlessbuilding.CommonConfig; -import nl.requios.effortlessbuilding.EffortlessBuilding; -import nl.requios.effortlessbuilding.buildmode.BuildModes; -import nl.requios.effortlessbuilding.buildmode.IBuildMode; -import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; +import nl.requios.effortlessbuilding.*; +import nl.requios.effortlessbuilding.buildmode.BuildModeEnum; import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; -import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; -import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.ModifierSettings; import nl.requios.effortlessbuilding.compatibility.CompatHelper; import nl.requios.effortlessbuilding.create.AllSpecialTextures; import nl.requios.effortlessbuilding.create.CreateClient; import nl.requios.effortlessbuilding.create.foundation.utility.Color; +import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem; +import nl.requios.effortlessbuilding.systems.BuilderChain; +import nl.requios.effortlessbuilding.utilities.BlockEntry; import nl.requios.effortlessbuilding.utilities.ReachHelper; import nl.requios.effortlessbuilding.utilities.SurvivalHelper; -import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import static nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.ModeSettings; - @OnlyIn(Dist.CLIENT) public class BlockPreviews { - private static final List placedDataList = new ArrayList<>(); - private static List previousCoordinates; - private static List previousBlockStates; - private static List previousItemStacks; - private static BlockPos previousFirstPos; - private static BlockPos previousSecondPos; - private static int soundTime = 0; + private final List placedBlocksList = new ArrayList<>(); - public static void drawPlacedBlocks(Player player, ModifierSettings modifierSettings) { + public void onTick() { + var player = Minecraft.getInstance().player; + + drawPlacedBlocks(player); + drawLookAtPreview(player); + drawOutlinesIfNoBlockInHand(player); + } + + public void drawPlacedBlocks(Player player) { //Render placed blocks with appear animation if (ClientConfig.visuals.showBlockPreviews.get()) { - for (PlacedData placed : placedDataList) { - if (placed.coordinates != null && !placed.coordinates.isEmpty()) { + for (PlacedBlocksEntry placed : placedBlocksList) { - int totalTime = placed.breaking ? CommonConfig.visuals.breakAnimationLength.get() : CommonConfig.visuals.appearAnimationLength.get(); - if (totalTime <= 0) continue; + int totalTime = placed.breaking ? CommonConfig.visuals.breakAnimationLength.get() : CommonConfig.visuals.appearAnimationLength.get(); + if (totalTime <= 0) continue; - float dissolve = (ClientEvents.ticksInGame - placed.time) / (float) totalTime; - renderBlockPreviews(player, modifierSettings, placed.coordinates, placed.blockStates, placed.itemStacks, dissolve, placed.firstPos, placed.secondPos, false, placed.breaking); - } + float dissolve = (ClientEvents.ticksInGame - placed.time) / (float) totalTime; + renderBlockPreviews(placed.blocks, placed.breaking, dissolve); } } //Expire - placedDataList.removeIf(placed -> { + placedBlocksList.removeIf(placed -> { int totalTime = placed.breaking ? CommonConfig.visuals.breakAnimationLength.get() : CommonConfig.visuals.appearAnimationLength.get(); return placed.time + totalTime < ClientEvents.ticksInGame; }); } - public static void drawLookAtPreview(Player player, ModeSettings modeSettings, ModifierSettings modifierSettings, BlockPos startPos, Direction sideHit, Vec3 hitVec) { -// if (!doShowBlockPreviews(modifierSettings, modeSettings, startPos)) return; -// -// //Keep blockstate the same for every block in the buildmode -// //So dont rotate blocks when in the middle of placing wall etc. -// if (BuildModes.isActive(player)) { -// IBuildMode buildModeInstance = modeSettings.getBuildMode().instance; -// if (buildModeInstance.getSideHit(player) != null) sideHit = buildModeInstance.getSideHit(player); -// if (buildModeInstance.getHitVec(player) != null) hitVec = buildModeInstance.getHitVec(player); -// } -// -// if (sideHit == null) return; -// -// //Should be red? -// boolean breaking = BuildModes.currentlyBreakingClient.get(player) != null && BuildModes.currentlyBreakingClient.get(player); -// -// //get coordinates -// List startCoordinates = BuildModes.findCoordinates(player, startPos, breaking || modifierSettings.doQuickReplace()); -// -// //Remember first and last point for the shader -// BlockPos firstPos = BlockPos.ZERO, secondPos = BlockPos.ZERO; -// if (!startCoordinates.isEmpty()) { -// firstPos = startCoordinates.get(0); -// secondPos = startCoordinates.get(startCoordinates.size() - 1); -// } -// -// //Limit number of blocks you can place -// int limit = ReachHelper.getMaxBlocksPlacedAtOnce(player); -// if (startCoordinates.size() > limit) { -// startCoordinates = startCoordinates.subList(0, limit); -// } -// -// List newCoordinates = BuildModifiers.findCoordinates(player, startCoordinates); -// -// sortOnDistanceToPlayer(newCoordinates, player); -// -// hitVec = new Vec3(Math.abs(hitVec.x - ((int) hitVec.x)), Math.abs(hitVec.y - ((int) hitVec.y)), -// Math.abs(hitVec.z - ((int) hitVec.z))); -// -// //Get blockstates -// List itemStacks = new ArrayList<>(); -// List blockStates = new ArrayList<>(); -// if (breaking) { -// //Find blockstate of world -// for (BlockPos coordinate : newCoordinates) { -// blockStates.add(player.level.getBlockState(coordinate)); -// } -// } else { -// blockStates = BuildModifiers.findBlockStates(player, startCoordinates, hitVec, sideHit, itemStacks); -// } -// -// -// //Check if they are different from previous -// //TODO fix triggering when moving player -// if (!BuildModifiers.compareCoordinates(previousCoordinates, newCoordinates)) { -// previousCoordinates = newCoordinates; -// //remember the rest for placed blocks -// previousBlockStates = blockStates; -// previousItemStacks = itemStacks; -// previousFirstPos = firstPos; -// previousSecondPos = secondPos; -// -// //if so, renew randomness of randomizer bag -// AbstractRandomizerBagItem.renewRandomness(); -// //and play sound (max once every tick) -// if (newCoordinates.size() > 1 && blockStates.size() > 1 && soundTime < ClientEvents.ticksInGame - 0) { -// soundTime = ClientEvents.ticksInGame; -// -// if (blockStates.get(0) != null) { -// SoundType soundType = blockStates.get(0).getBlock().getSoundType(blockStates.get(0), player.level, -// newCoordinates.get(0), player); -// player.level.playSound(player, player.blockPosition(), breaking ? soundType.getBreakSound() : soundType.getPlaceSound(), -// SoundSource.BLOCKS, 0.3f, 0.8f); -// } -// } -// } -// -// if (blockStates.size() == 0 || newCoordinates.size() != blockStates.size()) return; -// -// int blockCount; -// -// Object outlineID = firstPos; -// //Dont fade out the outline if we are still determining where to place -// //Every outline with same ID will not fade out (because it gets replaced) -// if (newCoordinates.size() == 1 || BuildModifiers.isEnabled(modifierSettings, firstPos)) outlineID = "single"; -// -// if (!breaking) { -// //Use fancy shader if config allows, otherwise outlines -// if (ClientConfig.visuals.showBlockPreviews.get() && newCoordinates.size() < ClientConfig.visuals.maxBlockPreviews.get()) { -// blockCount = renderBlockPreviews(player, modifierSettings, newCoordinates, blockStates, itemStacks, 0f, firstPos, secondPos, !breaking, breaking); -// -// CreateClient.OUTLINER.showCluster(outlineID, newCoordinates) -// .withFaceTexture(AllSpecialTextures.CHECKERED) -// .disableNormals() -// .lineWidth(1 / 32f) -// .colored(new Color(1f, 1f, 1f, 1f)); -// } else { -// //Thicker outline without block previews -// CreateClient.OUTLINER.showCluster(outlineID, newCoordinates) -// .withFaceTexture(AllSpecialTextures.HIGHLIGHT_CHECKERED) -// .disableNormals() -// .lineWidth(1 / 16f) -// .colored(new Color(1f, 1f, 1f, 1f)); -// -// blockCount = newCoordinates.size(); -// } -// -// } else { -// //Breaking -// CreateClient.OUTLINER.showCluster(outlineID, newCoordinates) -// .withFaceTexture(AllSpecialTextures.THIN_CHECKERED) -// .disableNormals() -// .lineWidth(1 / 16f) -// .colored(new Color(0.8f, 0.1f, 0.1f, 1f)); -// blockCount = newCoordinates.size(); -// } -// -// //Display block count and dimensions in actionbar -// if (BuildModes.isActive(player)) { -// -// //Find min and max values (not simply firstPos and secondPos because that doesn't work with circles) -// int minX = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE; -// int minY = Integer.MAX_VALUE, maxY = Integer.MIN_VALUE; -// int minZ = Integer.MAX_VALUE, maxZ = Integer.MIN_VALUE; -// for (BlockPos pos : startCoordinates) { -// if (pos.getX() < minX) minX = pos.getX(); -// if (pos.getX() > maxX) maxX = pos.getX(); -// if (pos.getY() < minY) minY = pos.getY(); -// if (pos.getY() > maxY) maxY = pos.getY(); -// if (pos.getZ() < minZ) minZ = pos.getZ(); -// if (pos.getZ() > maxZ) maxZ = pos.getZ(); -// } -// BlockPos dim = new BlockPos(maxX - minX + 1, maxY - minY + 1, maxZ - minZ + 1); -// -// String dimensions = "("; -// if (dim.getX() > 1) dimensions += dim.getX() + "x"; -// if (dim.getZ() > 1) dimensions += dim.getZ() + "x"; -// if (dim.getY() > 1) dimensions += dim.getY() + "x"; -// dimensions = dimensions.substring(0, dimensions.length() - 1); -// if (dimensions.length() > 1) dimensions += ")"; -// -// EffortlessBuilding.log(player, blockCount + " blocks " + dimensions, true); -// } + public void drawLookAtPreview(Player player) { + if (EffortlessBuildingClient.BUILD_MODES.getBuildMode() == BuildModeEnum.DISABLED && + !ClientConfig.visuals.alwaysShowBlockPreview.get()) return; + + var blocks = EffortlessBuildingClient.BUILDER_CHAIN.getBlocks(); + var state = EffortlessBuildingClient.BUILDER_CHAIN.getState(); + + if (blocks.size() == 0) return; + + var coordinates = blocks.stream().map(block -> block.blockPos).toList(); + + //Dont fade out the outline if we are still determining where to place + //Every outline with same ID will not fade out (because it gets replaced) + Object outlineID = "single"; + if (blocks.size() > 1) outlineID = blocks.get(0).blockPos; + + if (state != BuilderChain.State.BREAKING) { + //Use fancy shader if config allows, otherwise outlines + if (ClientConfig.visuals.showBlockPreviews.get() && blocks.size() < ClientConfig.visuals.maxBlockPreviews.get()) { + renderBlockPreviews(blocks, false, 0f); + + CreateClient.OUTLINER.showCluster(outlineID, coordinates) + .withFaceTexture(AllSpecialTextures.CHECKERED) + .disableNormals() + .lineWidth(1 / 32f) + .colored(new Color(1f, 1f, 1f, 1f)); + } else { + //Thicker outline without block previews + CreateClient.OUTLINER.showCluster(outlineID, coordinates) + .withFaceTexture(AllSpecialTextures.HIGHLIGHT_CHECKERED) + .disableNormals() + .lineWidth(1 / 16f) + .colored(new Color(1f, 1f, 1f, 1f)); + } + + } else { + //Breaking + CreateClient.OUTLINER.showCluster(outlineID, coordinates) + .withFaceTexture(AllSpecialTextures.THIN_CHECKERED) + .disableNormals() + .lineWidth(1 / 16f) + .colored(new Color(0.8f, 0.1f, 0.1f, 1f)); + } + + //Display block count and dimensions in actionbar + if (state != BuilderChain.State.IDLE) { + + //Find min and max values (not simply firstPos and secondPos because that doesn't work with circles) + int minX = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE; + int minY = Integer.MAX_VALUE, maxY = Integer.MIN_VALUE; + int minZ = Integer.MAX_VALUE, maxZ = Integer.MIN_VALUE; + for (BlockPos pos : coordinates) { + if (pos.getX() < minX) minX = pos.getX(); + if (pos.getX() > maxX) maxX = pos.getX(); + if (pos.getY() < minY) minY = pos.getY(); + if (pos.getY() > maxY) maxY = pos.getY(); + if (pos.getZ() < minZ) minZ = pos.getZ(); + if (pos.getZ() > maxZ) maxZ = pos.getZ(); + } + BlockPos dim = new BlockPos(maxX - minX + 1, maxY - minY + 1, maxZ - minZ + 1); + + String dimensions = "("; + if (dim.getX() > 1) dimensions += dim.getX() + "x"; + if (dim.getZ() > 1) dimensions += dim.getZ() + "x"; + if (dim.getY() > 1) dimensions += dim.getY() + "x"; + dimensions = dimensions.substring(0, dimensions.length() - 1); + if (dimensions.length() > 1) dimensions += ")"; + + EffortlessBuilding.log(player, blocks.size() + " blocks " + dimensions, true); + } } - public static void drawOutlinesIfNoBlockInHand(Player player, HitResult lookingAt) { + public void drawOutlinesIfNoBlockInHand(Player player) { + ItemStack mainhand = player.getMainHandItem(); + HitResult lookingAt = ClientEvents.getLookingAt(player); + if (EffortlessBuildingClient.BUILD_MODES.getBuildMode() == BuildModeEnum.DISABLED) + lookingAt = Minecraft.getInstance().hitResult; + + boolean noBlockInHand = !(!mainhand.isEmpty() && CompatHelper.isItemBlockProxy(mainhand)); + if (!noBlockInHand) return; + //Draw outlines if no block in hand //Find proper raytrace: either normal range or increased range depending on canBreakFar HitResult objectMouseOver = Minecraft.getInstance().hitResult; @@ -245,58 +172,35 @@ public class BlockPreviews { } } - //Whether to draw any block previews or outlines - public static boolean doShowBlockPreviews(ModifierSettings modifierSettings, ModeSettings modeSettings, BlockPos startPos) { - if (!ClientConfig.visuals.showBlockPreviews.get()) return false; - return modeSettings.getBuildMode() != BuildModes.BuildModeEnum.DISABLED || - (startPos != null && BuildModifiers.isEnabled(modifierSettings, startPos)) || - ClientConfig.visuals.alwaysShowBlockPreview.get(); - } + protected void renderBlockPreviews(List blocks, boolean breaking, float dissolve) { - protected static int renderBlockPreviews(Player player, ModifierSettings modifierSettings, List coordinates, - List blockStates, List itemStacks, float dissolve, - BlockPos firstPos, BlockPos secondPos, boolean checkCanPlace, boolean red) { - int blocksValid = 0; + var firstPos = blocks.get(0).blockPos; + var lastPos = blocks.get(blocks.size() - 1).blockPos; - if (coordinates.isEmpty()) return blocksValid; - - for (int i = coordinates.size() - 1; i >= 0; i--) { - BlockPos blockPos = coordinates.get(i); - BlockState blockState = blockStates.get(i); - ItemStack itemstack = itemStacks.isEmpty() ? ItemStack.EMPTY : itemStacks.get(i); - if (CompatHelper.isItemBlockProxy(itemstack)) - itemstack = CompatHelper.getItemBlockByState(itemstack, blockState); - - //Check if we can place - boolean canPlace = true; - if (checkCanPlace) { - canPlace = SurvivalHelper.canPlace(player.level, player, blockPos, blockState, itemstack, modifierSettings.doQuickReplace()); - } else { - //If check is turned off, check if blockstate is the same (for dissolve effect) - canPlace = player.level.getBlockState(blockPos) != blockState; - } - - if (canPlace) { - renderBlockPreview(blockPos, blockState, dissolve, firstPos, secondPos, red); - blocksValid++; - } + for (BlockEntry blockEntry : blocks) { + renderBlockPreview(blockEntry, breaking, dissolve, firstPos, lastPos); } - return blocksValid; } - protected static void renderBlockPreview(BlockPos blockPos, BlockState blockState, float dissolve, BlockPos firstPos, BlockPos secondPos, boolean breaking) { - if (blockState == null) return; + protected void renderBlockPreview(BlockEntry blockEntry, boolean breaking, float dissolve, BlockPos firstPos, BlockPos lastPos) { + if (blockEntry.blockState == null) return; + + var blockPos = blockEntry.blockPos; + var blockState = blockEntry.blockState; + if (breaking) { + blockState = Minecraft.getInstance().level.getBlockState(blockPos); + } float scale = 0.5f; float alpha = 0.7f; if (dissolve > 0f) { float animationLength = 0.8f; - double firstToSecond = secondPos.distSqr(firstPos); + double firstToSecond = lastPos.distSqr(firstPos); double place = 0; if (firstToSecond > 0.5) { double placeFromFirst = firstPos.distSqr(blockPos) / firstToSecond; - double placeFromSecond = secondPos.distSqr(blockPos) / firstToSecond; + double placeFromSecond = lastPos.distSqr(blockPos) / firstToSecond; place = (placeFromFirst + (1.0 - placeFromSecond)) / 2.0; } //else only one block @@ -328,7 +232,7 @@ public class BlockPreviews { } //A bezier easing function where implicit first and last control points are (0,0) and (1,1). - public static double bezier(double t, double x1, double y1, double x2, double y2) { + public double bezier(double t, double x1, double y1, double x2, double y2) { double t2 = t * t; double t3 = t2 * t; @@ -344,61 +248,25 @@ public class BlockPreviews { return (ay * t3) + (by * t2) + (cy * t) + 0; } - public static void onBlocksPlaced() { - onBlocksPlaced(previousCoordinates, previousItemStacks, previousBlockStates, previousFirstPos, previousSecondPos); + public void onBlocksPlaced(List blocks) { + if (!ClientConfig.visuals.showBlockPreviews.get()) return; + if (blocks.size() <= 1 || blocks.size() > ClientConfig.visuals.maxBlockPreviews.get()) return; + + placedBlocksList.add(new PlacedBlocksEntry(ClientEvents.ticksInGame, false, blocks)); + + CreateClient.OUTLINER.keep(blocks.get(0).blockPos, CommonConfig.visuals.appearAnimationLength.get()); } - public static void onBlocksPlaced(List coordinates, List itemStacks, List blockStates, - BlockPos firstPos, BlockPos secondPos) { - LocalPlayer player = Minecraft.getInstance().player; - ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); - ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); + public void onBlocksBroken(List blocks) { + if (!ClientConfig.visuals.showBlockPreviews.get()) return; + if (blocks.size() <= 1 || blocks.size() > ClientConfig.visuals.maxBlockPreviews.get()) return; - //Check if block previews are enabled - if (doShowBlockPreviews(modifierSettings, modeSettings, firstPos)) { - - //Save current coordinates, blockstates and itemstacks - if (!coordinates.isEmpty() && blockStates.size() == coordinates.size() && - coordinates.size() > 1 && coordinates.size() < ClientConfig.visuals.maxBlockPreviews.get()) { - - placedDataList.add(new PlacedData(ClientEvents.ticksInGame, coordinates, blockStates, - itemStacks, firstPos, secondPos, false)); - } - - CreateClient.OUTLINER.keep(firstPos, CommonConfig.visuals.appearAnimationLength.get()); - } + placedBlocksList.add(new PlacedBlocksEntry(ClientEvents.ticksInGame, true, blocks)); + CreateClient.OUTLINER.keep(blocks.get(0).blockPos, CommonConfig.visuals.breakAnimationLength.get()); } - public static void onBlocksBroken() { - onBlocksBroken(previousCoordinates, previousItemStacks, previousBlockStates, previousFirstPos, previousSecondPos); - } - - public static void onBlocksBroken(List coordinates, List itemStacks, List blockStates, - BlockPos firstPos, BlockPos secondPos) { - LocalPlayer player = Minecraft.getInstance().player; - ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); - ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); - - //Check if block previews are enabled - if (doShowBlockPreviews(modifierSettings, modeSettings, firstPos)) { - - //Save current coordinates, blockstates and itemstacks - if (!coordinates.isEmpty() && blockStates.size() == coordinates.size() && - coordinates.size() > 1 && coordinates.size() < ClientConfig.visuals.maxBlockPreviews.get()) { - - sortOnDistanceToPlayer(coordinates, player); - - placedDataList.add(new PlacedData(ClientEvents.ticksInGame, coordinates, blockStates, - itemStacks, firstPos, secondPos, true)); - } - - CreateClient.OUTLINER.keep(firstPos, CommonConfig.visuals.breakAnimationLength.get()); - } - - } - - private static void sortOnDistanceToPlayer(List coordinates, Player player) { + private void sortOnDistanceToPlayer(List coordinates, Player player) { Collections.sort(coordinates, (lhs, rhs) -> { // -1 - less than, 1 - greater than, 0 - equal @@ -409,24 +277,15 @@ public class BlockPreviews { } - static class PlacedData { + public static class PlacedBlocksEntry { float time; - List coordinates; - List blockStates; - List itemStacks; - BlockPos firstPos; - BlockPos secondPos; boolean breaking; + List blocks; - public PlacedData(float time, List coordinates, List blockStates, - List itemStacks, BlockPos firstPos, BlockPos secondPos, boolean breaking) { + public PlacedBlocksEntry(float time, boolean breaking, List blocks) { this.time = time; - this.coordinates = coordinates; - this.blockStates = blockStates; - this.itemStacks = itemStacks; - this.firstPos = firstPos; - this.secondPos = secondPos; this.breaking = breaking; + this.blocks = blocks; } } } diff --git a/src/main/java/nl/requios/effortlessbuilding/render/RenderHandler.java b/src/main/java/nl/requios/effortlessbuilding/render/RenderHandler.java index 24b1fdc..42513da 100644 --- a/src/main/java/nl/requios/effortlessbuilding/render/RenderHandler.java +++ b/src/main/java/nl/requios/effortlessbuilding/render/RenderHandler.java @@ -19,8 +19,8 @@ import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import nl.requios.effortlessbuilding.ClientEvents; -import nl.requios.effortlessbuilding.buildmode.BuildModes; -import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; +import nl.requios.effortlessbuilding.EffortlessBuildingClient; +import nl.requios.effortlessbuilding.buildmode.BuildModeEnum; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.compatibility.CompatHelper; import nl.requios.effortlessbuilding.utilities.SurvivalHelper; @@ -31,56 +31,6 @@ import nl.requios.effortlessbuilding.utilities.SurvivalHelper; @EventBusSubscriber(Dist.CLIENT) public class RenderHandler { - @SubscribeEvent - public static void onTick(TickEvent.ClientTickEvent event) { - if (!nl.requios.effortlessbuilding.create.events.ClientEvents.isGameActive()) return; - - var player = Minecraft.getInstance().player; - var modeSettings = ModeSettingsManager.getModeSettings(player); - var modifierSettings = ModifierSettingsManager.getModifierSettings(player); - - BlockPreviews.drawPlacedBlocks(player, modifierSettings); - - - HitResult lookingAt = ClientEvents.getLookingAt(player); - if (modeSettings.getBuildMode() == BuildModes.BuildModeEnum.DISABLED) - lookingAt = Minecraft.getInstance().hitResult; - - ItemStack mainhand = player.getMainHandItem(); - boolean noBlockInHand = !(!mainhand.isEmpty() && CompatHelper.isItemBlockProxy(mainhand)); - - //Find start position, side hit and hit vector - BlockPos startPos = null; - Direction sideHit = null; - Vec3 hitVec = null; - - //Checking for null is necessary! Even in vanilla when looking down ladders it is occasionally null (instead of Type MISS) - if (lookingAt != null && lookingAt.getType() == HitResult.Type.BLOCK) { - BlockHitResult blockLookingAt = (BlockHitResult) lookingAt; - startPos = blockLookingAt.getBlockPos(); - - //Check if tool (or none) in hand - boolean replaceable = player.level.getBlockState(startPos).getMaterial().isReplaceable(); - boolean becomesDoubleSlab = SurvivalHelper.doesBecomeDoubleSlab(player, startPos); - if (!modifierSettings.doQuickReplace() && !noBlockInHand && !replaceable && !becomesDoubleSlab) { - startPos = startPos.relative(blockLookingAt.getDirection()); - } - - //Get under tall grass and other replaceable blocks - if (modifierSettings.doQuickReplace() && !noBlockInHand && replaceable) { - startPos = startPos.below(); - } - - sideHit = blockLookingAt.getDirection(); - hitVec = blockLookingAt.getLocation(); - } - - - BlockPreviews.drawLookAtPreview(player, modeSettings, modifierSettings, startPos, sideHit, hitVec); - - if (noBlockInHand) BlockPreviews.drawOutlinesIfNoBlockInHand(player, lookingAt); - } - @SubscribeEvent public static void onRender(RenderLevelStageEvent event) { if (event.getStage() != RenderLevelStageEvent.Stage.AFTER_TRANSLUCENT_BLOCKS) return; @@ -92,7 +42,6 @@ public class RenderHandler { MultiBufferSource.BufferSource buffer = MultiBufferSource.immediate(bufferBuilder); Player player = Minecraft.getInstance().player; - ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); ms.pushPose(); diff --git a/src/main/java/nl/requios/effortlessbuilding/systems/BuilderChain.java b/src/main/java/nl/requios/effortlessbuilding/systems/BuilderChain.java index 8ec9865..abdd86c 100644 --- a/src/main/java/nl/requios/effortlessbuilding/systems/BuilderChain.java +++ b/src/main/java/nl/requios/effortlessbuilding/systems/BuilderChain.java @@ -1,8 +1,10 @@ package nl.requios.effortlessbuilding.systems; import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundSource; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.player.Player; @@ -19,11 +21,14 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import nl.requios.effortlessbuilding.ClientEvents; import nl.requios.effortlessbuilding.EffortlessBuildingClient; -import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; +import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.compatibility.CompatHelper; +import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem; import nl.requios.effortlessbuilding.network.PacketHandler; -import nl.requios.effortlessbuilding.network.ServerPlaceBlocksMessage; +import nl.requios.effortlessbuilding.network.ServerBreakBlocksPacket; +import nl.requios.effortlessbuilding.network.ServerPlaceBlocksPacket; +import nl.requios.effortlessbuilding.render.BlockPreviews; import nl.requios.effortlessbuilding.utilities.BlockEntry; import nl.requios.effortlessbuilding.utilities.ReachHelper; import nl.requios.effortlessbuilding.utilities.SurvivalHelper; @@ -38,6 +43,7 @@ import java.util.List; public class BuilderChain { private final List blocks = new ArrayList<>(); + private int soundTime = 0; public enum State { IDLE, @@ -47,7 +53,6 @@ public class BuilderChain { private State state = State.IDLE; - public void onRightClick() { var player = Minecraft.getInstance().player; @@ -68,12 +73,16 @@ public class BuilderChain { state = State.PLACING; } - var buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode(); + var buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode(); //Find out if we should place blocks now if (buildMode.instance.onClick(blocks)) { state = State.IDLE; - PacketHandler.INSTANCE.sendToServer(new ServerPlaceBlocksMessage(blocks)); + + if (!blocks.isEmpty()) { + EffortlessBuildingClient.BLOCK_PREVIEWS.onBlocksPlaced(blocks); + PacketHandler.INSTANCE.sendToServer(new ServerPlaceBlocksPacket(blocks)); + } } } @@ -94,12 +103,16 @@ public class BuilderChain { onTick(); } - var buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode(); + var buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode(); //Find out if we should break blocks now if (buildMode.instance.onClick(blocks)) { state = State.IDLE; - PacketHandler.INSTANCE.sendToServer(new ServerPlaceBlocksMessage(blocks)); + + if (!blocks.isEmpty()) { + EffortlessBuildingClient.BLOCK_PREVIEWS.onBlocksBroken(blocks); + PacketHandler.INSTANCE.sendToServer(new ServerBreakBlocksPacket(blocks)); + } } } @@ -119,11 +132,11 @@ public class BuilderChain { // } var modifierSettings = ModifierSettingsManager.getModifierSettings(player); - var buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode(); + var buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode(); BlockHitResult lookingAt = ClientEvents.getLookingAt(player); - BlockEntry startEntry = findStartPosition(player, lookingAt, modifierSettings.doQuickReplace()); + BlockEntry startEntry = findStartPosition(player, lookingAt); if (startEntry != null) { blocks.add(startEntry); } @@ -131,34 +144,36 @@ public class BuilderChain { EffortlessBuildingClient.BUILD_MODES.findCoordinates(blocks, player, buildMode); EffortlessBuildingClient.BUILD_MODIFIERS.findCoordinates(blocks, player, modifierSettings); - if (blockInHand && state != State.BREAKING) { - //find block states + if (blockInHand && state != State.BREAKING) + findBlockStates(player, itemStack); - if (itemStack.getItem() instanceof BlockItem) { - - for (BlockEntry blockEntry : blocks) { - blockEntry.blockState = getBlockState(player, InteractionHand.MAIN_HAND, itemStack, blockEntry); - } - - } else if (CompatHelper.isItemBlockProxy(itemStack, false)) { - - for (BlockEntry blockEntry : blocks) { - ItemStack itemBlockStack = CompatHelper.getItemBlockFromStack(itemStack); - if (itemBlockStack == null || itemBlockStack.isEmpty()) continue; - blockEntry.blockState = getBlockState(player, InteractionHand.MAIN_HAND, itemBlockStack, blockEntry); - } - } - } + //Check if they are different +// if (!BuildModifiers.compareCoordinates(previousCoordinates, newCoordinates)) { +// +// //Renew randomness of randomizer bag +// AbstractRandomizerBagItem.renewRandomness(); +// +// //Play sound (max once every tick) +// if (blocks.size() > 1 && blockStates.size() > 1 && soundTime < ClientEvents.ticksInGame) { +// soundTime = ClientEvents.ticksInGame; +// +// var firstBlockState = blocks.get(0).blockState; +// if (firstBlockState != null) { +// SoundType soundType = firstBlockState.getBlock().getSoundType(firstBlockState, player.level, +// blocks.get(0).blockPos, player); +// SoundEvent soundEvent = state == BuilderChain.State.BREAKING ? soundType.getBreakSound() : soundType.getPlaceSound(); +// player.level.playSound(player, player.blockPosition(), soundEvent, SoundSource.BLOCKS, 0.3f, 0.8f); +// } +// } +// } } public void cancel() { - var player = Minecraft.getInstance().player; - state = State.IDLE; - EffortlessBuildingClient.BUILD_MODES.onCancel(player); + EffortlessBuildingClient.BUILD_MODES.onCancel(); } - private BlockEntry findStartPosition(Player player, BlockHitResult lookingAt, boolean doingQuickReplace) { + private BlockEntry findStartPosition(Player player, BlockHitResult lookingAt) { if (lookingAt == null || lookingAt.getType() == HitResult.Type.MISS) return null; var startPos = lookingAt.getBlockPos(); @@ -169,14 +184,15 @@ public class BuilderChain { if (state != State.BREAKING) { //Offset in direction of sidehit if not quickreplace and not replaceable + boolean isQuickReplacing = EffortlessBuildingClient.QUICK_REPLACE.isQuickReplacing(); boolean replaceable = player.level.getBlockState(startPos).getMaterial().isReplaceable(); boolean becomesDoubleSlab = SurvivalHelper.doesBecomeDoubleSlab(player, startPos); - if (!doingQuickReplace && !replaceable && !becomesDoubleSlab) { + if (!isQuickReplacing && !replaceable && !becomesDoubleSlab) { startPos = startPos.relative(lookingAt.getDirection()); } //Get under tall grass and other replaceable blocks - if (doingQuickReplace && replaceable) { + if (isQuickReplacing && replaceable) { startPos = startPos.below(); } } @@ -194,6 +210,23 @@ public class BuilderChain { return blockEntry; } + private void findBlockStates(LocalPlayer player, ItemStack itemStack) { + if (itemStack.getItem() instanceof BlockItem) { + + for (BlockEntry blockEntry : blocks) { + blockEntry.blockState = getBlockState(player, InteractionHand.MAIN_HAND, itemStack, blockEntry); + } + + } else if (CompatHelper.isItemBlockProxy(itemStack, false)) { + + for (BlockEntry blockEntry : blocks) { + ItemStack itemBlockStack = CompatHelper.getItemBlockFromStack(itemStack); + if (itemBlockStack == null || itemBlockStack.isEmpty()) continue; + blockEntry.blockState = getBlockState(player, InteractionHand.MAIN_HAND, itemBlockStack, blockEntry); + } + } + } + public BlockState getBlockState(Player player, InteractionHand hand, ItemStack blockItemStack, BlockEntry blockEntry) { Block block = Block.byItem(blockItemStack.getItem()); //TODO convert lookingAt hitvec to relative hitvec @@ -230,4 +263,8 @@ public class BuilderChain { public State getState() { return state; } + + public List getBlocks() { + return blocks; + } } diff --git a/src/main/java/nl/requios/effortlessbuilding/systems/QuickReplace.java b/src/main/java/nl/requios/effortlessbuilding/systems/QuickReplace.java new file mode 100644 index 0000000..37223fe --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/systems/QuickReplace.java @@ -0,0 +1,30 @@ +package nl.requios.effortlessbuilding.systems; + +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import nl.requios.effortlessbuilding.EffortlessBuilding; +import nl.requios.effortlessbuilding.network.IsQuickReplacingPacket; +import nl.requios.effortlessbuilding.network.PacketHandler; + +@OnlyIn(Dist.CLIENT) +public class QuickReplace { + private boolean isQuickReplacing = false; + + public boolean isQuickReplacing() { + return isQuickReplacing; + } + + public void toggleQuickReplacing() { + setIsQuickReplacing(!isQuickReplacing); + } + + public void setIsQuickReplacing(boolean isQuickReplacing) { + this.isQuickReplacing = isQuickReplacing; + + EffortlessBuilding.log(Minecraft.getInstance().player, "Set " + ChatFormatting.GOLD + "Quick Replace " + + ChatFormatting.RESET + (this.isQuickReplacing ? "on" : "off")); + PacketHandler.INSTANCE.sendToServer(new IsQuickReplacingPacket(this.isQuickReplacing)); + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/systems/ServerBlockPlacer.java b/src/main/java/nl/requios/effortlessbuilding/systems/ServerBlockPlacer.java index ee0d7c3..6754f9e 100644 --- a/src/main/java/nl/requios/effortlessbuilding/systems/ServerBlockPlacer.java +++ b/src/main/java/nl/requios/effortlessbuilding/systems/ServerBlockPlacer.java @@ -3,17 +3,17 @@ package nl.requios.effortlessbuilding.systems; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.items.ItemHandlerHelper; import nl.requios.effortlessbuilding.EffortlessBuilding; +import nl.requios.effortlessbuilding.create.foundation.utility.BlockHelper; import nl.requios.effortlessbuilding.utilities.BlockEntry; import java.util.List; // Receives block placement requests from the client and places them public class ServerBlockPlacer { + private boolean isPlacingOrBreakingBlocks = false; public void placeBlocks(Player player, List blocks) { EffortlessBuilding.log(player, "Placing " + blocks.size() + " blocks"); @@ -27,31 +27,33 @@ public class ServerBlockPlacer { Level world = player.level; if (!world.isLoaded(block.blockPos)) return; - if (block.meansBreakBlock()) { - breakBlock(player, block.blockPos); - return; - } - - boolean success = world.setBlock(block.blockPos, block.blockState, 3); + isPlacingOrBreakingBlocks = true; + BlockHelper.placeSchematicBlock(world, block.blockState, block.blockPos, block.itemStack, null); + isPlacingOrBreakingBlocks = false; } - public void breakBlock(Player player, BlockPos pos) { + public void breakBlocks(Player player, List blocks) { + EffortlessBuilding.log(player, "Breaking " + blocks.size() + " blocks"); + + for (BlockEntry block : blocks) { + breakBlock(player, block); + } + } + + public void breakBlock(Player player, BlockEntry block) { ServerLevel world = (ServerLevel) player.level; - if (!world.isLoaded(pos) || world.isEmptyBlock(pos)) return; + if (!world.isLoaded(block.blockPos) || world.isEmptyBlock(block.blockPos)) return; - //Held tool - - if (!player.getAbilities().instabuild) { - - //Drops - BlockState blockState = world.getBlockState(pos); - List drops = Block.getDrops(blockState, world, pos, world.getBlockEntity(pos), player, player.getMainHandItem()); - for (ItemStack drop : drops) { - player.addItem(drop); + isPlacingOrBreakingBlocks = true; + BlockHelper.destroyBlockAs(world, block.blockPos, player, player.getMainHandItem(), 1.0f, stack -> { + if (!player.isCreative()) { + ItemHandlerHelper.giveItemToPlayer(player, stack); } - } - - world.removeBlock(pos, false); + }); + isPlacingOrBreakingBlocks = false; } + public boolean isPlacingOrBreakingBlocks() { + return isPlacingOrBreakingBlocks; + } } diff --git a/src/main/java/nl/requios/effortlessbuilding/systems/ServerBuildState.java b/src/main/java/nl/requios/effortlessbuilding/systems/ServerBuildState.java new file mode 100644 index 0000000..9e80ce0 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/systems/ServerBuildState.java @@ -0,0 +1,33 @@ +package nl.requios.effortlessbuilding.systems; + +import net.minecraft.world.entity.player.Player; +import nl.requios.effortlessbuilding.EffortlessBuilding; + +public class ServerBuildState { + private static final String IS_USING_BUILD_MODE_KEY = EffortlessBuilding.MODID + ":isUsingBuildMode"; + private static final String IS_QUICK_REPLACING_KEY = EffortlessBuilding.MODID + ":isQuickReplacing"; + + public static boolean isUsingBuildMode(Player player) { + return player.getPersistentData().contains(IS_USING_BUILD_MODE_KEY); + } + + public static void setIsUsingBuildMode(Player player, boolean isUsingBuildMode) { + if (isUsingBuildMode) { + player.getPersistentData().putBoolean(IS_USING_BUILD_MODE_KEY, true); + } else { + player.getPersistentData().remove(IS_USING_BUILD_MODE_KEY); + } + } + + public static boolean isQuickReplacing(Player player) { + return player.getPersistentData().contains(IS_QUICK_REPLACING_KEY); + } + + public static void setIsQuickReplacing(Player player, boolean isQuickReplacing) { + if (isQuickReplacing) { + player.getPersistentData().putBoolean(IS_QUICK_REPLACING_KEY, true); + } else { + player.getPersistentData().remove(IS_QUICK_REPLACING_KEY); + } + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/utilities/ReachHelper.java b/src/main/java/nl/requios/effortlessbuilding/utilities/ReachHelper.java index 94be093..a39608a 100644 --- a/src/main/java/nl/requios/effortlessbuilding/utilities/ReachHelper.java +++ b/src/main/java/nl/requios/effortlessbuilding/utilities/ReachHelper.java @@ -3,27 +3,60 @@ package nl.requios.effortlessbuilding.utilities; import net.minecraft.world.entity.player.Player; import net.minecraft.util.Mth; import nl.requios.effortlessbuilding.CommonConfig; +import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; public class ReachHelper { + private static final String REACH_UPGRADE_KEY = EffortlessBuilding.MODID + ":reachUpgrade"; + + public static int getReachUpgrade(Player player) { + if (!player.getPersistentData().contains(REACH_UPGRADE_KEY)) return 0; + return player.getPersistentData().getInt(REACH_UPGRADE_KEY); + } + + //Remember that to actually save it, this needs to be called on the server + public static void setReachUpgrade(Player player, int reachUpgrade) { + player.getPersistentData().putInt(REACH_UPGRADE_KEY, reachUpgrade); + + if (player.level.isClientSide) { + //Set mirror radius to max + int reach = 10; + switch (reachUpgrade) { + case 0: + reach = CommonConfig.reach.maxReachLevel0.get(); + break; + case 1: + reach = CommonConfig.reach.maxReachLevel1.get(); + break; + case 2: + reach = CommonConfig.reach.maxReachLevel2.get(); + break; + case 3: + reach = CommonConfig.reach.maxReachLevel3.get(); + break; + } + + //TODO enable +// if (this.mirrorSettings != null) +// this.mirrorSettings.radius = reach / 2; +// if (this.radialMirrorSettings != null) +// this.radialMirrorSettings.radius = reach / 2; + } else { + + } + } + public static int getMaxReach(Player player) { if (player.isCreative()) return CommonConfig.reach.maxReachCreative.get(); if (!CommonConfig.reach.enableReachUpgrades.get()) return CommonConfig.reach.maxReachLevel3.get(); - //Check buildsettings for reachUpgrade - int reachUpgrade = ModifierSettingsManager.getModifierSettings(player).getReachUpgrade(); - switch (reachUpgrade) { - case 0: - return CommonConfig.reach.maxReachLevel0.get(); - case 1: - return CommonConfig.reach.maxReachLevel1.get(); - case 2: - return CommonConfig.reach.maxReachLevel2.get(); - case 3: - return CommonConfig.reach.maxReachLevel3.get(); - } - return CommonConfig.reach.maxReachLevel0.get(); + return switch (getReachUpgrade(player)) { + case 1 -> CommonConfig.reach.maxReachLevel1.get(); + case 2 -> CommonConfig.reach.maxReachLevel2.get(); + case 3 -> CommonConfig.reach.maxReachLevel3.get(); + default -> CommonConfig.reach.maxReachLevel0.get(); + }; } public static int getPlacementReach(Player player) { diff --git a/src/main/java/nl/requios/effortlessbuilding/utilities/SurvivalHelper.java b/src/main/java/nl/requios/effortlessbuilding/utilities/SurvivalHelper.java index ed9438c..3e0d987 100644 --- a/src/main/java/nl/requios/effortlessbuilding/utilities/SurvivalHelper.java +++ b/src/main/java/nl/requios/effortlessbuilding/utilities/SurvivalHelper.java @@ -24,8 +24,10 @@ import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraftforge.event.ForgeEventFactory; import nl.requios.effortlessbuilding.CommonConfig; +import nl.requios.effortlessbuilding.EffortlessBuildingClient; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.compatibility.CompatHelper; +import nl.requios.effortlessbuilding.systems.ServerBuildState; import javax.annotation.Nullable; @@ -271,8 +273,12 @@ public class SurvivalHelper { } //Check quickreplace - if (placer != null && ModifierSettingsManager.getModifierSettings(((Player) placer)).doQuickReplace()) { - return true; + boolean isQuickReplacing = false; + if (placer instanceof Player player) { + if (world.isClientSide) EffortlessBuildingClient.QUICK_REPLACE.isQuickReplacing(); + else isQuickReplacing = ServerBuildState.isQuickReplacing(player); + + if (isQuickReplacing) return true; } return currentBlockState.getMaterial().isReplaceable() /*&& canPlaceBlockOnSide(world, pos, sidePlacedOn)*/;