Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sheeted Frame Revamp/ Improvements #306

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/main/java/supersymmetry/api/blocks/IForcedStates.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package supersymmetry.api.blocks;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better replace this with an accessor and a invoker ig


public interface IForcedStates {
void setForcedState(int val);
int getForcedState();
}
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
424 changes: 295 additions & 129 deletions src/main/java/supersymmetry/common/blocks/BlockSheetedFrame.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -44,6 +47,13 @@ public String getItemStackDisplayName(@Nonnull ItemStack stack) {
@Override
public void addInformation(@Nonnull ItemStack stack, @Nullable World worldIn, @Nonnull List<String> 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());
}
Expand Down
186 changes: 186 additions & 0 deletions src/main/java/supersymmetry/mixins/gregtech/BlockPipeMixin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
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<PipeType extends Enum<PipeType> & IPipeType<NodeDataType>, NodeDataType,
WorldPipeNetType extends WorldPipeNet<NodeDataType, ? extends PipeNet<NodeDataType>>>
extends BuiltInRenderBlock implements ITileEntityProvider, IFacadeWrapper, IBlockAppearance {

@Shadow @Final
protected ThreadLocal<IPipeTile<PipeType, NodeDataType>> tileEntities;

@Shadow
public abstract IPipeTile<PipeType, NodeDataType> getPipeTileEntity(IBlockAccess world, BlockPos selfPos);

@Shadow
public abstract ItemStack getDropItem(IPipeTile<PipeType, NodeDataType> var1);

@Shadow
public abstract boolean canPipesConnect(IPipeTile<PipeType, NodeDataType> var1, EnumFacing var2, IPipeTile<PipeType, NodeDataType> var3);

@Shadow
public abstract boolean canPipeConnectToBlock(IPipeTile<PipeType, NodeDataType> 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<PipeType, NodeDataType> pipeTile, CallbackInfoReturnable<Boolean> 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);
}
}

@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<PipeType, NodeDataType> pipeTile, CallbackInfoReturnable<Boolean> 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<PipeType, NodeDataType> 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
}

// <Lnet/minecraft/item/ItemStack;> - 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<ItemStack> drops, @NotNull IBlockAccess world, @NotNull BlockPos pos, @NotNull IBlockState state, int fortune, CallbackInfo callbackInfo) {
IPipeTile<PipeType, NodeDataType> 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<PipeType, NodeDataType> selfTile, EnumFacing facing, CallbackInfoReturnable<Boolean> 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<PipeType, NodeDataType>) other);
} else {
result = this.canPipeConnectToBlock(selfTile, facing, other);
}
}
}

callbackInfoR.setReturnValue(result);
}

// <Lnet/minecraft/util/math/AxisAlignedBB;> - 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<AxisAlignedBB> collidingBoxes,
@Nullable Entity entityIn, boolean isActualState, CallbackInfo callBackInfo) {
IPipeTile<PipeType, NodeDataType> 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();
}
}
Loading