diff --git a/media/2020-10-17_00.58.03.png b/media/2020-10-17_00.58.03.png new file mode 100644 index 0000000..4afd8ac Binary files /dev/null and b/media/2020-10-17_00.58.03.png differ diff --git a/src/main/java/de/ellpeck/prettypipes/Utility.java b/src/main/java/de/ellpeck/prettypipes/Utility.java index 69b8afb..573b23e 100644 --- a/src/main/java/de/ellpeck/prettypipes/Utility.java +++ b/src/main/java/de/ellpeck/prettypipes/Utility.java @@ -18,6 +18,7 @@ import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; import net.minecraft.util.text.*; +import net.minecraft.world.IBlockReader; import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.util.INBTSerializable; @@ -33,7 +34,7 @@ import java.util.stream.Stream; public final class Utility { - public static T getTileEntity(Class type, World world, BlockPos pos) { + public static T getTileEntity(Class type, IBlockReader world, BlockPos pos) { TileEntity tile = world.getTileEntity(pos); return type.isInstance(tile) ? (T) tile : null; } @@ -115,7 +116,7 @@ public final class Utility { public static void sendTileEntityToClients(TileEntity tile) { ServerWorld world = (ServerWorld) tile.getWorld(); Stream entities = world.getChunkProvider().chunkManager.getTrackingPlayers(new ChunkPos(tile.getPos()), false); - SUpdateTileEntityPacket packet = tile.getUpdatePacket(); + SUpdateTileEntityPacket packet = new SUpdateTileEntityPacket(tile.getPos(), -1, tile.write(new CompoundNBT())); entities.forEach(e -> e.connection.sendPacket(packet)); } diff --git a/src/main/java/de/ellpeck/prettypipes/items/WrenchItem.java b/src/main/java/de/ellpeck/prettypipes/items/WrenchItem.java index 90d25de..f1baca8 100644 --- a/src/main/java/de/ellpeck/prettypipes/items/WrenchItem.java +++ b/src/main/java/de/ellpeck/prettypipes/items/WrenchItem.java @@ -1,13 +1,20 @@ package de.ellpeck.prettypipes.items; import de.ellpeck.prettypipes.Registry; +import de.ellpeck.prettypipes.Utility; import de.ellpeck.prettypipes.pipe.PipeBlock; import de.ellpeck.prettypipes.pipe.ConnectionType; +import de.ellpeck.prettypipes.pipe.PipeTileEntity; import net.minecraft.block.Block; import net.minecraft.block.BlockState; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.item.ItemUseContext; +import net.minecraft.block.Blocks; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.enchantment.Enchantments; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.*; +import net.minecraft.loot.LootContext; import net.minecraft.state.EnumProperty; import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; @@ -16,11 +23,15 @@ import net.minecraft.util.SoundEvents; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.util.text.ITextComponent; import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; +import java.util.List; import java.util.Map; public class WrenchItem extends Item { + public WrenchItem() { super(new Item.Properties().maxStackSize(1).group(Registry.GROUP)); } @@ -29,20 +40,54 @@ public class WrenchItem extends Item { public ActionResultType onItemUse(ItemUseContext context) { World world = context.getWorld(); BlockPos pos = context.getPos(); + PlayerEntity player = context.getPlayer(); BlockState state = world.getBlockState(pos); if (!(state.getBlock() instanceof PipeBlock)) return ActionResultType.PASS; + PipeTileEntity tile = Utility.getTileEntity(PipeTileEntity.class, world, pos); + if (tile == null) + return ActionResultType.FAIL; - if (context.getPlayer().isSneaking()) { + if (player.isSneaking()) { if (!world.isRemote) { - Block.spawnDrops(state, world, pos, world.getTileEntity(pos), null, ItemStack.EMPTY); + if (tile.cover != null) { + // remove the cover + List drops = Block.getDrops(tile.cover, (ServerWorld) world, pos, null, player, player.getHeldItem(context.getHand())); + for (ItemStack drop : drops) + Block.spawnAsEntity(world, pos, drop); + + tile.cover = null; + Utility.sendTileEntityToClients(tile); + } else { + // remove the pipe + Block.spawnDrops(state, world, pos, tile, null, ItemStack.EMPTY); + world.removeBlock(pos, false); + } world.playSound(null, pos, SoundEvents.ENTITY_ITEM_FRAME_REMOVE_ITEM, SoundCategory.PLAYERS, 1, 1); - world.removeBlock(pos, false); } - return ActionResultType.SUCCESS; + return ActionResultType.func_233537_a_(world.isRemote); } - // Blocking + // placing covers + if (tile.cover == null) { + ItemStack offhand = player.getHeldItemOffhand(); + if (offhand.getItem() instanceof BlockItem) { + if (!world.isRemote) { + BlockItemUseContext blockContext = new BlockItemUseContext(context); + Block block = ((BlockItem) offhand.getItem()).getBlock(); + BlockState cover = block.getStateForPlacement(blockContext); + if (cover != null && !block.hasTileEntity(cover)) { + tile.cover = cover; + Utility.sendTileEntityToClients(tile); + offhand.shrink(1); + world.playSound(null, pos, SoundEvents.ENTITY_ITEM_FRAME_ADD_ITEM, SoundCategory.PLAYERS, 1, 1); + } + } + return ActionResultType.func_233537_a_(world.isRemote); + } + } + + // disabling directions for (Map.Entry entry : PipeBlock.DIR_SHAPES.entrySet()) { AxisAlignedBB box = entry.getValue().getBoundingBox().offset(pos).grow(0.001F); if (!box.contains(context.getHitVec())) @@ -66,8 +111,28 @@ public class WrenchItem extends Item { PipeBlock.onStateChanged(world, pos, newState); world.playSound(null, pos, SoundEvents.ENTITY_ITEM_FRAME_ROTATE_ITEM, SoundCategory.PLAYERS, 1, 1); } - return ActionResultType.SUCCESS; + return ActionResultType.func_233537_a_(world.isRemote); } return ActionResultType.PASS; } + + @Override + public void addInformation(ItemStack stack, World worldIn, List tooltip, ITooltipFlag flagIn) { + Utility.addTooltip(this.getRegistryName().getPath(), tooltip); + } + + @Override + public boolean isEnchantable(ItemStack stack) { + return true; + } + + @Override + public int getItemEnchantability(ItemStack stack) { + return 1; + } + + @Override + public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { + return enchantment == Enchantments.SILK_TOUCH; + } } diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlock.java b/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlock.java index 0914c6a..8266431 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlock.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlock.java @@ -24,6 +24,7 @@ import net.minecraft.util.Direction; import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.shapes.IBooleanFunction; import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShapes; @@ -34,6 +35,7 @@ import net.minecraftforge.fml.network.NetworkHooks; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.ItemHandlerHelper; +import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nullable; import java.util.HashMap; @@ -42,7 +44,7 @@ import java.util.Map; public class PipeBlock extends ContainerBlock implements IPipeConnectable { public static final Map> DIRECTIONS = new HashMap<>(); - private static final Map SHAPE_CACHE = new HashMap<>(); + private static final Map, VoxelShape> SHAPE_CACHE = new HashMap<>(); private static final VoxelShape CENTER_SHAPE = makeCuboidShape(5, 5, 5, 11, 11, 11); public static final Map DIR_SHAPES = ImmutableMap.builder() .put(Direction.UP, makeCuboidShape(5, 10, 5, 11, 16, 11)) @@ -131,16 +133,29 @@ public class PipeBlock extends ContainerBlock implements IPipeConnectable { @Override public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) { - VoxelShape shape = SHAPE_CACHE.get(state); - if (shape != null) - return shape; - - shape = CENTER_SHAPE; - for (Map.Entry> entry : DIRECTIONS.entrySet()) { - if (state.get(entry.getValue()).isConnected()) - shape = VoxelShapes.or(shape, DIR_SHAPES.get(entry.getKey())); + VoxelShape coverShape = null; + BlockState cover = null; + PipeTileEntity tile = Utility.getTileEntity(PipeTileEntity.class, worldIn, pos); + if (tile != null && tile.cover != null) { + cover = tile.cover; + // try catch since the block might expect to find itself at the position + try { + coverShape = cover.getShape(worldIn, pos, context); + } catch (Exception ignored) { + } + } + Pair key = Pair.of(state, cover); + VoxelShape shape = SHAPE_CACHE.get(key); + if (shape == null) { + shape = CENTER_SHAPE; + for (Map.Entry> entry : DIRECTIONS.entrySet()) { + if (state.get(entry.getValue()).isConnected()) + shape = VoxelShapes.or(shape, DIR_SHAPES.get(entry.getKey())); + } + if (coverShape != null) + shape = VoxelShapes.or(shape, coverShape); + SHAPE_CACHE.put(key, shape); } - SHAPE_CACHE.put(state, shape); return shape; } diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/PipeRenderer.java b/src/main/java/de/ellpeck/prettypipes/pipe/PipeRenderer.java index 666e706..80848af 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/PipeRenderer.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/PipeRenderer.java @@ -1,17 +1,22 @@ package de.ellpeck.prettypipes.pipe; import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.IVertexBuilder; +import de.ellpeck.prettypipes.Registry; import de.ellpeck.prettypipes.network.PipeItem; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BlockModelRenderer; import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.model.ItemCameraTransforms; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.RenderTypeLookup; import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; -import net.minecraft.item.BlockItem; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; +import net.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.client.model.data.EmptyModelData; import java.util.Random; @@ -24,17 +29,30 @@ public class PipeRenderer extends TileEntityRenderer { } @Override - public void render(PipeTileEntity tile, float partialTicks, MatrixStack matrixStack, IRenderTypeBuffer iRenderTypeBuffer, int k, int i1) { - if (tile.getItems().isEmpty()) - return; - matrixStack.push(); - BlockPos tilePos = tile.getPos(); - matrixStack.translate(-tilePos.getX(), -tilePos.getY(), -tilePos.getZ()); - for (PipeItem item : tile.getItems()) { + public void render(PipeTileEntity tile, float partialTicks, MatrixStack matrixStack, IRenderTypeBuffer buffer, int light, int overlay) { + if (!tile.getItems().isEmpty()) { matrixStack.push(); - item.render(tile, matrixStack, this.random, partialTicks, k, i1, iRenderTypeBuffer); + BlockPos tilePos = tile.getPos(); + matrixStack.translate(-tilePos.getX(), -tilePos.getY(), -tilePos.getZ()); + for (PipeItem item : tile.getItems()) { + matrixStack.push(); + item.render(tile, matrixStack, this.random, partialTicks, light, overlay, buffer); + matrixStack.pop(); + } + matrixStack.pop(); + } + if (tile.cover != null) { + matrixStack.push(); + BlockModelRenderer.enableCache(); + for (RenderType layer : RenderType.getBlockRenderTypes()) { + if (!RenderTypeLookup.canRenderInLayer(tile.cover, layer)) + continue; + ForgeHooksClient.setRenderLayer(layer); + Minecraft.getInstance().getBlockRendererDispatcher().renderBlock(tile.cover, matrixStack, buffer, light, overlay, EmptyModelData.INSTANCE); + } + ForgeHooksClient.setRenderLayer(null); + BlockModelRenderer.disableCache(); matrixStack.pop(); } - matrixStack.pop(); } } diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/PipeTileEntity.java b/src/main/java/de/ellpeck/prettypipes/pipe/PipeTileEntity.java index 98833c9..9a1ee07 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/PipeTileEntity.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/PipeTileEntity.java @@ -12,6 +12,7 @@ import de.ellpeck.prettypipes.network.PipeNetwork; import de.ellpeck.prettypipes.pipe.containers.MainPipeContainer; import de.ellpeck.prettypipes.pressurizer.PressurizerTileEntity; import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; import net.minecraft.block.ChestBlock; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; @@ -21,15 +22,21 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.ListNBT; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.play.server.SUpdateTileEntityPacket; import net.minecraft.profiler.IProfiler; import net.minecraft.tileentity.ChestTileEntity; import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; +import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TranslationTextComponent; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; @@ -66,6 +73,7 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide public final Queue craftIngredientRequests = new LinkedList<>(); public final List> craftResultRequests = new ArrayList<>(); public PressurizerTileEntity pressurizer; + public BlockState cover; public int moduleDropCheck; protected List items; private int lastItemAmount; @@ -84,6 +92,8 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide compound.put("modules", this.modules.serializeNBT()); compound.putInt("module_drop_check", this.moduleDropCheck); compound.put("requests", Utility.serializeAll(this.craftIngredientRequests)); + if (this.cover != null) + compound.put("cover", NBTUtil.writeBlockState(this.cover)); ListNBT results = new ListNBT(); for (Pair triple : this.craftResultRequests) { CompoundNBT nbt = new CompoundNBT(); @@ -99,6 +109,7 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide public void read(BlockState state, CompoundNBT compound) { this.modules.deserializeNBT(compound.getCompound("modules")); this.moduleDropCheck = compound.getInt("module_drop_check"); + this.cover = compound.contains("cover") ? NBTUtil.readBlockState(compound.getCompound("cover")) : null; this.craftIngredientRequests.clear(); this.craftIngredientRequests.addAll(Utility.deserializeAll(compound.getList("requests", NBT.TAG_COMPOUND), NetworkLock::new)); this.craftResultRequests.clear(); @@ -128,6 +139,11 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide items.addAll(Utility.deserializeAll(nbt.getList("items", NBT.TAG_COMPOUND), PipeItem::load)); } + @Override + public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket pkt) { + this.read(this.getBlockState(), pkt.getNbtCompound()); + } + @Override public void tick() { // invalidate our pressurizer reference if it was removed @@ -355,4 +371,11 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide public Container createMenu(int window, PlayerInventory inv, PlayerEntity player) { return new MainPipeContainer(Registry.pipeContainer, window, player, PipeTileEntity.this.pos); } + + @Override + @OnlyIn(Dist.CLIENT) + public AxisAlignedBB getRenderBoundingBox() { + // our render bounding box should always be the full block in case we're covered + return new AxisAlignedBB(this.pos); + } } diff --git a/src/main/java/de/ellpeck/prettypipes/pressurizer/PressurizerTileEntity.java b/src/main/java/de/ellpeck/prettypipes/pressurizer/PressurizerTileEntity.java index c91e8a7..a06d18a 100644 --- a/src/main/java/de/ellpeck/prettypipes/pressurizer/PressurizerTileEntity.java +++ b/src/main/java/de/ellpeck/prettypipes/pressurizer/PressurizerTileEntity.java @@ -78,11 +78,6 @@ public class PressurizerTileEntity extends TileEntity implements INamedContainer this.read(state, tag); } - @Override - public SUpdateTileEntityPacket getUpdatePacket() { - return new SUpdateTileEntityPacket(this.pos, -1, this.write(new CompoundNBT())); - } - @Override public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket pkt) { this.read(this.getBlockState(), pkt.getNbtCompound()); diff --git a/src/main/resources/assets/prettypipes/lang/en_us.json b/src/main/resources/assets/prettypipes/lang/en_us.json index f475d51..1bbcd4e 100644 --- a/src/main/resources/assets/prettypipes/lang/en_us.json +++ b/src/main/resources/assets/prettypipes/lang/en_us.json @@ -1,5 +1,6 @@ { "item.prettypipes.wrench": "Pipe Wrench", + "info.prettypipes.wrench": "Allows modifying pipe connections\nPlaces blocks in offhand as covers\nSneak to remove cover or pipe", "item.prettypipes.blank_module": "Blank Module", "item.prettypipes.pipe_frame": "Pipe Frame", "info.prettypipes.pipe_frame": "Attach to a pipe or pipe-adjacent block\nShows amount of an item in the pipe's network",