diff --git a/build.gradle b/build.gradle index 020320872..ebe1bf1bd 100644 --- a/build.gradle +++ b/build.gradle @@ -57,6 +57,7 @@ repositories { } ivy { artifactPattern "https://asie.pl/files/mods/Charset/LibOnly/[module]-[revision](-[classifier]).[ext]" } + maven { url "http://maven.amadornes.com/" } } configurations { @@ -68,6 +69,7 @@ configurations { dependencies { deobfProvided "mezz.jei:jei_1.12.2:4.8.5.159:api" deobfProvided "pl.asie:Charset-Lib:0.5.4.6" + deobfProvided "MCMultiPart2:MCMultiPart:2.5.3" runtime "mezz.jei:jei_1.12.2:4.8.5.159" diff --git a/src/main/java/dan200/computercraft/shared/integration/charset/IntegrationCharset.java b/src/main/java/dan200/computercraft/shared/integration/charset/IntegrationCharset.java index 4ed9c480c..fec2e8959 100644 --- a/src/main/java/dan200/computercraft/shared/integration/charset/IntegrationCharset.java +++ b/src/main/java/dan200/computercraft/shared/integration/charset/IntegrationCharset.java @@ -24,10 +24,10 @@ public final class IntegrationCharset private static final ResourceLocation CAPABILITY_KEY = new ResourceLocation( ComputerCraft.MOD_ID, "charset" ); @CapabilityInject( IBundledEmitter.class ) - public static final Capability CAPABILITY_EMITTER = null; + static Capability CAPABILITY_EMITTER = null; @CapabilityInject( IBundledReceiver.class ) - public static final Capability CAPABILITY_RECEIVER = null; + static Capability CAPABILITY_RECEIVER = null; private IntegrationCharset() { @@ -37,12 +37,12 @@ public final class IntegrationCharset { if( CAPABILITY_EMITTER == null || CAPABILITY_RECEIVER == null ) return; - MinecraftForge.EVENT_BUS.register( new IntegrationCharset() ); + MinecraftForge.EVENT_BUS.register( IntegrationCharset.class ); ComputerCraftAPI.registerBundledRedstoneProvider( new BundledRedstoneProvider() ); } @SubscribeEvent - public void attachGenericCapabilities( AttachCapabilitiesEvent event ) + public static void attachGenericCapabilities( AttachCapabilitiesEvent event ) { TileEntity tile = event.getObject(); if( tile instanceof TileGeneric ) diff --git a/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPHooks.java b/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPHooks.java new file mode 100644 index 000000000..35c0b47fe --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPHooks.java @@ -0,0 +1,51 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.integration.mcmp; + +import mcmultipart.MCMultiPart; +import mcmultipart.api.item.ItemBlockMultipart; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.fml.common.Loader; + +import javax.annotation.Nonnull; + +public final class MCMPHooks +{ + private MCMPHooks() + { + } + + public static EnumActionResult onItemUse( ItemBlock itemBlock, EntityPlayer player, World world, @Nonnull BlockPos pos, @Nonnull EnumHand hand, @Nonnull EnumFacing facing, float hitX, float hitY, float hitZ ) + { + if( !Loader.isModLoaded( MCMultiPart.MODID ) ) return EnumActionResult.PASS; + + return ItemBlockMultipart.place( + player, world, pos, hand, facing, hitX, hitY, hitZ, itemBlock, + itemBlock.getBlock()::getStateForPlacement, + MCMPIntegration.multipartMap.get( itemBlock.getBlock() ), + + ( + ItemStack stack, EntityPlayer thisPlayer, World thisWorld, BlockPos thisPos, EnumFacing thisFacing, + float thisX, float thisY, float thisZ, IBlockState thisState + ) -> + thisPlayer.canPlayerEdit( thisPos, thisFacing, stack ) && + thisWorld.getBlockState( thisPos ).getBlock().isReplaceable( thisWorld, thisPos ) && + itemBlock.getBlock().canPlaceBlockAt( thisWorld, thisPos ) && + itemBlock.getBlock().canPlaceBlockOnSide( thisWorld, thisPos, thisFacing ) && + itemBlock.placeBlockAt( stack, thisPlayer, thisWorld, thisPos, thisFacing, thisX, thisY, thisZ, thisState ), + ItemBlockMultipart::placePartAt + ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPIntegration.java b/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPIntegration.java new file mode 100644 index 000000000..bbc04d31d --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPIntegration.java @@ -0,0 +1,119 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.integration.mcmp; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.shared.peripheral.common.IPeripheralTile; +import dan200.computercraft.shared.peripheral.modem.wireless.TileAdvancedModem; +import dan200.computercraft.shared.peripheral.modem.wireless.TileWirelessModem; +import mcmultipart.api.addon.IMCMPAddon; +import mcmultipart.api.addon.MCMPAddon; +import mcmultipart.api.container.IMultipartContainer; +import mcmultipart.api.multipart.IMultipart; +import mcmultipart.api.multipart.IMultipartRegistry; +import mcmultipart.api.multipart.IMultipartTile; +import mcmultipart.api.ref.MCMPCapabilities; +import mcmultipart.api.slot.EnumFaceSlot; +import net.minecraft.block.Block; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.event.AttachCapabilitiesEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; + +@MCMPAddon +public class MCMPIntegration implements IMCMPAddon +{ + private static final ResourceLocation CAPABILITY_KEY = new ResourceLocation( ComputerCraft.MOD_ID, "mcmultipart" ); + + static final Map multipartMap = new HashMap<>(); + + private static void register( IMultipartRegistry registry, Block block, IMultipart multipart ) + { + registry.registerPartWrapper( block, multipart ); + multipartMap.put( block, multipart ); + } + + @Override + public void registerParts( IMultipartRegistry registry ) + { + // Setup all parts + register( registry, ComputerCraft.Blocks.peripheral, new PartNormalModem() ); + register( registry, ComputerCraft.Blocks.advancedModem, new PartAdvancedModem() ); + + // Subscribe to capability events + MinecraftForge.EVENT_BUS.register( MCMPIntegration.class ); + + // Register a peripheral provider + ComputerCraftAPI.registerPeripheralProvider( ( world, pos, side ) -> + { + TileEntity tile = world.getTileEntity( pos ); + if( tile == null || !tile.hasCapability( MCMPCapabilities.MULTIPART_CONTAINER, null ) ) return null; + IMultipartContainer container = tile.getCapability( MCMPCapabilities.MULTIPART_CONTAINER, null ); + if( container == null ) return null; + + IMultipartTile multipart = container.getPartTile( EnumFaceSlot.fromFace( side ) ).orElse( null ); + if( multipart == null ) return null; + if( multipart instanceof IPeripheral ) return (IPeripheral) multipart; + if( multipart instanceof IPeripheralTile ) return ((IPeripheralTile) multipart).getPeripheral( side ); + + TileEntity underlying = multipart.getTileEntity(); + if( underlying instanceof IPeripheral ) return (IPeripheral) underlying; + if( underlying instanceof IPeripheralTile ) return ((IPeripheralTile) underlying).getPeripheral( side ); + + return null; + } ); + } + + @SubscribeEvent + public static void attach( AttachCapabilitiesEvent event ) + { + TileEntity tile = event.getObject(); + if( tile instanceof TileAdvancedModem || tile instanceof TileWirelessModem ) + { + event.addCapability( CAPABILITY_KEY, new BasicMultipart( tile ) ); + } + } + + private static final class BasicMultipart implements ICapabilityProvider + { + private final TileEntity tile; + private IMultipartTile wrapped; + + private BasicMultipart( TileEntity tile ) {this.tile = tile;} + + @Override + public boolean hasCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) + { + return capability == MCMPCapabilities.MULTIPART_TILE; + } + + @Nullable + @Override + public T getCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) + { + if( capability == MCMPCapabilities.MULTIPART_TILE ) + { + IMultipartTile wrapped = this.wrapped; + if( wrapped == null ) wrapped = this.wrapped = IMultipartTile.wrap( tile ); + return MCMPCapabilities.MULTIPART_TILE.cast( wrapped ); + } + + return null; + } + } +} diff --git a/src/main/java/dan200/computercraft/shared/integration/mcmp/PartAdvancedModem.java b/src/main/java/dan200/computercraft/shared/integration/mcmp/PartAdvancedModem.java new file mode 100644 index 000000000..b72f3df4f --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/integration/mcmp/PartAdvancedModem.java @@ -0,0 +1,41 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.integration.mcmp; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.peripheral.modem.wireless.BlockAdvancedModem; +import mcmultipart.api.multipart.IMultipart; +import mcmultipart.api.slot.EnumFaceSlot; +import mcmultipart.api.slot.IPartSlot; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +public class PartAdvancedModem implements IMultipart +{ + @Override + public IPartSlot getSlotForPlacement( World world, BlockPos pos, IBlockState state, EnumFacing facing, float hitX, float hitY, float hitZ, EntityLivingBase placer ) + { + return EnumFaceSlot.fromFace( state.getValue( BlockAdvancedModem.Properties.FACING ) ); + } + + @Override + public IPartSlot getSlotFromWorld( IBlockAccess world, BlockPos pos, IBlockState state ) + { + return EnumFaceSlot.fromFace( state.getValue( BlockAdvancedModem.Properties.FACING ) ); + } + + @Override + public Block getBlock() + { + return ComputerCraft.Blocks.advancedModem; + } +} diff --git a/src/main/java/dan200/computercraft/shared/integration/mcmp/PartNormalModem.java b/src/main/java/dan200/computercraft/shared/integration/mcmp/PartNormalModem.java new file mode 100644 index 000000000..4f6b4e181 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/integration/mcmp/PartNormalModem.java @@ -0,0 +1,59 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.integration.mcmp; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.peripheral.common.BlockPeripheral; +import dan200.computercraft.shared.peripheral.common.BlockPeripheralVariant; +import mcmultipart.api.multipart.IMultipart; +import mcmultipart.api.slot.EnumFaceSlot; +import mcmultipart.api.slot.IPartSlot; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +public class PartNormalModem implements IMultipart +{ + @Override + public IPartSlot getSlotForPlacement( World world, BlockPos pos, IBlockState state, EnumFacing facing, float hitX, float hitY, float hitZ, EntityLivingBase placer ) + { + return EnumFaceSlot.fromFace( getFacing( state ) ); + } + + @Override + public IPartSlot getSlotFromWorld( IBlockAccess world, BlockPos pos, IBlockState state ) + { + return EnumFaceSlot.fromFace( getFacing( state ) ); + } + + private EnumFacing getFacing( IBlockState state ) + { + BlockPeripheralVariant type = state.getValue( BlockPeripheral.Properties.VARIANT ); + if( type == BlockPeripheralVariant.WirelessModemUpOn || type == BlockPeripheralVariant.WirelessModemUpOff ) + { + return EnumFacing.UP; + } + else if( type == BlockPeripheralVariant.WirelessModemDownOn || type == BlockPeripheralVariant.WirelessModemDownOff ) + { + return EnumFacing.UP; + } + else + { + return state.getValue( BlockPeripheral.Properties.FACING ); + } + } + + @Override + public Block getBlock() + { + return ComputerCraft.Blocks.peripheral; + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/ItemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/common/ItemPeripheral.java index f02167c54..ae39d5541 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/ItemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/common/ItemPeripheral.java @@ -7,11 +7,18 @@ package dan200.computercraft.shared.peripheral.common; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.integration.mcmp.MCMPHooks; import dan200.computercraft.shared.peripheral.PeripheralType; import net.minecraft.block.Block; import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; import net.minecraft.util.NonNullList; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; import javax.annotation.Nonnull; @@ -31,41 +38,27 @@ public class ItemPeripheral extends ItemPeripheralBase switch( type ) { case DiskDrive: - { stack = new ItemStack( this, quantity, 0 ); break; - } case WirelessModem: - { stack = new ItemStack( this, quantity, 1 ); break; - } case Monitor: - { stack = new ItemStack( this, quantity, 2 ); break; - } case Printer: - { stack = new ItemStack( this, quantity, 3 ); break; - } case AdvancedMonitor: - { stack = new ItemStack( this, quantity, 4 ); break; - } case Speaker: - { stack = new ItemStack( this, quantity, 5 ); break; - } default: - { // Ignore types we can't handle return ItemStack.EMPTY; - } } if( label != null ) { @@ -93,29 +86,30 @@ public class ItemPeripheral extends ItemPeripheralBase { case 0: default: - { return PeripheralType.DiskDrive; - } case 1: - { return PeripheralType.WirelessModem; - } case 2: - { return PeripheralType.Monitor; - } case 3: - { return PeripheralType.Printer; - } case 4: - { return PeripheralType.AdvancedMonitor; - } case 5: - { return PeripheralType.Speaker; - } } } + + @Nonnull + @Override + public EnumActionResult onItemUse( EntityPlayer player, World world, @Nonnull BlockPos pos, @Nonnull EnumHand hand, @Nonnull EnumFacing facing, float hitX, float hitY, float hitZ ) + { + if( getPeripheralType( player.getHeldItem( hand ) ) == PeripheralType.WirelessModem ) + { + EnumActionResult result = MCMPHooks.onItemUse( this, player, world, pos, hand, facing, hitX, hitY, hitZ ); + if( result != EnumActionResult.PASS ) return result; + } + + return super.onItemUse( player, world, pos, hand, facing, hitX, hitY, hitZ ); + } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/ItemAdvancedModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/ItemAdvancedModem.java index b994140bb..5e494257e 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/ItemAdvancedModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/ItemAdvancedModem.java @@ -7,13 +7,20 @@ package dan200.computercraft.shared.peripheral.modem.wireless; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.integration.mcmp.MCMPHooks; import dan200.computercraft.shared.peripheral.PeripheralType; import dan200.computercraft.shared.peripheral.common.ItemPeripheralBase; import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory; import net.minecraft.block.Block; import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; import net.minecraft.util.NonNullList; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -39,4 +46,14 @@ public class ItemAdvancedModem extends ItemPeripheralBase { return PeripheralType.AdvancedModem; } + + @Nonnull + @Override + public EnumActionResult onItemUse( EntityPlayer player, World worldIn, @Nonnull BlockPos pos, @Nonnull EnumHand hand, @Nonnull EnumFacing facing, float hitX, float hitY, float hitZ ) + { + EnumActionResult result = MCMPHooks.onItemUse( this, player, worldIn, pos, hand, facing, hitX, hitY, hitZ ); + if( result != EnumActionResult.PASS ) return result; + + return super.onItemUse( player, worldIn, pos, hand, facing, hitX, hitY, hitZ ); + } }