diff --git a/src/main/java/net/fabricmc/fabric/api/registry/FlammableBlockRegistry.java b/src/main/java/net/fabricmc/fabric/api/registry/FlammableBlockRegistry.java new file mode 100644 index 000000000..065fd8d9f --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/api/registry/FlammableBlockRegistry.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2016, 2017, 2018 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 net.fabricmc.fabric.api.util.Block2ObjectMap; +import net.fabricmc.fabric.impl.registry.FlammableBlockRegistryImpl; +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; +import net.minecraft.tag.Tag; + +public interface FlammableBlockRegistry extends Block2ObjectMap { + static FlammableBlockRegistry getDefaultInstance() { + return getInstance(Blocks.FIRE); + } + + static FlammableBlockRegistry getInstance(Block block) { + return FlammableBlockRegistryImpl.getInstance(block); + } + + default void add(Block block, int burn, int spread) { + this.add(block, new Entry(burn, spread)); + } + + default void add(Tag tag, int burn, int spread) { + this.add(tag, new Entry(burn, spread)); + } + + public static final class Entry { + private final int burn, spread; + + public Entry(int burn, int spread) { + this.burn = burn; + this.spread = spread; + } + + public int getBurnChance() { + return burn; + } + + public int getSpreadChance() { + return spread; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Entry)) { + return false; + } else { + Entry other = (Entry) o; + return other.burn == burn && other.spread == spread; + } + } + + @Override + public int hashCode() { + return burn * 11 + spread; + } + } +} diff --git a/src/main/java/net/fabricmc/fabric/api/util/Block2ObjectMap.java b/src/main/java/net/fabricmc/fabric/api/util/Block2ObjectMap.java index 703dcfe36..0ae014c1e 100644 --- a/src/main/java/net/fabricmc/fabric/api/util/Block2ObjectMap.java +++ b/src/main/java/net/fabricmc/fabric/api/util/Block2ObjectMap.java @@ -17,6 +17,7 @@ package net.fabricmc.fabric.api.util; import net.minecraft.block.Block; +import net.minecraft.item.Item; import net.minecraft.item.ItemProvider; import net.minecraft.tag.Tag; @@ -26,4 +27,6 @@ public interface Block2ObjectMap { void add(Tag tag, V value); void remove(Block block); void remove(Tag tag); + void clear(Block block); + void clear(Tag tag); } diff --git a/src/main/java/net/fabricmc/fabric/api/util/Item2ObjectMap.java b/src/main/java/net/fabricmc/fabric/api/util/Item2ObjectMap.java index 25b507940..b402d94b3 100644 --- a/src/main/java/net/fabricmc/fabric/api/util/Item2ObjectMap.java +++ b/src/main/java/net/fabricmc/fabric/api/util/Item2ObjectMap.java @@ -26,4 +26,6 @@ public interface Item2ObjectMap { void add(Tag tag, V value); void remove(ItemProvider item); void remove(Tag tag); + void clear(ItemProvider item); + void clear(Tag tag); } diff --git a/src/main/java/net/fabricmc/fabric/impl/registry/CompostingChanceRegistryImpl.java b/src/main/java/net/fabricmc/fabric/impl/registry/CompostingChanceRegistryImpl.java index 2e34a3be6..8e4ef25bf 100644 --- a/src/main/java/net/fabricmc/fabric/impl/registry/CompostingChanceRegistryImpl.java +++ b/src/main/java/net/fabricmc/fabric/impl/registry/CompostingChanceRegistryImpl.java @@ -22,6 +22,9 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemProvider; import net.minecraft.tag.Tag; +import java.util.ArrayList; +import java.util.List; + public class CompostingChanceRegistryImpl implements CompostingChanceRegistry { @Override public Float get(ItemProvider item) { @@ -47,4 +50,14 @@ public class CompostingChanceRegistryImpl implements CompostingChanceRegistry { public void remove(Tag tag) { throw new UnsupportedOperationException("Tags currently not supported!"); } + + @Override + public void clear(ItemProvider item) { + throw new UnsupportedOperationException("CompostingChanceRegistry operates directly on the vanilla map - clearing not supported!"); + } + + @Override + public void clear(Tag tag) { + throw new UnsupportedOperationException("CompostingChanceRegistry operates directly on the vanilla map - clearing not supported!"); + } } diff --git a/src/main/java/net/fabricmc/fabric/impl/registry/FireBlockHooks.java b/src/main/java/net/fabricmc/fabric/impl/registry/FireBlockHooks.java new file mode 100644 index 000000000..7d73d068f --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/impl/registry/FireBlockHooks.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry; + +import net.fabricmc.fabric.api.registry.FlammableBlockRegistry; +import net.minecraft.block.Block; + +public interface FireBlockHooks { + FlammableBlockRegistry.Entry fabric_getVanillaEntry(Block block); +} diff --git a/src/main/java/net/fabricmc/fabric/impl/registry/FlammableBlockRegistryImpl.java b/src/main/java/net/fabricmc/fabric/impl/registry/FlammableBlockRegistryImpl.java new file mode 100644 index 000000000..999ef0bde --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/impl/registry/FlammableBlockRegistryImpl.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import net.fabricmc.fabric.api.registry.FlammableBlockRegistry; +import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; +import net.fabricmc.fabric.api.resource.ResourceManagerHelper; +import net.fabricmc.fabric.api.resource.ResourceReloadListenerKeys; +import net.minecraft.block.Block; +import net.minecraft.resource.ResourceManager; +import net.minecraft.resource.ResourceType; +import net.minecraft.tag.Tag; +import net.minecraft.util.Identifier; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class FlammableBlockRegistryImpl implements FlammableBlockRegistry, IdentifiableResourceReloadListener { + private static final FlammableBlockRegistry.Entry REMOVED = new FlammableBlockRegistry.Entry(0, 0); + private static final Map REGISTRIES = new HashMap<>(); + private static final Collection RELOAD_DEPS = Collections.singletonList(ResourceReloadListenerKeys.TAGS); + private static int idCounter = 0; + + private final Map registeredEntriesBlock = new HashMap<>(); + private final Map, FlammableBlockRegistry.Entry> registeredEntriesTag = new HashMap<>(); + private final Map computedEntries = new HashMap<>(); + private final Object2IntMap computedBurnChances = new Object2IntOpenHashMap<>(); + private final Object2IntMap computedSpreadChances = new Object2IntOpenHashMap<>(); + private final Identifier id; + private final Block key; + private boolean tagsPresent = false; + + private FlammableBlockRegistryImpl(Block key) { + ResourceManagerHelper.get(ResourceType.DATA).addReloadListener(this); + this.id = new Identifier("fabric:private/fire_registry_" + (++idCounter)); + this.key = key; + } + + @Override + public void onResourceReload(ResourceManager var1) { + reload(); + tagsPresent = true; + } + + private void reload() { + computedEntries.clear(); + // tags take precedence before blocks + for (Tag tag : registeredEntriesTag.keySet()) { + FlammableBlockRegistry.Entry entry = registeredEntriesTag.get(tag); + for (Block block : tag.values()) { + computedEntries.put(block, entry); + } + } + computedEntries.putAll(registeredEntriesBlock); + + computedBurnChances.clear(); + computedSpreadChances.clear(); + + for (Block block : computedEntries.keySet()) { + FlammableBlockRegistry.Entry entry = computedEntries.get(block); + computedBurnChances.put(block, entry.getBurnChance()); + computedSpreadChances.put(block, entry.getSpreadChance()); + } + } + + // User-facing fire registry interface - queries vanilla fire block + @Override + public Entry get(Block block) { + Entry entry = computedEntries.get(block); + if (entry != null) { + return entry; + } else { + return ((FireBlockHooks) key).fabric_getVanillaEntry(block); + } + } + + public Entry getFabric(Block block) { + return computedEntries.get(block); + } + + @Override + public void add(Block block, Entry value) { + registeredEntriesBlock.put(block, value); + + if (tagsPresent) { + reload(); + } + } + + @Override + public void add(Tag tag, Entry value) { + registeredEntriesTag.put(tag, value); + + if (tagsPresent) { + reload(); + } + } + + @Override + public void remove(Block block) { + add(block, REMOVED); + } + + @Override + public void remove(Tag tag) { + add(tag, REMOVED); + } + + @Override + public void clear(Block block) { + registeredEntriesBlock.remove(block); + + if (tagsPresent) { + reload(); + } + } + + @Override + public void clear(Tag tag) { + registeredEntriesTag.remove(tag); + + if (tagsPresent) { + reload(); + } + } + + public static FlammableBlockRegistryImpl getInstance(Block block) { + if (!(block instanceof FireBlockHooks)) { + throw new RuntimeException("Not a hookable fire block: " + block); + } + + return REGISTRIES.computeIfAbsent(block, FlammableBlockRegistryImpl::new); + } + + @Override + public Identifier getFabricId() { + return id; + } + + @Override + public Collection getFabricDependencies() { + return RELOAD_DEPS; + } +} diff --git a/src/main/java/net/fabricmc/fabric/impl/registry/FuelRegistryImpl.java b/src/main/java/net/fabricmc/fabric/impl/registry/FuelRegistryImpl.java index 140cbf772..c588a711d 100644 --- a/src/main/java/net/fabricmc/fabric/impl/registry/FuelRegistryImpl.java +++ b/src/main/java/net/fabricmc/fabric/impl/registry/FuelRegistryImpl.java @@ -70,16 +70,18 @@ public class FuelRegistryImpl implements FuelRegistry { add(tag, 0); } - public void apply(Map map) { - for (ItemProvider item : itemCookTimes.keySet()) { - int time = itemCookTimes.getInt(item); - if (time <= 0) { - map.remove(item.getItem()); - } else { - map.put(item.getItem(), time); - } - } + @Override + public void clear(ItemProvider item) { + itemCookTimes.removeInt(item); + } + @Override + public void clear(Tag tag) { + tagCookTimes.removeInt(tag); + } + + public void apply(Map map) { + // tags take precedence before blocks for (Tag tag : tagCookTimes.keySet()) { int time = tagCookTimes.getInt(tag); if (time <= 0) { @@ -92,5 +94,14 @@ public class FuelRegistryImpl implements FuelRegistry { } } } + + for (ItemProvider item : itemCookTimes.keySet()) { + int time = itemCookTimes.getInt(item); + if (time <= 0) { + map.remove(item.getItem()); + } else { + map.put(item.getItem(), time); + } + } } } \ No newline at end of file diff --git a/src/main/java/net/fabricmc/fabric/mixin/block/MixinFireBlock.java b/src/main/java/net/fabricmc/fabric/mixin/block/MixinFireBlock.java new file mode 100644 index 000000000..e466ce688 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/mixin/block/MixinFireBlock.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.block; + +import net.fabricmc.fabric.api.registry.FlammableBlockRegistry; +import net.fabricmc.fabric.impl.registry.FireBlockHooks; +import net.fabricmc.fabric.impl.registry.FlammableBlockRegistryImpl; +import net.minecraft.block.Block; +import net.minecraft.block.FireBlock; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(FireBlock.class) +public class MixinFireBlock implements FireBlockHooks { + private FlammableBlockRegistryImpl fabric_registry; + + @Shadow + private int getSpreadChance(Block block_1) { + return 0; + } + + @Shadow + private int getBurnChance(Block block_1) { + return 0; + } + + @Inject(at = @At("RETURN"), method = "") + private void afterConstruct(Block.Settings settings, CallbackInfo info) { + fabric_registry = FlammableBlockRegistryImpl.getInstance((Block) (Object) this); + } + + @Inject(at = @At("HEAD"), method = "getBurnChance", cancellable = true) + private void getFabricBurnChance(Block block, CallbackInfoReturnable info) { + FlammableBlockRegistry.Entry entry = fabric_registry.getFabric(block); + if (entry != null) { + info.setReturnValue(entry.getBurnChance()); + info.cancel(); + } + } + + @Inject(at = @At("HEAD"), method = "getSpreadChance", cancellable = true) + private void getFabricSpreadChance(Block block, CallbackInfoReturnable info) { + FlammableBlockRegistry.Entry entry = fabric_registry.getFabric(block); + if (entry != null) { + info.setReturnValue(entry.getSpreadChance()); + info.cancel(); + } + } + + @Override + public FlammableBlockRegistry.Entry fabric_getVanillaEntry(Block block) { + return new FlammableBlockRegistry.Entry(getBurnChance(block), getSpreadChance(block)); + } +} diff --git a/src/main/resources/net.fabricmc.fabric.mixins.common.json b/src/main/resources/net.fabricmc.fabric.mixins.common.json index 2bed80f0a..f20eaeeef 100644 --- a/src/main/resources/net.fabricmc.fabric.mixins.common.json +++ b/src/main/resources/net.fabricmc.fabric.mixins.common.json @@ -4,6 +4,7 @@ "compatibilityLevel": "JAVA_8", "mixins": [ "block.MixinBlockBuilder", + "block.MixinFireBlock", "block.entity.MixinBlockEntity", "commands.MixinServerCommandManager", "container.MixinServerPlayerEntity", diff --git a/src/test/java/net/fabricmc/fabric/block/FireMod.java b/src/test/java/net/fabricmc/fabric/block/FireMod.java new file mode 100644 index 000000000..c41acd010 --- /dev/null +++ b/src/test/java/net/fabricmc/fabric/block/FireMod.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.block; + +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.registry.FlammableBlockRegistry; +import net.minecraft.block.Blocks; + +public class FireMod implements ModInitializer { + @Override + public void onInitialize() { + FlammableBlockRegistry.getDefaultInstance().add(Blocks.STONE, 100, 100); + FlammableBlockRegistry.getDefaultInstance().remove(Blocks.OAK_PLANKS); + } +}