Fix modded oxidizable blocks not oxidizing ()

Fixes 

`OxidizableBlocksRegistry.registerOxidizableBlockPair` will now re-cache the value of the `ticksRandomly` field of the passed blocks' states to ensure that the default implementation of oxidization will actually work on the blocks.

This may be considered a slightly dirty workaround, but it works well and isn't particularly intrusive, despite using 2 mixins.

I've also included a test (though not a GameTest) to ensure that this works, and split the `OxidizableBlocksRegistry` into separate API and impl classes to more easily allow for potential extensibility in future while not breaking compatibility.
This commit is contained in:
Shnupbups 2025-02-16 01:38:08 +11:00 committed by GitHub
parent 6816ccd43b
commit 25d1a67691
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 156 additions and 13 deletions
fabric-content-registries-v0/src
main
testmod/java/net/fabricmc/fabric/test/content/registry

View file

@ -16,11 +16,9 @@
package net.fabricmc.fabric.api.registry;
import java.util.Objects;
import net.minecraft.block.Block;
import net.minecraft.block.Oxidizable;
import net.minecraft.item.HoneycombItem;
import net.fabricmc.fabric.impl.content.registry.OxidizableBlocksRegistryImpl;
/**
* Provides methods for registering oxidizable and waxable blocks.
@ -36,9 +34,7 @@ public final class OxidizableBlocksRegistry {
* @param more the variant with more oxidation
*/
public static void registerOxidizableBlockPair(Block less, Block more) {
Objects.requireNonNull(less, "Oxidizable block cannot be null!");
Objects.requireNonNull(more, "Oxidizable block cannot be null!");
Oxidizable.OXIDATION_LEVEL_INCREASES.get().put(less, more);
OxidizableBlocksRegistryImpl.registerOxidizableBlockPair(less, more);
}
/**
@ -48,8 +44,6 @@ public final class OxidizableBlocksRegistry {
* @param waxed the waxed variant
*/
public static void registerWaxableBlockPair(Block unwaxed, Block waxed) {
Objects.requireNonNull(unwaxed, "Unwaxed block cannot be null!");
Objects.requireNonNull(waxed, "Waxed block cannot be null!");
HoneycombItem.UNWAXED_TO_WAXED_BLOCKS.get().put(unwaxed, waxed);
OxidizableBlocksRegistryImpl.registerWaxableBlockPair(unwaxed, waxed);
}
}

View file

