From db2cde4a4c98325ff7ce3693e5a140ee81af6abc Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 5 Jun 2021 14:48:38 +0100 Subject: [PATCH] Add MoreRed support I've written three or four integrations with bundled cables now over the various versions, and I'm still not convinced this one is right. It appears to work though, so we'll see. We need depend on the main jar here (rather than the API jar), as otherwise our javadoc tools fails - the API references some internal classes which aren't on our classpath. It might be nice to write tests for this (and CT) in the future - goodness knows these features are fragile - but that'll require some more gradle work which I don't want to do right now. Closes #772 --- build.gradle | 41 +++--- .../computercraft/shared/BundledRedstone.java | 7 +- .../dan200/computercraft/shared/Registry.java | 5 + .../morered/MoreRedIntegration.java | 124 ++++++++++++++++++ .../shared/util/CapabilityUtil.java | 6 + .../shared/util/FixedPointTileEntityType.java | 5 + 6 files changed, 165 insertions(+), 23 deletions(-) create mode 100644 src/main/java/dan200/computercraft/shared/integration/morered/MoreRedIntegration.java diff --git a/build.gradle b/build.gradle index 4e5524725..c55cbaf7e 100644 --- a/build.gradle +++ b/build.gradle @@ -53,6 +53,9 @@ minecraft { property 'forge.logging.markers', 'REGISTRIES' property 'forge.logging.console.level', 'debug' + property 'mixin.env.remapRefMap', 'true' + property 'mixin.env.refMapRemappingFile', "${buildDir}/createSrgToMcp/output.srg" + mods { computercraft { source sourceSets.main @@ -138,6 +141,7 @@ dependencies { compileOnly fg.deobf("mezz.jei:jei-1.16.5:7.7.0.104:api") compileOnly fg.deobf("com.blamejared.crafttweaker:CraftTweaker-1.16.5:7.1.0.313") + compileOnly fg.deobf("commoble.morered:morered-1.16.5:2.1.1.0") runtimeOnly fg.deobf("mezz.jei:jei-1.16.5:7.7.0.104") @@ -180,12 +184,12 @@ task luaJavadoc(type: Javadoc) { jar { manifest { - attributes(["Specification-Title": "computercraft", - "Specification-Vendor": "SquidDev", - "Specification-Version": "1", - "Implementation-Title": "CC: Tweaked", - "Implementation-Version": "${mod_version}", - "Implementation-Vendor" :"SquidDev", + attributes(["Specification-Title" : "computercraft", + "Specification-Vendor" : "SquidDev", + "Specification-Version" : "1", + "Implementation-Title" : "CC: Tweaked", + "Implementation-Version" : "${mod_version}", + "Implementation-Vendor" : "SquidDev", "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")]) } @@ -211,7 +215,7 @@ processResources { ["git", "-C", projectDir, "log", "--format=tformat:%an%n%cn"].execute().text.split('\n').each { if (!blacklist.contains(it)) contributors.add(it) } - } catch(Exception e) { + } catch (Exception e) { e.printStackTrace() } inputs.property "commithash", hash @@ -221,8 +225,8 @@ processResources { include 'data/computercraft/lua/rom/help/credits.txt' expand 'version': mod_version, - 'mcversion': mc_version, - 'gitcontributors': contributors.sort(false, String.CASE_INSENSITIVE_ORDER).join('\n') + 'mcversion': mc_version, + 'gitcontributors': contributors.sort(false, String.CASE_INSENSITIVE_ORDER).join('\n') } from(sourceSets.main.resources.srcDirs) { @@ -233,6 +237,9 @@ processResources { // Web tasks + +import com.hierynomus.gradle.license.tasks.LicenseCheck +import com.hierynomus.gradle.license.tasks.LicenseFormat import org.apache.tools.ant.taskdefs.condition.Os List mkCommand(String command) { @@ -302,10 +309,6 @@ jacocoTestReport { check.dependsOn jacocoTestReport - -import com.hierynomus.gradle.license.tasks.LicenseCheck -import com.hierynomus.gradle.license.tasks.LicenseFormat - license { mapping("java", "SLASHSTAR_STYLE") strictCheck true @@ -335,8 +338,8 @@ gradle.projectsEvaluated { } -task licenseAPI(type: LicenseCheck); -task licenseFormatAPI(type: LicenseFormat); +task licenseAPI(type: LicenseCheck) +task licenseFormatAPI(type: LicenseFormat) [licenseAPI, licenseFormatAPI].forEach { it.configure { source = sourceSets.main.java @@ -432,7 +435,7 @@ task checkRelease { ok = false project.logger.error("Must mention the changelog in whatsnew.txt") } else { - whatsnew = whatsnew.getAt(0 ..< idx) + whatsnew = whatsnew.getAt(0.. providers = new LinkedHashSet<>(); + private static final ArrayList providers = new ArrayList<>(); private BundledRedstone() {} public static synchronized void register( @Nonnull IBundledRedstoneProvider provider ) { Objects.requireNonNull( provider, "provider cannot be null" ); - providers.add( provider ); + if( !providers.contains( provider ) ) providers.add( provider ); } public static int getDefaultOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) diff --git a/src/main/java/dan200/computercraft/shared/Registry.java b/src/main/java/dan200/computercraft/shared/Registry.java index 6c14d93b4..4b18fa6b8 100644 --- a/src/main/java/dan200/computercraft/shared/Registry.java +++ b/src/main/java/dan200/computercraft/shared/Registry.java @@ -25,6 +25,7 @@ import dan200.computercraft.shared.computer.recipe.ComputerUpgradeRecipe; import dan200.computercraft.shared.data.BlockNamedEntityLootCondition; import dan200.computercraft.shared.data.HasComputerIdLootCondition; import dan200.computercraft.shared.data.PlayerCreativeLootCondition; +import dan200.computercraft.shared.integration.morered.MoreRedIntegration; import dan200.computercraft.shared.media.items.ItemDisk; import dan200.computercraft.shared.media.items.ItemPrintout; import dan200.computercraft.shared.media.items.ItemTreasureDisk; @@ -85,6 +86,7 @@ import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fml.DeferredWorkQueue; +import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.RegistryObject; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; @@ -387,6 +389,9 @@ public final class Registry ComputerCraftAPI.registerGenericCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY ); ComputerCraftAPI.registerGenericCapability( CapabilityEnergy.ENERGY ); ComputerCraftAPI.registerGenericCapability( CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY ); + + // Mod integration code. + if( ModList.get().isLoaded( MoreRedIntegration.MOD_ID ) ) MoreRedIntegration.initialise(); } public static void registerLoot() diff --git a/src/main/java/dan200/computercraft/shared/integration/morered/MoreRedIntegration.java b/src/main/java/dan200/computercraft/shared/integration/morered/MoreRedIntegration.java new file mode 100644 index 000000000..1570bd9d1 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/integration/morered/MoreRedIntegration.java @@ -0,0 +1,124 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.shared.integration.morered; + +import commoble.morered.api.ChanneledPowerSupplier; +import commoble.morered.api.MoreRedAPI; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.shared.common.IBundledRedstoneBlock; +import dan200.computercraft.shared.util.CapabilityUtil; +import dan200.computercraft.shared.util.FixedPointTileEntityType; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.event.AttachCapabilitiesEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class MoreRedIntegration +{ + public static final String MOD_ID = "morered"; + + private static final ResourceLocation ID = new ResourceLocation( ComputerCraft.MOD_ID, "morered" ); + + private static final class BundledPowerSupplier implements ICapabilityProvider, ChanneledPowerSupplier + { + private final IBundledRedstoneBlock block; + private final TileEntity tile; + private LazyOptional instance; + + private BundledPowerSupplier( IBundledRedstoneBlock block, TileEntity tile ) + { + this.block = block; + this.tile = tile; + } + + @Nonnull + @Override + public LazyOptional getCapability( @Nonnull Capability cap, @Nullable Direction side ) + { + if( cap != MoreRedAPI.CHANNELED_POWER_CAPABILITY ) return LazyOptional.empty(); + + if( tile.isRemoved() || !block.getBundledRedstoneConnectivity( tile.getLevel(), tile.getBlockPos(), side ) ) + { + return LazyOptional.empty(); + } + + return (instance == null ? (instance = LazyOptional.of( () -> this )) : instance).cast(); + } + + @Override + public int getPowerOnChannel( @Nonnull World world, @Nonnull BlockPos wirePos, @Nonnull BlockState wireState, @Nullable Direction wireFace, int channel ) + { + if( wireFace == null ) return 0; + + BlockPos pos = wirePos.relative( wireFace ); + BlockState state = world.getBlockState( pos ); + if( !(state.getBlock() instanceof IBundledRedstoneBlock) ) return 0; + + IBundledRedstoneBlock block = (IBundledRedstoneBlock) state.getBlock(); + return (block.getBundledRedstoneOutput( world, pos, wireFace.getOpposite() ) & (1 << channel)) != 0 ? 31 : 0; + } + + void invalidate() + { + instance = CapabilityUtil.invalidate( instance ); + } + } + + @SubscribeEvent + public static void attachBlockCapabilities( AttachCapabilitiesEvent event ) + { + TileEntity tile = event.getObject(); + if( !(tile.getType() instanceof FixedPointTileEntityType) ) return; + + Block block = ((FixedPointTileEntityType) tile.getType()).getBlock(); + if( !(block instanceof IBundledRedstoneBlock) ) return; + + BundledPowerSupplier provider = new BundledPowerSupplier( (IBundledRedstoneBlock) block, tile ); + event.addCapability( ID, provider ); + event.addListener( provider::invalidate ); + } + + public static void initialise() + { + MinecraftForge.EVENT_BUS.register( MoreRedIntegration.class ); + ComputerCraftAPI.registerBundledRedstoneProvider( MoreRedIntegration::getBundledPower ); + } + + private static int getBundledPower( World world, BlockPos pos, Direction side ) + { + TileEntity tile = world.getBlockEntity( pos ); + if( tile == null ) return -1; + + ChanneledPowerSupplier power = CapabilityUtil.unwrapUnsafe( tile.getCapability( MoreRedAPI.CHANNELED_POWER_CAPABILITY, side ) ); + if( power == null ) return -1; + + BlockState state = tile.getBlockState(); + + // Skip ones already handled by CC. We can do this more efficiently. + if( state.getBlock() instanceof IBundledRedstoneBlock ) return -1; + + int mask = 0; + for( int i = 0; i < 16; i++ ) + { + mask |= power.getPowerOnChannel( world, pos, state, side, i ) > 0 ? (1 << i) : 0; + } + + return mask; + } +} diff --git a/src/main/java/dan200/computercraft/shared/util/CapabilityUtil.java b/src/main/java/dan200/computercraft/shared/util/CapabilityUtil.java index baed8c497..e542294d5 100644 --- a/src/main/java/dan200/computercraft/shared/util/CapabilityUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/CapabilityUtil.java @@ -43,4 +43,10 @@ public final class CapabilityUtil p.addListener( invalidate ); return p.orElseThrow( NullPointerException::new ); } + + @Nullable + public static T unwrapUnsafe( LazyOptional p ) + { + return !p.isPresent() ? null : p.orElseThrow( NullPointerException::new ); + } } diff --git a/src/main/java/dan200/computercraft/shared/util/FixedPointTileEntityType.java b/src/main/java/dan200/computercraft/shared/util/FixedPointTileEntityType.java index 2eb921f20..066cfcac3 100644 --- a/src/main/java/dan200/computercraft/shared/util/FixedPointTileEntityType.java +++ b/src/main/java/dan200/computercraft/shared/util/FixedPointTileEntityType.java @@ -40,6 +40,11 @@ public final class FixedPointTileEntityType extends TileEn return block == this.block.get(); } + public Block getBlock() + { + return block.get(); + } + private static final class FixedPointSupplier implements Supplier { final FixedPointTileEntityType factory;