From 395438d776f8def6b4bc6482c918c93ce59ac431 Mon Sep 17 00:00:00 2001 From: EightXOR8 <122228099+EightXOR8@users.noreply.github.com> Date: Sun, 8 Sep 2024 17:02:09 -0700 Subject: [PATCH 1/2] Revamp Sheeted Frames to have all the same functionality you would expect from frame blocks. Does not force frame boxes to treat sheeted frames as if they were equivalent to frame boxes themselves, but sheeted frames will treat frame boxes specially. --- .../api/blocks/IForcedStates.java | 6 + .../material/info/SuSyMaterialIconType.java | 2 + .../common/blocks/BlockSheetedFrame.java | 424 ++++++++++++------ .../common/blocks/SheetedFrameItemBlock.java | 10 + .../mixins/gregtech/BlockPipeMixin.java | 218 +++++++++ .../mixins/gregtech/PipeRendererMixin.java | 205 +++++++++ .../gregtech/TileEntityPipeBaseMixin.java | 90 ++++ .../mixins/xnet/FacadeItemBlockMixin.java | 2 +- .../material_sets/dull/sheeted_frame.json | 8 +- .../material_sets/dull/sheeted_frame_all.png | Bin 0 -> 794 bytes .../material_sets/dull/sheeted_frame_end.png | Bin 0 -> 522 bytes .../resources/assets/susy/lang/en_us.lang | 3 + src/main/resources/mixins.susy.gregtech.json | 7 +- src/main/resources/mixins.susy.json | 10 + 14 files changed, 851 insertions(+), 134 deletions(-) create mode 100644 src/main/java/supersymmetry/api/blocks/IForcedStates.java create mode 100644 src/main/java/supersymmetry/mixins/gregtech/BlockPipeMixin.java create mode 100644 src/main/java/supersymmetry/mixins/gregtech/PipeRendererMixin.java create mode 100644 src/main/java/supersymmetry/mixins/gregtech/TileEntityPipeBaseMixin.java create mode 100644 src/main/resources/assets/gregtech/textures/blocks/material_sets/dull/sheeted_frame_all.png create mode 100644 src/main/resources/assets/gregtech/textures/blocks/material_sets/dull/sheeted_frame_end.png create mode 100644 src/main/resources/mixins.susy.json diff --git a/src/main/java/supersymmetry/api/blocks/IForcedStates.java b/src/main/java/supersymmetry/api/blocks/IForcedStates.java new file mode 100644 index 000000000..343b8ef0a --- /dev/null +++ b/src/main/java/supersymmetry/api/blocks/IForcedStates.java @@ -0,0 +1,6 @@ +package supersymmetry.api.blocks; + +public interface IForcedStates { + void setForcedState(int val); + int getForcedState(); +} diff --git a/src/main/java/supersymmetry/api/unification/material/info/SuSyMaterialIconType.java b/src/main/java/supersymmetry/api/unification/material/info/SuSyMaterialIconType.java index 9a5732de2..50e59f937 100644 --- a/src/main/java/supersymmetry/api/unification/material/info/SuSyMaterialIconType.java +++ b/src/main/java/supersymmetry/api/unification/material/info/SuSyMaterialIconType.java @@ -6,6 +6,8 @@ public class SuSyMaterialIconType { public static MaterialIconType catalystBed = new MaterialIconType("catalystBed"); public static MaterialIconType catalystPellet = new MaterialIconType("catalystPellet"); public static MaterialIconType sheetedFrame = new MaterialIconType("sheetedFrame"); + public static MaterialIconType sheetedFrameAll = new MaterialIconType("sheetedFrameAll"); + public static MaterialIconType sheetedFrameEnd = new MaterialIconType("sheetedFrameEnd"); // Could not get this working unless I referenced it in a model public static MaterialIconType sifted = new MaterialIconType("sifted"); public static MaterialIconType flotated = new MaterialIconType("flotated"); public static MaterialIconType concentrate = new MaterialIconType("concentrate"); diff --git a/src/main/java/supersymmetry/common/blocks/BlockSheetedFrame.java b/src/main/java/supersymmetry/common/blocks/BlockSheetedFrame.java index cad88a00c..c5cce67b5 100644 --- a/src/main/java/supersymmetry/common/blocks/BlockSheetedFrame.java +++ b/src/main/java/supersymmetry/common/blocks/BlockSheetedFrame.java @@ -1,16 +1,23 @@ package supersymmetry.common.blocks; import gregtech.api.GregTechAPI; +import gregtech.api.capability.GregtechDataCodes; +import gregtech.api.items.toolitem.ToolClasses; +import gregtech.api.pipenet.block.BlockPipe; +import gregtech.api.pipenet.block.ItemBlockPipe; +import gregtech.api.pipenet.tile.IPipeTile; +import gregtech.api.pipenet.tile.TileEntityPipeBase; import gregtech.api.recipes.ModHandler; import gregtech.api.unification.material.Materials; import gregtech.api.util.GTUtility; +import gregtech.common.blocks.BlockFrame; +import gregtech.common.blocks.MetaBlocks; import gregtech.common.blocks.properties.PropertyMaterial; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.minecraft.block.Block; -import net.minecraft.block.BlockRotatedPillar; +import net.minecraft.block.BlockAir; import net.minecraft.block.SoundType; import net.minecraft.block.material.EnumPushReaction; -import net.minecraft.block.properties.IProperty; import net.minecraft.block.properties.PropertyEnum; import net.minecraft.block.state.BlockFaceShape; import net.minecraft.block.state.BlockStateContainer; @@ -20,8 +27,11 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; +import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; import net.minecraft.util.*; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; @@ -35,14 +45,20 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import org.jetbrains.annotations.NotNull; +import supersymmetry.api.SusyLog; +import supersymmetry.api.blocks.IForcedStates; import supersymmetry.api.unification.material.info.SuSyMaterialIconType; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Map; +import static supersymmetry.common.blocks.SuSyMetaBlocks.SHEETED_FRAMES; + public class BlockSheetedFrame extends Block { + public static final int UPDATE_ROTATION_STATE = GregtechDataCodes.assignId(); + public static final PropertyEnum SHEETED_FRAME_AXIS = PropertyEnum.create("axis", BlockSheetedFrame.FrameEnumAxis.class); public final PropertyMaterial variantProperty; @@ -68,7 +84,7 @@ public BlockSheetedFrame(Material[] materials) * IBlockstate */ @Override @NotNull - public IBlockState getStateForPlacement(World worldIn, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer) + public IBlockState getStateForPlacement(@NotNull World worldIn, @NotNull BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, @NotNull EntityLivingBase placer) { return this.getStateFromMeta(meta).withProperty(SHEETED_FRAME_AXIS, BlockSheetedFrame.FrameEnumAxis.fromFacingAxis(facing.getAxis())); } @@ -89,40 +105,37 @@ protected BlockStateContainer createBlockState() { * fine. */ @Override - public IBlockState withRotation(IBlockState state, Rotation rot) + public @NotNull IBlockState withRotation(@NotNull IBlockState state, Rotation rot) { - switch (rot) - { - case COUNTERCLOCKWISE_90: - case CLOCKWISE_90: - - switch (state.getValue(SHEETED_FRAME_AXIS)) - { - case X: - return state.withProperty(SHEETED_FRAME_AXIS, BlockSheetedFrame.FrameEnumAxis.Z); - case Z: - return state.withProperty(SHEETED_FRAME_AXIS, BlockSheetedFrame.FrameEnumAxis.X); - default: - return state; - } + switch (rot) { + case COUNTERCLOCKWISE_90, CLOCKWISE_90 -> { + return switch (state.getValue(SHEETED_FRAME_AXIS)) { + case X -> state.withProperty(SHEETED_FRAME_AXIS, FrameEnumAxis.Z); + case Z -> state.withProperty(SHEETED_FRAME_AXIS, FrameEnumAxis.X); + default -> state; + }; + } - default: + default -> { return state; + } } } - public static enum FrameEnumAxis implements IStringSerializable + public enum FrameEnumAxis implements IStringSerializable { - X("x"), - Y("y"), - Z("z"), - NONE("none"); + X("x", EnumFacing.Axis.X), + Y("y", EnumFacing.Axis.Y), + Z("z", EnumFacing.Axis.Z), + NONE("none", null); private final String name; - private FrameEnumAxis(String name) - { + private final EnumFacing.Axis axis; + + FrameEnumAxis(String name, EnumFacing.Axis axis) { this.name = name; + this.axis = axis; } public String toString() @@ -132,31 +145,33 @@ public String toString() public static FrameEnumAxis fromFacingAxis(EnumFacing.Axis axis) { - switch (axis) - { - case X: - return X; - case Y: - return Y; - case Z: - return Z; - default: - return NONE; - } + if (axis == null) return NONE; + return switch (axis) { + case X -> X; + case Y -> Y; + case Z -> Z; + }; } - public String getName() + public @NotNull String getName() { return this.name; } + + public @Nullable EnumFacing.Axis getAxis() { return this.axis; } + + // never returns none + public static FrameEnumAxis fromFacing(EnumFacing facing) { + return FrameEnumAxis.values()[facing.getAxis().ordinal()]; + } } @Override @Deprecated - public boolean isOpaqueCube(IBlockState state) { return false; } + public boolean isOpaqueCube(@NotNull IBlockState state) { return false; } @Override @SideOnly(Side.CLIENT) - public BlockRenderLayer getRenderLayer() + public @NotNull BlockRenderLayer getRenderLayer() { return BlockRenderLayer.CUTOUT_MIPPED; } @@ -212,14 +227,41 @@ public void getSubBlocks(@Nonnull CreativeTabs tab, @Nonnull NonNullList list.add(getItem(blockState))); } - public static ItemStack getItem(IBlockState blockState) { - return GTUtility.toItem(blockState); + // returns null to indicate an invalid/ non-existent sheeted frame state equivalent, or returns the equivalent sheeted state + public static IBlockState determineSheetedState(IBlockAccess world, BlockPos pos) { + IBlockState state = world.getBlockState(pos); + + if (state.getBlock() instanceof BlockSheetedFrame) { + return state; + } + + if (state.getBlock() instanceof BlockPipe) { + IPipeTile pipetile = ((BlockPipe) state.getBlock()).getPipeTileEntity(world, pos); + if (pipetile == null) return null; + + int rotationOrdinal = ((IForcedStates) pipetile).getForcedState() - 1; + Material mat = pipetile.getFrameMaterial(); + if (rotationOrdinal < 0 || mat == null) return null; + + return SHEETED_FRAMES.get(mat).getDefaultState().withProperty(SHEETED_FRAME_AXIS, FrameEnumAxis.values()[rotationOrdinal]); + } + + return null; } public ItemStack getItem(Material material) { return getItem(this.getDefaultState().withProperty(this.variantProperty, material).withProperty(SHEETED_FRAME_AXIS, FrameEnumAxis.Y)); } + // doesn't really make sense to drop based on orientation, but the method is here just in case + public ItemStack getItem(Material material, int orientationOrdinal) { + return getItem(this.getDefaultState().withProperty(this.variantProperty, material).withProperty(SHEETED_FRAME_AXIS, FrameEnumAxis.values()[orientationOrdinal])); + } + + public static ItemStack getItem(IBlockState blockState) { + return GTUtility.toItem(blockState); + } + public IBlockState getBlock(Material material) { return getDefaultState().withProperty(this.variantProperty, material).withProperty(SHEETED_FRAME_AXIS, FrameEnumAxis.Y); } @@ -237,107 +279,231 @@ public boolean canCreatureSpawn(@Nonnull IBlockState state, @Nonnull IBlockAcces return false; } - /* - public boolean replaceWithFramedPipe(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, ItemStack stackInHand, EnumFacing facing) { - BlockPipe blockPipe = (BlockPipe)((ItemBlockPipe)stackInHand.getItem()).getBlock(); - if (((IPipeType)blockPipe.getItemPipeType(stackInHand)).getThickness() < 1.0F) { - ItemBlock itemBlock = (ItemBlock)stackInHand.getItem(); - IBlockState pipeState = blockPipe.getDefaultState(); - itemBlock.placeBlockAt(stackInHand, playerIn, worldIn, pos, facing, 0.0F, 0.0F, 0.0F, pipeState); - IPipeTile pipeTile = blockPipe.getPipeTileEntity(worldIn, pos); - if (pipeTile instanceof TileEntityPipeBase) { - ((TileEntityPipeBase)pipeTile).setFrameMaterial(this.getGtMaterial(this.getMetaFromState(state))); - SoundType type = blockPipe.getSoundType(state, worldIn, pos, playerIn); - worldIn.playSound(playerIn, pos, type.getPlaceSound(), SoundCategory.BLOCKS, (type.getVolume() + 1.0F) / 2.0F, type.getPitch() * 0.8F); - if (!playerIn.capabilities.isCreativeMode) { - stackInHand.shrink(1); - } + public enum ToolReactions { + ROTATE, + MUTATE, + NONE; - return true; - } else { - GTLog.logger.error("Pipe was not placed!"); - return false; + public static ToolReactions getReaction(ItemStack stack) { + if (stack == null) return NONE; + if (stack.getItem().getToolClasses(stack).contains(ToolClasses.SCREWDRIVER)) return ROTATE; + if (stack.getItem().getToolClasses(stack).contains(ToolClasses.HARD_HAMMER)) return MUTATE; + return NONE; + } + + public static int reactionResult(ToolReactions reaction, int state) { + if (reaction == ROTATE) { + return (state + 1) % 3; + } else if (reaction == MUTATE) { + return state == FrameEnumAxis.NONE.ordinal() ? FrameEnumAxis.Y.ordinal() : FrameEnumAxis.NONE.ordinal(); } - } else { - return false; + + return state; } } - public boolean removeFrame(World world, BlockPos pos, EntityPlayer player, ItemStack stack) { - TileEntity te = world.getTileEntity(pos); - if (te instanceof TileEntityPipeBase && ((IPipeTile)te).getFrameMaterial() != null) { - TileEntityPipeBase pipeTile = (TileEntityPipeBase)te; - Material frameMaterial = pipeTile.getFrameMaterial(); - pipeTile.setFrameMaterial((Material)null); - Block.spawnAsEntity(world, pos, this.getItem(frameMaterial)); - ToolHelper.damageItem(stack, player); - ToolHelper.playToolSound(stack, player); - return true; - } else { - return false; - } + @Override + public boolean onBlockActivated(@NotNull World world, @NotNull BlockPos pos, @NotNull IBlockState state, + @NotNull EntityPlayer player, @NotNull EnumHand hand, @NotNull EnumFacing facing, + float hitX, float hitY, float hitZ) { + return onBlockActivated(false, world, pos, state, player, hand, facing, hitX, hitY, hitZ); } - public boolean onBlockActivated(@Nonnull World worldIn, @Nonnull BlockPos pos, @Nonnull IBlockState state, EntityPlayer playerIn, @Nonnull EnumHand hand, @Nonnull EnumFacing facing, float hitX, float hitY, float hitZ) { - ItemStack stackInHand = playerIn.getHeldItem(hand); - if (stackInHand.isEmpty()) { - return false; - } else if (stackInHand.getItem() instanceof ItemBlockPipe) { - return this.replaceWithFramedPipe(worldIn, pos, state, playerIn, stackInHand, facing); - } else if (stackInHand.getItem().getToolClasses(stackInHand).contains("crowbar")) { - return this.removeFrame(worldIn, pos, playerIn, stackInHand); - } else if (!(stackInHand.getItem() instanceof FrameItemBlock)) { + public boolean onBlockActivated(boolean isPipe, @NotNull World world, @NotNull BlockPos pos, @NotNull IBlockState state, + @NotNull EntityPlayer player, @NotNull EnumHand hand, @NotNull EnumFacing facing, + float hitX, float hitY, float hitZ) { + ItemStack stack = player.getHeldItem(hand); + if (stack.isEmpty()) { return false; + } + + // pipes surrounded by frames have their own implementation within the mixin for these behaviors + if (!isPipe) { + // special action on screwdrivers and wrenches, though changes are done pipe-side if blockstate "contains" pipe + if ((state.getBlock() instanceof BlockSheetedFrame)) { + if (ToolReactions.getReaction(stack) == ToolReactions.MUTATE) { + world.setBlockState(pos, state.withProperty(SHEETED_FRAME_AXIS, state.getValue(SHEETED_FRAME_AXIS) == FrameEnumAxis.NONE ? FrameEnumAxis.Y : FrameEnumAxis.NONE)); + return true; + } else if (ToolReactions.getReaction(stack) == ToolReactions.ROTATE) { + world.setBlockState(pos, state.withProperty(SHEETED_FRAME_AXIS, FrameEnumAxis.values()[(state.getValue(SHEETED_FRAME_AXIS).ordinal() + 1) % 3])); + return true; + } + } + + // replace frame with pipe and set the frame material to this frame + if (stack.getItem() instanceof ItemBlockPipe) { + return replaceWithFramedPipe(world, pos, state, player, stack, facing); + } + } + + // check if frame block, return if not + BlockSheetedFrame sheetedFrameBlock = getFrameBlockFromItem(stack); + if (sheetedFrameBlock == null) return false; + + BlockPos.PooledMutableBlockPos blockPos = BlockPos.PooledMutableBlockPos.retain(); + blockPos.setPos(pos); + + // determine ordinal for orientation + int rotationOrdinal; + if (state.getBlock() instanceof BlockSheetedFrame) { + rotationOrdinal = state.getValue(SHEETED_FRAME_AXIS).ordinal(); } else { - BlockPos.PooledMutableBlockPos blockPos = BlockPos.PooledMutableBlockPos.retain(); - blockPos.setPos(pos); - - for(int i = 0; i < 32; ++i) { - if (worldIn.getBlockState(blockPos).getBlock() instanceof BlockFrame) { - blockPos.move(EnumFacing.UP); - } else { - TileEntity te = worldIn.getTileEntity(blockPos); - if (!(te instanceof IPipeTile) || ((IPipeTile)te).getFrameMaterial() == null) { - if (this.canPlaceBlockAt(worldIn, blockPos)) { - worldIn.setBlockState(blockPos, ((FrameItemBlock)stackInHand.getItem()).getBlockState(stackInHand)); - SoundType type = this.getSoundType(stackInHand); - worldIn.playSound((EntityPlayer)null, pos, type.getPlaceSound(), SoundCategory.BLOCKS, (type.getVolume() + 1.0F) / 2.0F, type.getPitch() * 0.8F); - if (!playerIn.capabilities.isCreativeMode) { - stackInHand.shrink(1); - } - - blockPos.release(); - return true; - } else if (te instanceof TileEntityPipeBase && ((TileEntityPipeBase)te).getFrameMaterial() == null) { - Material material = ((BlockFrame)((FrameItemBlock)stackInHand.getItem()).getBlock()).getGtMaterial(stackInHand.getMetadata()); - ((TileEntityPipeBase)te).setFrameMaterial(material); - SoundType type = this.getSoundType(stackInHand); - worldIn.playSound((EntityPlayer)null, pos, type.getPlaceSound(), SoundCategory.BLOCKS, (type.getVolume() + 1.0F) / 2.0F, type.getPitch() * 0.8F); - if (!playerIn.capabilities.isCreativeMode) { - stackInHand.shrink(1); - } - - blockPos.release(); - return true; - } else { - blockPos.release(); - return false; - } + // in theory te should always be pipe, otherwise this would never be called, but other methods double check, so I will too + TileEntity te = world.getTileEntity(blockPos); + + // get rotationOrdinal from stack in hand if state at pos is not valid + if (!(te instanceof IPipeTile) || ((IPipeTile) te).getFrameMaterial() == null || ((IForcedStates) te).getForcedState() == 0) { // stored state of 0 implies no value, so 0 - 1 -> no value/ default 0) { + rotationOrdinal = getStateFromMeta(stack.getMetadata()).getValue(SHEETED_FRAME_AXIS).ordinal(); // always going to be y + } else { + rotationOrdinal = ((IForcedStates) te).getForcedState() - 1; // stored state of 0 implies no value, so 0 - 1 -> no value/ default + } + } + + EnumFacing currBaseDir = facing; // default to side clicked if orientation is NONE + if (rotationOrdinal != FrameEnumAxis.NONE.ordinal()) { + try { + // default to positive, or do neg if target has NONE in pos dir and only sheeted frame ahead (this is a monster) + currBaseDir = EnumFacing.getFacingFromAxis(EnumFacing.AxisDirection.POSITIVE, FrameEnumAxis.values()[rotationOrdinal].axis); + IBlockState currDirState = world.getBlockState((pos.offset(currBaseDir))); + Block oppDirBlock = world.getBlockState((pos.offset(currBaseDir.getOpposite()))).getBlock(); + if (!(currDirState.getBlock() instanceof BlockAir) && oppDirBlock instanceof BlockAir || + oppDirBlock instanceof BlockSheetedFrame && + currDirState.getBlock() instanceof BlockSheetedFrame && + currDirState.getValue(SHEETED_FRAME_AXIS) == FrameEnumAxis.NONE) { + + currBaseDir = currBaseDir.getOpposite(); + } + } catch (Exception e) { + // if an error occurred, don't try to place + return false; + } + } + + // attempts to place more frames vertically, up to 32 block tall tower + for (int i = 0; i < 32; i++) { + IBlockState targetState = world.getBlockState(blockPos); + if (targetState.getBlock() instanceof BlockFrame || targetState.getBlock() instanceof BlockSheetedFrame) { + blockPos.move(currBaseDir); + continue; + } + + // skips over pipes with non-null frame materials (has frame around it) + TileEntity te = world.getTileEntity(blockPos); + if (te instanceof IPipeTile && ((IPipeTile) te).getFrameMaterial() != null) { + blockPos.move(currBaseDir); + continue; + } + + // try to place frame block if allowed, and if not check if the obstruction is a pipe base which can be framed + if (canPlaceBlockAt(world, blockPos)) { + // ensure placed block orientation matches base + world.setBlockState(blockPos, + sheetedFrameBlock.getStateFromMeta(stack.getItem().getMetadata(stack.getItemDamage())).withProperty(SHEETED_FRAME_AXIS, FrameEnumAxis.fromFacing(currBaseDir))); + + SoundType type = ModHandler.isMaterialWood(sheetedFrameBlock.getGtMaterial(stack)) ? SoundType.WOOD : SoundType.METAL; + world.playSound(null, pos, type.getPlaceSound(), SoundCategory.BLOCKS, (type.getVolume() + 1.0F) / 2.0F, + type.getPitch() * 0.8F); + if (!player.capabilities.isCreativeMode) { + stack.shrink(1); + } + blockPos.release(); + return true; + } else if (te instanceof TileEntityPipeBase pipeTile && pipeTile.getFrameMaterial() == null) { + // "sheet" pipe if it is blocking further frame scaffolding + pipeTile.setFrameMaterial(sheetedFrameBlock.getGtMaterial(stack)); + ((IForcedStates) pipeTile).setForcedState(rotationOrdinal + 1); // should work with mixin to store orientation + + // clear "blocked" connections [setConnection is the connection facing relative to the one calling, the connection state, and if the neighbor is the one making the call/ "updating" caller + if (rotationOrdinal != BlockSheetedFrame.FrameEnumAxis.NONE.ordinal()) { + for (EnumFacing.Axis currAxis : EnumFacing.Axis.values()) { + if (currAxis.ordinal() == rotationOrdinal) continue; // don't prune connections on axis + pipeTile.setConnection(EnumFacing.getFacingFromAxis(EnumFacing.AxisDirection.POSITIVE, currAxis), false, false); + pipeTile.setConnection(EnumFacing.getFacingFromAxis(EnumFacing.AxisDirection.NEGATIVE, currAxis), false, false); } + } - blockPos.move(EnumFacing.UP); + SoundType type = ModHandler.isMaterialWood(getGtMaterial(stack)) ? SoundType.WOOD : SoundType.METAL; + world.playSound(null, pos, type.getPlaceSound(), SoundCategory.BLOCKS, (type.getVolume() + 1.0F) / 2.0F, + type.getPitch() * 0.8F); + if (!player.capabilities.isCreativeMode) { + stack.shrink(1); } + + blockPos.release(); + return true; + } else { // stops at obstructions, rather than continuing + blockPos.release(); + return false; } + } - blockPos.release(); - return false; + blockPos.release(); + return false; + } + + public boolean replaceWithFramedPipe(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, + ItemStack stackInHand, EnumFacing facing) { + BlockPipe blockPipe = (BlockPipe) ((ItemBlockPipe) stackInHand.getItem()).getBlock(); + if (blockPipe.getItemPipeType(stackInHand).getThickness() < 1) { + ItemBlock itemBlock = (ItemBlock) stackInHand.getItem(); + IBlockState pipeState = blockPipe.getDefaultState(); + + // these 0 values are not actually used by forge + itemBlock.placeBlockAt(stackInHand, playerIn, worldIn, pos, facing, 0, 0, 0, pipeState); + + IPipeTile pipeTile = blockPipe.getPipeTileEntity(worldIn, pos); + if (pipeTile instanceof TileEntityPipeBase) { + ((TileEntityPipeBase) pipeTile).setFrameMaterial(getGtMaterial(state)); + ((IForcedStates) pipeTile).setForcedState(state.getValue(SHEETED_FRAME_AXIS).ordinal() + 1); + } else { + SusyLog.logger.atError().log("Pipe was not placed!"); + return false; + } + + SoundType type = blockPipe.getSoundType(state, worldIn, pos, playerIn); + worldIn.playSound(playerIn, pos, type.getPlaceSound(), SoundCategory.BLOCKS, + (type.getVolume() + 1.0F) / 2.0F, type.getPitch() * 0.8F); + if (!playerIn.capabilities.isCreativeMode) { + stackInHand.shrink(1); + } + return true; } + + return false; + } + + public SoundType getSoundType(ItemStack stack) { + return ModHandler.isMaterialWood(getGtMaterial(stack)) ? SoundType.WOOD : SoundType.METAL; + } + + public Material getGtMaterial(ItemStack stack) { + return variantProperty.getAllowedValues().get(stack.getMetadata() & 3); + } + + public static BlockFrame getFrameFromSheeted(ItemStack stack) { + BlockSheetedFrame itemBlock = getFrameBlockFromItem(stack); + if (itemBlock == null) return null; + + return MetaBlocks.FRAMES.get(itemBlock.getGtMaterial(stack)); + } + + public static @Nullable BlockSheetedFrame getFrameBlockFromItem(ItemStack stack) { + Item item = stack.getItem(); + if (item instanceof ItemBlock) { + Block block = ((ItemBlock)item).getBlock(); + if (block instanceof BlockSheetedFrame) { + return (BlockSheetedFrame)block; + } + } + + return null; } - */ public void onEntityCollision(@Nonnull World worldIn, @Nonnull BlockPos pos, @Nonnull IBlockState state, Entity entityIn) { + // this is only called when the "shorter" side is collided with for some reason. Colliding with a solid block does nothing entityIn.motionX = MathHelper.clamp(entityIn.motionX, -0.15, 0.15); entityIn.motionZ = MathHelper.clamp(entityIn.motionZ, -0.15, 0.15); + entityIn.fallDistance = 0.0F; if (entityIn.motionY < -0.15) { entityIn.motionY = -0.15; @@ -358,16 +524,16 @@ public EnumPushReaction getPushReaction(@Nonnull IBlockState state) { return EnumPushReaction.NORMAL; } + @Override @NotNull public AxisAlignedBB getCollisionBoundingBox(@Nonnull IBlockState blockState, @Nonnull IBlockAccess worldIn, @Nonnull BlockPos pos) { - AxisAlignedBB boundingBox = switch (this.getMetaFromState(blockState) >>> 2) { + return switch (this.getMetaFromState(blockState) >>> 2) { //x - case (0) -> new AxisAlignedBB(0.05, 0.0, 0.00, 0.95, 1.0, 1.00); + case (0) -> new AxisAlignedBB(0.05, 0.0, 0.0, 0.95, 1.0, 1.0); //z - case (2) -> new AxisAlignedBB(0.00, 0.0, 0.05, 1.0, 1.0, 0.95); + case (2) -> new AxisAlignedBB(0.0, 0.0, 0.05, 1.0, 1.0, 0.95); //NONE (all sided) or y [1] as the climbable axis would be on the top of the block - default -> new AxisAlignedBB(0.00, 0.0, 0.00, 1.0, 1.0, 1.0); + default -> new AxisAlignedBB(0.0, 0.0, 0.0, 1.0, 1.0, 1.0); }; - return boundingBox; } @Nonnull @@ -392,7 +558,7 @@ public void onModelRegister() { } */ - //function adapted by me from tictem's original implementation + // function adapted by me [Eight/EightXOR8] from tictem's original implementation @SideOnly(Side.CLIENT) public void onModelRegister() { Map map = new Object2ObjectOpenHashMap<>(); diff --git a/src/main/java/supersymmetry/common/blocks/SheetedFrameItemBlock.java b/src/main/java/supersymmetry/common/blocks/SheetedFrameItemBlock.java index aee70bd5c..cabece816 100644 --- a/src/main/java/supersymmetry/common/blocks/SheetedFrameItemBlock.java +++ b/src/main/java/supersymmetry/common/blocks/SheetedFrameItemBlock.java @@ -1,11 +1,14 @@ package supersymmetry.common.blocks; import gregtech.api.unification.material.Material; +import gregtech.client.utils.TooltipHelper; import gregtech.common.ConfigHolder; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.resources.I18n; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; +import net.minecraft.util.text.TextFormatting; import net.minecraft.world.World; import supersymmetry.api.unification.ore.SusyOrePrefix; @@ -44,6 +47,13 @@ public String getItemStackDisplayName(@Nonnull ItemStack stack) { @Override public void addInformation(@Nonnull ItemStack stack, @Nullable World worldIn, @Nonnull List tooltip, @Nonnull ITooltipFlag flagIn) { super.addInformation(stack, worldIn, tooltip, flagIn); + tooltip.add(I18n.format("tile.sheeted_frame_block.tooltip")); + if (TooltipHelper.isShiftDown()) { + tooltip.add(TextFormatting.GREEN + I18n.format("tile.sheeted_frame_block.tooltip_extra")); + } else { + tooltip.add(TextFormatting.DARK_GRAY + I18n.format("gregtech.tooltip.hold_shift")); + } + if (ConfigHolder.misc.debug) { tooltip.add("MetaItem Id: sheeted_frame" + frameBlock.getGtMaterial(stack.getMetadata()).toCamelCaseString()); } diff --git a/src/main/java/supersymmetry/mixins/gregtech/BlockPipeMixin.java b/src/main/java/supersymmetry/mixins/gregtech/BlockPipeMixin.java new file mode 100644 index 000000000..780cfc184 --- /dev/null +++ b/src/main/java/supersymmetry/mixins/gregtech/BlockPipeMixin.java @@ -0,0 +1,218 @@ +package supersymmetry.mixins.gregtech; + +import codechicken.lib.raytracer.CuboidRayTraceResult; +import gregtech.api.block.BuiltInRenderBlock; +import gregtech.api.cover.Cover; +import gregtech.api.items.toolitem.ToolClasses; +import gregtech.api.pipenet.IBlockAppearance; +import gregtech.api.pipenet.PipeNet; +import gregtech.api.pipenet.WorldPipeNet; +import gregtech.api.pipenet.block.BlockPipe; +import gregtech.api.pipenet.block.IPipeType; +import gregtech.api.pipenet.tile.IPipeTile; +import gregtech.api.pipenet.tile.TileEntityPipeBase; +import gregtech.api.unification.material.Material; +import gregtech.integration.ctm.IFacadeWrapper; +import net.minecraft.block.ITileEntityProvider; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.NonNullList; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import supersymmetry.api.blocks.IForcedStates; +import supersymmetry.common.blocks.BlockSheetedFrame; + +import java.util.List; + +import static supersymmetry.common.blocks.SuSyMetaBlocks.SHEETED_FRAMES; + +@Mixin(value = BlockPipe.class, remap = false) +public abstract class BlockPipeMixin & IPipeType, NodeDataType, + WorldPipeNetType extends WorldPipeNet>> + extends BuiltInRenderBlock implements ITileEntityProvider, IFacadeWrapper, IBlockAppearance { + + @Shadow @Final + protected ThreadLocal> tileEntities; + + @Shadow + public abstract IPipeTile getPipeTileEntity(IBlockAccess world, BlockPos selfPos); + + @Shadow + public abstract ItemStack getDropItem(IPipeTile var1); + + @Shadow + public abstract boolean canPipesConnect(IPipeTile var1, EnumFacing var2, IPipeTile var3); + + @Shadow + public abstract boolean canPipeConnectToBlock(IPipeTile var1, EnumFacing var2, @Nullable TileEntity var3); + + // shouldn't ever be used + public BlockPipeMixin(net.minecraft.block.material.Material materialIn) { + super(materialIn); + } + + //@Inject(method = "onPipeActivated", at = @At(value = "INVOKE_ASSIGN", ordinal = 0)) + // mixin methods always return void, with any potential "return" calls done through callBackInfo + // removing descriptor causes unable to locate obfuscation mapping + @Inject(method = "onPipeActivated(Lnet/minecraft/world/World;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/EnumHand;Lnet/minecraft/util/EnumFacing;Lcodechicken/lib/raytracer/CuboidRayTraceResult;Lgregtech/api/pipenet/tile/IPipeTile;)Z", + at = @At("HEAD"), cancellable = true) + protected void onOnPipeActivated(World world, IBlockState state, BlockPos pos, EntityPlayer entityPlayer, EnumHand hand, + EnumFacing side, CuboidRayTraceResult hit, IPipeTile pipeTile, CallbackInfoReturnable callBackInfoR) { + if (pipeTile == null || pipeTile.getFrameMaterial() == null || ((IForcedStates) pipeTile).getForcedState() == 0) return; + + ItemStack handStack = entityPlayer.getHeldItem(hand); + + // try to change its saved orientation + BlockSheetedFrame.ToolReactions itemToolCheck = BlockSheetedFrame.ToolReactions.getReaction(handStack); + if (itemToolCheck != BlockSheetedFrame.ToolReactions.NONE) { + int resultOrdinal = BlockSheetedFrame.ToolReactions.reactionResult(itemToolCheck, ((IForcedStates) pipeTile).getForcedState() - 1); + ((IForcedStates) pipeTile).setForcedState(resultOrdinal + 1); + + // clear "blocked" connections [setConnection is the connection facing relative to the one calling, the connection state, and if the neighbor is the one making the call/ "updating" caller + if (resultOrdinal != BlockSheetedFrame.FrameEnumAxis.NONE.ordinal()) { + for (EnumFacing.Axis currAxis : EnumFacing.Axis.values()) { + if (currAxis.ordinal() == resultOrdinal) continue; // don't prune connections on axis + pipeTile.setConnection(EnumFacing.getFacingFromAxis(EnumFacing.AxisDirection.POSITIVE, currAxis), false, false); + pipeTile.setConnection(EnumFacing.getFacingFromAxis(EnumFacing.AxisDirection.NEGATIVE, currAxis), false, false); + } + } + + callBackInfoR.setReturnValue(true); + } + + if (handStack.getItem().getToolClasses(handStack).contains(ToolClasses.CROWBAR)) { + final Material prevMat = pipeTile.getFrameMaterial(); + ((IForcedStates) pipeTile).setForcedState(0); + ((TileEntityPipeBase) pipeTile).setFrameMaterial(null); + spawnAsEntity(world, pos, SHEETED_FRAMES.get(prevMat).getItem(prevMat)); + callBackInfoR.setReturnValue(true); + } + + /* + BlockSheetedFrame sheetedFrame = BlockSheetedFrame.getFrameBlockFromItem(handStack); + if (sheetedFrame == null) return; // avoids cancellation if item is not sheeted frame + + // sets forced state + Material newMat = sheetedFrame.getStateFromMeta(handStack.getMetadata()).getValue(sheetedFrame.variantProperty); + Material prevMat = pipeTile.getFrameMaterial(); + if (newMat.equals(prevMat)) return; // cancel custom logic if the materials are the same + ((TileEntityPipeBase) pipeTile).setFrameMaterial(newMat); + + SoundType type = sheetedFrame.getSoundType(handStack); + world.playSound(entityPlayer, pos, type.getPlaceSound(), SoundCategory.BLOCKS, (type.getVolume() + 1.0F) / 2.0F, type.getPitch() * 0.8F); + if (!entityPlayer.capabilities.isCreativeMode) { + handStack.shrink(1); + } + + // drop old frame + spawnAsEntity(world, pos, SHEETED_FRAMES.get(prevMat).getItem(prevMat)); + + callBackInfoR.setReturnValue(true); + */ + } + + @Inject(method = "activateFrame(Lnet/minecraft/world/World;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/EnumHand;Lcodechicken/lib/raytracer/CuboidRayTraceResult;Lgregtech/api/pipenet/tile/IPipeTile;)Z", + at = @At("HEAD"), cancellable = true) + private void onOnActivateFrame(World world, IBlockState state, BlockPos pos, EntityPlayer entityPlayer, EnumHand hand, CuboidRayTraceResult hit, IPipeTile pipeTile, CallbackInfoReturnable callBackInfoR) { + if (pipeTile.getFrameMaterial() == null || ((IForcedStates) pipeTile).getForcedState() == 0) return; // cancel custom logic early if normal block or no frame exists + callBackInfoR.setReturnValue(SHEETED_FRAMES.get(pipeTile.getFrameMaterial()).onBlockActivated(true, world, pos, state, entityPlayer, hand, hit.sideHit, (float) hit.hitVec.x, (float) hit.hitVec.y, (float) hit.hitVec.z)); + } + + //@Inject(method = "onEntityCollision", at = @At(value = "INVOKE_ASSIGN", ordinal = 1), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) + @Inject(method = "onEntityCollision(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/entity/Entity;)V", + at = @At("HEAD"), cancellable = true) + public void onOnEntityCollision(World worldIn, BlockPos pos, IBlockState state, Entity entityIn, CallbackInfo callbackInfo) { + // only called when shorter side of frame is collided with for some reason + IPipeTile pipeTile = getPipeTileEntity(worldIn, pos); + if (pipeTile == null || pipeTile.getFrameMaterial() == null || ((IForcedStates) pipeTile).getForcedState() == 0) return; + SHEETED_FRAMES.get(pipeTile.getFrameMaterial()).onEntityCollision(worldIn, pos, state, entityIn); + callbackInfo.cancel(); // don't do frame logic + } + + /* + @Inject(method = "getCollisionBox(Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/entity/Entity;)Ljava/util/List;", at = @At("HEAD"), cancellable = true) + private void getCollisionBox(IBlockAccess world, BlockPos pos, @Nullable Entity entityIn, CallbackInfoReturnable> callbackInfoR) { + IPipeTile pipeTile = getPipeTileEntity(world, pos); + if (pipeTile == null || pipeTile.getFrameMaterial() == null || ((IForcedStates) pipeTile).getForcedState() == 0) return; + callbackInfoR.setReturnValue(Collections.singletonList(new IndexedCuboid6(null, + SHEETED_FRAMES.get(pipeTile.getFrameMaterial()).getCollisionBoundingBox(BlockSheetedFrame.determineSheetedState(world, pos), world, pos)))); + } + */ + + // - https://fabricmc.net/wiki/tutorial:mixin_injects : because generics dont exist at run time, they arent needed + @Inject(method = "getDrops(Lnet/minecraft/util/NonNullList;Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/state/IBlockState;I)V", + at = @At("HEAD"), cancellable = true) + public void onGetDrops(@NotNull NonNullList drops, @NotNull IBlockAccess world, @NotNull BlockPos pos, @NotNull IBlockState state, int fortune, CallbackInfo callbackInfo) { + IPipeTile pipeTile = this.tileEntities.get() == null ? this.getPipeTileEntity(world, pos) : this.tileEntities.get(); + if (pipeTile.getFrameMaterial() == null || ((IForcedStates) pipeTile).getForcedState() == 0) return; + BlockSheetedFrame sheetedFrame = SHEETED_FRAMES.get(pipeTile.getFrameMaterial()); + drops.add(sheetedFrame.getItem(pipeTile.getFrameMaterial())); + drops.add(getDropItem(pipeTile)); + + callbackInfo.cancel(); + } + + @Inject(method = "canConnect(Lgregtech/api/pipenet/tile/IPipeTile;Lnet/minecraft/util/EnumFacing;)Z", at = @At("HEAD"), cancellable = true) + public void onCanConnect(IPipeTile selfTile, EnumFacing facing, CallbackInfoReturnable callbackInfoR) { + if (((IForcedStates) selfTile).getForcedState() == 0) return; + int rotationOrdinal = ((IForcedStates) selfTile).getForcedState() - 1; + + boolean result = rotationOrdinal == BlockSheetedFrame.FrameEnumAxis.NONE.ordinal() || rotationOrdinal == facing.getAxis().ordinal(); + if (!result) callbackInfoR.setReturnValue(false); + + // simplified version of blockPipe check which only attempts to set the result to true + result = false; // reset result to default as false, now that frame check has been done + if (selfTile.getPipeWorld().getBlockState(selfTile.getPipePos().offset(facing)).getBlock() != Blocks.AIR) { + Cover cover = selfTile.getCoverableImplementation().getCoverAtSide(facing); + if (cover == null || cover.canPipePassThrough()) { + TileEntity other = selfTile.getNeighbor(facing); + if (other instanceof IPipeTile) { + cover = ((IPipeTile)other).getCoverableImplementation().getCoverAtSide(facing.getOpposite()); + result = (cover == null || cover.canPipePassThrough()) && this.canPipesConnect(selfTile, facing, (IPipeTile) other); + } else { + result = this.canPipeConnectToBlock(selfTile, facing, other); + } + } + } + + callbackInfoR.setReturnValue(result); + } + + // - generics are not real + @Inject(method = "addCollisionBoxToList(Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/AxisAlignedBB;Ljava/util/List;Lnet/minecraft/entity/Entity;Z)V", + at = @At("HEAD"), cancellable = true) + public void onAddCollisionBoxToList(@NotNull IBlockState state, @NotNull World worldIn, @NotNull BlockPos pos, + @NotNull AxisAlignedBB entityBox, @NotNull List collidingBoxes, + @Nullable Entity entityIn, boolean isActualState, CallbackInfo callBackInfo) { + IPipeTile pipeTile = getPipeTileEntity(worldIn, pos); + if (pipeTile == null || pipeTile.getFrameMaterial() == null || ((IForcedStates) pipeTile).getForcedState() == 0) return; + + // get equivalent state for calculation of bounding box + IBlockState equivalentSheetedState = BlockSheetedFrame.determineSheetedState(worldIn, pos); + if (equivalentSheetedState == null) return; // if something went wrong in getting state, let typical logic run + + // do custom bounding box based on sheeted frame + AxisAlignedBB box = SHEETED_FRAMES.get(pipeTile.getFrameMaterial()).getCollisionBoundingBox(equivalentSheetedState, worldIn, pos).offset(pos); + if (box.intersects(entityBox)) collidingBoxes.add(box); + + // only hitbox is frame + callBackInfo.cancel(); + } +} diff --git a/src/main/java/supersymmetry/mixins/gregtech/PipeRendererMixin.java b/src/main/java/supersymmetry/mixins/gregtech/PipeRendererMixin.java new file mode 100644 index 000000000..f6c9ee013 --- /dev/null +++ b/src/main/java/supersymmetry/mixins/gregtech/PipeRendererMixin.java @@ -0,0 +1,205 @@ +package supersymmetry.mixins.gregtech; + +import codechicken.lib.render.BlockRenderer; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.render.pipeline.ColourMultiplier; +import codechicken.lib.render.pipeline.IVertexOperation; +import codechicken.lib.vec.Cuboid6; +import codechicken.lib.vec.Translation; +import codechicken.lib.vec.uv.IconTransformation; +import codechicken.lib.vec.uv.UV; +import codechicken.lib.vec.uv.UVTransformation; +import gregtech.api.pipenet.tile.IPipeTile; +import gregtech.api.unification.material.Material; +import gregtech.api.util.GTUtility; +import gregtech.client.renderer.pipe.PipeRenderer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import supersymmetry.api.blocks.IForcedStates; +import supersymmetry.api.unification.material.info.SuSyMaterialIconType; +import supersymmetry.common.blocks.BlockSheetedFrame; + +@Mixin(value = PipeRenderer.class, remap = false) +public abstract class PipeRendererMixin { + + @Shadow + @Final @NotNull + protected static ThreadLocal blockFaces; + + @Inject(method = "renderFrame(Lgregtech/api/pipenet/tile/IPipeTile;Lnet/minecraft/util/math/BlockPos;Lcodechicken/lib/render/CCRenderState;I)V", + at = @At("HEAD"), cancellable = true) + private static void renderFrame(IPipeTile pipeTile, BlockPos pos, CCRenderState renderState, int connections, CallbackInfo callbackInfo) { + // assumes pipeTile is not null + Material frameMaterial = pipeTile.getFrameMaterial(); + if (frameMaterial == null || ((IForcedStates) pipeTile).getForcedState() == 0) return; + + int rotationOrdinal = ((IForcedStates) pipeTile).getForcedState() - 1; + EnumFacing.Axis axis = BlockSheetedFrame.FrameEnumAxis.values()[rotationOrdinal].getAxis(); + + ResourceLocation rl = axis == null ? SuSyMaterialIconType.sheetedFrameAll.getBlockTexturePath(frameMaterial.getMaterialIconSet()) : + SuSyMaterialIconType.sheetedFrame.getBlockTexturePath(frameMaterial.getMaterialIconSet()); + + // if an array initializer is used for pipeline, modifying elements causes color to disappear + final TextureAtlasSprite sprite = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(rl.toString()); + + // rotate standing model over towards positive direction for Z and negative for X + final boolean isX = EnumFacing.Axis.X.equals(axis); + final boolean isZ = EnumFacing.Axis.Z.equals(axis); + final boolean isHorizontal = isX || isZ; + + final boolean isY = EnumFacing.Axis.Y.equals(axis); + final boolean isAll = axis == null; + + final UVTransformation rotCW = new UVTransformation(){ + @Override + public void apply(UV uv) { + // translate center to middle of texture + uv.u -= 0.5; + uv.v -= 0.5; + + // do rotation with matrix [[cos-90, -sin-90],[sin-90, cos-90]] -> [[0, 1],[-1, 0]]; * A = + double tempStorage = uv.u; + uv.u = uv.v; + uv.v = -tempStorage; + + // undo translation + uv.u += 0.5; + uv.v += 0.5; + + uv.u = sprite.getInterpolatedU(uv.u * 16.0); + uv.v = sprite.getInterpolatedV(uv.v * 16.0); + } + + // coordinate swap undoes itself + @Override + public UVTransformation inverse() { + return this; + } + }; + + final UVTransformation rotCCW = new UVTransformation() { + @Override + public void apply(UV uv) { + // translate center to middle of texture + uv.u -= 0.5; + uv.v -= 0.5; + + // do rotation with matrix [[cos90, -sin90],[sin90, cos90]] -> [[0, -1],[1, 0]]; * A = <-v, u> + double tempStorage = uv.u; + uv.u = -uv.v; + uv.v = tempStorage; + + // undo translation + uv.u += 0.5; + uv.v += 0.5; + + uv.u = sprite.getInterpolatedU(uv.u * 16.0); + uv.v = sprite.getInterpolatedV(uv.v * 16.0); + } + + @Override + public UVTransformation inverse() { + return this; + } + }; + + IVertexOperation[] pipeline = { + new Translation(pos), + renderState.lightMatrix, + new IconTransformation(sprite), + new ColourMultiplier(GTUtility.convertRGBtoOpaqueRGBA_CL(frameMaterial.getMaterialRGB())) + }; + + IVertexOperation[] pipelineRotateCCW = { + new Translation(pos), + renderState.lightMatrix, + rotCCW, + new ColourMultiplier(GTUtility.convertRGBtoOpaqueRGBA_CL(frameMaterial.getMaterialRGB())) + }; + + IVertexOperation[] pipelineRotateCW = { + new Translation(pos), + renderState.lightMatrix, + rotCW, + new ColourMultiplier(GTUtility.convertRGBtoOpaqueRGBA_CL(frameMaterial.getMaterialRGB())) + }; + + // stops z-fighting for pipes on axis + final Cuboid6 FULL_SHEETED_CUBOID = new Cuboid6(isX || isAll ? 0.00009 : 0, isY || isAll ? 0.00009 : 0, + isZ || isAll ? 0.00009 : 0, isX || isAll ? 0.99996 : 1, isY || isAll ? 0.99996 : 1, isZ || isAll ? 0.99996 : 1); + + // renders interior + final Cuboid6 INTERIOR_SHEETED_CUBOID = new Cuboid6(isX || isAll ? 0.9999 : 0.9375, isY || isAll ? 0.9999 : 0.9375, + isZ || isAll ? 0.9999 : 0.9375, isX || isAll ? 0.0001 : 0.0625, isY || isAll ? 0.0001 : 0.0625, isZ || isAll ? 0.0001 :0.0625); + + EnumFacing[] skippedFacings = new EnumFacing[2]; + int index = 0; + + for (EnumFacing side : EnumFacing.VALUES) { + EnumFacing.Axis sideAxis = side.getAxis(); + + // skips sides "on axis" with sheeted frame + if (sideAxis.equals(axis)) { + skippedFacings[index++] = side; + continue; + } + + final boolean isSideY = side.getAxis().equals(EnumFacing.Axis.Y); + final boolean shouldRot = isHorizontal && !(isSideY && !isX); + + // only render frame if it doesn't have a cover + if ((connections & 1 << (12 + side.getIndex())) == 0) { + BlockRenderer.BlockFace blockFace = blockFaces.get(); + blockFace.loadCuboidFace(FULL_SHEETED_CUBOID, side.getIndex()); + renderState.setPipeline(blockFace, 0, blockFace.verts.length, shouldRot ? + (side.getAxisDirection().getOffset() < 0 ? pipelineRotateCW : pipelineRotateCCW) : pipeline); + renderState.render(); + + // render interior for off axis sides + blockFace.loadCuboidFace(INTERIOR_SHEETED_CUBOID, side.getIndex()); + renderState.setPipeline(blockFace, 0, blockFace.verts.length, (isX || isZ) && !(isSideY && !isX) ? + (side.getAxisDirection().getOffset() > 0 ? pipelineRotateCW : pipelineRotateCCW) : pipeline); + renderState.render(); + } + } + + // will be done, but not used, if orientation is none + // must be included in a model at some point to be included into the texture atlas + rl = SuSyMaterialIconType.sheetedFrameEnd.getBlockTexturePath(frameMaterial.getMaterialIconSet()); + TextureAtlasSprite endSprite = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(rl.toString()); + //pipeline[3] = new IconTransformation(sprite); this does not work for some reason, the entire thing must be re-initialized + pipeline = new IVertexOperation[] { + new Translation(pos), + renderState.lightMatrix, + new IconTransformation(endSprite), + new ColourMultiplier(GTUtility.convertRGBtoOpaqueRGBA_CL(frameMaterial.getMaterialRGB())), + }; + + for (int i = 0; i < index; ++i) { + // only render frame if it doesn't have a cover + if ((connections & 1 << (12 + skippedFacings[i].getIndex())) == 0) { + BlockRenderer.BlockFace blockFace = blockFaces.get(); + blockFace.loadCuboidFace(FULL_SHEETED_CUBOID, skippedFacings[i].getIndex()); + renderState.setPipeline(blockFace, 0, blockFace.verts.length, pipeline); + renderState.render(); + + // render interior for off axis sides + blockFace.loadCuboidFace(INTERIOR_SHEETED_CUBOID, skippedFacings[i].getIndex()); + renderState.setPipeline(blockFace, 0, blockFace.verts.length, pipeline); + renderState.render(); + } + } + + callbackInfo.cancel(); + } +} diff --git a/src/main/java/supersymmetry/mixins/gregtech/TileEntityPipeBaseMixin.java b/src/main/java/supersymmetry/mixins/gregtech/TileEntityPipeBaseMixin.java new file mode 100644 index 000000000..9ab3f8e46 --- /dev/null +++ b/src/main/java/supersymmetry/mixins/gregtech/TileEntityPipeBaseMixin.java @@ -0,0 +1,90 @@ +package supersymmetry.mixins.gregtech; + +import gregtech.api.capability.GregtechDataCodes; +import gregtech.api.metatileentity.NeighborCacheTileEntityBase; +import gregtech.api.pipenet.block.IPipeType; +import gregtech.api.pipenet.tile.IPipeTile; +import gregtech.api.pipenet.tile.TileEntityPipeBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.EnumFacing; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import supersymmetry.api.blocks.IForcedStates; +import supersymmetry.common.blocks.BlockSheetedFrame; + +@Mixin(value = TileEntityPipeBase.class, remap = false) +public abstract class TileEntityPipeBaseMixin & IPipeType, NodeDataType> extends NeighborCacheTileEntityBase implements IPipeTile, IForcedStates { + int rotationState = 0; + + @Shadow + private TileEntityPipeBase tickingPipe; + + public void setForcedState(int val) { + rotationState = val; + if (world != null && world.isRemote) { + this.writeCustomData(GregtechDataCodes.UPDATE_FRAME_MATERIAL, (buf) -> buf.writeVarInt(val)); + } + } + + public int getForcedState() { + return rotationState; + } + + @Inject(method = "setConnection(Lnet/minecraft/util/EnumFacing;ZZ)V", at = @At("HEAD"), cancellable = true) + public void onSetConnection(EnumFacing side, boolean connected, boolean fromNeighbor, CallbackInfo callbackInfo) { + int rotationOrdinal = ((IForcedStates) this).getForcedState() - 1; + if (this.getWorld().isRemote || rotationOrdinal < 0) return; + + // cancel if connection is attempted on non axis sides for rotations that are not omnidirectional + if (rotationOrdinal != BlockSheetedFrame.FrameEnumAxis.NONE.ordinal() && rotationOrdinal != side.getAxis().ordinal() && connected) { + callbackInfo.cancel(); + } + } + + // (DIIIZ)Lcom/mypackage/ThingType; + @Inject(method = "transferDataFrom(Lgregtech/api/pipenet/tile/IPipeTile;)V", at = @At("TAIL")) + public void onTransferDataFrom(IPipeTile tileEntity, CallbackInfo callbackInfo) { + setForcedState(((IForcedStates) tileEntity).getForcedState()); // this method should only ever be called with TE instance of this mixin's target + } + + @Inject(method = "writeToNBT(Lnet/minecraft/nbt/NBTTagCompound;)Lnet/minecraft/nbt/NBTTagCompound;", at = @At("TAIL")) + public void onWriteToNBT(@NotNull NBTTagCompound compound, CallbackInfoReturnable callbackInfoR) { + compound.setInteger("rotationState", getForcedState()); + } + + @Inject(method = "readFromNBT(Lnet/minecraft/nbt/NBTTagCompound;)V", at = @At("HEAD")) + public void onReadFromNBT(@NotNull NBTTagCompound compound, CallbackInfo callbackInfo) { + // actual read from is only called when tickingPipe is null + if (tickingPipe == null) { + setForcedState(compound.getInteger("rotationState")); + } + } + + @Inject(method = "writeInitialSyncData(Lnet/minecraft/network/PacketBuffer;)V", at = @At("HEAD")) + public void onWriteInitialSyncData(PacketBuffer buf, CallbackInfo callbackInfo) { + buf.writeInt(getForcedState()); + } + + @Inject(method = "receiveInitialSyncData(Lnet/minecraft/network/PacketBuffer;)V", at = @At("HEAD")) + public void onReceiveInitialSyncData(PacketBuffer buf, CallbackInfo callbackInfo) { + // actual receive only called when tickingPipe is null + if (tickingPipe == null) { + setForcedState(buf.readInt()); + } + } + + @Inject(method = "receiveCustomData(ILnet/minecraft/network/PacketBuffer;)V", at = @At("HEAD")) + public void onReceiveCustomData(int discriminator, PacketBuffer buf, CallbackInfo callbackInfo) { + if (tickingPipe == null && discriminator == BlockSheetedFrame.UPDATE_ROTATION_STATE) { + rotationState = buf.readInt(); + + this.scheduleChunkForRenderUpdate(); + } + } +} diff --git a/src/main/java/supersymmetry/mixins/xnet/FacadeItemBlockMixin.java b/src/main/java/supersymmetry/mixins/xnet/FacadeItemBlockMixin.java index 71dd9163d..ed2dc88d2 100644 --- a/src/main/java/supersymmetry/mixins/xnet/FacadeItemBlockMixin.java +++ b/src/main/java/supersymmetry/mixins/xnet/FacadeItemBlockMixin.java @@ -16,7 +16,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -@Mixin(value = FacadeItemBlock.class) +@Mixin(value = FacadeItemBlock.class, remap = false) public class FacadeItemBlockMixin { @Inject(method = "onItemUse(Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/EnumHand;Lnet/minecraft/util/EnumFacing;FFF)Lnet/minecraft/util/EnumActionResult;", diff --git a/src/main/resources/assets/gregtech/blockstates/material_sets/dull/sheeted_frame.json b/src/main/resources/assets/gregtech/blockstates/material_sets/dull/sheeted_frame.json index c484077b3..758f0403c 100644 --- a/src/main/resources/assets/gregtech/blockstates/material_sets/dull/sheeted_frame.json +++ b/src/main/resources/assets/gregtech/blockstates/material_sets/dull/sheeted_frame.json @@ -3,15 +3,17 @@ "defaults": { "model": "susy:no_cull_tinted_cube_column", "textures": { - "end": "gregtech:blocks/material_sets/dull/frame_gt", - "side": "gregtech:blocks/material_sets/dull/sheeted_frame" + "end": "gregtech:blocks/material_sets/dull/sheeted_frame_end", + "side": "gregtech:blocks/material_sets/dull/sheeted_frame", + "all": "gregtech:blocks/material_sets/dull/sheeted_frame_all" } }, "variants": { "axis": { "none": { "textures": { - "end": "#side" + "end": "#all", + "side": "#all" } }, "x": { diff --git a/src/main/resources/assets/gregtech/textures/blocks/material_sets/dull/sheeted_frame_all.png b/src/main/resources/assets/gregtech/textures/blocks/material_sets/dull/sheeted_frame_all.png new file mode 100644 index 0000000000000000000000000000000000000000..0077d1f225ec5a3d5f5fba72ea2b11d8bfc498ea GIT binary patch literal 794 zcmV+#1LgdQP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0Z*ovr6PA8w;PON zsf5VmFj}n^3dIt#*(~&ux=g3ja5|mv`+ewiIs)!?I|Amh*{pE6#!#=Js_V$csqmE{?iR_=h$mjFW;yXJArIK}j{{TL}AIq_*7?nCt zOIu!#8zz%kzKwgmI6OR*_K4BhBMqZ*`Fsv;<#@GvB|sjB!=cReOY-&gwKA?Qz6>zB zZFCf!?k)BY4y4L|FNy+YvdiUyMYYISe)3cc1cQR%m~~z<$!s=@F?9O!@=}@RmwQTO z&kQOW1i$go-}Txw$zUA0Ok{^A{Rr6U3#mS}l09wx->Y zr7$$4E6=_lskTwu-rhD$CKK)j15*9n`wxgNEg~9?;^nK?TmgLg7&js_v#2Q30?Heb z=kf)V%Vi8Rfo=~ZbK_3c0yS@Lu(7dWc-7oBO-Hp-Rs>Zc7>rr|1xn|S!5}kL#9}do zr>EsPKR=Jf#RVxs1s4}NX)TdRh~YBEg@py#yi6u5Np~Z4$nG;JmET#BV8+tYlFG5; YAA6T|oF~^!zW@LL07*qoM6N<$f`DCT&;S4c literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/blocks/material_sets/dull/sheeted_frame_end.png b/src/main/resources/assets/gregtech/textures/blocks/material_sets/dull/sheeted_frame_end.png new file mode 100644 index 0000000000000000000000000000000000000000..d7abce63baa1e5ca8e7353bde274616a3f32f689 GIT binary patch literal 522 zcmV+l0`>igP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0iQ`kK~y+Tg;PsT z0znikkN_FoU>L1*0Lp=gf!wJ+KOLe0$dIYvA8wDe>k|E*{Abb*V zs+lIuIA|r4O!uqzUcE{`Pdc6M_j*0dMIs0U0%*0{ScuNUG;8>(R>j?PCSD5Kl$qF%4#!y@uy?D6RtXXh7KTU|k; z(SRqFO7(NO9AdE;3WWkPnT$uY8-rvr+27gT!p-d+;_*1Ve!m}yL_#DV9UcgR&HV+& z$YC;bnCoRA7z~Qe$0w&kiCYogF-8u#%;|JGg8~u^xG9mHog>mCpZ!0CO%UB=5w$bV z5-c#HKtfgWm${mz4NM$|%d2bb@9o+rcepB0XQp(gClYM#qmy)0f<%{@hn_e`85u$C ztP)jER3+jiau--6o6Y|F8l^gN_>lO_g$GP_>+FQ8ggJyzP^;C3RaHOSz=e`($rS~n z(I{qTbd;?XeJ>WpYU{d=37-#bYrUr?HIbYzyg?6##lKOhpxJEV2gJ$^F#jnk?EnA( M07*qoM6N<$g4np)kpKVy literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/susy/lang/en_us.lang b/src/main/resources/assets/susy/lang/en_us.lang index beb8e78aa..fef01d1b5 100644 --- a/src/main/resources/assets/susy/lang/en_us.lang +++ b/src/main/resources/assets/susy/lang/en_us.lang @@ -95,6 +95,9 @@ tile.home_block.home_renewal_brutalist.tooltip=Renewal Brutalist tile.home_block.home_scifi.name=Home Block tile.home_block.home_scifi.tooltip=Sci-Fi +tile.sheeted_frame_block.tooltip=Use a screwdriver to rotate, a hammer to toggle omnidirectionality, and a crowbar to remove from pipes. +tile.sheeted_frame_block.tooltip_extra=Lighting bugs are known. Pipe connections may only be made "on axis" with the surrounding sheeted frame, save for the omnidirectional state. Omnidirectional sheeted frames, when clicked with a frame, place with the orientation of the side clicked. All sheeted frames adjacent to an omnidirectional sheeted frame place away from it, on their axis, when they are clicked with a sheeted frame. The side facing open air will be preferred for all frames, or the positive direction if neither/ both face open air. Contact me (Eight) for any other bugs. + # Rocks tile.susy_stone_smooth.gabbro.name=Gabbro tile.susy_stone_smooth.gneiss.name=Gneiss diff --git a/src/main/resources/mixins.susy.gregtech.json b/src/main/resources/mixins.susy.gregtech.json index 8afc7773f..ef8d23745 100644 --- a/src/main/resources/mixins.susy.gregtech.json +++ b/src/main/resources/mixins.susy.gregtech.json @@ -5,6 +5,11 @@ "minVersion" : "0.8", "compatibilityLevel" : "JAVA_8", "mixins" : [ - "BlockMachineMixin" + "BlockMachineMixin", + "BlockPipeMixin", + "TileEntityPipeBaseMixin" + ], + "client" : [ + "PipeRendererMixin" ] } diff --git a/src/main/resources/mixins.susy.json b/src/main/resources/mixins.susy.json new file mode 100644 index 000000000..793a1a4cc --- /dev/null +++ b/src/main/resources/mixins.susy.json @@ -0,0 +1,10 @@ +{ + "package": "supersymmetry.mixins", + "refmap": "mixins.susy.refmap.json", + "target": "@env(DEFAULT)", + "minVersion": "0.8", + "compatibilityLevel": "JAVA_8", + "mixins": [], + "client": [], + "server": [] +} From 0853855585f0e6f53b660f36246f8332c10d9c30 Mon Sep 17 00:00:00 2001 From: EightXOR8 <122228099+EightXOR8@users.noreply.github.com> Date: Sun, 8 Sep 2024 17:22:50 -0700 Subject: [PATCH 2/2] Remove Large Commented Out Blocks --- .../mixins/gregtech/BlockPipeMixin.java | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/src/main/java/supersymmetry/mixins/gregtech/BlockPipeMixin.java b/src/main/java/supersymmetry/mixins/gregtech/BlockPipeMixin.java index 780cfc184..b122ded42 100644 --- a/src/main/java/supersymmetry/mixins/gregtech/BlockPipeMixin.java +++ b/src/main/java/supersymmetry/mixins/gregtech/BlockPipeMixin.java @@ -104,28 +104,6 @@ protected void onOnPipeActivated(World world, IBlockState state, BlockPos pos, E spawnAsEntity(world, pos, SHEETED_FRAMES.get(prevMat).getItem(prevMat)); callBackInfoR.setReturnValue(true); } - - /* - BlockSheetedFrame sheetedFrame = BlockSheetedFrame.getFrameBlockFromItem(handStack); - if (sheetedFrame == null) return; // avoids cancellation if item is not sheeted frame - - // sets forced state - Material newMat = sheetedFrame.getStateFromMeta(handStack.getMetadata()).getValue(sheetedFrame.variantProperty); - Material prevMat = pipeTile.getFrameMaterial(); - if (newMat.equals(prevMat)) return; // cancel custom logic if the materials are the same - ((TileEntityPipeBase) pipeTile).setFrameMaterial(newMat); - - SoundType type = sheetedFrame.getSoundType(handStack); - world.playSound(entityPlayer, pos, type.getPlaceSound(), SoundCategory.BLOCKS, (type.getVolume() + 1.0F) / 2.0F, type.getPitch() * 0.8F); - if (!entityPlayer.capabilities.isCreativeMode) { - handStack.shrink(1); - } - - // drop old frame - spawnAsEntity(world, pos, SHEETED_FRAMES.get(prevMat).getItem(prevMat)); - - callBackInfoR.setReturnValue(true); - */ } @Inject(method = "activateFrame(Lnet/minecraft/world/World;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/EnumHand;Lcodechicken/lib/raytracer/CuboidRayTraceResult;Lgregtech/api/pipenet/tile/IPipeTile;)Z", @@ -146,16 +124,6 @@ public void onOnEntityCollision(World worldIn, BlockPos pos, IBlockState state, callbackInfo.cancel(); // don't do frame logic } - /* - @Inject(method = "getCollisionBox(Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/entity/Entity;)Ljava/util/List;", at = @At("HEAD"), cancellable = true) - private void getCollisionBox(IBlockAccess world, BlockPos pos, @Nullable Entity entityIn, CallbackInfoReturnable> callbackInfoR) { - IPipeTile pipeTile = getPipeTileEntity(world, pos); - if (pipeTile == null || pipeTile.getFrameMaterial() == null || ((IForcedStates) pipeTile).getForcedState() == 0) return; - callbackInfoR.setReturnValue(Collections.singletonList(new IndexedCuboid6(null, - SHEETED_FRAMES.get(pipeTile.getFrameMaterial()).getCollisionBoundingBox(BlockSheetedFrame.determineSheetedState(world, pos), world, pos)))); - } - */ - // - https://fabricmc.net/wiki/tutorial:mixin_injects : because generics dont exist at run time, they arent needed @Inject(method = "getDrops(Lnet/minecraft/util/NonNullList;Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/state/IBlockState;I)V", at = @At("HEAD"), cancellable = true)