@ -0,0 +1,51 @@
/*
* 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.impl.content.registry;
import java.util.Objects;
import net.minecraft.block.Block;
import net.minecraft.block.Oxidizable;
import net.minecraft.item.HoneycombItem;
public final class OxidizableBlocksRegistryImpl {
private OxidizableBlocksRegistryImpl() {
}
public static void registerOxidizableBlockPair(Block less, Block more) {
Objects.requireNonNull(less, "Oxidizable block cannot be null!");
Objects.requireNonNull(more, "Oxidizable block cannot be null!");
Oxidizable.OXIDATION_LEVEL_INCREASES.get().put(less, more);
// Fix #4371
refreshRandomTickCache(less);
refreshRandomTickCache(more);
}
public static void registerWaxableBlockPair(Block unwaxed, Block waxed) {
Objects.requireNonNull(unwaxed, "Unwaxed block cannot be null!");
Objects.requireNonNull(waxed, "Waxed block cannot be null!");
HoneycombItem.UNWAXED_TO_WAXED_BLOCKS.get().put(unwaxed, waxed);
}
private static void refreshRandomTickCache(Block block) {
block.getStateManager().getStates().forEach(state -> ((RandomTickCacheRefresher) state).fabric_api$refreshRandomTickCache());
}
public interface RandomTickCacheRefresher {
void fabric_api$refreshRandomTickCache();
}
}

View file

@ -0,0 +1,29 @@
/*
* 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 org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.BlockState;
@Mixin(AbstractBlock.class)
public interface AbstractBlockMixin {
@Invoker
boolean callHasRandomTicks(BlockState state);
}

View file

@ -0,0 +1,50 @@
/*
* 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 com.mojang.serialization.MapCodec;
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.state.State;
import net.minecraft.state.property.Property;
import net.fabricmc.fabric.impl.content.registry.OxidizableBlocksRegistryImpl;
@Mixin(AbstractBlock.AbstractBlockState.class)
public abstract class AbstractBlockStateMixin extends State<Block, BlockState> implements OxidizableBlocksRegistryImpl.RandomTickCacheRefresher {
@Shadow
private boolean ticksRandomly;
private AbstractBlockStateMixin(Block owner, Reference2ObjectArrayMap<Property<?>, Comparable<?>> propertyMap, MapCodec<BlockState> codec) {
super(owner, propertyMap, codec);
}
@Override
public void fabric_api$refreshRandomTickCache() {
this.ticksRandomly = ((AbstractBlockMixin) this.owner).callHasRandomTicks(this.asBlockState());
}
@Shadow
protected BlockState asBlockState() {
return null;
}
}

View file

@ -3,18 +3,20 @@
"package": "net.fabricmc.fabric.mixin.content.registry",
"compatibilityLevel": "JAVA_21",
"mixins": [
"AbstractBlockMixin",
"AbstractBlockStateMixin",
"AxeItemAccessor",
"BrewingRecipeRegistryBuilderMixin",
"PathContextMixin",
"FarmerWorkTaskAccessor",
"FireBlockMixin",
"FuelRegistryMixin",
"GiveGiftsToHeroTaskAccessor",
"GiveGiftsToHeroTaskMixin",
"HoeItemAccessor",
"HoneycombItemMixin",
"LandPathNodeMakerMixin",
"FireBlockMixin",
"OxidizableMixin",
"PathContextMixin",
"ShovelItemAccessor",
"VillagerEntityAccessor",
"VillagerEntityMixin"

View file

@ -23,6 +23,8 @@ import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.Oxidizable;
import net.minecraft.block.OxidizableBlock;
import net.minecraft.entity.ai.pathing.PathNodeType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.HoeItem;
@ -79,6 +81,9 @@ public final class ContentRegistryTest implements ModInitializer {
public static final RegistryKey<Block> TEST_EVENT_BLOCK_KEY = RegistryKey.of(RegistryKeys.BLOCK, TEST_EVENT_ID);
public static final RegistryEntry.Reference<GameEvent> TEST_EVENT = Registry.registerReference(Registries.GAME_EVENT, TEST_EVENT_ID, new GameEvent(GameEvent.DEFAULT_RANGE));
public static final RegistryKey<Block> TEST_OXIDIZING_BLOCK_KEY = RegistryKey.of(RegistryKeys.BLOCK, id("test_oxidizing"));
public static final RegistryKey<Block> EXPOSED_TEST_OXIDIZING_BLOCK_KEY = RegistryKey.of(RegistryKeys.BLOCK, id("exposed_test_oxidizing"));
@Override
public void onInitialize() {
// Expected behavior:
@ -92,6 +97,7 @@ public final class ContentRegistryTest implements ModInitializer {
// - green wool is tillable to lime wool
// - copper ore, iron ore, gold ore, and diamond ore can be waxed into their deepslate variants and scraped back again
// - aforementioned ores can be scraped from diamond -> gold -> iron -> copper
// - the 'test_oxidizing' block will randomly tick to oxidize into an 'exposed_test_oxidizing' block
// - villagers can now collect, consume (at the same level of bread) and compost apples
// - villagers can now collect oak saplings
// - assign a loot table to the nitwit villager type
@ -149,9 +155,20 @@ public final class ContentRegistryTest implements ModInitializer {
throw new AssertionError("OxidizableBlocksRegistry didn't throw when blocks were null!");
} catch (NullPointerException e) {
// expected behavior
LOGGER.info("OxidizableBlocksRegistry test passed!");
LOGGER.info("OxidizableBlocksRegistry null test passed!");
}
Block testOxidizingBlock = Registry.register(Registries.BLOCK, TEST_OXIDIZING_BLOCK_KEY, new OxidizableBlock(Oxidizable.OxidationLevel.UNAFFECTED, AbstractBlock.Settings.copy(Blocks.COPPER_BLOCK).registryKey(TEST_OXIDIZING_BLOCK_KEY)));
Block exposedTestOxidizingBlock = Registry.register(Registries.BLOCK, EXPOSED_TEST_OXIDIZING_BLOCK_KEY, new OxidizableBlock(Oxidizable.OxidationLevel.EXPOSED, AbstractBlock.Settings.copy(Blocks.EXPOSED_COPPER).registryKey(EXPOSED_TEST_OXIDIZING_BLOCK_KEY)));
OxidizableBlocksRegistry.registerOxidizableBlockPair(testOxidizingBlock, exposedTestOxidizingBlock);
if (!testOxidizingBlock.getStateManager().getDefaultState().hasRandomTicks()) {
throw new AssertionError("OxidizableBlocksRegistry didn't refresh random ticks cache for state!");
}
LOGGER.info("OxidizableBlocksRegistry random ticks test passed!");
VillagerInteractionRegistries.registerFood(Items.APPLE, 4);
VillagerInteractionRegistries.registerCompostable(Items.APPLE);