diff --git a/SpongeAPI b/SpongeAPI index a490075071b..24ccd49a15b 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit a490075071b22f7b6a51d92ed1dda84cae796ca5 +Subproject commit 24ccd49a15b76d206e91759a67259e8ad5f4ca2b diff --git a/src/main/java/org/spongepowered/common/registry/SpongeRegistries.java b/src/main/java/org/spongepowered/common/registry/SpongeRegistries.java index 29ba343d72a..dc16e9b7b38 100644 --- a/src/main/java/org/spongepowered/common/registry/SpongeRegistries.java +++ b/src/main/java/org/spongepowered/common/registry/SpongeRegistries.java @@ -75,6 +75,7 @@ public static void registerEarlyGlobalRegistries(final SpongeRegistryHolder hold holder.createFrozenRegistry(RegistryTypes.PARTICLE_OPTION, SpongeRegistryLoader.particleOption()); holder.createFrozenRegistry(RegistryTypes.QUERY_TYPE, SpongeRegistryLoader.queryType()); holder.createFrozenRegistry(RegistryTypes.RESOLVE_OPERATION, SpongeRegistryLoader.resolveOperation()); + holder.createFrozenRegistry(RegistryTypes.SIGNAL_TYPE, SpongeRegistryLoader.signalType()); holder.createFrozenRegistry(RegistryTypes.SKIN_PART, SpongeRegistryLoader.skinPart()); holder.createFrozenRegistry(RegistryTypes.SPAWN_TYPE, SpongeRegistryLoader.spawnType()); holder.createFrozenRegistry(RegistryTypes.TRANSACTION_TYPE, SpongeRegistryLoader.transactionType()); diff --git a/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java b/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java index b8f9f664823..56943ce58a7 100644 --- a/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java +++ b/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java @@ -97,6 +97,8 @@ import org.spongepowered.api.world.ChunkRegenerateFlag; import org.spongepowered.api.world.ChunkRegenerateFlags; import org.spongepowered.api.world.PositionSource; +import org.spongepowered.api.world.SignalType; +import org.spongepowered.api.world.SignalTypes; import org.spongepowered.api.world.generation.config.flat.FlatGeneratorConfig; import org.spongepowered.api.world.generation.config.noise.NoiseConfig; import org.spongepowered.api.world.generation.config.noise.NoiseConfigs; @@ -150,6 +152,7 @@ import org.spongepowered.common.registry.RegistryLoader; import org.spongepowered.common.util.SpongeOrientation; import org.spongepowered.common.world.SpongeChunkRegenerateFlag; +import org.spongepowered.common.world.SpongeSignalType; import org.spongepowered.common.world.schematic.SpongePaletteType; import org.spongepowered.common.world.weather.SpongeWeatherType; import org.spongepowered.math.vector.Vector3d; @@ -415,6 +418,15 @@ public static RegistryLoader resolveOperation() { }); } + public static RegistryLoader signalType() { + return RegistryLoader.of(l -> { + l.add(SignalTypes.DIRECT, k -> SpongeSignalType.DIRECT); + l.add(SignalTypes.INDIRECT, k -> SpongeSignalType.INDIRECT); + l.add(SignalTypes.COMPOSITE, k -> SpongeSignalType.COMPOSITE); + l.add(SignalTypes.ANALOG, k -> SpongeSignalType.ANALOG); + }); + } + public static RegistryLoader skinPart() { return RegistryLoader.of(l -> { l.add(SkinParts.CAPE, k -> new SpongeSkinPart("cape")); diff --git a/src/main/java/org/spongepowered/common/util/DirectionUtil.java b/src/main/java/org/spongepowered/common/util/DirectionUtil.java index d7d8dd9365f..9051444b26c 100644 --- a/src/main/java/org/spongepowered/common/util/DirectionUtil.java +++ b/src/main/java/org/spongepowered/common/util/DirectionUtil.java @@ -26,14 +26,15 @@ import net.minecraft.world.level.block.state.properties.EnumProperty; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.util.Direction; import java.util.Objects; public final class DirectionUtil { - public static net.minecraft.core.Direction getFor(final Direction direction) { - Objects.requireNonNull(direction); + public static net.minecraft.core.@Nullable Direction getFor(final Direction direction) { + Objects.requireNonNull(direction, "direction"); return switch (direction) { case UP -> net.minecraft.core.Direction.UP; case DOWN -> net.minecraft.core.Direction.DOWN; @@ -58,6 +59,14 @@ public static Direction getFor(final net.minecraft.core.Direction facing) { }; } + public static net.minecraft.core.Direction getForOrThrow(final Direction direction) { + final net.minecraft.core.@Nullable Direction result = DirectionUtil.getFor(direction); + if (result == null) { + throw new IllegalArgumentException("Direction must be cardinal: " + direction); + } + return result; + } + public static net.minecraft.world.level.block.state.BlockState set(final net.minecraft.world.level.block.state.BlockState holder, final Direction value, final EnumProperty property) { final net.minecraft.core.Direction direction = DirectionUtil.getFor(value); if (direction == null || !property.getPossibleValues().contains(direction)) { diff --git a/src/main/java/org/spongepowered/common/world/SpongeSignalType.java b/src/main/java/org/spongepowered/common/world/SpongeSignalType.java new file mode 100644 index 00000000000..4f46924e2bd --- /dev/null +++ b/src/main/java/org/spongepowered/common/world/SpongeSignalType.java @@ -0,0 +1,41 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.world; + +import org.spongepowered.api.world.SignalType; + +public class SpongeSignalType implements SignalType { + + public static final SignalType DIRECT = new SpongeSignalType(); + + public static final SignalType INDIRECT = new SpongeSignalType(); + + public static final SignalType COMPOSITE = new SpongeSignalType(); + + public static final SignalType ANALOG = new SpongeSignalType(); + + private SpongeSignalType() { + } +} diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/SignalGetterMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/SignalGetterMixin_API.java new file mode 100644 index 00000000000..231e32b2511 --- /dev/null +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/SignalGetterMixin_API.java @@ -0,0 +1,166 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.mixin.api.minecraft.world.level; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.SignalGetter; +import org.spongepowered.api.registry.RegistryTypes; +import org.spongepowered.api.util.Direction; +import org.spongepowered.api.world.SignalType; +import org.spongepowered.api.world.volume.game.SignalAwareVolume; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.common.util.DirectionUtil; +import org.spongepowered.common.world.SpongeSignalType; + +import java.util.Objects; +import java.util.function.ToIntBiFunction; + +@Mixin(SignalGetter.class) +public interface SignalGetterMixin_API extends BlockGetter, SignalAwareVolume { + + @Shadow int shadow$getSignal(BlockPos $$0, net.minecraft.core.Direction $$1); + @Shadow int shadow$getBestNeighborSignal(BlockPos $$0); + @Shadow int shadow$getDirectSignal(BlockPos $$0, net.minecraft.core.Direction $$1); + @Shadow int shadow$getDirectSignalTo(BlockPos $$0); + @Shadow boolean shadow$hasNeighborSignal(BlockPos $$0); + + @Override + default boolean canConductSignal(final int x, final int y, final int z) { + final BlockPos pos = new BlockPos(x, y, z); + return this.getBlockState(pos).isRedstoneConductor(this, pos); + } + + @Override + default boolean canEmitSignal(final SignalType type, final int x, final int y, final int z) { + Objects.requireNonNull(type, "type"); + final BlockPos pos = new BlockPos(x, y, z); + if (type == SpongeSignalType.ANALOG) { + return this.getBlockState(pos).hasAnalogOutputSignal(); + } else if (type == SpongeSignalType.DIRECT || type == SpongeSignalType.INDIRECT || type == SpongeSignalType.COMPOSITE) { + return this.getBlockState(pos).isSignalSource(); + } + + throw this.impl$unsupportedType(type); + } + + @Override + default int signalFrom(final SignalType type, final int x, final int y, final int z, final Direction direction) { + Objects.requireNonNull(type, "type"); + final BlockPos pos = new BlockPos(x, y, z); + if (type == SpongeSignalType.ANALOG) { + return this.impl$analogSignalFrom(pos); + } else if (type == SpongeSignalType.DIRECT) { + return this.impl$regularSignalFrom(pos, DirectionUtil.getForOrThrow(direction).getOpposite()); + } else if (type == SpongeSignalType.INDIRECT) { + return this.shadow$getDirectSignal(pos, DirectionUtil.getForOrThrow(direction).getOpposite()); + } else if (type == SpongeSignalType.COMPOSITE) { + return this.shadow$getSignal(pos, DirectionUtil.getForOrThrow(direction).getOpposite()); + } + + throw this.impl$unsupportedType(type); + } + + @Override + default int highestSignalAt(final SignalType type, final int x, final int y, final int z) { + Objects.requireNonNull(type, "type"); + final BlockPos pos = new BlockPos(x, y, z); + if (type == SpongeSignalType.ANALOG) { + return this.impl$highestSignalAt(pos, (relativePos, $) -> this.impl$analogSignalFrom(relativePos)); + } else if (type == SpongeSignalType.DIRECT) { + return this.impl$highestSignalAt(pos, this::impl$regularSignalFrom); + } else if (type == SpongeSignalType.INDIRECT) { + return this.shadow$getDirectSignalTo(pos); + } else if (type == SpongeSignalType.COMPOSITE) { + return this.shadow$getBestNeighborSignal(pos); + } + + throw this.impl$unsupportedType(type); + } + + @Override + default boolean hasSignalAt(final SignalType type, final int x, final int y, final int z) { + Objects.requireNonNull(type, "type"); + final BlockPos pos = new BlockPos(x, y, z); + if (type == SpongeSignalType.ANALOG) { + return this.impl$hasSignalAt(pos, (relativePos, $) -> this.impl$analogSignalFrom(relativePos)); + } else if (type == SpongeSignalType.DIRECT) { + return this.impl$hasSignalAt(pos, this::impl$regularSignalFrom); + } else if (type == SpongeSignalType.INDIRECT) { + return this.impl$hasSignalAt(pos, this::shadow$getDirectSignal); + } else if (type == SpongeSignalType.COMPOSITE) { + return this.shadow$hasNeighborSignal(pos); + } + + throw this.impl$unsupportedType(type); + } + + private int impl$highestSignalAt( + final BlockPos pos, final ToIntBiFunction signalProvider + ) { + int maxSignal = 0; + for (final net.minecraft.core.Direction direction : SignalGetter.DIRECTIONS) { + final int signal = signalProvider.applyAsInt(pos.relative(direction), direction); + if (signal >= 15) { + return 15; + } + + if (signal > maxSignal) { + maxSignal = signal; + } + } + return maxSignal; + } + + private boolean impl$hasSignalAt( + final BlockPos pos, final ToIntBiFunction signalProvider + ) { + for (final net.minecraft.core.Direction direction : SignalGetter.DIRECTIONS) { + final int signal = signalProvider.applyAsInt(pos.relative(direction), direction); + if (signal > 0) { + return true; + } + } + return false; + } + + private int impl$analogSignalFrom(final BlockPos pos) { + if (this instanceof final Level level) { + return this.getBlockState(pos).getAnalogOutputSignal(level, pos); + } else { + throw new UnsupportedOperationException("This volume doesn't support getting analog signal"); + } + } + + private int impl$regularSignalFrom(final BlockPos pos, final net.minecraft.core.Direction direction) { + return this.getBlockState(pos).getSignal(this, pos, direction); + } + + private RuntimeException impl$unsupportedType(final SignalType type) { + return new IllegalArgumentException("Unsupported signal type: " + type.key(RegistryTypes.SIGNAL_TYPE).asString()); + } +} diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json index 73022a8caef..4294bde1e8e 100644 --- a/src/mixins/resources/mixins.sponge.api.json +++ b/src/mixins/resources/mixins.sponge.api.json @@ -359,6 +359,7 @@ "minecraft.world.level.LevelWriterMixin_API", "minecraft.world.level.LightLayerMixin_API", "minecraft.world.level.ServerExplosionMixin_API", + "minecraft.world.level.SignalGetterMixin_API", "minecraft.world.level.biome.AmbientAdditionsSettingsMixin_API", "minecraft.world.level.biome.AmbientMoodSettingsMixin_API", "minecraft.world.level.biome.AmbientParticleSettingsMixin_API",