diff --git a/src/main/java/com/simibubi/create/AllItems.java b/src/main/java/com/simibubi/create/AllItems.java index 1398cdb5d..0e7382866 100644 --- a/src/main/java/com/simibubi/create/AllItems.java +++ b/src/main/java/com/simibubi/create/AllItems.java @@ -17,6 +17,7 @@ import com.simibubi.create.modules.curiosities.deforester.DeforesterItem; import com.simibubi.create.modules.curiosities.symmetry.SymmetryWandItem; import com.simibubi.create.modules.curiosities.tools.SandPaperItem; import com.simibubi.create.modules.curiosities.zapper.blockzapper.BlockzapperItem; +import com.simibubi.create.modules.curiosities.zapper.terrainzapper.TerrainzapperItem; import com.simibubi.create.modules.gardens.TreeFertilizerItem; import com.simibubi.create.modules.logistics.item.filter.FilterItem; import com.simibubi.create.modules.schematics.item.SchematicAndQuillItem; @@ -95,6 +96,7 @@ public enum AllItems { __CURIOSITIES__(module()), TREE_FERTILIZER(TreeFertilizerItem::new), PLACEMENT_HANDGUN(BlockzapperItem::new), + TERRAIN_ZAPPER(TerrainzapperItem::new), DEFORESTER(DeforesterItem::new), SYMMETRY_WAND(SymmetryWandItem::new), diff --git a/src/main/java/com/simibubi/create/AllPackets.java b/src/main/java/com/simibubi/create/AllPackets.java index 6a0d021ec..5e9173724 100644 --- a/src/main/java/com/simibubi/create/AllPackets.java +++ b/src/main/java/com/simibubi/create/AllPackets.java @@ -12,7 +12,7 @@ import com.simibubi.create.foundation.packet.SimplePacketBase; import com.simibubi.create.foundation.utility.ServerSpeedProvider; import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionStallPacket; import com.simibubi.create.modules.curiosities.symmetry.SymmetryEffectPacket; -import com.simibubi.create.modules.curiosities.zapper.blockzapper.BlockzapperBeamPacket; +import com.simibubi.create.modules.curiosities.zapper.ZapperBeamPacket; import com.simibubi.create.modules.logistics.item.filter.FilterScreenPacket; import com.simibubi.create.modules.logistics.packet.ConfigureFlexcratePacket; import com.simibubi.create.modules.logistics.packet.ConfigureStockswitchPacket; @@ -42,7 +42,7 @@ public enum AllPackets { // Server to Client SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new), SERVER_SPEED(ServerSpeedProvider.Packet.class, ServerSpeedProvider.Packet::new), - BEAM_EFFECT(BlockzapperBeamPacket.class, BlockzapperBeamPacket::new), + BEAM_EFFECT(ZapperBeamPacket.class, ZapperBeamPacket::new), CONFIGURE_CONFIG(ConfigureConfigPacket.class, ConfigureConfigPacket::new), CONTRAPTION_STALL(ContraptionStallPacket.class, ContraptionStallPacket::new), diff --git a/src/main/java/com/simibubi/create/ClientEvents.java b/src/main/java/com/simibubi/create/ClientEvents.java index bb9c0cadc..c17309f55 100644 --- a/src/main/java/com/simibubi/create/ClientEvents.java +++ b/src/main/java/com/simibubi/create/ClientEvents.java @@ -14,6 +14,7 @@ import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.modules.contraptions.components.contraptions.ChassisRangeDisplay; import com.simibubi.create.modules.contraptions.components.turntable.TurntableHandler; import com.simibubi.create.modules.contraptions.relays.belt.BeltConnectorItemHandler; +import com.simibubi.create.modules.curiosities.zapper.terrainzapper.TerrainZapperRenderHandler; import net.minecraft.client.Minecraft; import net.minecraft.item.ItemStack; @@ -60,6 +61,7 @@ public class ClientEvents { public static void onGameTick() { CreateClient.gameTick(); BeltConnectorItemHandler.gameTick(); + TerrainZapperRenderHandler.tick(); } @SubscribeEvent @@ -69,6 +71,7 @@ public class ClientEvents { CreateClient.schematicHologram.render(); KineticDebugger.renderSourceOutline(); ChassisRangeDisplay.renderOutlines(event.getPartialTicks()); + TerrainZapperRenderHandler.render(); } @SubscribeEvent diff --git a/src/main/java/com/simibubi/create/ScreenResources.java b/src/main/java/com/simibubi/create/ScreenResources.java index e65f94bb2..0d9679885 100644 --- a/src/main/java/com/simibubi/create/ScreenResources.java +++ b/src/main/java/com/simibubi/create/ScreenResources.java @@ -10,7 +10,9 @@ public enum ScreenResources { // Inventories PLAYER_INVENTORY("player_inventory.png", 176, 108), WAND_SYMMETRY("wand_symmetry.png", 207, 58), - PLACEMENT_GUN("placement_handgun.png", 217, 70), + BLOCKZAPPER("zapper.png", 217, 70), + TERRAINZAPPER("zapper.png", 0, 70, 217, 105), + TERRAINZAPPER_INACTIVE_PARAM("zapper.png", 0, 175, 14, 14), SCHEMATIC_TABLE("schematic_table.png", 207, 89), SCHEMATIC_TABLE_PROGRESS("schematic_table.png", 209, 0, 24, 17), @@ -127,6 +129,15 @@ public enum ScreenResources { I_REPLACE_SOLID(1, 2), I_REPLACE_ANY(2, 2), I_REPLACE_EMPTY(3, 2), + I_CENTERED(4, 2), + I_ATTACHED(5, 2), + I_INSERTED(6, 2), + I_FILL(7, 2), + I_PLACE(8, 2), + I_REPLACE(9, 2), + I_CLEAR(10, 2), + I_OVERLAY(11, 2), + I_FLATTEN(12, 2), I_TOOL_DEPLOY(0, 3), I_SKIP_TILES(2, 3), diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/deployer/DeployerTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/deployer/DeployerTileEntity.java index 77d2c2e62..af449a658 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/deployer/DeployerTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/deployer/DeployerTileEntity.java @@ -259,7 +259,8 @@ public class DeployerTileEntity extends KineticTileEntity { player.rotationPitch = direction == Direction.UP ? -90 : direction == Direction.DOWN ? 90 : 0; DeployerHandler.activate(player, center, clickedPos, movementVector, mode); - heldItem = player.getHeldItemMainhand(); + if (player != null) + heldItem = player.getHeldItemMainhand(); } protected void returnAndDeposit() { diff --git a/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltMovementHandler.java b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltMovementHandler.java index 435dce9f6..f6c33e786 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltMovementHandler.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltMovementHandler.java @@ -4,6 +4,8 @@ import static net.minecraft.entity.MoverType.SELF; import static net.minecraft.util.Direction.AxisDirection.NEGATIVE; import static net.minecraft.util.Direction.AxisDirection.POSITIVE; +import java.util.List; + import com.simibubi.create.AllBlocks; import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState; import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Part; @@ -62,9 +64,9 @@ public class BeltMovementHandler { TileEntity te = world.getTileEntity(pos); TileEntity tileEntityBelowPassenger = world.getTileEntity(entityIn.getPosition()); BlockState blockState = info.lastCollidedState; - Direction movementFacing = Direction.getFacingFromAxisDirection( - blockState.get(BlockStateProperties.HORIZONTAL_FACING).getAxis(), - beltTe.getSpeed() < 0 ? POSITIVE : NEGATIVE); + Direction movementFacing = + Direction.getFacingFromAxisDirection(blockState.get(BlockStateProperties.HORIZONTAL_FACING).getAxis(), + beltTe.getSpeed() < 0 ? POSITIVE : NEGATIVE); boolean collidedWithBelt = te instanceof BeltTileEntity; boolean betweenBelts = tileEntityBelowPassenger instanceof BeltTileEntity && tileEntityBelowPassenger != te; @@ -105,8 +107,8 @@ public class BeltMovementHandler { float movementSpeed = beltTe.getBeltMovementSpeed(); final Direction movementDirection = Direction.getFacingFromAxis(axis == Axis.X ? NEGATIVE : POSITIVE, axis); - Vec3i centeringDirection = Direction.getFacingFromAxis(POSITIVE, beltFacing.rotateY().getAxis()) - .getDirectionVec(); + Vec3i centeringDirection = + Direction.getFacingFromAxis(POSITIVE, beltFacing.rotateY().getAxis()).getDirectionVec(); Vec3d movement = new Vec3d(movementDirection.getDirectionVec()).scale(movementSpeed); double diffCenter = axis == Axis.Z ? (pos.getX() + .5f - entityIn.posX) : (pos.getZ() + .5f - entityIn.posZ); @@ -145,10 +147,11 @@ public class BeltMovementHandler { Vec3d checkDistance = movement.normalize().scale(0.5); AxisAlignedBB bb = entityIn.getBoundingBox(); AxisAlignedBB checkBB = new AxisAlignedBB(bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ); - if (!world - .getEntitiesWithinAABBExcludingEntity(entityIn, checkBB.offset(checkDistance) - .grow(-Math.abs(checkDistance.x), -Math.abs(checkDistance.y), -Math.abs(checkDistance.z))) - .isEmpty()) { + checkBB = checkBB.offset(checkDistance).grow(-Math.abs(checkDistance.x), -Math.abs(checkDistance.y), + -Math.abs(checkDistance.z)); + List list = world.getEntitiesWithinAABBExcludingEntity(entityIn, checkBB); + list.removeIf(e -> entityIn.isRidingOrBeingRiddenBy(e)); + if (!list.isEmpty()) { entityIn.setMotion(0, 0, 0); info.ticksSinceLastCollision--; return; diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/PlacementPatterns.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/PlacementPatterns.java new file mode 100644 index 000000000..4709afa3f --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/PlacementPatterns.java @@ -0,0 +1,63 @@ +package com.simibubi.create.modules.curiosities.zapper; + +import java.util.List; +import java.util.Random; +import java.util.function.Predicate; + +import com.google.common.base.Predicates; +import com.simibubi.create.ScreenResources; +import com.simibubi.create.foundation.utility.Lang; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.math.BlockPos; + +public enum PlacementPatterns { + + Solid(ScreenResources.I_PATTERN_SOLID), + Checkered(ScreenResources.I_PATTERN_CHECKERED), + InverseCheckered(ScreenResources.I_PATTERN_CHECKERED_INVERSED), + Chance25(ScreenResources.I_PATTERN_CHANCE_25), + Chance50(ScreenResources.I_PATTERN_CHANCE_50), + Chance75(ScreenResources.I_PATTERN_CHANCE_75); + + public String translationKey; + public ScreenResources icon; + + private PlacementPatterns(ScreenResources icon) { + this.translationKey = Lang.asId(name()); + this.icon = icon; + } + + public static void applyPattern(List blocksIn, ItemStack stack) { + CompoundNBT tag = stack.getTag(); + PlacementPatterns pattern = + !tag.contains("Pattern") ? Solid : valueOf(tag.getString("Pattern")); + Random r = new Random(); + Predicate filter = Predicates.alwaysFalse(); + + switch (pattern) { + case Chance25: + filter = pos -> r.nextBoolean() || r.nextBoolean(); + break; + case Chance50: + filter = pos -> r.nextBoolean(); + break; + case Chance75: + filter = pos -> r.nextBoolean() && r.nextBoolean(); + break; + case Checkered: + filter = pos -> (pos.getX() + pos.getY() + pos.getZ()) % 2 == 0; + break; + case InverseCheckered: + filter = pos -> (pos.getX() + pos.getY() + pos.getZ()) % 2 != 0; + break; + case Solid: + default: + break; + } + + blocksIn.removeIf(filter); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/BlockzapperBeamPacket.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperBeamPacket.java similarity index 72% rename from src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/BlockzapperBeamPacket.java rename to src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperBeamPacket.java index e92594d05..db434fdb5 100644 --- a/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/BlockzapperBeamPacket.java +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperBeamPacket.java @@ -1,9 +1,9 @@ -package com.simibubi.create.modules.curiosities.zapper.blockzapper; +package com.simibubi.create.modules.curiosities.zapper; import java.util.function.Supplier; import com.simibubi.create.foundation.packet.SimplePacketBase; -import com.simibubi.create.modules.curiosities.zapper.blockzapper.BlockzapperHandler.LaserBeam; +import com.simibubi.create.modules.curiosities.zapper.ZapperRenderHandler.LaserBeam; import net.minecraft.client.Minecraft; import net.minecraft.network.PacketBuffer; @@ -14,21 +14,21 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.network.NetworkEvent.Context; -public class BlockzapperBeamPacket extends SimplePacketBase { +public class ZapperBeamPacket extends SimplePacketBase { public Vec3d start; public Vec3d target; public Hand hand; public boolean self; - public BlockzapperBeamPacket(Vec3d start, Vec3d target, Hand hand, boolean self) { + public ZapperBeamPacket(Vec3d start, Vec3d target, Hand hand, boolean self) { this.start = start; this.target = target; this.hand = hand; this.self = self; } - public BlockzapperBeamPacket(PacketBuffer buffer) { + public ZapperBeamPacket(PacketBuffer buffer) { start = new Vec3d(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()); target = new Vec3d(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()); hand = buffer.readBoolean()? Hand.MAIN_HAND : Hand.OFF_HAND; @@ -51,12 +51,12 @@ public class BlockzapperBeamPacket extends SimplePacketBase { context.get().enqueueWork(() -> DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { if (Minecraft.getInstance().player.getPositionVector().distanceTo(start) > 100) return; - BlockzapperHandler.addBeam(new LaserBeam(start, target).followPlayer(self, hand == Hand.MAIN_HAND)); + ZapperRenderHandler.addBeam(new LaserBeam(start, target).followPlayer(self, hand == Hand.MAIN_HAND)); if (self) - BlockzapperHandler.shoot(hand); + ZapperRenderHandler.shoot(hand); else - BlockzapperHandler.playSound(hand, new BlockPos(start)); + ZapperRenderHandler.playSound(hand, new BlockPos(start)); })); context.get().setPacketHandled(true); } diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperItem.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperItem.java index 62421b5ef..f8e15387f 100644 --- a/src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperItem.java +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperItem.java @@ -2,28 +2,47 @@ package com.simibubi.create.modules.curiosities.zapper; import java.util.List; +import com.simibubi.create.AllPackets; +import com.simibubi.create.AllSoundEvents; import com.simibubi.create.foundation.item.ItemDescription; +import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.Lang; import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUseContext; import net.minecraft.item.Rarity; import net.minecraft.item.UseAction; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.NBTUtil; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.state.properties.StairsShape; +import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResultType; import net.minecraft.util.Hand; +import net.minecraft.util.HandSide; +import net.minecraft.util.SoundCategory; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.RayTraceContext; +import net.minecraft.util.math.RayTraceContext.BlockMode; +import net.minecraft.util.math.RayTraceContext.FluidMode; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.fml.network.PacketDistributor; public abstract class ZapperItem extends Item { @@ -35,13 +54,27 @@ public abstract class ZapperItem extends Item { @OnlyIn(Dist.CLIENT) public void addInformation(ItemStack stack, World worldIn, List tooltip, ITooltipFlag flagIn) { if (stack.hasTag() && stack.getTag().contains("BlockUsed")) { - String usedblock = NBTUtil.readBlockState(stack.getTag().getCompound("BlockUsed")).getBlock() - .getTranslationKey(); + String usedblock = + NBTUtil.readBlockState(stack.getTag().getCompound("BlockUsed")).getBlock().getTranslationKey(); ItemDescription.add(tooltip, TextFormatting.DARK_GRAY + Lang.translate("blockzapper.usingBlock", TextFormatting.GRAY + new TranslationTextComponent(usedblock).getFormattedText())); } } + @Override + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { + boolean differentBlock = false; + if (oldStack.hasTag() && newStack.hasTag() && oldStack.getTag().contains("BlockUsed") + && newStack.getTag().contains("BlockUsed")) + differentBlock = NBTUtil.readBlockState(oldStack.getTag().getCompound("BlockUsed")) != NBTUtil + .readBlockState(newStack.getTag().getCompound("BlockUsed")); + return slotChanged || !isZapper(newStack) || differentBlock; + } + + public boolean isZapper(ItemStack newStack) { + return newStack.getItem() instanceof ZapperItem; + } + @Override public ActionResultType onItemUse(ItemUseContext context) { // Shift -> open GUI @@ -57,11 +90,110 @@ public abstract class ZapperItem extends Item { return super.onItemUse(context); } + @Override + public ActionResult onItemRightClick(World world, PlayerEntity player, Hand hand) { + ItemStack item = player.getHeldItem(hand); + CompoundNBT nbt = item.getOrCreateTag(); + + // Shift -> Open GUI + if (player.isSneaking()) { + if (world.isRemote) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { + openHandgunGUI(item, hand == Hand.OFF_HAND); + }); + applyCooldown(player, item, false); + } + return new ActionResult(ActionResultType.SUCCESS, item); + } + + boolean mainHand = hand == Hand.MAIN_HAND; + boolean isSwap = item.getTag().contains("_Swap"); + boolean gunInOtherHand = isZapper(player.getHeldItem(mainHand ? Hand.OFF_HAND : Hand.MAIN_HAND)); + + // Pass To Offhand + if (mainHand && isSwap && gunInOtherHand) + return new ActionResult(ActionResultType.FAIL, item); + if (mainHand && !isSwap && gunInOtherHand) + item.getTag().putBoolean("_Swap", true); + if (!mainHand && isSwap) + item.getTag().remove("_Swap"); + if (!mainHand && gunInOtherHand) + player.getHeldItem(Hand.MAIN_HAND).getTag().remove("_Swap"); + player.setActiveHand(hand); + + // Check if can be used + String msg = validateUsage(item); + if (msg != null) { + world.playSound(player, player.getPosition(), AllSoundEvents.BLOCKZAPPER_DENY.get(), SoundCategory.BLOCKS, + 1f, 0.5f); + player.sendStatusMessage(new StringTextComponent(TextFormatting.RED + msg), true); + return new ActionResult(ActionResultType.FAIL, item); + } + + BlockState stateToUse = Blocks.AIR.getDefaultState(); + if (nbt.contains("BlockUsed")) + stateToUse = NBTUtil.readBlockState(nbt.getCompound("BlockUsed")); + + // Raytrace - Find the target + Vec3d start = player.getPositionVec().add(0, player.getEyeHeight(), 0); + Vec3d range = player.getLookVec().scale(getRange(item)); + BlockRayTraceResult raytrace = world.rayTraceBlocks( + new RayTraceContext(start, start.add(range), BlockMode.OUTLINE, FluidMode.NONE, player)); + BlockPos pos = raytrace.getPos(); + BlockState stateReplaced = world.getBlockState(pos); + + // No target + if (pos == null || stateReplaced.getBlock() == Blocks.AIR) { + applyCooldown(player, item, gunInOtherHand); + return new ActionResult(ActionResultType.SUCCESS, item); + } + + // Find exact position of gun barrel for VFX + float yaw = (float) ((player.rotationYaw) / -180 * Math.PI); + float pitch = (float) ((player.rotationPitch) / -180 * Math.PI); + Vec3d barrelPosNoTransform = + new Vec3d(mainHand == (player.getPrimaryHand() == HandSide.RIGHT) ? -.35f : .35f, -0.1f, 1); + Vec3d barrelPos = start.add(barrelPosNoTransform.rotatePitch(pitch).rotateYaw(yaw)); + + // Client side + if (world.isRemote) { + ZapperRenderHandler.dontAnimateItem(hand); + return new ActionResult(ActionResultType.SUCCESS, item); + } + + // Server side + if (activate(world, player, item, stateToUse, raytrace)) { + applyCooldown(player, item, gunInOtherHand); + AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> player), + new ZapperBeamPacket(barrelPos, raytrace.getHitVec(), hand, false)); + AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), + new ZapperBeamPacket(barrelPos, raytrace.getHitVec(), hand, true)); + } + + return new ActionResult(ActionResultType.SUCCESS, item); + } + + public String validateUsage(ItemStack item) { + CompoundNBT tag = item.getOrCreateTag(); + if (!canActivateWithoutSelectedBlock(item) && !tag.contains("BlockUsed")) + return Lang.translate("blockzapper.leftClickToSet"); + return null; + } + + protected abstract boolean activate(World world, PlayerEntity player, ItemStack item, BlockState stateToUse, + BlockRayTraceResult raytrace); + @OnlyIn(Dist.CLIENT) protected abstract void openHandgunGUI(ItemStack item, boolean b); protected abstract int getCooldownDelay(ItemStack item); + protected abstract int getRange(ItemStack stack); + + protected boolean canActivateWithoutSelectedBlock(ItemStack stack) { + return false; + } + protected void applyCooldown(PlayerEntity playerIn, ItemStack item, boolean dual) { int delay = getCooldownDelay(item); playerIn.getCooldownTracker().setCooldown(item.getItem(), dual ? delay * 2 / 3 : delay); @@ -77,4 +209,50 @@ public abstract class ZapperItem extends Item { return UseAction.NONE; } + @Override + public boolean onEntitySwing(ItemStack stack, LivingEntity entity) { + if (!(entity instanceof PlayerEntity)) + return false; + if (entity.isSneaking()) + return true; + + Vec3d start = entity.getPositionVec().add(0, entity.getEyeHeight(), 0); + Vec3d range = entity.getLookVec().scale(getRange(stack)); + BlockRayTraceResult raytrace = entity.world.rayTraceBlocks( + new RayTraceContext(start, start.add(range), BlockMode.OUTLINE, FluidMode.NONE, entity)); + BlockPos pos = raytrace.getPos(); + if (pos == null) + return true; + + entity.world.sendBlockBreakProgress(entity.getEntityId(), pos, -1); + BlockState newState = entity.world.getBlockState(pos); + + if (BlockHelper.getRequiredItem(newState).isEmpty()) + return true; + if (entity.world.getTileEntity(pos) != null) + return true; + if (newState.has(BlockStateProperties.DOUBLE_BLOCK_HALF)) + return true; + if (newState.has(BlockStateProperties.ATTACHED)) + return true; + if (newState.has(BlockStateProperties.HANGING)) + return true; + if (newState.has(BlockStateProperties.BED_PART)) + return true; + if (newState.has(BlockStateProperties.STAIRS_SHAPE)) + newState = newState.with(BlockStateProperties.STAIRS_SHAPE, StairsShape.STRAIGHT); + if (newState.has(BlockStateProperties.PERSISTENT)) + newState = newState.with(BlockStateProperties.PERSISTENT, true); + + CompoundNBT tag = stack.getOrCreateTag(); + if (tag.contains("BlockUsed") && NBTUtil.readBlockState(stack.getTag().getCompound("BlockUsed")) == newState) + return true; + + tag.put("BlockUsed", NBTUtil.writeBlockState(newState)); + entity.world.playSound((PlayerEntity) entity, entity.getPosition(), AllSoundEvents.BLOCKZAPPER_CONFIRM.get(), + SoundCategory.BLOCKS, 0.5f, 0.8f); + + return true; + } + } diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperItemRenderer.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperItemRenderer.java new file mode 100644 index 000000000..24ab6cfb5 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperItemRenderer.java @@ -0,0 +1,32 @@ +package com.simibubi.create.modules.curiosities.zapper; + +import com.mojang.blaze3d.platform.GlStateManager; + +import net.minecraft.block.BlockState; +import net.minecraft.block.FourWayBlock; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.tileentity.ItemStackTileEntityRenderer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTUtil; + +public abstract class ZapperItemRenderer extends ItemStackTileEntityRenderer { + + protected void renderBlockUsed(ItemStack stack, ItemRenderer itemRenderer) { + BlockState state = NBTUtil.readBlockState(stack.getTag().getCompound("BlockUsed")); + + GlStateManager.pushMatrix(); + GlStateManager.translatef(-0.3F, -0.45F, -0.0F); + GlStateManager.scalef(0.25F, 0.25F, 0.25F); + IBakedModel modelForState = Minecraft.getInstance().getBlockRendererDispatcher().getModelForState(state); + + if (state.getBlock() instanceof FourWayBlock) + modelForState = Minecraft.getInstance().getItemRenderer() + .getModelWithOverrides(new ItemStack(state.getBlock())); + + itemRenderer.renderItem(new ItemStack(state.getBlock()), modelForState); + GlStateManager.popMatrix(); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapLog.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperLog.java similarity index 95% rename from src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapLog.java rename to src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperLog.java index 08b4e1969..1813a1d3c 100644 --- a/src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapLog.java +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperLog.java @@ -11,11 +11,11 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.gen.feature.template.Template.BlockInfo; -public class ZapLog { +public class ZapperLog { private World activeWorld; private List> log = new LinkedList<>(); - private int redoIndex; +// private int redoIndex; /* * Undo and redo operations applied by tools what information is necessary? @@ -42,7 +42,7 @@ public class ZapLog { }).collect(Collectors.toList()); log.add(0, blocks); - redoIndex = 0; +// redoIndex = 0; if (maxLogLength() < log.size()) log.remove(log.size() - 1); diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/BlockzapperHandler.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperRenderHandler.java similarity index 96% rename from src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/BlockzapperHandler.java rename to src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperRenderHandler.java index d070fe535..eecc637fa 100644 --- a/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/BlockzapperHandler.java +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperRenderHandler.java @@ -1,15 +1,14 @@ -package com.simibubi.create.modules.curiosities.zapper.blockzapper; +package com.simibubi.create.modules.curiosities.zapper; import java.util.LinkedList; import java.util.List; import java.util.Random; import java.util.function.Supplier; -import com.simibubi.create.AllSoundEvents; import org.lwjgl.opengl.GL11; import com.mojang.blaze3d.platform.GlStateManager; -import com.simibubi.create.AllItems; +import com.simibubi.create.AllSoundEvents; import com.simibubi.create.foundation.utility.TessellatorHelper; import net.minecraft.client.Minecraft; @@ -40,7 +39,7 @@ import net.minecraftforge.fml.common.Mod.EventBusSubscriber; @SuppressWarnings("deprecation") @EventBusSubscriber(value = Dist.CLIENT) -public class BlockzapperHandler { +public class ZapperRenderHandler { public static List cachedBeams; public static float leftHandAnimation; @@ -171,10 +170,9 @@ public class BlockzapperHandler { @SubscribeEvent public static void onRenderPlayerHand(RenderSpecificHandEvent event) { ItemStack heldItem = event.getItemStack(); - if (!AllItems.PLACEMENT_HANDGUN.typeOf(heldItem)) + if (!(heldItem.getItem() instanceof ZapperItem)) return; - boolean idle = !heldItem.getOrCreateTag().contains("BlockUsed"); Minecraft mc = Minecraft.getInstance(); boolean rightHand = event.getHand() == Hand.MAIN_HAND ^ mc.player.getPrimaryHand() == HandSide.LEFT; @@ -189,9 +187,7 @@ public class BlockzapperHandler { equipProgress = 0; if (!rightHand && (leftHandAnimation > .01f || dontReequipLeft)) equipProgress = 0; - if (idle) - equipProgress = 1 - event.getEquipProgress(); - + // Render arm float f = rightHand ? 1.0F : -1.0F; float f1 = MathHelper.sqrt(event.getSwingProgress()); diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperScreen.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperScreen.java new file mode 100644 index 000000000..035e94f0b --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/ZapperScreen.java @@ -0,0 +1,185 @@ +package com.simibubi.create.modules.curiosities.zapper; + +import java.util.Vector; + +import org.lwjgl.opengl.GL11; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.AllPackets; +import com.simibubi.create.ScreenResources; +import com.simibubi.create.foundation.gui.AbstractSimiScreen; +import com.simibubi.create.foundation.gui.widgets.IconButton; +import com.simibubi.create.foundation.packet.NbtPacket; +import com.simibubi.create.foundation.utility.Lang; + +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; +import net.minecraft.client.renderer.texture.AtlasTexture; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraftforge.client.model.data.EmptyModelData; + +@SuppressWarnings("deprecation") +public class ZapperScreen extends AbstractSimiScreen { + + protected ItemStack zapper; + protected boolean offhand; + protected float animationProgress; + protected ScreenResources background; + + protected final String patternSection = Lang.translate("gui.blockzapper.patternSection"); + + protected String title; + protected Vector patternButtons; + protected int brightColor; + protected int fontColor; + + public ZapperScreen(ScreenResources background, ItemStack zapper, boolean offhand) { + super(); + this.background = background; + this.zapper = zapper; + this.offhand = offhand; + title = ""; + brightColor = 0xCCDDFF; + fontColor = ScreenResources.FONT_COLOR; + } + + @Override + protected void init() { + animationProgress = 0; + setWindowSize(background.width + 40, background.height); + super.init(); + widgets.clear(); + + int i = guiLeft - 20; + int j = guiTop; + CompoundNBT nbt = zapper.getOrCreateTag(); + + patternButtons = new Vector<>(6); + for (int row = 0; row <= 1; row++) { + for (int col = 0; col <= 2; col++) { + int id = patternButtons.size(); + PlacementPatterns pattern = PlacementPatterns.values()[id]; + patternButtons.add(new IconButton(i + 147 + col * 18, j + 23 + row * 18, pattern.icon)); + patternButtons.get(id).setToolTip(Lang.translate("gui.blockzapper.pattern." + pattern.translationKey)); + } + } + + if (nbt.contains("Pattern")) + patternButtons.get(PlacementPatterns.valueOf(nbt.getString("Pattern")).ordinal()).active = false; + + widgets.addAll(patternButtons); + } + + @Override + protected void renderWindow(int mouseX, int mouseY, float partialTicks) { + int i = guiLeft - 20; + int j = guiTop; + + background.draw(this, i, j); + drawOnBackground(i, j); + + minecraft.getTextureManager().bindTexture(AtlasTexture.LOCATION_BLOCKS_TEXTURE); + GlStateManager.enableBlend(); + + renderBlock(); + renderZapper(); + } + + protected void drawOnBackground(int i, int j) { + font.drawStringWithShadow(title, i + 8, j + 10, brightColor); + font.drawString(patternSection, i + 148, j + 11, fontColor); + } + + @Override + public void tick() { + super.tick(); + animationProgress += 5; + } + + @Override + public void onClose() { + CompoundNBT nbt = zapper.getTag(); + writeAdditionalOptions(nbt); + AllPackets.channel.sendToServer(new NbtPacket(zapper, offhand ? Hand.OFF_HAND : Hand.MAIN_HAND)); + super.onClose(); + } + + @Override + public boolean mouseClicked(double x, double y, int button) { + CompoundNBT nbt = zapper.getTag(); + + for (IconButton patternButton : patternButtons) { + if (patternButton.isHovered()) { + patternButtons.forEach(b -> b.active = true); + patternButton.active = false; + patternButton.playDownSound(Minecraft.getInstance().getSoundHandler()); + nbt.putString("Pattern", PlacementPatterns.values()[patternButtons.indexOf(patternButton)].name()); + } + } + + return super.mouseClicked(x, y, button); + } + + protected void renderZapper() { + GlStateManager.pushLightingAttributes(); + GlStateManager.pushMatrix(); + + RenderHelper.enableStandardItemLighting(); + GlStateManager.enableBlend(); + GlStateManager.enableRescaleNormal(); + GlStateManager.enableAlphaTest(); + GlStateManager.alphaFunc(516, 0.1F); + GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); + GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F); + + GlStateManager.translated((this.width - this.sWidth) / 2 + 260, this.height / 2 - this.sHeight / 4, 100); + GlStateManager.rotatef(90 + 0.2f * animationProgress, 0, 1, 0); + GlStateManager.rotatef(-40, .8f, 0, -.0f); + GlStateManager.scaled(100, -100, 100); + + IBakedModel model = itemRenderer.getModelWithOverrides(zapper); + model.handlePerspective(TransformType.FIXED); + itemRenderer.renderItem(zapper, model); + + GlStateManager.disableAlphaTest(); + GlStateManager.disableRescaleNormal(); + GlStateManager.disableLighting(); + + GlStateManager.popMatrix(); + GlStateManager.popAttributes(); + } + + protected void renderBlock() { + GlStateManager.pushMatrix(); + BufferBuilder buffer = Tessellator.getInstance().getBuffer(); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK); + GlStateManager.translated(guiLeft + 1.7f, guiTop - 49, 120); + GlStateManager.rotatef(-30f, .5f, .9f, -.1f); + GlStateManager.scaled(20, -20, 20); + + BlockState state = Blocks.AIR.getDefaultState(); + if (zapper.hasTag() && zapper.getTag().contains("BlockUsed")) + state = NBTUtil.readBlockState(zapper.getTag().getCompound("BlockUsed")); + + minecraft.getBlockRendererDispatcher().renderBlock(state, new BlockPos(0, -5, 0), minecraft.world, buffer, + minecraft.world.rand, EmptyModelData.INSTANCE); + + Tessellator.getInstance().draw(); + GlStateManager.popMatrix(); + } + + protected void writeAdditionalOptions(CompoundNBT nbt) { + } + +} diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/BlockzapperItem.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/BlockzapperItem.java index 7a2e0ea26..20c0480b6 100644 --- a/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/BlockzapperItem.java +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/BlockzapperItem.java @@ -3,14 +3,9 @@ package com.simibubi.create.modules.curiosities.zapper.blockzapper; import java.util.HashSet; import java.util.LinkedList; import java.util.List; -import java.util.Random; import java.util.Set; -import java.util.function.Predicate; -import com.google.common.base.Predicates; import com.simibubi.create.AllItems; -import com.simibubi.create.AllPackets; -import com.simibubi.create.AllSoundEvents; import com.simibubi.create.Create; import com.simibubi.create.foundation.block.render.CustomRenderedItemModel; import com.simibubi.create.foundation.gui.ScreenOpener; @@ -20,34 +15,25 @@ import com.simibubi.create.foundation.item.ItemDescription.Palette; import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.NBTHelper; +import com.simibubi.create.modules.curiosities.zapper.PlacementPatterns; import com.simibubi.create.modules.curiosities.zapper.ZapperItem; import net.minecraft.advancements.CriteriaTriggers; import net.minecraft.block.Block; import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.Entity; -import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.fluid.IFluidState; import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; -import net.minecraft.nbt.NBTUtil; -import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.state.properties.StairsShape; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.ActionResult; -import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; -import net.minecraft.util.Hand; -import net.minecraft.util.HandSide; import net.minecraft.util.NonNullList; -import net.minecraft.util.SoundCategory; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.RayTraceContext; @@ -63,8 +49,6 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.util.BlockSnapshot; import net.minecraftforge.event.ForgeEventFactory; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.fml.network.PacketDistributor; public class BlockzapperItem extends ZapperItem implements IHaveCustomItemModel { @@ -72,23 +56,6 @@ public class BlockzapperItem extends ZapperItem implements IHaveCustomItemModel super(properties); } - public static enum ComponentTier { - None(TextFormatting.DARK_GRAY), Brass(TextFormatting.GOLD), Chromatic(TextFormatting.LIGHT_PURPLE), - - ; - - public TextFormatting color; - - private ComponentTier(TextFormatting color) { - this.color = color; - } - - } - - public static enum Components { - Body, Amplifier, Accelerator, Retriever, Scope - } - @Override @OnlyIn(Dist.CLIENT) public void addInformation(ItemStack stack, World worldIn, List tooltip, ITooltipFlag flagIn) { @@ -99,10 +66,10 @@ public class BlockzapperItem extends ZapperItem implements IHaveCustomItemModel for (Components c : Components.values()) { ComponentTier tier = getTier(c, stack); - ItemDescription.add(tooltip, - "> " + TextFormatting.GRAY + Lang.translate("blockzapper.component." + Lang.asId(c.name())) - + ": " + tier.color - + Lang.translate("blockzapper.componentTier." + Lang.asId(tier.name()))); + String componentName = + TextFormatting.GRAY + Lang.translate("blockzapper.component." + Lang.asId(c.name())); + String tierName = tier.color + Lang.translate("blockzapper.componentTier." + Lang.asId(tier.name())); + ItemDescription.add(tooltip, "> " + componentName + ": " + tierName); } } } @@ -125,183 +92,51 @@ public class BlockzapperItem extends ZapperItem implements IHaveCustomItemModel } } - @Override - public ActionResult onItemRightClick(World world, PlayerEntity player, Hand hand) { - ItemStack item = player.getHeldItem(hand); - CompoundNBT nbt = item.getOrCreateTag(); - - // Shift -> Open GUI - if (player.isSneaking()) { - if (world.isRemote) { - DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { - openHandgunGUI(item, hand == Hand.OFF_HAND); - }); - applyCooldown(player, item, false); - } - return new ActionResult(ActionResultType.SUCCESS, item); - } - - boolean mainHand = hand == Hand.MAIN_HAND; - boolean isSwap = item.getTag().contains("_Swap"); - boolean gunInOtherHand = AllItems.PLACEMENT_HANDGUN - .typeOf(player.getHeldItem(mainHand ? Hand.OFF_HAND : Hand.MAIN_HAND)); - - // Pass To Offhand - if (mainHand && isSwap && gunInOtherHand) - return new ActionResult(ActionResultType.FAIL, item); - if (mainHand && !isSwap && gunInOtherHand) - item.getTag().putBoolean("_Swap", true); - if (!mainHand && isSwap) - item.getTag().remove("_Swap"); - if (!mainHand && gunInOtherHand) - player.getHeldItem(Hand.MAIN_HAND).getTag().remove("_Swap"); - player.setActiveHand(hand); - - // Check if block setting is present - BlockState stateToUse = Blocks.AIR.getDefaultState(); - if (nbt.contains("BlockUsed")) - stateToUse = NBTUtil.readBlockState(nbt.getCompound("BlockUsed")); - else { - world.playSound(player, player.getPosition(), AllSoundEvents.BLOCKZAPPER_DENY.get(), SoundCategory.BLOCKS, 1f, - 0.5f); - player.sendStatusMessage( - new StringTextComponent(TextFormatting.RED + Lang.translate("blockzapper.leftClickToSet")), true); - return new ActionResult(ActionResultType.FAIL, item); - } - - // Raytrace - Find the target - Vec3d start = player.getPositionVec().add(0, player.getEyeHeight(), 0); - Vec3d range = player.getLookVec().scale(getReachDistance(item)); - BlockRayTraceResult raytrace = world.rayTraceBlocks( - new RayTraceContext(start, start.add(range), BlockMode.OUTLINE, FluidMode.NONE, player)); - BlockPos pos = raytrace.getPos(); - BlockState stateReplaced = world.getBlockState(pos); - - // No target - if (pos == null || stateReplaced.getBlock() == Blocks.AIR) { - applyCooldown(player, item, gunInOtherHand); - return new ActionResult(ActionResultType.SUCCESS, item); - } - - // Find exact position of gun barrel for VFX - float yaw = (float) ((player.rotationYaw) / -180 * Math.PI); - float pitch = (float) ((player.rotationPitch) / -180 * Math.PI); - Vec3d barrelPosNoTransform = new Vec3d(mainHand == (player.getPrimaryHand() == HandSide.RIGHT) ? -.35f : .35f, - -0.1f, 1); - Vec3d barrelPos = start.add(barrelPosNoTransform.rotatePitch(pitch).rotateYaw(yaw)); - - // Client side - if (world.isRemote) { - BlockzapperHandler.dontAnimateItem(hand); - return new ActionResult(ActionResultType.SUCCESS, item); - } - - // Server side - Replace Blocks + protected boolean activate(World world, PlayerEntity player, ItemStack stack, BlockState selectedState, + BlockRayTraceResult raytrace) { + CompoundNBT nbt = stack.getOrCreateTag(); boolean replace = nbt.contains("Replace") && nbt.getBoolean("Replace"); - List selectedBlocks = getSelectedBlocks(item, world, player); - applyPattern(selectedBlocks, item); + + List selectedBlocks = getSelectedBlocks(stack, world, player); + PlacementPatterns.applyPattern(selectedBlocks, stack); Direction face = raytrace.getFace(); for (BlockPos placed : selectedBlocks) { - if (world.getBlockState(placed) == stateToUse) + if (world.getBlockState(placed) == selectedState) continue; - if (!stateToUse.isValidPosition(world, placed)) + if (!selectedState.isValidPosition(world, placed)) continue; - if (!player.isCreative() && !canBreak(item, world.getBlockState(placed), world, placed)) + if (!player.isCreative() && !canBreak(stack, world.getBlockState(placed), world, placed)) continue; - if (!player.isCreative() && BlockHelper.findAndRemoveInInventory(stateToUse, player, 1) == 0) { - player.getCooldownTracker().setCooldown(item.getItem(), 20); + if (!player.isCreative() && BlockHelper.findAndRemoveInInventory(selectedState, player, 1) == 0) { + player.getCooldownTracker().setCooldown(stack.getItem(), 20); player.sendStatusMessage( new StringTextComponent(TextFormatting.RED + Lang.translate("blockzapper.empty")), true); - return new ActionResult(ActionResultType.SUCCESS, item); + return false; } if (!player.isCreative() && replace) - dropBlocks(world, player, item, face, placed); + dropBlocks(world, player, stack, face, placed); for (Direction updateDirection : Direction.values()) - stateToUse = stateToUse.updatePostPlacement(updateDirection, + selectedState = selectedState.updatePostPlacement(updateDirection, world.getBlockState(placed.offset(updateDirection)), world, placed, placed.offset(updateDirection)); BlockSnapshot blocksnapshot = BlockSnapshot.getBlockSnapshot(world, placed); IFluidState ifluidstate = world.getFluidState(placed); world.setBlockState(placed, ifluidstate.getBlockState(), 18); - world.setBlockState(placed, stateToUse); + world.setBlockState(placed, selectedState); if (ForgeEventFactory.onBlockPlace(player, blocksnapshot, Direction.UP)) { blocksnapshot.restore(true, false); - return new ActionResult(ActionResultType.FAIL, item); + return false; } if (player instanceof ServerPlayerEntity) CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayerEntity) player, placed, - new ItemStack(stateToUse.getBlock())); - + new ItemStack(selectedState.getBlock())); } - applyCooldown(player, item, gunInOtherHand); - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> player), - new BlockzapperBeamPacket(barrelPos, raytrace.getHitVec(), hand, false)); - AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), - new BlockzapperBeamPacket(barrelPos, raytrace.getHitVec(), hand, true)); - - return new ActionResult(ActionResultType.SUCCESS, item); - - } - - @Override - public boolean onBlockDestroyed(ItemStack stack, World worldIn, BlockState state, BlockPos pos, - LivingEntity entityLiving) { - if (entityLiving instanceof PlayerEntity && ((PlayerEntity) entityLiving).isCreative()) { - worldIn.setBlockState(pos, state); - return false; - } - return super.onBlockDestroyed(stack, worldIn, state, pos, entityLiving); - } - - @Override - public boolean onEntitySwing(ItemStack stack, LivingEntity entity) { - if (!(entity instanceof PlayerEntity)) - return false; - if (entity.isSneaking()) - return true; - - Vec3d start = entity.getPositionVec().add(0, entity.getEyeHeight(), 0); - Vec3d range = entity.getLookVec().scale(getReachDistance(stack)); - BlockRayTraceResult raytrace = entity.world.rayTraceBlocks( - new RayTraceContext(start, start.add(range), BlockMode.OUTLINE, FluidMode.NONE, entity)); - BlockPos pos = raytrace.getPos(); - if (pos == null) - return true; - - entity.world.sendBlockBreakProgress(entity.getEntityId(), pos, -1); - BlockState newState = entity.world.getBlockState(pos); - - if (BlockHelper.getRequiredItem(newState).isEmpty()) - return true; - if (entity.world.getTileEntity(pos) != null) - return true; - if (newState.has(BlockStateProperties.DOUBLE_BLOCK_HALF)) - return true; - if (newState.has(BlockStateProperties.ATTACHED)) - return true; - if (newState.has(BlockStateProperties.HANGING)) - return true; - if (newState.has(BlockStateProperties.BED_PART)) - return true; - if (newState.has(BlockStateProperties.STAIRS_SHAPE)) - newState = newState.with(BlockStateProperties.STAIRS_SHAPE, StairsShape.STRAIGHT); - if (newState.has(BlockStateProperties.PERSISTENT)) - newState = newState.with(BlockStateProperties.PERSISTENT, true); - - if (stack.getTag().contains("BlockUsed") - && NBTUtil.readBlockState(stack.getTag().getCompound("BlockUsed")) == newState) - return true; - - stack.getTag().put("BlockUsed", NBTUtil.writeBlockState(newState)); - entity.world.playSound((PlayerEntity) entity, entity.getPosition(), AllSoundEvents.BLOCKZAPPER_CONFIRM.get(), - SoundCategory.BLOCKS, 0.5f, 0.8f); - return true; } @@ -322,38 +157,13 @@ public class BlockzapperItem extends ZapperItem implements IHaveCustomItemModel } } - @Override - public boolean onBlockStartBreak(ItemStack itemstack, BlockPos pos, PlayerEntity player) { - return true; - } - - @Override - public int getUseDuration(ItemStack stack) { - return 0; - } - - @Override - public void onPlayerStoppedUsing(ItemStack stack, World worldIn, LivingEntity entityLiving, int timeLeft) { - super.onPlayerStoppedUsing(stack, worldIn, entityLiving, timeLeft); - } - - @Override - public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { - boolean differentBlock = true; - if (oldStack.hasTag() && newStack.hasTag() && oldStack.getTag().contains("BlockUsed") - && newStack.getTag().contains("BlockUsed")) - differentBlock = NBTUtil.readBlockState(oldStack.getTag().getCompound("BlockUsed")) != NBTUtil - .readBlockState(newStack.getTag().getCompound("BlockUsed")); - return slotChanged || !AllItems.PLACEMENT_HANDGUN.typeOf(newStack) || differentBlock; - } - @Override @OnlyIn(Dist.CLIENT) protected void openHandgunGUI(ItemStack handgun, boolean offhand) { ScreenOpener.open(new BlockzapperScreen(handgun, offhand)); } - public static List getSelectedBlocks(ItemStack stack, World worldIn, PlayerEntity player) { + public List getSelectedBlocks(ItemStack stack, World worldIn, PlayerEntity player) { List list = new LinkedList<>(); CompoundNBT tag = stack.getTag(); if (tag == null) @@ -368,7 +178,7 @@ public class BlockzapperItem extends ZapperItem implements IHaveCustomItemModel List frontier = new LinkedList<>(); Vec3d start = player.getPositionVec().add(0, player.getEyeHeight(), 0); - Vec3d range = player.getLookVec().scale(getReachDistance(stack)); + Vec3d range = player.getLookVec().scale(getRange(stack)); BlockRayTraceResult raytrace = player.world.rayTraceBlocks( new RayTraceContext(start, start.add(range), BlockMode.COLLIDER, FluidMode.NONE, player)); BlockPos pos = raytrace.getPos().toImmutable(); @@ -479,11 +289,12 @@ public class BlockzapperItem extends ZapperItem implements IHaveCustomItemModel return 6; if (tier == ComponentTier.Chromatic) return 2; - + return 20; } - - public static int getReachDistance(ItemStack stack) { + + @Override + protected int getRange(ItemStack stack) { ComponentTier tier = getTier(Components.Scope, stack); if (tier == ComponentTier.None) return 15; @@ -495,37 +306,6 @@ public class BlockzapperItem extends ZapperItem implements IHaveCustomItemModel return 0; } - public static void applyPattern(List blocksIn, ItemStack stack) { - CompoundNBT tag = stack.getTag(); - PlacementPatterns pattern = !tag.contains("Pattern") ? PlacementPatterns.Solid - : PlacementPatterns.valueOf(tag.getString("Pattern")); - Random r = new Random(); - Predicate filter = Predicates.alwaysFalse(); - - switch (pattern) { - case Chance25: - filter = pos -> r.nextBoolean() || r.nextBoolean(); - break; - case Chance50: - filter = pos -> r.nextBoolean(); - break; - case Chance75: - filter = pos -> r.nextBoolean() && r.nextBoolean(); - break; - case Checkered: - filter = pos -> (pos.getX() + pos.getY() + pos.getZ()) % 2 == 0; - break; - case InverseCheckered: - filter = pos -> (pos.getX() + pos.getY() + pos.getZ()) % 2 != 0; - break; - case Solid: - default: - break; - } - - blocksIn.removeIf(filter); - } - protected static void dropBlocks(World worldIn, PlayerEntity playerIn, ItemStack item, Direction face, BlockPos placed) { TileEntity tileentity = worldIn.getBlockState(placed).hasTileEntity() ? worldIn.getTileEntity(placed) : null; @@ -554,6 +334,20 @@ public class BlockzapperItem extends ZapperItem implements IHaveCustomItemModel stack.getOrCreateTag().putString(component.name(), NBTHelper.writeEnum(tier)); } + public static enum ComponentTier { + None(TextFormatting.DARK_GRAY), Brass(TextFormatting.GOLD), Chromatic(TextFormatting.LIGHT_PURPLE); + public TextFormatting color; + + private ComponentTier(TextFormatting color) { + this.color = color; + } + + } + + public static enum Components { + Body, Amplifier, Accelerator, Retriever, Scope + } + @Override @OnlyIn(value = Dist.CLIENT) public CustomRenderedItemModel createModel(IBakedModel original) { diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/BlockzapperItemRenderer.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/BlockzapperItemRenderer.java index 6501607a3..bb62182c9 100644 --- a/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/BlockzapperItemRenderer.java +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/BlockzapperItemRenderer.java @@ -9,24 +9,22 @@ import static com.simibubi.create.modules.curiosities.zapper.blockzapper.Blockza import com.mojang.blaze3d.platform.GLX; import com.mojang.blaze3d.platform.GlStateManager; import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.modules.curiosities.zapper.ZapperRenderHandler; +import com.simibubi.create.modules.curiosities.zapper.ZapperItemRenderer; import com.simibubi.create.modules.curiosities.zapper.blockzapper.BlockzapperItem.ComponentTier; import com.simibubi.create.modules.curiosities.zapper.blockzapper.BlockzapperItem.Components; -import net.minecraft.block.BlockState; -import net.minecraft.block.FourWayBlock; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.renderer.ItemRenderer; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; -import net.minecraft.client.renderer.tileentity.ItemStackTileEntityRenderer; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTUtil; import net.minecraft.util.HandSide; import net.minecraft.util.math.MathHelper; @SuppressWarnings("deprecation") -public class BlockzapperItemRenderer extends ItemStackTileEntityRenderer { +public class BlockzapperItemRenderer extends ZapperItemRenderer { @Override public void renderByItem(ItemStack stack) { @@ -56,10 +54,10 @@ public class BlockzapperItemRenderer extends ItemStackTileEntityRenderer { boolean leftHanded = player.getPrimaryHand() == HandSide.LEFT; boolean mainHand = player.getHeldItemMainhand() == stack; boolean offHand = player.getHeldItemOffhand() == stack; - float last = mainHand ^ leftHanded ? BlockzapperHandler.lastRightHandAnimation - : BlockzapperHandler.lastLeftHandAnimation; - float current = mainHand ^ leftHanded ? BlockzapperHandler.rightHandAnimation - : BlockzapperHandler.leftHandAnimation; + float last = mainHand ^ leftHanded ? ZapperRenderHandler.lastRightHandAnimation + : ZapperRenderHandler.lastLeftHandAnimation; + float current = mainHand ^ leftHanded ? ZapperRenderHandler.rightHandAnimation + : ZapperRenderHandler.leftHandAnimation; float animation = MathHelper.clamp(MathHelper.lerp(pt, last, current) * 5, 0, 1); // Core glows @@ -90,22 +88,6 @@ public class BlockzapperItemRenderer extends ItemStackTileEntityRenderer { GlStateManager.popMatrix(); } - public void renderBlockUsed(ItemStack stack, ItemRenderer itemRenderer) { - BlockState state = NBTUtil.readBlockState(stack.getTag().getCompound("BlockUsed")); - - GlStateManager.pushMatrix(); - GlStateManager.translatef(-0.3F, -0.45F, -0.0F); - GlStateManager.scalef(0.25F, 0.25F, 0.25F); - IBakedModel modelForState = Minecraft.getInstance().getBlockRendererDispatcher().getModelForState(state); - - if (state.getBlock() instanceof FourWayBlock) - modelForState = Minecraft.getInstance().getItemRenderer() - .getModelWithOverrides(new ItemStack(state.getBlock())); - - itemRenderer.renderItem(new ItemStack(state.getBlock()), modelForState); - GlStateManager.popMatrix(); - } - public void renderComponent(ItemStack stack, BlockzapperModel model, Components component, ItemRenderer itemRenderer) { ComponentTier tier = BlockzapperItem.getTier(component, stack); diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/BlockzapperScreen.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/BlockzapperScreen.java index 1eeeb3a49..452ca4d77 100644 --- a/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/BlockzapperScreen.java +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/BlockzapperScreen.java @@ -1,48 +1,22 @@ package com.simibubi.create.modules.curiosities.zapper.blockzapper; import java.util.Collections; -import java.util.Vector; -import org.lwjgl.opengl.GL11; - -import com.mojang.blaze3d.platform.GlStateManager; -import com.simibubi.create.AllPackets; import com.simibubi.create.ScreenResources; -import com.simibubi.create.foundation.gui.AbstractSimiScreen; import com.simibubi.create.foundation.gui.widgets.IconButton; import com.simibubi.create.foundation.gui.widgets.Indicator; import com.simibubi.create.foundation.gui.widgets.Indicator.State; import com.simibubi.create.foundation.gui.widgets.Label; import com.simibubi.create.foundation.gui.widgets.ScrollInput; -import com.simibubi.create.foundation.packet.NbtPacket; import com.simibubi.create.foundation.utility.Lang; +import com.simibubi.create.modules.curiosities.zapper.ZapperScreen; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.RenderHelper; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.model.IBakedModel; -import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; -import net.minecraft.client.renderer.texture.AtlasTexture; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; -import net.minecraft.nbt.NBTUtil; -import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextFormatting; -import net.minecraftforge.client.model.data.EmptyModelData; -@SuppressWarnings("deprecation") -public class BlockzapperScreen extends AbstractSimiScreen { +public class BlockzapperScreen extends ZapperScreen { - private ItemStack item; - private boolean offhand; - private float animationProgress; - - private final String title = Lang.translate("gui.blockzapper.title"); - private final String patternSection = Lang.translate("gui.blockzapper.patternSection"); private final String needsUpgradedAmplifier = Lang.translate("gui.blockzapper.needsUpgradedAmplifier"); private IconButton replaceModeButton; @@ -54,26 +28,20 @@ public class BlockzapperScreen extends AbstractSimiScreen { private ScrollInput spreadRangeInput; private Label spreadRangeLabel; - - private Vector patternButtons; - - public BlockzapperScreen(ItemStack handgun, boolean offhand) { - super(); - item = handgun; - this.offhand = offhand; + + public BlockzapperScreen(ItemStack zapper, boolean offhand) { + super(ScreenResources.BLOCKZAPPER, zapper, offhand); + title = Lang.translate("gui.blockzapper.title"); } @Override protected void init() { - animationProgress = 0; - setWindowSize(ScreenResources.PLACEMENT_GUN.width + 40, ScreenResources.PLACEMENT_GUN.height); super.init(); + int i = guiLeft - 20; int j = guiTop; + CompoundNBT nbt = zapper.getOrCreateTag(); - CompoundNBT nbt = item.getOrCreateTag(); - - widgets.clear(); replaceModeIndicator = new Indicator(i + 51, j + 36, ""); replaceModeButton = new IconButton(i + 51, j + 41, ScreenResources.I_REPLACE_SOLID); if (nbt.contains("Replace") && nbt.getBoolean("Replace")) @@ -93,39 +61,22 @@ public class BlockzapperScreen extends AbstractSimiScreen { spreadMaterialButton.setToolTip(Lang.translate("gui.blockzapper.searchFuzzy")); spreadRangeLabel = new Label(i + 119, j + 46, "").withShadow().withSuffix("m"); - spreadRangeInput = new ScrollInput(i + 115, j + 43, 22, 14).withRange(1, BlockzapperItem.getMaxAoe(item)) + spreadRangeInput = new ScrollInput(i + 115, j + 43, 22, 14).withRange(1, BlockzapperItem.getMaxAoe(zapper)) .setState(1).titled(Lang.translate("gui.blockzapper.range")).writingTo(spreadRangeLabel); if (nbt.contains("SearchDistance")) spreadRangeInput.setState(nbt.getInt("SearchDistance")); - if (BlockzapperItem.getMaxAoe(item) == 2) + if (BlockzapperItem.getMaxAoe(zapper) == 2) spreadRangeInput.getToolTip().add(1, TextFormatting.RED + needsUpgradedAmplifier); Collections.addAll(widgets, replaceModeButton, replaceModeIndicator, spreadDiagonallyButton, spreadDiagonallyIndicator, spreadMaterialButton, spreadMaterialIndicator, spreadRangeLabel, spreadRangeInput); - - patternButtons = new Vector<>(6); - for (int row = 0; row <= 1; row++) { - for (int col = 0; col <= 2; col++) { - int id = patternButtons.size(); - PlacementPatterns pattern = PlacementPatterns.values()[id]; - patternButtons.add(new IconButton(i + 147 + col * 18, j + 23 + row * 18, pattern.icon)); - patternButtons.get(id).setToolTip(Lang.translate("gui.blockzapper.pattern." + pattern.translationKey)); - - } - } - - if (nbt.contains("Pattern")) - patternButtons.get(PlacementPatterns.valueOf(nbt.getString("Pattern")).ordinal()).active = false; - - widgets.addAll(patternButtons); - } @Override public boolean mouseClicked(double x, double y, int button) { - CompoundNBT nbt = item.getTag(); + CompoundNBT nbt = zapper.getTag(); if (replaceModeButton.isHovered()) { boolean mode = nbt.contains("Replace") && nbt.getBoolean("Replace"); @@ -148,91 +99,13 @@ public class BlockzapperScreen extends AbstractSimiScreen { nbt.putBoolean("SearchFuzzy", mode); } - for (IconButton patternButton : patternButtons) { - if (patternButton.isHovered()) { - patternButtons.forEach(b -> b.active = true); - patternButton.active = false; - patternButton.playDownSound(Minecraft.getInstance().getSoundHandler()); - nbt.putString("Pattern", PlacementPatterns.values()[patternButtons.indexOf(patternButton)].name()); - } - } - return super.mouseClicked(x, y, button); } + @Override - public void onClose() { - CompoundNBT nbt = item.getTag(); + protected void writeAdditionalOptions(CompoundNBT nbt) { nbt.putInt("SearchDistance", spreadRangeInput.getState()); - AllPackets.channel.sendToServer(new NbtPacket(item, offhand ? -2 : -1)); - super.onClose(); - } - - @Override - public void tick() { - super.tick(); - animationProgress += 5; - } - - @Override - protected void renderWindow(int mouseX, int mouseY, float partialTicks) { - int i = guiLeft - 20; - int j = guiTop; - ScreenResources.PLACEMENT_GUN.draw(this, i, j); - - font.drawStringWithShadow(title, i + 8, j + 10, 0xCCDDFF); - font.drawString(patternSection, i + 148, j + 11, ScreenResources.FONT_COLOR); - - minecraft.getTextureManager().bindTexture(AtlasTexture.LOCATION_BLOCKS_TEXTURE); - GlStateManager.enableBlend(); - - renderBlock(); - - GlStateManager.pushLightingAttributes(); - GlStateManager.pushMatrix(); - - RenderHelper.enableStandardItemLighting(); - GlStateManager.enableBlend(); - GlStateManager.enableRescaleNormal(); - GlStateManager.enableAlphaTest(); - GlStateManager.alphaFunc(516, 0.1F); - GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); - GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F); - - GlStateManager.translated((this.width - this.sWidth) / 2 + 260, this.height / 2 - this.sHeight / 4, 100); - GlStateManager.rotatef(90 + 0.2f * animationProgress, 0, 1, 0); - GlStateManager.rotatef(-40, .8f, 0, -.0f); - GlStateManager.scaled(100, -100, 100); - - IBakedModel model = itemRenderer.getModelWithOverrides(item); - model.handlePerspective(TransformType.FIXED); - itemRenderer.renderItem(item, model); - - GlStateManager.disableAlphaTest(); - GlStateManager.disableRescaleNormal(); - GlStateManager.disableLighting(); - - GlStateManager.popMatrix(); - GlStateManager.popAttributes(); - } - - private void renderBlock() { - GlStateManager.pushMatrix(); - BufferBuilder buffer = Tessellator.getInstance().getBuffer(); - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK); - GlStateManager.translated(guiLeft + 1.7f, guiTop - 49, 120); - GlStateManager.rotatef(-30f, .5f, .9f, -.1f); - GlStateManager.scaled(20, -20, 20); - - BlockState state = Blocks.BEACON.getDefaultState(); - if (item.hasTag() && item.getTag().contains("BlockUsed")) - state = NBTUtil.readBlockState(item.getTag().getCompound("BlockUsed")); - - minecraft.getBlockRendererDispatcher().renderBlock(state, new BlockPos(0, -5, 0), minecraft.world, buffer, - minecraft.world.rand, EmptyModelData.INSTANCE); - - Tessellator.getInstance().draw(); - GlStateManager.popMatrix(); } } diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/PlacementPatterns.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/PlacementPatterns.java deleted file mode 100644 index 8065dd692..000000000 --- a/src/main/java/com/simibubi/create/modules/curiosities/zapper/blockzapper/PlacementPatterns.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.simibubi.create.modules.curiosities.zapper.blockzapper; - -import com.simibubi.create.ScreenResources; -import com.simibubi.create.foundation.utility.Lang; - -public enum PlacementPatterns { - - Solid(ScreenResources.I_PATTERN_SOLID), - Checkered(ScreenResources.I_PATTERN_CHECKERED), - InverseCheckered(ScreenResources.I_PATTERN_CHECKERED_INVERSED), - Chance25(ScreenResources.I_PATTERN_CHANCE_25), - Chance50(ScreenResources.I_PATTERN_CHANCE_50), - Chance75(ScreenResources.I_PATTERN_CHANCE_75); - - public String translationKey; - public ScreenResources icon; - - private PlacementPatterns(ScreenResources icon) { - this.translationKey = Lang.asId(name()); - this.icon = icon; - } - -} diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/Brush.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/Brush.java new file mode 100644 index 000000000..1f4ae95e9 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/Brush.java @@ -0,0 +1,54 @@ +package com.simibubi.create.modules.curiosities.zapper.terrainzapper; + +import java.util.List; + +import com.simibubi.create.foundation.utility.Lang; + +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.shapes.VoxelShape; + +public abstract class Brush { + + protected int param0; + protected int param1; + protected int param2; + int amtParams; + + public Brush(int amtParams) { + this.amtParams = amtParams; + } + + public void set(int param0, int param1, int param2) { + this.param0 = param0; + this.param1 = param1; + this.param2 = param2; + } + + int getMax(int paramIndex) { + return Integer.MAX_VALUE; + } + + int getMin(int paramIndex) { + return 0; + } + + String getParamLabel(int paramIndex) { + return Lang + .translate(paramIndex == 0 ? "generic.width" : paramIndex == 1 ? "generic.height" : "generic.length"); + } + + public int get(int paramIndex) { + return paramIndex == 0 ? param0 : paramIndex == 1 ? param1 : param2; + } + + public BlockPos getOffset(Vec3d ray, Direction face, PlacementOptions option) { + return BlockPos.ZERO; + } + + abstract VoxelShape getSelectionBox(); + + abstract List getIncludedPositions(); + +} diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/CuboidBrush.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/CuboidBrush.java new file mode 100644 index 000000000..0bd7c07b9 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/CuboidBrush.java @@ -0,0 +1,79 @@ +package com.simibubi.create.modules.curiosities.zapper.terrainzapper; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.AxisDirection; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.util.math.shapes.VoxelShapes; + +public class CuboidBrush extends Brush { + + public static final int MAX_SIZE = 32; + private VoxelShape shape; + private List positions; + + public CuboidBrush() { + super(3); + shape = VoxelShapes.empty(); + positions = new ArrayList<>(); + } + + @Override + public void set(int param0, int param1, int param2) { + boolean updateShape = this.param0 != param0 || this.param1 != param1 || this.param2 != param2; + super.set(param0, param1, param2); + + if (updateShape) { + BlockPos zero = BlockPos.ZERO; + shape = VoxelShapes.create(new AxisAlignedBB(zero).grow(1 / 32f) + .grow(((param0 - 1) / 2f), ((param1 - 1) / 2f), ((param2 - 1) / 2f)) + .offset((1 - param0 % 2) * .5f, (1 - param1 % 2) * .5f, (1 - param2 % 2) * .5f)); + positions = BlockPos + .getAllInBox(zero.add((param0 - 1) / -2, (param1 - 1) / -2, (param2 - 1) / -2), + zero.add((param0) / 2, (param1) / 2, (param2) / 2)) + .map(BlockPos::new).collect(Collectors.toList()); + } + } + + @Override + int getMin(int paramIndex) { + return 1; + } + + @Override + int getMax(int paramIndex) { + return MAX_SIZE; + } + + @Override + public BlockPos getOffset(Vec3d ray, Direction face, PlacementOptions option) { + if (option == PlacementOptions.Merged) + return BlockPos.ZERO; + + int offset = + option == PlacementOptions.Attached ? face.getAxisDirection() == AxisDirection.NEGATIVE ? 2 : 1 : 0; + int x = (param0 + (param0 == 0 ? 0 : offset)) / 2; + int y = (param1 + (param1 == 0 ? 0 : offset)) / 2; + int z = (param2 + (param2 == 0 ? 0 : offset)) / 2; + + return BlockPos.ZERO.offset(face, + face.getAxis().getCoordinate(x, y, z) * (option == PlacementOptions.Attached ? 1 : -1)); + } + + @Override + List getIncludedPositions() { + return positions; + } + + @Override + VoxelShape getSelectionBox() { + return shape; + } + +} diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/CylinderBrush.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/CylinderBrush.java index 12834c87b..b1311134a 100644 --- a/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/CylinderBrush.java +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/CylinderBrush.java @@ -1,5 +1,6 @@ package com.simibubi.create.modules.curiosities.zapper.terrainzapper; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -7,45 +8,95 @@ import java.util.stream.Collectors; import org.apache.commons.lang3.tuple.Pair; +import com.simibubi.create.foundation.utility.Lang; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.block.Block; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShapes; -public class CylinderBrush { +public class CylinderBrush extends Brush { public static final int MAX_RADIUS = 6; - public static final int MAX_HEIGHT = 6; + public static final int MAX_HEIGHT = 8; private Map, Pair, VoxelShape>> cachedBrushes; public CylinderBrush() { + super(2); + cachedBrushes = new HashMap<>(); - VoxelShape fullCube = VoxelShapes.fullCube(); + VoxelShape fullCube = Block.makeCuboidShape(-.5f, -.5f, -.5f, 16.5f, 16.5f, 16.5f); for (int i = 0; i <= MAX_RADIUS; i++) { int radius = i; VoxelShape shape = VoxelShapes.empty(); - List positions = BlockPos.getAllInBox(BlockPos.ZERO.add(-i, 0, -i), BlockPos.ZERO.add(i, 0, i)) - .filter(p -> p.withinDistance(BlockPos.ZERO, radius)).collect(Collectors.toList()); + List positions = + BlockPos.getAllInBox(BlockPos.ZERO.add(-i - 1, 0, -i - 1), BlockPos.ZERO.add(i + 1, 0, i + 1)) + .map(BlockPos::new).filter(p -> VecHelper.getCenterOf(p) + .distanceTo(VecHelper.getCenterOf(BlockPos.ZERO)) < radius + .42f) + .collect(Collectors.toList()); for (BlockPos p : positions) shape = VoxelShapes.or(shape, fullCube.withOffset(p.getX(), p.getY(), p.getZ())); for (int h = 0; h <= MAX_HEIGHT; h++) { + List stackedPositions = new ArrayList<>(); VoxelShape stackedShape = shape.simplify(); - for (int layer = 0; layer <= layer; i++) - stackedShape = VoxelShapes.or(stackedShape, shape.withOffset(0, layer - h / 2, 0)); - cachedBrushes.put(Pair.of(i, h), Pair.of(positions, stackedShape.simplify())); + for (int layer = 0; layer < h; layer++) { + int yOffset = layer - h / 2; + stackedShape = VoxelShapes.or(stackedShape, shape.withOffset(0, yOffset, 0)); + for (BlockPos p : positions) + stackedPositions.add(p.up(yOffset)); + } + cachedBrushes.put(Pair.of(i, h), Pair.of(stackedPositions, stackedShape.simplify())); } } } - public VoxelShape getSelectionBox(int radius, int height) { - return get(radius, height).getRight(); + @Override + public BlockPos getOffset(Vec3d ray, Direction face, PlacementOptions option) { + if (option == PlacementOptions.Merged) + return BlockPos.ZERO; + + int offset = option == PlacementOptions.Attached ? 0 : -1; + boolean negative = face.getAxisDirection() == AxisDirection.NEGATIVE; + int yOffset = option == PlacementOptions.Attached ? negative ? 1 : 2 : negative ? 0 : -1; + int r = (param0 + 1 + offset); + int y = (param1 + (param1 == 0 ? 0 : yOffset)) / 2; + + return BlockPos.ZERO.offset(face, + (face.getAxis().isVertical() ? y : r) * (option == PlacementOptions.Attached ? 1 : -1)); } - public List getIncludedPositions(int radius, int height) { - return get(radius, height).getLeft(); + @Override + int getMax(int paramIndex) { + return paramIndex == 0 ? MAX_RADIUS : MAX_HEIGHT; } - protected Pair, VoxelShape> get(int radius, int height) { + @Override + int getMin(int paramIndex) { + return paramIndex == 0 ? 0 : 1; + } + + @Override + String getParamLabel(int paramIndex) { + return paramIndex == 0 ? Lang.translate("generic.radius") : super.getParamLabel(paramIndex); + } + + @Override + VoxelShape getSelectionBox() { + return getEntry(param0, param1).getRight(); + } + + @Override + public List getIncludedPositions() { + return getEntry(param0, param1).getLeft(); + } + + protected Pair, VoxelShape> getEntry(int radius, int height) { return cachedBrushes.get(Pair.of(Integer.valueOf(radius), Integer.valueOf(height))); } + } diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/FlattenTool.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/FlattenTool.java new file mode 100644 index 000000000..88da6c719 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/FlattenTool.java @@ -0,0 +1,180 @@ +package com.simibubi.create.modules.curiosities.zapper.terrainzapper; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.tuple.Pair; + +import net.minecraft.block.BlockState; +import net.minecraft.block.FlowingFluidBlock; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; + +public class FlattenTool { + + // gaussian with sig=1 + static float[][] kernel = { + + { 0.003765f, 0.015019f, 0.023792f, 0.015019f, 0.003765f }, + { 0.015019f, 0.059912f, 0.094907f, 0.059912f, 0.015019f }, + { 0.023792f, 0.094907f, 0.150342f, 0.094907f, 0.023792f }, + { 0.015019f, 0.059912f, 0.094907f, 0.059912f, 0.015019f }, + { 0.003765f, 0.015019f, 0.023792f, 0.015019f, 0.003765f }, + + }; + + private static int[][] applyKernel(int[][] values) { + int[][] result = new int[values.length][values[0].length]; + for (int i = 0; i < values.length; i++) { + for (int j = 0; j < values[i].length; j++) { + int value = values[i][j]; + float newValue = 0; + for (int iOffset = -2; iOffset <= 2; iOffset++) { + for (int jOffset = -2; jOffset <= 2; jOffset++) { + int iTarget = i + iOffset; + int jTarget = j + jOffset; + int ref = 0; + if (iTarget < 0 || iTarget >= values.length || jTarget < 0 || jTarget >= values[0].length) + ref = value; + else + ref = values[iTarget][jTarget]; + if (ref == Integer.MIN_VALUE) + ref = value; + newValue += kernel[iOffset + 2][jOffset + 2] * ref; + } + } + result[i][j] = MathHelper.floor(newValue + .5f); + } + } + return result; + } + + public static void apply(World world, List targetPositions, Direction facing) { + List surfaces = new ArrayList<>(); + Map, Integer> heightMap = new HashMap<>(); + int offset = facing.getAxisDirection().getOffset(); + + int minEntry = Integer.MAX_VALUE; + int minCoord1 = Integer.MAX_VALUE; + int minCoord2 = Integer.MAX_VALUE; + int maxEntry = Integer.MIN_VALUE; + int maxCoord1 = Integer.MIN_VALUE; + int maxCoord2 = Integer.MIN_VALUE; + + for (BlockPos p : targetPositions) { + Pair coords = getCoords(p, facing); + BlockState belowSurface = world.getBlockState(p); + + minCoord1 = Math.min(minCoord1, coords.getKey()); + minCoord2 = Math.min(minCoord2, coords.getValue()); + maxCoord1 = Math.max(maxCoord1, coords.getKey()); + maxCoord2 = Math.max(maxCoord2, coords.getValue()); + + if (TerrainTools.isReplaceable(belowSurface)) { + if (!heightMap.containsKey(coords)) + heightMap.put(coords, Integer.MIN_VALUE); + continue; + } + + p = p.offset(facing); + BlockState surface = world.getBlockState(p); + + if (!TerrainTools.isReplaceable(surface)) { + if (!heightMap.containsKey(coords) || heightMap.get(coords).equals(Integer.MIN_VALUE)) + heightMap.put(coords, Integer.MAX_VALUE); + continue; + } + + surfaces.add(p); + int coordinate = facing.getAxis().getCoordinate(p.getX(), p.getY(), p.getZ()); + if (!heightMap.containsKey(coords) || heightMap.get(coords).equals(Integer.MAX_VALUE) + || heightMap.get(coords).equals(Integer.MIN_VALUE) + || heightMap.get(coords) * offset < coordinate * offset) { + heightMap.put(coords, coordinate); + maxEntry = Math.max(maxEntry, coordinate); + minEntry = Math.min(minEntry, coordinate); + } + } + + if (surfaces.isEmpty()) + return; + + // fill heightmap + int[][] heightMapArray = new int[maxCoord1 - minCoord1 + 1][maxCoord2 - minCoord2 + 1]; + for (int i = 0; i < heightMapArray.length; i++) { + for (int j = 0; j < heightMapArray[i].length; j++) { + Pair pair = Pair.of(minCoord1 + i, minCoord2 + j); + if (!heightMap.containsKey(pair)) { + heightMapArray[i][j] = Integer.MIN_VALUE; + continue; + } + Integer height = heightMap.get(pair); + if (height.equals(Integer.MAX_VALUE)) { + heightMapArray[i][j] = offset == 1 ? maxEntry + 2 : minEntry - 2; + continue; + } + if (height.equals(Integer.MIN_VALUE)) { + heightMapArray[i][j] = offset == 1 ? minEntry - 2 : maxEntry + 2; + continue; + } + + heightMapArray[i][j] = height; + } + } + + heightMapArray = applyKernel(heightMapArray); + + for (BlockPos p : surfaces) { + Pair coords = getCoords(p, facing); + int surfaceCoord = facing.getAxis().getCoordinate(p.getX(), p.getY(), p.getZ()) * offset; + int targetCoord = heightMapArray[coords.getKey() - minCoord1][coords.getValue() - minCoord2] * offset; + + // Keep surface + if (surfaceCoord == targetCoord) + continue; + + // Lower surface + BlockState blockState = world.getBlockState(p); + int timeOut = 1000; + while (surfaceCoord > targetCoord) { + BlockPos below = p.offset(facing.getOpposite()); + world.setBlockState(below, blockState); + world.setBlockState(p, blockState.getFluidState().getBlockState()); + p = p.offset(facing.getOpposite()); + surfaceCoord--; + if (timeOut-- <= 0) + break; + } + + // Raise surface + while (surfaceCoord < targetCoord) { + BlockPos above = p.offset(facing); + if (!(blockState.getBlock() instanceof FlowingFluidBlock)) + world.setBlockState(above, blockState); + world.setBlockState(p, world.getBlockState(p.offset(facing.getOpposite()))); + p = p.offset(facing); + surfaceCoord++; + if (timeOut-- <= 0) + break; + } + + } + } + + private static Pair getCoords(BlockPos pos, Direction facing) { + switch (facing.getAxis()) { + case X: + return Pair.of(pos.getZ(), pos.getY()); + case Y: + return Pair.of(pos.getX(), pos.getZ()); + case Z: + return Pair.of(pos.getX(), pos.getY()); + } + return null; + } + +} diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/PlacementOptions.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/PlacementOptions.java new file mode 100644 index 000000000..b443495ef --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/PlacementOptions.java @@ -0,0 +1,20 @@ +package com.simibubi.create.modules.curiosities.zapper.terrainzapper; + +import com.simibubi.create.ScreenResources; +import com.simibubi.create.foundation.utility.Lang; + +public enum PlacementOptions { + + Merged(ScreenResources.I_CENTERED), + Attached(ScreenResources.I_ATTACHED), + Inserted(ScreenResources.I_INSERTED); + + public String translationKey; + public ScreenResources icon; + + private PlacementOptions(ScreenResources icon) { + this.translationKey = Lang.asId(name()); + this.icon = icon; + } + +} diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/SphereBrush.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/SphereBrush.java index d12ee8f88..27af6a085 100644 --- a/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/SphereBrush.java +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/SphereBrush.java @@ -7,23 +7,34 @@ import java.util.stream.Collectors; import org.apache.commons.lang3.tuple.Pair; +import com.simibubi.create.foundation.utility.Lang; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.block.Block; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShapes; -public class SphereBrush { +public class SphereBrush extends Brush { public static final int MAX_RADIUS = 6; private Map, VoxelShape>> cachedBrushes; public SphereBrush() { + super(1); + cachedBrushes = new HashMap<>(); for (int i = 0; i <= MAX_RADIUS; i++) { int radius = i; VoxelShape shape = VoxelShapes.empty(); - List positions = BlockPos.getAllInBox(BlockPos.ZERO.add(-i, -i, -i), BlockPos.ZERO.add(i, i, i)) - .filter(p -> p.withinDistance(BlockPos.ZERO, radius)).collect(Collectors.toList()); - VoxelShape fullCube = VoxelShapes.fullCube(); + List positions = + BlockPos.getAllInBox(BlockPos.ZERO.add(-i - 1, -i - 1, -i - 1), BlockPos.ZERO.add(i + 1, i + 1, i + 1)) + .map(BlockPos::new).filter(p -> VecHelper.getCenterOf(p) + .distanceTo(VecHelper.getCenterOf(BlockPos.ZERO)) < radius + .5f) + .collect(Collectors.toList()); + VoxelShape fullCube = Block.makeCuboidShape(-.5f, -.5f, -.5f, 16.5f, 16.5f, 16.5f); for (BlockPos p : positions) shape = VoxelShapes.or(shape, fullCube.withOffset(p.getX(), p.getY(), p.getZ())); shape = shape.simplify(); @@ -31,15 +42,38 @@ public class SphereBrush { } } - public VoxelShape getSelectionBox(int size) { - return get(size).getRight(); + @Override + public BlockPos getOffset(Vec3d ray, Direction face, PlacementOptions option) { + if (option == PlacementOptions.Merged) + return BlockPos.ZERO; + + int offset = option == PlacementOptions.Attached ? 0 : -1; + int r = (param0 + 1 + offset); + + return BlockPos.ZERO.offset(face, r * (option == PlacementOptions.Attached ? 1 : -1)); } - public List getIncludedPositions(int size) { - return get(size).getLeft(); + @Override + int getMax(int paramIndex) { + return MAX_RADIUS; } - protected Pair, VoxelShape> get(int size) { + @Override + VoxelShape getSelectionBox() { + return getEntry(param0).getRight(); + } + + @Override + String getParamLabel(int paramIndex) { + return Lang.translate("generic.radius"); + } + + @Override + List getIncludedPositions() { + return getEntry(param0).getLeft(); + } + + protected Pair, VoxelShape> getEntry(int size) { return cachedBrushes.get(Integer.valueOf(size)); } diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainBrushes.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainBrushes.java new file mode 100644 index 000000000..a4709b35f --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainBrushes.java @@ -0,0 +1,25 @@ +package com.simibubi.create.modules.curiosities.zapper.terrainzapper; + +public enum TerrainBrushes { + + Cuboid(new CuboidBrush()), + Sphere(new SphereBrush()), + Cylinder(new CylinderBrush()), + + ; + + private Brush brush; + + private TerrainBrushes(Brush brush) { + this.brush = brush; + } + + public Brush get() { +// if (this == Cylinder) +// brush = new CylinderBrush(); +// if (this == Sphere) +// brush = new SphereBrush(); + return brush; + } + +} diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainTools.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainTools.java new file mode 100644 index 000000000..38c068572 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainTools.java @@ -0,0 +1,89 @@ +package com.simibubi.create.modules.curiosities.zapper.terrainzapper; + +import java.util.List; + +import javax.annotation.Nullable; + +import com.simibubi.create.ScreenResources; +import com.simibubi.create.foundation.utility.Lang; + +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public enum TerrainTools { + + Fill(ScreenResources.I_FILL), + Place(ScreenResources.I_PLACE), + Replace(ScreenResources.I_REPLACE), + Clear(ScreenResources.I_CLEAR), + Overlay(ScreenResources.I_OVERLAY), + Flatten(ScreenResources.I_FLATTEN); + + public String translationKey; + public ScreenResources icon; + + private TerrainTools(ScreenResources icon) { + this.translationKey = Lang.asId(name()); + this.icon = icon; + } + + public boolean requiresSelectedBlock() { + return this != Clear && this != Flatten; + } + + public void run(World world, List targetPositions, Direction facing, @Nullable BlockState paintedState) { + switch (this) { + case Clear: + targetPositions.forEach(p -> world.setBlockState(p, Blocks.AIR.getDefaultState())); + break; + case Fill: + targetPositions.forEach(p -> { + BlockState toReplace = world.getBlockState(p); + if (!isReplaceable(toReplace)) + return; + world.setBlockState(p, paintedState); + }); + break; + case Flatten: + FlattenTool.apply(world, targetPositions, facing); + break; + case Overlay: + targetPositions.forEach(p -> { + BlockState toOverlay = world.getBlockState(p); + if (isReplaceable(toOverlay)) + return; + if (toOverlay == paintedState) + return; + + p = p.up(); + + BlockState toReplace = world.getBlockState(p); + if (!isReplaceable(toReplace)) + return; + world.setBlockState(p, paintedState); + }); + break; + case Place: + targetPositions.forEach(p -> { + world.setBlockState(p, paintedState); + }); + break; + case Replace: + targetPositions.forEach(p -> { + BlockState toReplace = world.getBlockState(p); + if (isReplaceable(toReplace)) + return; + world.setBlockState(p, paintedState); + }); + break; + } + } + + public static boolean isReplaceable(BlockState toReplace) { + return toReplace.getMaterial().isReplaceable(); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainZapperItem.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainZapperItem.java deleted file mode 100644 index 9002a3999..000000000 --- a/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainZapperItem.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.simibubi.create.modules.curiosities.zapper.terrainzapper; - -import com.simibubi.create.modules.curiosities.zapper.ZapperItem; - -import net.minecraft.item.ItemStack; - -public class TerrainZapperItem extends ZapperItem { - - public TerrainZapperItem(Properties properties) { - super(properties); - } - - @Override - protected void openHandgunGUI(ItemStack item, boolean b) { - // TODO Auto-generated method stub - - } - - @Override - protected int getCooldownDelay(ItemStack item) { - return 2; - } - -} diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainZapperRenderHandler.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainZapperRenderHandler.java new file mode 100644 index 000000000..95c0c3ce1 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainZapperRenderHandler.java @@ -0,0 +1,94 @@ +package com.simibubi.create.modules.curiosities.zapper.terrainzapper; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.AllItems; +import com.simibubi.create.foundation.utility.NBTHelper; +import com.simibubi.create.foundation.utility.TessellatorHelper; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.ClientPlayerEntity; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.RayTraceContext; +import net.minecraft.util.math.RayTraceContext.BlockMode; +import net.minecraft.util.math.RayTraceContext.FluidMode; +import net.minecraft.util.math.RayTraceResult.Type; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.shapes.VoxelShape; + +public class TerrainZapperRenderHandler { + + private static VoxelShape renderedShape; + private static BlockPos renderedPosition; + + public static void tick() { + ClientPlayerEntity player = Minecraft.getInstance().player; + ItemStack heldMain = player.getHeldItemMainhand(); + ItemStack heldOff = player.getHeldItemOffhand(); + boolean zapperInMain = AllItems.TERRAIN_ZAPPER.typeOf(heldMain); + boolean zapperInOff = AllItems.TERRAIN_ZAPPER.typeOf(heldOff); + + if (zapperInMain) { + CompoundNBT tag = heldMain.getOrCreateTag(); + if (!tag.contains("_Swap")) { + createBrushOutline(tag, player, heldMain); + return; + } + } + + if (zapperInOff) { + CompoundNBT tag = heldOff.getOrCreateTag(); + createBrushOutline(tag, player, heldOff); + return; + } + + renderedPosition = null; + } + + public static void createBrushOutline(CompoundNBT tag, ClientPlayerEntity player, ItemStack zapper) { + if (!tag.contains("BrushParams")) { + renderedPosition = null; + return; + } + + Brush brush = NBTHelper.readEnum(tag.getString("Brush"), TerrainBrushes.class).get(); + PlacementOptions placement = NBTHelper.readEnum(tag.getString("Placement"), PlacementOptions.class); + BlockPos params = NBTUtil.readBlockPos(tag.getCompound("BrushParams")); + brush.set(params.getX(), params.getY(), params.getZ()); + renderedShape = brush.getSelectionBox(); + + Vec3d start = player.getPositionVec().add(0, player.getEyeHeight(), 0); + Vec3d range = player.getLookVec().scale(128); + BlockRayTraceResult raytrace = player.world.rayTraceBlocks( + new RayTraceContext(start, start.add(range), BlockMode.OUTLINE, FluidMode.NONE, player)); + if (raytrace == null || raytrace.getType() == Type.MISS) { + renderedPosition = null; + return; + } + + BlockPos pos = raytrace.getPos(); + renderedPosition = pos.add(brush.getOffset(player.getLookVec(), raytrace.getFace(), placement)); + } + + public static void render() { + if (renderedPosition == null) + return; + + GlStateManager.lineWidth(2); + TessellatorHelper.prepareForDrawing(); + GlStateManager.disableTexture(); + + GlStateManager.translated(renderedPosition.getX(), renderedPosition.getY(), renderedPosition.getZ()); + WorldRenderer.drawShape(renderedShape, 0, 0, 0, 0f, 0f, 0f, 0.5f); + + GlStateManager.enableTexture(); + TessellatorHelper.cleanUpAfterDrawing(); + GlStateManager.lineWidth(1); + + } + +} diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainzapperItem.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainzapperItem.java new file mode 100644 index 000000000..ca1c8db20 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainzapperItem.java @@ -0,0 +1,90 @@ +package com.simibubi.create.modules.curiosities.zapper.terrainzapper; + +import java.util.ArrayList; +import java.util.List; + +import com.simibubi.create.foundation.block.render.CustomRenderedItemModel; +import com.simibubi.create.foundation.gui.ScreenOpener; +import com.simibubi.create.foundation.item.IHaveCustomItemModel; +import com.simibubi.create.foundation.utility.Lang; +import com.simibubi.create.foundation.utility.NBTHelper; +import com.simibubi.create.modules.curiosities.zapper.PlacementPatterns; +import com.simibubi.create.modules.curiosities.zapper.ZapperItem; + +import net.minecraft.block.BlockState; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class TerrainzapperItem extends ZapperItem implements IHaveCustomItemModel { + + public TerrainzapperItem(Properties properties) { + super(properties); + } + + @Override + protected void openHandgunGUI(ItemStack item, boolean b) { + ScreenOpener.open(new TerrainzapperScreen(item, b)); + } + + @Override + protected int getRange(ItemStack stack) { + return 128; + } + + @Override + protected int getCooldownDelay(ItemStack item) { + return 2; + } + + @Override + @OnlyIn(value = Dist.CLIENT) + public CustomRenderedItemModel createModel(IBakedModel original) { + return new TerrainzapperModel(original); + } + + @Override + public String validateUsage(ItemStack item) { + if (!item.getOrCreateTag().contains("BrushParams")) + return Lang.translate("terrainzapper.shiftRightClickToSet"); + return super.validateUsage(item); + } + + @Override + protected boolean canActivateWithoutSelectedBlock(ItemStack stack) { + CompoundNBT tag = stack.getOrCreateTag(); + TerrainTools tool = NBTHelper.readEnum(tag.getString("Tool"), TerrainTools.class); + return !tool.requiresSelectedBlock(); + } + + @Override + protected boolean activate(World world, PlayerEntity player, ItemStack stack, BlockState stateToUse, + BlockRayTraceResult raytrace) { + + BlockPos targetPos = raytrace.getPos(); + List affectedPositions = new ArrayList<>(); + + CompoundNBT tag = stack.getOrCreateTag(); + Brush brush = NBTHelper.readEnum(tag.getString("Brush"), TerrainBrushes.class).get(); + BlockPos params = NBTUtil.readBlockPos(tag.getCompound("BrushParams")); + PlacementOptions option = NBTHelper.readEnum(tag.getString("Placement"), PlacementOptions.class); + TerrainTools tool = NBTHelper.readEnum(tag.getString("Tool"), TerrainTools.class); + + brush.set(params.getX(), params.getY(), params.getZ()); + targetPos = targetPos.add(brush.getOffset(player.getLookVec(), raytrace.getFace(), option)); + for (BlockPos blockPos : brush.getIncludedPositions()) + affectedPositions.add(targetPos.add(blockPos)); + PlacementPatterns.applyPattern(affectedPositions, stack); + tool.run(world, affectedPositions, raytrace.getFace(), stateToUse); + + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainzapperItemRenderer.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainzapperItemRenderer.java new file mode 100644 index 000000000..fe9d91a28 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainzapperItemRenderer.java @@ -0,0 +1,76 @@ +package com.simibubi.create.modules.curiosities.zapper.terrainzapper; + +import com.mojang.blaze3d.platform.GLX; +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.modules.curiosities.zapper.ZapperRenderHandler; +import com.simibubi.create.modules.curiosities.zapper.ZapperItemRenderer; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.ClientPlayerEntity; +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; +import net.minecraft.item.ItemStack; +import net.minecraft.util.HandSide; +import net.minecraft.util.math.MathHelper; + +@SuppressWarnings("deprecation") +public class TerrainzapperItemRenderer extends ZapperItemRenderer { + + @Override + public void renderByItem(ItemStack stack) { + ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer(); + TerrainzapperModel mainModel = (TerrainzapperModel) itemRenderer.getModelWithOverrides(stack); + float pt = Minecraft.getInstance().getRenderPartialTicks(); + float worldTime = AnimationTickHolder.getRenderTick() / 20; + + GlStateManager.pushMatrix(); + GlStateManager.translatef(0.5F, 0.5F, 0.5F); + float lastCoordx = GLX.lastBrightnessX; + float lastCoordy = GLX.lastBrightnessY; + GLX.glMultiTexCoord2f(GLX.GL_TEXTURE1, Math.min(lastCoordx + 60, 240), Math.min(lastCoordy + 120, 240)); + itemRenderer.renderItem(stack, mainModel.getBakedModel()); + + // Block indicator + if (mainModel.getCurrentPerspective() == TransformType.GUI && stack.hasTag() + && stack.getTag().contains("BlockUsed")) + renderBlockUsed(stack, itemRenderer); + + ClientPlayerEntity player = Minecraft.getInstance().player; + boolean leftHanded = player.getPrimaryHand() == HandSide.LEFT; + boolean mainHand = player.getHeldItemMainhand() == stack; + boolean offHand = player.getHeldItemOffhand() == stack; + float last = mainHand ^ leftHanded ? ZapperRenderHandler.lastRightHandAnimation + : ZapperRenderHandler.lastLeftHandAnimation; + float current = mainHand ^ leftHanded ? ZapperRenderHandler.rightHandAnimation + : ZapperRenderHandler.leftHandAnimation; + float animation = MathHelper.clamp(MathHelper.lerp(pt, last, current) * 5, 0, 1); + + // Core glows + GlStateManager.disableLighting(); + float multiplier = MathHelper.sin(worldTime * 5); + if (mainHand || offHand) { + multiplier = animation; + } + + GLX.glMultiTexCoord2f(GLX.GL_TEXTURE1, multiplier * 240, 120); + itemRenderer.renderItem(stack, mainModel.getPartial("terrain_core")); + GLX.glMultiTexCoord2f(GLX.GL_TEXTURE1, lastCoordx, lastCoordy); + GlStateManager.enableLighting(); + + // Accelerator spins + float angle = worldTime * -25; + if (mainHand || offHand) + angle += 360 * animation; + + angle %= 360; + float offset = -.155f; + GlStateManager.translatef(0, offset, 0); + GlStateManager.rotatef(angle, 0, 0, 1); + GlStateManager.translatef(0, -offset, 0); + itemRenderer.renderItem(stack, mainModel.getPartial("terrain_accelerator")); + + GlStateManager.popMatrix(); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainzapperModel.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainzapperModel.java new file mode 100644 index 000000000..1c2cc9428 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainzapperModel.java @@ -0,0 +1,20 @@ +package com.simibubi.create.modules.curiosities.zapper.terrainzapper; + +import com.simibubi.create.foundation.block.render.CustomRenderedItemModel; + +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.tileentity.ItemStackTileEntityRenderer; + +public class TerrainzapperModel extends CustomRenderedItemModel { + + public TerrainzapperModel(IBakedModel template) { + super(template, "blockzapper"); + addPartials("terrain_core", "terrain_accelerator"); + } + + @Override + public ItemStackTileEntityRenderer createRenderer() { + return new TerrainzapperItemRenderer(); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainzapperScreen.java b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainzapperScreen.java new file mode 100644 index 000000000..0937dedea --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/curiosities/zapper/terrainzapper/TerrainzapperScreen.java @@ -0,0 +1,181 @@ +package com.simibubi.create.modules.curiosities.zapper.terrainzapper; + +import java.util.List; +import java.util.Vector; + +import com.simibubi.create.ScreenResources; +import com.simibubi.create.foundation.gui.widgets.IconButton; +import com.simibubi.create.foundation.gui.widgets.Label; +import com.simibubi.create.foundation.gui.widgets.ScrollInput; +import com.simibubi.create.foundation.gui.widgets.SelectionScrollInput; +import com.simibubi.create.foundation.utility.Lang; +import com.simibubi.create.foundation.utility.NBTHelper; +import com.simibubi.create.modules.curiosities.zapper.ZapperScreen; + +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.util.math.BlockPos; + +public class TerrainzapperScreen extends ZapperScreen { + + protected final String placementSection = Lang.translate("gui.terrainzapper.placement"); + protected final String toolSection = Lang.translate("gui.terrainzapper.tool"); + protected final List brushOptions = + Lang.translatedOptions("gui.terrainzapper.brush", "cuboid", "sphere", "cylinder"); + + protected Vector toolButtons; + protected Vector placementButtons; + + protected ScrollInput brushInput; + protected Label brushLabel; + protected Vector brushParams; + protected Vector