diff --git a/fabric-content-registries-v0/build.gradle b/fabric-content-registries-v0/build.gradle index 5f94f75df..4629bc4fe 100644 --- a/fabric-content-registries-v0/build.gradle +++ b/fabric-content-registries-v0/build.gradle @@ -1,5 +1,5 @@ archivesBaseName = "fabric-content-registries-v0" -version = getSubprojectVersion(project, "0.2.4") +version = getSubprojectVersion(project, "0.3.0") loom { accessWidener = file("src/main/resources/fabric-content-registries-v0.accesswidener") diff --git a/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/api/registry/FlattenableBlockRegistry.java b/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/api/registry/FlattenableBlockRegistry.java new file mode 100644 index 000000000..99ffd555c --- /dev/null +++ b/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/api/registry/FlattenableBlockRegistry.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.registry; + +import java.util.Objects; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; + +import net.fabricmc.fabric.mixin.content.registry.ShovelItemAccessor; + +/** + * A registry for shovel flattening interactions. A vanilla example is turning dirt to dirt paths. + */ +public final class FlattenableBlockRegistry { + private static final Logger LOGGER = LogManager.getLogger(); + + private FlattenableBlockRegistry() { + } + + /** + * Registers a flattening interaction. + * + * @param input the input block that can be flattened + * @param flattened the flattened result block state + */ + public static void register(Block input, BlockState flattened) { + Objects.requireNonNull(input, "input block cannot be null"); + Objects.requireNonNull(flattened, "flattened block state cannot be null"); + BlockState old = ShovelItemAccessor.getPathStates().put(input, flattened); + + if (old != null) { + LOGGER.debug("Replaced old flattening mapping from {} to {} with {}", input, old, flattened); + } + } +} diff --git a/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/api/registry/StrippableBlockRegistry.java b/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/api/registry/StrippableBlockRegistry.java new file mode 100644 index 000000000..3b70dbc93 --- /dev/null +++ b/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/api/registry/StrippableBlockRegistry.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.registry; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import net.minecraft.block.Block; +import net.minecraft.state.property.Properties; + +import net.fabricmc.fabric.mixin.content.registry.AxeItemAccessor; + +/** + * A registry for axe stripping interactions. A vanilla example is turning logs to stripped logs. + */ +public final class StrippableBlockRegistry { + private static final Logger LOGGER = LogManager.getLogger(); + + private StrippableBlockRegistry() { + } + + /** + * Registers a stripping interaction. + * + * <p>Both blocks must have the {@link Properties#AXIS axis} property. + * + * @param input the input block that can be stripped + * @param stripped the stripped result block + * @throws IllegalArgumentException if the input or the output doesn't have the {@link Properties#AXIS axis} property + */ + public static void register(Block input, Block stripped) { + requireNonNullAndAxisProperty(input, "input block"); + requireNonNullAndAxisProperty(stripped, "stripped block"); + Map<Block, Block> strippedBlocks = AxeItemAccessor.getStrippedBlocks(); + + if (!(strippedBlocks instanceof HashMap<?, ?>)) { + strippedBlocks = new HashMap<>(strippedBlocks); + AxeItemAccessor.setStrippedBlocks(strippedBlocks); + } + + Block old = strippedBlocks.put(input, stripped); + + if (old != null) { + LOGGER.debug("Replaced old stripping mapping from {} to {} with {}", input, old, stripped); + } + } + + private static void requireNonNullAndAxisProperty(Block block, String name) { + Objects.requireNonNull(block, name + " cannot be null"); + + if (!block.getStateManager().getProperties().contains(Properties.AXIS)) { + throw new IllegalArgumentException(name + " must have the 'axis' property"); + } + } +} diff --git a/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/api/registry/TillableBlockRegistry.java b/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/api/registry/TillableBlockRegistry.java new file mode 100644 index 000000000..037205e9b --- /dev/null +++ b/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/api/registry/TillableBlockRegistry.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.registry; + +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Predicate; + +import com.mojang.datafixers.util.Pair; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.item.HoeItem; +import net.minecraft.item.ItemConvertible; +import net.minecraft.item.ItemUsageContext; + +import net.fabricmc.fabric.mixin.content.registry.HoeItemAccessor; + +/** + * A registry for hoe tilling interactions. A vanilla example is turning dirt to dirt paths. + */ +public final class TillableBlockRegistry { + private TillableBlockRegistry() { + } + + /** + * Registers a tilling interaction. + * + * <p>Tilling interactions are a two-step process. First, a usage predicate is run that decides whether to till + * a block. If the predicate returns {@code true}, an action is executed. Default instances of these can be created + * with these {@link HoeItem} methods: + * <ul> + * <li>usage predicate for farmland-like behavior: {@link HoeItem#usagePredicate(ItemUsageContext)}</li> + * <li>simple action: {@link HoeItem#getTillingConsumer(BlockState)}</li> + * <li>simple action that also drops an item: {@link HoeItem#getTillingConsumer(BlockState, ItemConvertible)}</li> + * </ul> + * + * @param input the input block that can be tilled + * @param usagePredicate a predicate that filters if the block can be tilled + * @param tillingAction an action that is executed if the predicate returns {@code true} + */ + public static void register(Block input, Predicate<ItemUsageContext> usagePredicate, Consumer<ItemUsageContext> tillingAction) { + Objects.requireNonNull(input, "input block cannot be null"); + HoeItemAccessor.getTilledBlocks().put(input, Pair.of(usagePredicate, tillingAction)); + } + + /** + * Registers a simple tilling interaction. + * + * @param input the input block that can be tilled + * @param usagePredicate a predicate that filters if the block can be tilled + * @param tilled the tilled result block state + */ + public static void register(Block input, Predicate<ItemUsageContext> usagePredicate, BlockState tilled) { + Objects.requireNonNull(tilled, "tilled block state cannot be null"); + register(input, usagePredicate, HoeItem.getTillingConsumer(tilled)); + } + + /** + * Registers a simple tilling interaction that also drops an item. + * + * @param input the input block that can be tilled + * @param usagePredicate a predicate that filters if the block can be tilled + * @param tilled the tilled result block state + * @param droppedItem an item that is dropped when the input block is tilled + */ + public static void register(Block input, Predicate<ItemUsageContext> usagePredicate, BlockState tilled, ItemConvertible droppedItem) { + Objects.requireNonNull(tilled, "tilled block state cannot be null"); + Objects.requireNonNull(droppedItem, "dropped item cannot be null"); + register(input, usagePredicate, HoeItem.getTillingConsumer(tilled, droppedItem)); + } +} diff --git a/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/mixin/content/registry/AxeItemAccessor.java b/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/mixin/content/registry/AxeItemAccessor.java new file mode 100644 index 000000000..8e61926bc --- /dev/null +++ b/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/mixin/content/registry/AxeItemAccessor.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.content.registry; + +import java.util.Map; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +import net.minecraft.block.Block; +import net.minecraft.item.AxeItem; + +@Mixin(AxeItem.class) +public interface AxeItemAccessor { + @Accessor("STRIPPED_BLOCKS") + static Map<Block, Block> getStrippedBlocks() { + throw new AssertionError("Untransformed @Accessor"); + } + + @Accessor("STRIPPED_BLOCKS") + @Mutable + static void setStrippedBlocks(Map<Block, Block> strippedBlocks) { + throw new AssertionError("Untransformed @Accessor"); + } +} diff --git a/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/mixin/content/registry/HoeItemAccessor.java b/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/mixin/content/registry/HoeItemAccessor.java new file mode 100644 index 000000000..9d35665f6 --- /dev/null +++ b/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/mixin/content/registry/HoeItemAccessor.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.content.registry; + +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Predicate; + +import com.mojang.datafixers.util.Pair; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import net.minecraft.block.Block; +import net.minecraft.item.HoeItem; +import net.minecraft.item.ItemUsageContext; + +@Mixin(HoeItem.class) +public interface HoeItemAccessor { + @Accessor("TILLED_BLOCKS") + static Map<Block, Pair<Predicate<ItemUsageContext>, Consumer<ItemUsageContext>>> getTilledBlocks() { + throw new AssertionError("Untransformed @Accessor"); + } +} diff --git a/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/mixin/content/registry/ShovelItemAccessor.java b/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/mixin/content/registry/ShovelItemAccessor.java new file mode 100644 index 000000000..79b73f918 --- /dev/null +++ b/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/mixin/content/registry/ShovelItemAccessor.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.content.registry; + +import java.util.Map; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.item.ShovelItem; + +@Mixin(ShovelItem.class) +public interface ShovelItemAccessor { + @Accessor("PATH_STATES") + static Map<Block, BlockState> getPathStates() { + throw new AssertionError("Untransformed @Accessor"); + } +} diff --git a/fabric-content-registries-v0/src/main/resources/fabric-content-registries-v0.mixins.json b/fabric-content-registries-v0/src/main/resources/fabric-content-registries-v0.mixins.json index fe3232675..f1a87ae74 100644 --- a/fabric-content-registries-v0/src/main/resources/fabric-content-registries-v0.mixins.json +++ b/fabric-content-registries-v0/src/main/resources/fabric-content-registries-v0.mixins.json @@ -3,8 +3,11 @@ "package": "net.fabricmc.fabric.mixin.content.registry", "compatibilityLevel": "JAVA_16", "mixins": [ + "AxeItemAccessor", + "HoeItemAccessor", "MixinAbstractFurnaceBlockEntity", - "MixinFireBlock" + "MixinFireBlock", + "ShovelItemAccessor" ], "client": [ "client.MixinClientPlayNetworkHandler" diff --git a/fabric-content-registries-v0/src/testmod/java/net/fabricmc/fabric/test/content/registry/ContentRegistryTest.java b/fabric-content-registries-v0/src/testmod/java/net/fabricmc/fabric/test/content/registry/ContentRegistryTest.java new file mode 100644 index 000000000..7ea7be8d2 --- /dev/null +++ b/fabric-content-registries-v0/src/testmod/java/net/fabricmc/fabric/test/content/registry/ContentRegistryTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.content.registry; + +import net.minecraft.block.Blocks; +import net.minecraft.item.HoeItem; + +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.registry.FlattenableBlockRegistry; +import net.fabricmc.fabric.api.registry.StrippableBlockRegistry; +import net.fabricmc.fabric.api.registry.TillableBlockRegistry; + +public final class ContentRegistryTest implements ModInitializer { + @Override + public void onInitialize() { + // Expected behavior: + // - red wool is flattenable to yellow wool + // - quartz pillars are strippable to hay blocks + // - green wool is tillable to lime wool + + FlattenableBlockRegistry.register(Blocks.RED_WOOL, Blocks.YELLOW_WOOL.getDefaultState()); + StrippableBlockRegistry.register(Blocks.QUARTZ_PILLAR, Blocks.HAY_BLOCK); + + // assert that StrippableBlockRegistry throws when the blocks don't have 'axis' + try { + StrippableBlockRegistry.register(Blocks.BLUE_WOOL, Blocks.OAK_LOG); + StrippableBlockRegistry.register(Blocks.HAY_BLOCK, Blocks.BLUE_WOOL); + throw new AssertionError("StrippableBlockRegistry didn't throw when blocks where missing the 'axis' property!"); + } catch (IllegalArgumentException e) { + // expected behavior + } + + TillableBlockRegistry.register(Blocks.GREEN_WOOL, context -> true, HoeItem.getTillingConsumer(Blocks.LIME_WOOL.getDefaultState())); + } +} diff --git a/fabric-content-registries-v0/src/testmod/resources/fabric.mod.json b/fabric-content-registries-v0/src/testmod/resources/fabric.mod.json new file mode 100644 index 000000000..a0e697e2f --- /dev/null +++ b/fabric-content-registries-v0/src/testmod/resources/fabric.mod.json @@ -0,0 +1,16 @@ +{ + "schemaVersion": 1, + "id": "fabric-content-registries-v0-testmod", + "name": "Fabric Content Registries (v0) Test Mod", + "version": "1.0.0", + "environment": "*", + "license": "Apache-2.0", + "depends": { + "fabric-content-registries-v0": "*" + }, + "entrypoints": { + "main": [ + "net.fabricmc.fabric.test.content.registry.ContentRegistryTest" + ] + } +}