diff --git a/buildSrc/src/main/kotlin/cc-tweaked.java-convention.gradle.kts b/buildSrc/src/main/kotlin/cc-tweaked.java-convention.gradle.kts index d349dc40ea..16c9d31f1b 100644 --- a/buildSrc/src/main/kotlin/cc-tweaked.java-convention.gradle.kts +++ b/buildSrc/src/main/kotlin/cc-tweaked.java-convention.gradle.kts @@ -59,6 +59,7 @@ repositories { includeGroup("cc.tweaked") includeModule("org.squiddev", "Cobalt") // Things we mirror + includeGroup("commoble.morered") includeGroup("dev.architectury") includeGroup("dev.emi") includeGroup("maven.modrinth") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3e79aefc0a..8ec26b533e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -38,6 +38,7 @@ fabricPermissions = "0.3.20230723" iris = "1.6.4+1.20" jei = "15.2.0.22" modmenu = "7.1.0" +moreRed = "4.0.0.4" oculus = "1.2.5" rei = "12.0.626" rubidium = "0.6.1" @@ -102,6 +103,7 @@ jei-fabric = { module = "mezz.jei:jei-1.20.1-fabric", version.ref = "jei" } jei-forge = { module = "mezz.jei:jei-1.20.1-forge", version.ref = "jei" } mixin = { module = "org.spongepowered:mixin", version.ref = "mixin" } modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu" } +moreRed = { module = "commoble.morered:morered-1.20.1", version.ref = "moreRed" } oculus = { module = "maven.modrinth:oculus", version.ref = "oculus" } rei-api = { module = "me.shedaniel:RoughlyEnoughItems-api", version.ref = "rei" } rei-builtin = { module = "me.shedaniel:RoughlyEnoughItems-default-plugin", version.ref = "rei" } @@ -153,7 +155,7 @@ kotlin = ["kotlin-stdlib", "kotlin-coroutines"] # Minecraft externalMods-common = ["jei-api", "nightConfig-core", "nightConfig-toml"] -externalMods-forge-compile = ["oculus", "jei-api"] +externalMods-forge-compile = ["moreRed", "oculus", "jei-api"] externalMods-forge-runtime = ["jei-forge"] externalMods-fabric = ["nightConfig-core", "nightConfig-toml"] externalMods-fabric-compile = ["fabricPermissions", "iris", "jei-api", "rei-api", "rei-builtin"] diff --git a/projects/fabric/build.gradle.kts b/projects/fabric/build.gradle.kts index 5c1e167481..9b49129961 100644 --- a/projects/fabric/build.gradle.kts +++ b/projects/fabric/build.gradle.kts @@ -53,13 +53,11 @@ dependencies { exclude("net.fabricmc", "fabric-loader") exclude("net.fabricmc.fabric-api") } - /* modClientRuntimeOnly(libs.bundles.externalMods.fabric.runtime) { exclude("net.fabricmc", "fabric-loader") exclude("net.fabricmc.fabric-api") } - */ "modTestWithSodium"(libs.sodium) "modTestWithIris"(libs.iris) diff --git a/projects/forge/src/main/java/dan200/computercraft/ComputerCraft.java b/projects/forge/src/main/java/dan200/computercraft/ComputerCraft.java index 3533d29e0a..d549825b6f 100644 --- a/projects/forge/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/projects/forge/src/main/java/dan200/computercraft/ComputerCraft.java @@ -15,6 +15,7 @@ import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.config.ConfigSpec; import dan200.computercraft.shared.details.FluidData; +import dan200.computercraft.shared.integration.MoreRedIntegration; import dan200.computercraft.shared.peripheral.generic.methods.EnergyMethods; import dan200.computercraft.shared.peripheral.generic.methods.FluidMethods; import dan200.computercraft.shared.peripheral.generic.methods.InventoryMethods; @@ -23,6 +24,7 @@ import net.minecraftforge.common.capabilities.ForgeCapabilities; import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; @@ -73,6 +75,8 @@ public static void init(FMLCommonSetupEvent event) { ForgeComputerCraftAPI.registerGenericCapability(ForgeCapabilities.FLUID_HANDLER); ForgeDetailRegistries.FLUID_STACK.addProvider(FluidData::fill); + + if (ModList.get().isLoaded(MoreRedIntegration.MOD_ID)) MoreRedIntegration.setup(); } @SubscribeEvent diff --git a/projects/forge/src/main/java/dan200/computercraft/shared/integration/MoreRedIntegration.java b/projects/forge/src/main/java/dan200/computercraft/shared/integration/MoreRedIntegration.java new file mode 100644 index 0000000000..202b6f89a5 --- /dev/null +++ b/projects/forge/src/main/java/dan200/computercraft/shared/integration/MoreRedIntegration.java @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.shared.integration; + +import commoble.morered.api.MoreRedAPI; +import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.shared.common.IBundledRedstoneBlock; +import dan200.computercraft.shared.util.SidedCapabilityProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.AttachCapabilitiesEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +public class MoreRedIntegration { + public static final String MOD_ID = "morered"; + + private static final ResourceLocation ID = new ResourceLocation(ComputerCraftAPI.MOD_ID, MOD_ID); + + @SubscribeEvent + public static void attachBlockCapabilities(AttachCapabilitiesEvent event) { + var blockEntity = event.getObject(); + + if (blockEntity.getBlockState().getBlock() instanceof IBundledRedstoneBlock bundledBlock) { + // The API is a little unclear on whether this needs to be sided. The API design mirrors Block.getSignal + // (suggesting we can use wireFace.getOpposite(), which is what we did on older versions), but on the other + // hand that parameter is not guaranteed to be non-null (suggesting we should use the cap side instead). + SidedCapabilityProvider.attach(event, ID, MoreRedAPI.CHANNELED_POWER_CAPABILITY, side -> (world, wirePos, wireState, wireFace, channel) -> { + if (side == null) return 0; // It's not clear if there's a sensible implementation here. + + var level = bundledBlock.getBundledRedstoneOutput(world, blockEntity.getBlockPos(), side); + return (level & (1 << channel)) != 0 ? 31 : 0; + }); + } + } + + public static void setup() { + MinecraftForge.EVENT_BUS.register(MoreRedIntegration.class); + ComputerCraftAPI.registerBundledRedstoneProvider(MoreRedIntegration::getBundledPower); + } + + private static int getBundledPower(Level world, BlockPos pos, Direction side) { + var blockEntity = world.getBlockEntity(pos); + if (blockEntity == null) return -1; + + var blockState = blockEntity.getBlockState(); + + // Skip ones already handled by CC. We can do this more efficiently. + if (blockState.getBlock() instanceof IBundledRedstoneBlock) return -1; + + var powerCap = blockEntity.getCapability(MoreRedAPI.CHANNELED_POWER_CAPABILITY, side); + if (!powerCap.isPresent()) return -1; + var power = powerCap.orElseThrow(NullPointerException::new); + + var mask = 0; + for (var i = 0; i < 16; i++) { + mask |= power.getPowerOnChannel(world, pos, blockState, side, i) > 0 ? (1 << i) : 0; + } + return mask; + } +}