From ce84ba86f06ed53aad9d83bec59d74ff857ae669 Mon Sep 17 00:00:00 2001 From: Dennis C Date: Sat, 10 Jun 2023 10:13:29 +0200 Subject: [PATCH] Re-implement missing level-sensitive block light hook in ChunkAccess (#9536) --- .../world/level/chunk/ChunkAccess.java.patch | 36 ++++ .../level/chunk/ImposterProtoChunk.java.patch | 14 ++ .../common/extensions/IForgeBlock.java | 20 +++ src/main/resources/forge.exc | 2 + .../block/LevelSensitiveLightBlockTest.java | 168 ++++++++++++++++++ src/test/resources/META-INF/mods.toml | 2 + .../blockstates/light_block.json | 7 + .../models/item/light_block.json | 3 + 8 files changed, 252 insertions(+) create mode 100644 patches/minecraft/net/minecraft/world/level/chunk/ImposterProtoChunk.java.patch create mode 100644 src/test/java/net/minecraftforge/debug/block/LevelSensitiveLightBlockTest.java create mode 100644 src/test/resources/assets/level_sensitive_light_block_test/blockstates/light_block.json create mode 100644 src/test/resources/assets/level_sensitive_light_block_test/models/item/light_block.json diff --git a/patches/minecraft/net/minecraft/world/level/chunk/ChunkAccess.java.patch b/patches/minecraft/net/minecraft/world/level/chunk/ChunkAccess.java.patch index a78e6e3f3b..9538fbc649 100644 --- a/patches/minecraft/net/minecraft/world/level/chunk/ChunkAccess.java.patch +++ b/patches/minecraft/net/minecraft/world/level/chunk/ChunkAccess.java.patch @@ -1,5 +1,41 @@ --- a/net/minecraft/world/level/chunk/ChunkAccess.java +++ b/net/minecraft/world/level/chunk/ChunkAccess.java +@@ -299,25 +_,30 @@ + public abstract CompoundTag m_8051_(BlockPos p_62104_); + + public final void m_284254_(BiConsumer p_285269_) { +- this.m_284478_((p_284897_) -> { +- return p_284897_.m_60791_() != 0; ++ this.findBlocks((p_284897_, pos) -> { ++ return p_284897_.getLightEmission(this, pos) != 0; + }, p_285269_); + } + + public void m_284478_(Predicate p_285343_, BiConsumer p_285030_) { ++ findBlocks((state, pos) -> p_285343_.test(state), p_285030_); ++ } ++ ++ public void findBlocks(java.util.function.BiPredicate p_285343_, BiConsumer p_285030_) { + BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos(); + + for(int i = this.m_151560_(); i < this.m_151561_(); ++i) { + LevelChunkSection levelchunksection = this.m_183278_(this.m_151566_(i)); +- if (levelchunksection.m_63002_(p_285343_)) { ++ if (levelchunksection.m_63002_((state) -> p_285343_.test(state, BlockPos.f_121853_))) { + BlockPos blockpos = SectionPos.m_123196_(this.f_187604_, i).m_123249_(); + + for(int j = 0; j < 16; ++j) { + for(int k = 0; k < 16; ++k) { + for(int l = 0; l < 16; ++l) { + BlockState blockstate = levelchunksection.m_62982_(l, j, k); +- if (p_285343_.test(blockstate)) { +- p_285030_.accept(blockpos$mutableblockpos.m_122154_(blockpos, l, j, k), blockstate); ++ blockpos$mutableblockpos.m_122154_(blockpos, l, j, k); ++ if (p_285343_.test(blockstate, blockpos$mutableblockpos.m_7949_())) { ++ p_285030_.accept(blockpos$mutableblockpos, blockstate); + } + } + } @@ -463,4 +_,7 @@ public static record TicksToSave(SerializableTickContainer f_187680_, SerializableTickContainer f_187681_) { diff --git a/patches/minecraft/net/minecraft/world/level/chunk/ImposterProtoChunk.java.patch b/patches/minecraft/net/minecraft/world/level/chunk/ImposterProtoChunk.java.patch new file mode 100644 index 0000000000..1699fe3e3c --- /dev/null +++ b/patches/minecraft/net/minecraft/world/level/chunk/ImposterProtoChunk.java.patch @@ -0,0 +1,14 @@ +--- a/net/minecraft/world/level/chunk/ImposterProtoChunk.java ++++ b/net/minecraft/world/level/chunk/ImposterProtoChunk.java +@@ -181,6 +_,11 @@ + this.f_62685_.m_284478_(p_285465_, p_285061_); + } + ++ @Override ++ public void findBlocks(java.util.function.BiPredicate p_285465_, BiConsumer p_285061_) { ++ this.f_62685_.findBlocks(p_285465_, p_285061_); ++ } ++ + public TickContainerAccess m_183531_() { + return this.f_187918_ ? this.f_62685_.m_183531_() : BlackholeTickAccess.m_193144_(); + } diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java b/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java index 30a5b0e642..448b0f4ab3 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java @@ -87,7 +87,27 @@ public interface IForgeBlock /** * Get a light value for this block, taking into account the given state and coordinates, normal ranges are between 0 and 15 * + * @param state The state of this block + * @param level The level this block is in + * @param pos The position of this block in the level, will be {@link BlockPos#ZERO} when the chunk being loaded or + * generated calls this to check whether it contains any light sources * @return The light value + * @implNote
    + *
  • + * If the given state of this block may emit light but requires position context to determine the light + * value, then it must return a non-zero light value if {@code (pos == BlockPos.ZERO)} in order for the + * chunk calling this to be considered as containing light sources. + *
  • + *
  • + * The given {@link BlockGetter} may be a chunk. Block, fluid or block entity accesses outside of its bounds + * will cause issues such as wrapping coordinates returning values from the opposing chunk edge + *
  • + *
  • + * This method may be called on a worker thread and must therefore use + * {@link IForgeBlockGetter#getExistingBlockEntity(BlockPos)} to retrieve the {@link BlockEntity} + * at the given position + *
  • + *
*/ default int getLightEmission(BlockState state, BlockGetter level, BlockPos pos) { diff --git a/src/main/resources/forge.exc b/src/main/resources/forge.exc index 6553175424..923e02cf5b 100644 --- a/src/main/resources/forge.exc +++ b/src/main/resources/forge.exc @@ -96,6 +96,8 @@ net/minecraft/world/level/block/FlowerBlock.(Ljava/util/function/Supplier; net/minecraft/world/level/block/FlowerPotBlock.(Ljava/util/function/Supplier;Ljava/util/function/Supplier;Lnet/minecraft/world/level/block/state/BlockBehaviour$Properties;)V=|emptyPot,p_53528_,properties net/minecraft/world/level/block/LiquidBlock.(Ljava/util/function/Supplier;Lnet/minecraft/world/level/block/state/BlockBehaviour$Properties;)V=|p_54694_,p_54695_ net/minecraft/world/level/block/PoweredRailBlock.(Lnet/minecraft/world/level/block/state/BlockBehaviour$Properties;Z)V=|p_55218_,isPoweredRail +net/minecraft/world/level/chunk/ChunkAccess.findBlocks(Ljava/util/function/BiPredicate;Ljava/util/function/BiConsumer;)V=|p_285343_,p_285030_ +net/minecraft/world/level/chunk/ImposterProtoChunk.findBlocks(Ljava/util/function/BiPredicate;Ljava/util/function/BiConsumer;)V=|p_285343_,p_285030_ net/minecraft/world/level/entity/PersistentEntitySectionManager.addEntityWithoutEvent(Lnet/minecraft/world/level/entity/EntityAccess;Z)Z=|p_157539_,p_157540_ net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.processEntityInfos(Lnet/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate;Lnet/minecraft/world/level/LevelAccessor;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/levelgen/structure/templatesystem/StructurePlaceSettings;Ljava/util/List;)Ljava/util/List;=|template,p_215387_0_,p_215387_1_,p_215387_2_,p_215387_3_ net/minecraft/world/level/storage/loot/LootContext.(Lnet/minecraft/world/level/storage/loot/LootParams;Lnet/minecraft/util/RandomSource;Lnet/minecraft/world/level/storage/loot/LootDataResolver;Lnet/minecraft/resources/ResourceLocation;)V=|p_287722_,p_287702_,p_287619_,queriedLootTableId \ No newline at end of file diff --git a/src/test/java/net/minecraftforge/debug/block/LevelSensitiveLightBlockTest.java b/src/test/java/net/minecraftforge/debug/block/LevelSensitiveLightBlockTest.java new file mode 100644 index 0000000000..0a49705375 --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/block/LevelSensitiveLightBlockTest.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.debug.block; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.Connection; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; + +/** + * Adds a light source block that can be switched on and off by right-clicking and saves its state in a BlockEntity + * to test whether level/pos-sensitive light sources work correctly + */ +@Mod(LevelSensitiveLightBlockTest.MOD_ID) +public class LevelSensitiveLightBlockTest +{ + static final String MOD_ID = "level_sensitive_light_block_test"; + private static final DeferredRegister BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, MOD_ID); + private static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MOD_ID); + private static final DeferredRegister> BLOCK_ENTITIES = DeferredRegister.create(ForgeRegistries.BLOCK_ENTITY_TYPES, MOD_ID); + + private static final RegistryObject LIGHT_BLOCK = BLOCKS.register("light_block", LightBlock::new); + private static final RegistryObject LIGHT_BLOCK_ITEM = ITEMS.register( + "light_block", () -> new BlockItem(LIGHT_BLOCK.get(), new Item.Properties()) + ); + private static final RegistryObject> LIGHT_BLOCK_ENTITY = BLOCK_ENTITIES.register( + "light_block", () -> BlockEntityType.Builder.of(LightBlockEntity::new, LIGHT_BLOCK.get()).build(null) + ); + + public LevelSensitiveLightBlockTest() + { + IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus(); + BLOCKS.register(bus); + ITEMS.register(bus); + BLOCK_ENTITIES.register(bus); + } + + private static class LightBlock extends Block implements EntityBlock + { + public LightBlock() + { + super(BlockBehaviour.Properties.of()); + } + + @Override + @SuppressWarnings("deprecation") + public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) + { + if (!level.isClientSide() && level.getBlockEntity(pos) instanceof LightBlockEntity be) + { + be.switchLight(); + } + return InteractionResult.SUCCESS; + } + + @Override + public int getLightEmission(BlockState state, BlockGetter level, BlockPos pos) + { + if (pos == BlockPos.ZERO || (level.getExistingBlockEntity(pos) instanceof LightBlockEntity be && be.lit)) + { + return 15; + } + return 0; + } + + @Override + public BlockEntity newBlockEntity(BlockPos pos, BlockState state) + { + return new LightBlockEntity(pos, state); + } + } + + private static class LightBlockEntity extends BlockEntity + { + private boolean lit = false; + + public LightBlockEntity(BlockPos pos, BlockState state) + { + super(LIGHT_BLOCK_ENTITY.get(), pos, state); + } + + public void switchLight() + { + setLit(!lit); + level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), Block.UPDATE_ALL); + setChanged(); + } + + private void setLit(boolean lit) + { + if (lit != this.lit) + { + this.lit = lit; + level.getLightEngine().checkBlock(worldPosition); + } + } + + @Override + public Packet getUpdatePacket() + { + return ClientboundBlockEntityDataPacket.create(this); + } + + @Override + public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt) + { + CompoundTag tag = pkt.getTag(); + if (tag != null) + { + setLit(tag.getBoolean("lit")); + } + } + + @Override + public CompoundTag getUpdateTag() + { + CompoundTag tag = super.getUpdateTag(); + tag.putBoolean("lit", lit); + return tag; + } + + @Override + public void handleUpdateTag(CompoundTag tag) + { + super.handleUpdateTag(tag); + lit = tag.getBoolean("lit"); + } + + @Override + public void load(CompoundTag tag) + { + super.load(tag); + lit = tag.getBoolean("lit"); + } + + @Override + protected void saveAdditional(CompoundTag tag) + { + super.saveAdditional(tag); + tag.putBoolean("lit", lit); + } + } +} diff --git a/src/test/resources/META-INF/mods.toml b/src/test/resources/META-INF/mods.toml index 472cd4ef4c..bc7a65099e 100644 --- a/src/test/resources/META-INF/mods.toml +++ b/src/test/resources/META-INF/mods.toml @@ -32,6 +32,8 @@ modId="mdk_datagen" modId="custom_game_rule_test" [[mods]] modId="custom_preset_editor_test" +[[mods]] + modId="level_sensitive_light_block_test" # LEGACY TEST CASES ###### The mods below are from the old test framework and need to be yeeted later again. diff --git a/src/test/resources/assets/level_sensitive_light_block_test/blockstates/light_block.json b/src/test/resources/assets/level_sensitive_light_block_test/blockstates/light_block.json new file mode 100644 index 0000000000..02f229446c --- /dev/null +++ b/src/test/resources/assets/level_sensitive_light_block_test/blockstates/light_block.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "minecraft:block/glowstone" + } + } +} \ No newline at end of file diff --git a/src/test/resources/assets/level_sensitive_light_block_test/models/item/light_block.json b/src/test/resources/assets/level_sensitive_light_block_test/models/item/light_block.json new file mode 100644 index 0000000000..42950a8df8 --- /dev/null +++ b/src/test/resources/assets/level_sensitive_light_block_test/models/item/light_block.json @@ -0,0 +1,3 @@ +{ + "parent": "minecraft:item/glowstone" +} \ No newline at end of file