diff --git a/src/main/java/com/hbm/blocks/BlockDummyable.java b/src/main/java/com/hbm/blocks/BlockDummyable.java index d802eac32..b81f81db6 100644 --- a/src/main/java/com/hbm/blocks/BlockDummyable.java +++ b/src/main/java/com/hbm/blocks/BlockDummyable.java @@ -6,6 +6,7 @@ import java.util.Random; import com.hbm.handler.MultiblockHandlerXR; import com.hbm.handler.ThreeInts; +import com.hbm.interfaces.ICopiable; import com.hbm.main.MainRegistry; import com.hbm.tileentity.IPersistentNBT; @@ -32,7 +33,7 @@ import net.minecraft.world.World; import net.minecraftforge.client.event.DrawBlockHighlightEvent; import net.minecraftforge.common.util.ForgeDirection; -public abstract class BlockDummyable extends BlockContainer implements ICustomBlockHighlight { +public abstract class BlockDummyable extends BlockContainer implements ICustomBlockHighlight, ICopiable { public BlockDummyable(Material mat) { super(mat); @@ -507,4 +508,31 @@ public abstract class BlockDummyable extends BlockContainer implements ICustomBl for(AxisAlignedBB aabb : this.bounding) event.context.drawOutlinedBoundingBox(getAABBRotationOffset(aabb.expand(exp, exp, exp), 0, 0, 0, ForgeDirection.getOrientation(meta - offset).getRotation(ForgeDirection.UP)).getOffsetBoundingBox(x - dX + 0.5, y - dY, z - dZ + 0.5), -1); ICustomBlockHighlight.cleanup(); } + + @Override + public NBTTagCompound getSettings(World world, int x, int y, int z) { + int[] pos = findCore(world, x, y, z); + TileEntity tile = world.getTileEntity(pos[0], pos[1], pos[2]); + if (tile instanceof ICopiable) + return ((ICopiable) tile).getSettings(world, pos[0], pos[1], pos[2]); + else + return null; + } + + @Override + public void pasteSettings(NBTTagCompound nbt, int index, World world, int x, int y, int z) { + int[] pos = findCore(world, x, y, z); + TileEntity tile = world.getTileEntity(pos[0], pos[1], pos[2]); + if (tile instanceof ICopiable) + ((ICopiable) tile).pasteSettings(nbt, index, world, pos[0], pos[1], pos[2]); + } + + @Override + public String[] infoForDisplay(World world, int x, int y, int z) { + int[] pos = findCore(world, x, y, z); + TileEntity tile = world.getTileEntity(pos[0], pos[1], pos[2]); + if (tile instanceof ICopiable) + return ((ICopiable) tile).infoForDisplay(world, x, y, z); + return null; + } } diff --git a/src/main/java/com/hbm/handler/HbmKeybinds.java b/src/main/java/com/hbm/handler/HbmKeybinds.java index 39f59ced2..767c28ad7 100644 --- a/src/main/java/com/hbm/handler/HbmKeybinds.java +++ b/src/main/java/com/hbm/handler/HbmKeybinds.java @@ -39,13 +39,12 @@ public class HbmKeybinds { ClientRegistry.registerKeyBinding(reloadKey); ClientRegistry.registerKeyBinding(dashKey); ClientRegistry.registerKeyBinding(trainKey); - ClientRegistry.registerKeyBinding(copyToolAlt); - ClientRegistry.registerKeyBinding(craneUpKey); ClientRegistry.registerKeyBinding(craneDownKey); ClientRegistry.registerKeyBinding(craneLeftKey); ClientRegistry.registerKeyBinding(craneRightKey); ClientRegistry.registerKeyBinding(craneLoadKey); + ClientRegistry.registerKeyBinding(copyToolAlt); } @SubscribeEvent @@ -74,11 +73,11 @@ public class HbmKeybinds { RELOAD, DASH, TRAIN, - COPY_TOOL, CRANE_UP, CRANE_DOWN, CRANE_LEFT, CRANE_RIGHT, - CRANE_LOAD + CRANE_LOAD, + COPY_TOOL } } diff --git a/src/main/java/com/hbm/interfaces/ICopiable.java b/src/main/java/com/hbm/interfaces/ICopiable.java index 6e6d98996..5a8f2997f 100644 --- a/src/main/java/com/hbm/interfaces/ICopiable.java +++ b/src/main/java/com/hbm/interfaces/ICopiable.java @@ -1,10 +1,28 @@ package com.hbm.interfaces; +import com.hbm.util.Either; +import net.minecraft.block.Block; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; public interface ICopiable { - NBTTagCompound getSettings(); + NBTTagCompound getSettings(World world, int x, int y, int z); - void pasteSettings(NBTTagCompound nbt, boolean alt); + void pasteSettings(NBTTagCompound nbt, int index, World world, int x, int y, int z); + + default String getSettingsSourceID(Either self) { + Block block = self.isLeft() ? self.left().getBlockType() : self.right(); + return block.getUnlocalizedName(); + } + + default String getSettingsSourceDisplay(Either self) { + Block block = self.isLeft() ? self.left().getBlockType() : self.right(); + return block.getLocalizedName(); + } + + default String[] infoForDisplay(World world, int x, int y, int z){ + return null; + } } diff --git a/src/main/java/com/hbm/items/tool/ItemSettingsTool.java b/src/main/java/com/hbm/items/tool/ItemSettingsTool.java index 6aefa2905..b50462675 100644 --- a/src/main/java/com/hbm/items/tool/ItemSettingsTool.java +++ b/src/main/java/com/hbm/items/tool/ItemSettingsTool.java @@ -3,25 +3,56 @@ package com.hbm.items.tool; import com.hbm.extprop.HbmPlayerProps; import com.hbm.handler.HbmKeybinds; import com.hbm.interfaces.ICopiable; -import com.hbm.main.MainRegistry; -import com.hbm.tileentity.TileEntityProxyBase; -import com.hbm.tileentity.network.IDroneLinkable; +import com.hbm.packet.PacketDispatcher; +import com.hbm.packet.PlayerInformPacket; import com.hbm.util.ChatBuilder; -import com.hbm.util.fauxpointtwelve.BlockPos; +import com.hbm.util.Either; +import net.minecraft.block.Block; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumChatFormatting; import net.minecraft.world.World; +import javax.annotation.Nullable; +import java.util.ArrayList; import java.util.List; public class ItemSettingsTool extends Item { + @Override + public void onUpdate(ItemStack stack, World world, Entity entity, int i, boolean bool) { + NBTTagList displayInfo; + if(!(entity instanceof EntityPlayerMP)) return; + if(((EntityPlayer) entity).getHeldItem() == stack && stack.hasTagCompound()) { + EntityPlayer player = ((EntityPlayer) entity); + displayInfo = stack.stackTagCompound.getTagList("displayInfo", 10); + + if (HbmPlayerProps.getData(player).getKeyPressed(HbmKeybinds.EnumKeybind.COPY_TOOL)) { + int index = stack.stackTagCompound.getInteger("copyIndex") + 1; + if(index > displayInfo.tagCount() - 1) index = 0; + stack.stackTagCompound.setInteger("copyIndex", index); + } + + if(world.getTotalWorldTime() % 5 != 0) return; + + if(displayInfo.tagCount() > 0){ + for (int j = 0; j < displayInfo.tagCount(); j++) { + NBTTagCompound nbt = displayInfo.getCompoundTagAt(j); + String info = nbt.getString("info"); + EnumChatFormatting format = stack.stackTagCompound.getInteger("copyIndex") == j ? EnumChatFormatting.AQUA : EnumChatFormatting.YELLOW; + PacketDispatcher.wrapper.sendTo(new PlayerInformPacket(format + info, 897 + j, 4000 ), (EntityPlayerMP) entity); + } + } + } + + } @SuppressWarnings("unchecked") @Override public void addInformation(ItemStack stack, EntityPlayer player, List list, boolean bool) { @@ -36,28 +67,52 @@ public class ItemSettingsTool extends Item { } @Override public boolean onItemUseFirst(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float fX, float fY, float fZ) { - TileEntity tile = world.getTileEntity(x, y, z); - if(tile instanceof TileEntityProxyBase){ - tile = ((TileEntityProxyBase) tile).getTE(); - } - if (tile instanceof ICopiable) { - ICopiable te = ((ICopiable) tile); + Either schrodinger = getCopyInfoSource(world, x, y, z); + if(schrodinger == null) return false; + ICopiable copiable = schrodinger.cast(); - if (player.isSneaking()) { - stack.stackTagCompound = ((ICopiable) tile).getSettings(); - stack.stackTagCompound.setString("tileName", tile.getBlockType().getLocalizedName()); - - player.addChatMessage(ChatBuilder.start("[").color(EnumChatFormatting.DARK_AQUA) - .nextTranslation(this.getUnlocalizedName() + ".name").color(EnumChatFormatting.DARK_AQUA) - .next("] ").color(EnumChatFormatting.DARK_AQUA) - .next("Copied settings of " + tile.getBlockType().getLocalizedName()).color(EnumChatFormatting.AQUA).flush()); - - } else if (stack.hasTagCompound()) { - boolean alt = HbmPlayerProps.getData(player).getKeyPressed(HbmKeybinds.EnumKeybind.COPY_TOOL); - te.pasteSettings(stack.stackTagCompound, alt); + if(player.isSneaking()) { + stack.stackTagCompound = copiable.getSettings(world, x, y, z); + stack.stackTagCompound.setString("tileName", copiable.getSettingsSourceID(schrodinger)); + stack.stackTagCompound.setInteger("copyIndex", 0); + String[] info = copiable.infoForDisplay(world, x, y, z); + if(info != null) { + NBTTagList displayInfo = new NBTTagList(); + for (String str : info) { + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setString("info", str); + displayInfo.appendTag(nbt); + } + stack.stackTagCompound.setTag("displayInfo", displayInfo); } + if(world.isRemote) { + player.addChatMessage(ChatBuilder.start("[").color(EnumChatFormatting.DARK_AQUA) + .nextTranslation(this.getUnlocalizedName() + ".name").color(EnumChatFormatting.DARK_AQUA) + .next("] ").color(EnumChatFormatting.DARK_AQUA) + .next("Copied settings of " + copiable.getSettingsSourceDisplay(schrodinger)).color(EnumChatFormatting.AQUA).flush()); + } + + } else if(stack.hasTagCompound()) { + int index = stack.stackTagCompound.getInteger("copyIndex"); + copiable.pasteSettings(stack.stackTagCompound, index, world, x, y, z); } - return true; + + return !world.isRemote; + } + + @Nullable + private Either getCopyInfoSource(World world, int x, int y, int z) { + TileEntity te = world.getTileEntity(x, y, z); + if(te instanceof ICopiable) { + return Either.left(te); + } + + Block block = world.getBlock(x, y, z); + if(block instanceof ICopiable) { + return Either.right(block); + } + + return null; } } diff --git a/src/main/java/com/hbm/main/ClientProxy.java b/src/main/java/com/hbm/main/ClientProxy.java index 6f3b52609..1f2167262 100644 --- a/src/main/java/com/hbm/main/ClientProxy.java +++ b/src/main/java/com/hbm/main/ClientProxy.java @@ -2113,6 +2113,7 @@ public class ClientProxy extends ServerProxy { case CRANE_LEFT: return HbmKeybinds.craneLeftKey.getIsKeyPressed(); case CRANE_RIGHT: return HbmKeybinds.craneRightKey.getIsKeyPressed(); case CRANE_LOAD: return HbmKeybinds.craneLoadKey.getIsKeyPressed(); + case COPY_TOOL: return HbmKeybinds.copyToolAlt.getIsKeyPressed(); } return false; diff --git a/src/main/java/com/hbm/tileentity/IControlReceiverFilter.java b/src/main/java/com/hbm/tileentity/IControlReceiverFilter.java index f2cd224f8..2e6c5a15a 100644 --- a/src/main/java/com/hbm/tileentity/IControlReceiverFilter.java +++ b/src/main/java/com/hbm/tileentity/IControlReceiverFilter.java @@ -3,14 +3,13 @@ package com.hbm.tileentity; import com.hbm.interfaces.IControlReceiver; import com.hbm.interfaces.ICopiable; -import com.hbm.module.ModulePatternMatcher; import net.minecraft.inventory.IInventory; -import net.minecraft.inventory.Slot; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; public interface IControlReceiverFilter extends IControlReceiver, ICopiable { @@ -47,7 +46,7 @@ public interface IControlReceiverFilter extends IControlReceiver, ICopiable { int[] getFilterSlots(); @Override - default NBTTagCompound getSettings() { + default NBTTagCompound getSettings(World world, int x, int y, int z) { IInventory inv = (IInventory) this; NBTTagCompound nbt = new NBTTagCompound(); NBTTagList tags = new NBTTagList(); @@ -67,7 +66,7 @@ public interface IControlReceiverFilter extends IControlReceiver, ICopiable { } @Override - default void pasteSettings(NBTTagCompound nbt, boolean alt) { + default void pasteSettings(NBTTagCompound nbt, int index, World world, int x, int y, int z) { TileEntity tile = (TileEntity) this; IInventory inv = (IInventory) this; NBTTagList items = nbt.getTagList("items", 10); diff --git a/src/main/java/com/hbm/tileentity/IFluidCopiable.java b/src/main/java/com/hbm/tileentity/IFluidCopiable.java index 67b90580c..61933e829 100644 --- a/src/main/java/com/hbm/tileentity/IFluidCopiable.java +++ b/src/main/java/com/hbm/tileentity/IFluidCopiable.java @@ -6,9 +6,9 @@ import com.hbm.inventory.fluid.Fluids; import com.hbm.inventory.fluid.tank.FluidTank; import com.hbm.util.BobMathUtil; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; import java.util.ArrayList; -import java.util.Arrays; public interface IFluidCopiable extends ICopiable { /** @@ -18,11 +18,10 @@ public interface IFluidCopiable extends ICopiable { IFluidStandardTransceiver tile = (IFluidStandardTransceiver) this; ArrayList types = new ArrayList<>(); - if(tile.getReceivingTanks() != null && !tile.getReceivingTanks()[0].getTankType().hasNoID()) - types.add(tile.getReceivingTanks()[0].getTankType().getID()); - - if(tile.getSendingTanks() != null && !tile.getSendingTanks()[0].getTankType().hasNoID()) - types.add(tile.getSendingTanks()[0].getTankType().getID()); + for (FluidTank tank : tile.getAllTanks()) { + if (!tank.getTankType().hasNoID()) + types.add(tank.getTankType().getID()); + } return BobMathUtil.intCollectionToArray(types); } @@ -33,7 +32,7 @@ public interface IFluidCopiable extends ICopiable { } @Override - default NBTTagCompound getSettings(){ + default NBTTagCompound getSettings(World world, int x, int y, int z){ NBTTagCompound tag = new NBTTagCompound(); if(getFluidIDToCopy().length > 0) tag.setIntArray("fluidID", getFluidIDToCopy()); @@ -41,14 +40,23 @@ public interface IFluidCopiable extends ICopiable { } @Override - default void pasteSettings(NBTTagCompound nbt, boolean alt) { + default void pasteSettings(NBTTagCompound nbt, int index, World world, int x, int y, int z) { if(getTankToPaste() != null) { int[] ids = nbt.getIntArray("fluidID"); if(ids.length > 0) { - int id = ids[alt ? 1 : 0]; + int id = ids[index]; getTankToPaste().setTankType(Fluids.fromID(id)); } } } + @Override + default String[] infoForDisplay(World world, int x, int y, int z) { + int[] ids = getFluidIDToCopy(); + String[] names = new String[ids.length]; + for (int i = 0; i < ids.length; i++) { + names[i] = Fluids.fromID(ids[i]).getUnlocalizedName(); + } + return names; + } } diff --git a/src/main/java/com/hbm/tileentity/machine/TileEntityHeaterOilburner.java b/src/main/java/com/hbm/tileentity/machine/TileEntityHeaterOilburner.java index 5b1fd2685..33c9910c2 100644 --- a/src/main/java/com/hbm/tileentity/machine/TileEntityHeaterOilburner.java +++ b/src/main/java/com/hbm/tileentity/machine/TileEntityHeaterOilburner.java @@ -11,7 +11,6 @@ import com.hbm.lib.Library; import com.hbm.tileentity.IFluidCopiable; import com.hbm.tileentity.IGUIProvider; import com.hbm.tileentity.TileEntityMachinePolluting; -import com.hbm.util.BobMathUtil; import com.hbm.util.fauxpointtwelve.DirPos; import api.hbm.fluid.IFluidStandardTransceiver; @@ -26,8 +25,6 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.AxisAlignedBB; import net.minecraft.world.World; -import java.util.Arrays; - public class TileEntityHeaterOilburner extends TileEntityMachinePolluting implements IGUIProvider, IFluidStandardTransceiver, IHeatSource, IControlReceiver, IFluidCopiable { public boolean isOn = false; @@ -223,7 +220,7 @@ public class TileEntityHeaterOilburner extends TileEntityMachinePolluting implem } @Override - public NBTTagCompound getSettings() { + public NBTTagCompound getSettings(World world, int x, int y, int z) { NBTTagCompound tag = new NBTTagCompound(); tag.setIntArray("fluidID", new int[]{tank.getTankType().getID()}); tag.setInteger("burnRate", setting); @@ -231,8 +228,8 @@ public class TileEntityHeaterOilburner extends TileEntityMachinePolluting implem } @Override - public void pasteSettings(NBTTagCompound nbt, boolean alt) { - int id = nbt.getIntArray("fluidID")[alt ? 1 : 0]; + public void pasteSettings(NBTTagCompound nbt, int index, World world, int x, int y, int z) { + int id = nbt.getIntArray("fluidID")[index]; tank.setTankType(Fluids.fromID(id)); setting = nbt.getInteger("burnRate"); } diff --git a/src/main/java/com/hbm/tileentity/machine/TileEntityMachineCrystallizer.java b/src/main/java/com/hbm/tileentity/machine/TileEntityMachineCrystallizer.java index 4ad2b1a2f..9c81c20ad 100644 --- a/src/main/java/com/hbm/tileentity/machine/TileEntityMachineCrystallizer.java +++ b/src/main/java/com/hbm/tileentity/machine/TileEntityMachineCrystallizer.java @@ -395,4 +395,14 @@ public class TileEntityMachineCrystallizer extends TileEntityMachineBase impleme if(type == UpgradeType.OVERDRIVE) return 3; return 0; } + + @Override + public int[] getFluidIDToCopy() { + return new int[]{ tank.getTankType().getID()}; + } + + @Override + public FluidTank getTankToPaste() { + return tank; + } } diff --git a/src/main/java/com/hbm/tileentity/machine/TileEntityMachineMixer.java b/src/main/java/com/hbm/tileentity/machine/TileEntityMachineMixer.java index a96fd4b84..0a2f9a195 100644 --- a/src/main/java/com/hbm/tileentity/machine/TileEntityMachineMixer.java +++ b/src/main/java/com/hbm/tileentity/machine/TileEntityMachineMixer.java @@ -378,8 +378,4 @@ public class TileEntityMachineMixer extends TileEntityMachineBase implements INB return this.tanks[2]; } - @Override - public int[] getFluidIDToCopy() { - return new int[]{tanks[2].getTankType().getID()}; - } } diff --git a/src/main/java/com/hbm/tileentity/network/TileEntityCraneBase.java b/src/main/java/com/hbm/tileentity/network/TileEntityCraneBase.java index c780bad42..7f7815c78 100644 --- a/src/main/java/com/hbm/tileentity/network/TileEntityCraneBase.java +++ b/src/main/java/com/hbm/tileentity/network/TileEntityCraneBase.java @@ -10,7 +10,7 @@ import net.minecraft.nbt.NBTTagList; import net.minecraft.network.NetworkManager; import net.minecraft.network.Packet; import net.minecraft.network.play.server.S35PacketUpdateTileEntity; -import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.ForgeDirection; @@ -109,7 +109,7 @@ public abstract class TileEntityCraneBase extends TileEntityMachineBase implemen } @Override - public NBTTagCompound getSettings() { + public NBTTagCompound getSettings(World world, int x, int y, int z) { NBTTagCompound nbt = new NBTTagCompound(); nbt.setInteger("inputSide", getInputSide().ordinal()); nbt.setInteger("outputSide", getOutputSide().ordinal()); @@ -136,8 +136,8 @@ public abstract class TileEntityCraneBase extends TileEntityMachineBase implemen } @Override - public void pasteSettings(NBTTagCompound nbt, boolean alt) { - if(alt) { + public void pasteSettings(NBTTagCompound nbt, int index, World world, int x, int y, int z) { + if(index == 1) { if (nbt.hasKey("outputSide")) { outputOverride = ForgeDirection.getOrientation(nbt.getInteger("outputSide")); onBlockChanged(); @@ -171,4 +171,9 @@ public abstract class TileEntityCraneBase extends TileEntityMachineBase implemen } } } + + @Override + public String[] infoForDisplay(World world, int x, int y, int z) { + return new String[]{"Filter", "Orientation"}; + } } diff --git a/src/main/java/com/hbm/tileentity/network/TileEntityPipeBaseNT.java b/src/main/java/com/hbm/tileentity/network/TileEntityPipeBaseNT.java index 832143613..6fb76c124 100644 --- a/src/main/java/com/hbm/tileentity/network/TileEntityPipeBaseNT.java +++ b/src/main/java/com/hbm/tileentity/network/TileEntityPipeBaseNT.java @@ -13,6 +13,7 @@ import net.minecraft.network.NetworkManager; import net.minecraft.network.Packet; import net.minecraft.network.play.server.S35PacketUpdateTileEntity; import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.common.util.ForgeDirection; @@ -180,10 +181,14 @@ public class TileEntityPipeBaseNT extends TileEntity implements IFluidConductor, } @Override - public void pasteSettings(NBTTagCompound nbt, boolean alt) { + public void pasteSettings(NBTTagCompound nbt, int index, World world, int x, int y, int z) { int[] ids = nbt.getIntArray("fluidID"); if(ids.length > 0) { - int id = ids[alt ? 1 : 0]; + int id; + if (index < ids.length) + id = ids[index]; + else + id = 0; this.setType(Fluids.fromID(id)); } } diff --git a/src/main/java/com/hbm/util/Either.java b/src/main/java/com/hbm/util/Either.java new file mode 100644 index 000000000..fa2848ee3 --- /dev/null +++ b/src/main/java/com/hbm/util/Either.java @@ -0,0 +1,76 @@ +package com.hbm.util; + +import java.util.function.Function; + +/** + * Represents a value that is either of generic type L or R + * @author martinthedragon + */ +@SuppressWarnings("unchecked") +public final class Either { + public static Either left(L value) { + return new Either<>(value, true); + } + + public static Either right(R value) { + return new Either<>(value, false); + } + + private final Object value; + private final boolean isLeft; + + private Either(Object value, boolean isLeft) { + this.value = value; + this.isLeft = isLeft; + } + + public boolean isLeft() { + return isLeft; + } + + public boolean isRight() { + return !isLeft; + } + + public L left() { + if(isLeft) + return (L) value; + else + throw new IllegalStateException("Tried accessing value as the L type, but was R type"); + } + + public R right() { + if(!isLeft) + return (R) value; + else + throw new IllegalStateException("Tried accessing value as the R type, but was L type"); + } + + public L leftOrNull() { + return isLeft ? (L) value : null; + } + + public R rightOrNull() { + return !isLeft ? (R) value : null; + } + + public V cast() { + return (V) value; + } + + public T run(Function leftFunc, Function rightFunc) { + return isLeft ? leftFunc.apply((L) value) : rightFunc.apply((R) value); + } + + public T runLeftOrNull(Function func) { + return isLeft ? func.apply((L) value) : null; + } + + public T runRightOrNull(Function func) { + return !isLeft ? func.apply((R) value) : null; + } + + public T runCasting(Function func) { + return func.apply((V) value); + } +}