Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issues with modded tile entities and lights #3838

Merged
merged 2 commits into from
Apr 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* This file is part of Sponge, licensed under the MIT License (MIT).
*
* Copyright (c) SpongePowered <https://www.spongepowered.org>
* 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.forge.mixin.core.world.level.block.state;

import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.extensions.IForgeBlockState;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.common.bridge.world.level.block.state.BlockStateBridge;

@Mixin(value = BlockState.class, priority = 1300)
public abstract class BlockStateMixin_Forge implements BlockStateBridge {

@Override
public boolean bridge$hasTileEntity() {
return ((IForgeBlockState) this).hasTileEntity();
}

@Override
public @Nullable BlockEntity bridge$createTileEntity(Level world) {
return ((IForgeBlockState) this).createTileEntity(world);
}

@Override
public int bridge$getLightValue(ServerLevel world, BlockPos pos) {
return ((IForgeBlockState) this).getLightValue(world, pos);
}
}
1 change: 1 addition & 0 deletions forge/src/mixins/resources/mixins.spongeforge.core.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"world.entity.vehicle.BoatMixin_Forge",
"world.level.LevelMixin_Forge",
"world.level.block.FireBlockMixin_Forge",
"world.level.block.state.BlockStateMixin_Forge",
"world.level.storage.LevelStorageSourceMixin_Forge"
],
"client": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.LevelChunk;
Expand Down Expand Up @@ -81,9 +80,7 @@ public interface TrackedWorldBridge {

/**
* Creates a {@link BlockSnapshot} but performs an additional {@link LevelChunk#getTileEntity(BlockPos, Chunk.CreateEntityType)}
* lookup if the providing {@link BlockState#getBlock()} {@code instanceof} is
* {@code true} for being an {@link EntityBlock} or
* {@link BlockStateBridge#bridge$hasTileEntity()}, and associates
* lookup if {@link BlockStateBridge#bridge$hasTileEntity()} is {@code true}, and associates
* the resulting snapshot of said Tile with the snapshot. This is useful for in-progress
* snapshot creation during transaction building for {@link TransactionalCaptureSupplier}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public interface BlockStateBridge {

boolean bridge$hasTileEntity();

@Nullable BlockEntity bridge$createNewTileEntity(Level world);
@Nullable BlockEntity bridge$createTileEntity(Level world);

int bridge$getLightValue(ServerLevel world, BlockPos pos);
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ public static RefreshOldTileEntityOnChunkChangeEffect getInstance() {
public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState,
final SpongeBlockChangeFlag flag, final int limit
) {
final @Nullable BlockEntity existing = pipeline.getAffectedChunk().getBlockEntity(oldState.pos, LevelChunk.EntityCreationType.CHECK);
if (((BlockStateBridge) oldState.state).bridge$hasTileEntity()) {
final @Nullable BlockEntity existing = pipeline.getAffectedChunk().getBlockEntity(oldState.pos, LevelChunk.EntityCreationType.CHECK);
if (existing != null) {
existing.clearCache();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.state.BlockState;
import org.spongepowered.common.bridge.world.level.block.state.BlockStateBridge;
import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline;
import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor;
import org.spongepowered.common.world.SpongeBlockChangeFlag;
Expand All @@ -51,7 +52,6 @@ public EffectResult processSideEffect(
if (!flag.updateLighting()) {
return EffectResult.NULL_PASS;
}
final int originalOpactiy = oldState.opacity;
final ServerLevel serverWorld = pipeline.getServerWorld();
final BlockState currentState = pipeline.getAffectedChunk().getBlockState(oldState.pos);
// local variable notes:
Expand All @@ -68,8 +68,8 @@ public EffectResult processSideEffect(
// )
// ) {
if (oldState.state != currentState
&& (currentState.getLightBlock(serverWorld, oldState.pos) != originalOpactiy
|| currentState.getLightEmission() != oldState.state.getLightEmission()
&& (currentState.getLightBlock(serverWorld, oldState.pos) != oldState.opacity
|| ((BlockStateBridge) currentState).bridge$getLightValue(serverWorld, oldState.pos) != oldState.light
Yeregorix marked this conversation as resolved.
Show resolved Hide resolved
|| currentState.useShapeForLightOcclusion()
|| oldState.state.useShapeForLightOcclusion()
)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,18 @@ public static UpdateOrCreateNewTileEntityPostPlacementEffect getInstance() {
public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState,
final SpongeBlockChangeFlag flag, final int limit
) {
final ServerLevel serverWorld = pipeline.getServerWorld();
final LevelChunk chunk = pipeline.getAffectedChunk();
final @Nullable BlockEntity maybeNewTileEntity = chunk.getBlockEntity(oldState.pos, LevelChunk.EntityCreationType.CHECK);
if (((BlockStateBridge) newState).bridge$hasTileEntity()) {
if (maybeNewTileEntity == null) {
// tileentity1 = ((ITileEntityProvider)block).createNewTileEntity(this.world); // Vanilla
// tileentity1 = state.createTileEntity(this.world); // Forge
final ServerLevel serverWorld = pipeline.getServerWorld();
final LevelChunk chunk = pipeline.getAffectedChunk();
final @Nullable BlockEntity existing = chunk.getBlockEntity(oldState.pos, LevelChunk.EntityCreationType.CHECK);

if (existing == null) {
// blockEntity = ((EntityBlock) block).newBlockEntity(this.level); // Vanilla
// blockEntity = state.createTileEntity(this.level); // Forge
// We cast to our bridge for easy access
serverWorld.setBlockEntity(oldState.pos, ((BlockStateBridge) newState).bridge$createNewTileEntity(serverWorld));
serverWorld.setBlockEntity(oldState.pos, ((BlockStateBridge) newState).bridge$createTileEntity(serverWorld));
} else {
maybeNewTileEntity.clearCache();
existing.clearCache();
}
}
return EffectResult.NULL_PASS;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import net.minecraft.world.level.chunk.LevelChunkSection;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.common.bridge.world.level.block.state.BlockStateBridge;
import org.spongepowered.common.event.tracking.PhaseContext;
import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor;
import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect;
Expand Down Expand Up @@ -111,10 +112,11 @@ public LevelChunkSection getAffectedSection() {
return null;
}
final ServerLevel serverWorld = this.serverWorld.get();
final int oldLight = ((BlockStateBridge) currentState).bridge$getLightValue(serverWorld, pos);
final int oldOpacity = currentState.getLightBlock(serverWorld, pos);
final SpongeBlockChangeFlag flag = this.transaction.getBlockChangeFlag();
final @Nullable BlockEntity existing = this.chunkSupplier.get().getBlockEntity(pos, LevelChunk.EntityCreationType.CHECK);
PipelineCursor formerState = new PipelineCursor(currentState, oldOpacity, pos, existing, (Entity) null, limit);
PipelineCursor formerState = new PipelineCursor(currentState, oldLight, oldOpacity, pos, existing, (Entity) null, limit);

for (final ResultingTransactionBySideEffect effect : this.chunkEffects) {
try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) {
Expand All @@ -129,7 +131,7 @@ public LevelChunkSection getAffectedSection() {
return result.resultingState;
}
if (formerState.drops.isEmpty() && !result.drops.isEmpty()) {
formerState = new PipelineCursor(currentState, oldOpacity, pos, existing, null, result.drops, limit);
formerState = new PipelineCursor(currentState, oldLight, oldOpacity, pos, existing, null, result.drops, limit);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,20 @@

public final class PipelineCursor {
public final BlockState state;
public final int light;
public final int opacity;
public final BlockPos pos;
public final @Nullable BlockEntity tileEntity;
public final @Nullable Entity destroyer;
public final List<ItemStack> drops;
public final int limit;

public PipelineCursor(final BlockState state, final int opacity, final BlockPos pos,
public PipelineCursor(final BlockState state, final int light, final int opacity, final BlockPos pos,
final @Nullable BlockEntity tileEntity,
final @Nullable Entity destroyer, final int limit
) {
this.state = state;
this.light = light;
this.opacity = opacity;
this.pos = pos;
this.tileEntity = tileEntity;
Expand All @@ -57,13 +59,14 @@ public PipelineCursor(final BlockState state, final int opacity, final BlockPos
this.limit = limit;
}

public PipelineCursor(final BlockState state, final int opacity, final BlockPos pos,
public PipelineCursor(final BlockState state, final int light, final int opacity, final BlockPos pos,
final @Nullable BlockEntity tileEntity,
final @Nullable Entity destroyer,
final List<ItemStack> drops,
final int limit
) {
this.state = state;
this.light = light;
this.opacity = opacity;
this.pos = pos;
this.tileEntity = tileEntity;
Expand All @@ -74,12 +77,9 @@ public PipelineCursor(final BlockState state, final int opacity, final BlockPos

@Override
public String toString() {
return new StringJoiner(
", ",
PipelineCursor.class.getSimpleName() + "[",
"]"
)
return new StringJoiner(", ", PipelineCursor.class.getSimpleName() + "[", "]")
.add("state=" + this.state)
.add("light=" + this.light)
.add("opacity=" + this.opacity)
.add("pos=" + this.pos)
.add("tileEntity=" + this.tileEntity)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ public boolean processEffects(final PhaseContext<?> context, final PipelineCurso
if (result.resultingState != currentCursor.state) {
currentCursor = new PipelineCursor(
result.resultingState,
currentCursor.light,
currentCursor.opacity,
currentCursor.pos,
currentCursor.tileEntity,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import net.minecraft.world.level.chunk.LevelChunkSection;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.common.bridge.world.level.block.state.BlockStateBridge;
import org.spongepowered.common.event.tracking.PhaseContext;
import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor;
import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect;
Expand Down Expand Up @@ -98,8 +99,9 @@ public boolean processEffects(final PhaseContext<?> context, final BlockState cu
if (oldState == null) {
return false;
}
final int oldLight = ((BlockStateBridge) oldState).bridge$getLightValue(serverWorld, pos);
final int oldOpacity = oldState.getLightBlock(serverWorld, pos);
PipelineCursor formerState = new PipelineCursor(oldState, oldOpacity, pos, existing, destroyer, limit);
PipelineCursor formerState = new PipelineCursor(oldState, oldLight, oldOpacity, pos, existing, destroyer, limit);

for (final ResultingTransactionBySideEffect effect : this.worldEffects) {
try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) {
Expand All @@ -114,7 +116,7 @@ public boolean processEffects(final PhaseContext<?> context, final BlockState cu
return result.resultingState != null;
}
if (formerState.drops.isEmpty() && !result.drops.isEmpty()) {
formerState = new PipelineCursor(oldState, oldOpacity, pos, existing, formerState.destroyer, result.drops, limit);
formerState = new PipelineCursor(oldState, oldLight, oldOpacity, pos, existing, formerState.destroyer, result.drops, limit);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.spongepowered.common.block.BlockStateSerializerDeserializer;
import org.spongepowered.common.block.SpongeBlockSnapshot;
import org.spongepowered.common.bridge.data.SpongeDataHolderBridge;
import org.spongepowered.common.bridge.world.level.block.state.BlockStateBridge;
import org.spongepowered.common.util.Constants;

import java.util.Arrays;
Expand Down Expand Up @@ -71,7 +72,7 @@ public BlockSnapshot snapshotFor(final ServerLocation location) {
.blockState((net.minecraft.world.level.block.state.BlockState) (Object) this)
.position(location.blockPosition())
.world((ServerLevel) location.world());
if (this.shadow$getBlock().isEntityBlock() && location.block().type().equals(this.shadow$getBlock())) {
if (((BlockStateBridge) this).bridge$hasTileEntity() && location.block().type().equals(this.shadow$getBlock())) {
final BlockEntity tileEntity = location.blockEntity()
.orElseThrow(() -> new IllegalStateException("Unable to retrieve a TileEntity for location: " + location));
builder.add(((SpongeDataHolderBridge) tileEntity).bridge$getManipulator());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@
@Mixin(BlockState.class)
public abstract class BlockStateMixin extends BlockBehaviour.BlockStateBase implements BlockStateBridge {

protected BlockStateMixin(Block p_i231870_1_,
ImmutableMap<Property<?>, Comparable<?>> p_i231870_2_,
MapCodec<BlockState> p_i231870_3_
protected BlockStateMixin(Block block,
ImmutableMap<Property<?>, Comparable<?>> properties,
MapCodec<BlockState> codec
) {
super(p_i231870_1_, p_i231870_2_, p_i231870_3_);
super(block, properties, codec);
}


Expand All @@ -56,7 +56,7 @@ protected BlockStateMixin(Block p_i231870_1_,
}

@Override
public @Nullable BlockEntity bridge$createNewTileEntity(Level world) {
public @Nullable BlockEntity bridge$createTileEntity(Level world) {
return ((EntityBlock) this.getBlock()).newBlockEntity(world);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,8 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable
.addEffect(RemoveTileEntityFromWorldEffect.getInstance())
.addEffect(RemoveTileEntityFromChunkEffect.getInstance())
.build();
pipeline.processEffects(current, new PipelineCursor(tileentity.getBlockState(), 0,immutable, tileentity, (Entity) null, Constants.World.DEFAULT_BLOCK_CHANGE_LIMIT));
pipeline.processEffects(current, new PipelineCursor(tileentity.getBlockState(), 0, 0, immutable, tileentity, (Entity) null,
Constants.World.DEFAULT_BLOCK_CHANGE_LIMIT));
return;
}
super.shadow$removeBlockEntity(immutable);
Expand Down Expand Up @@ -670,7 +671,7 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable
.addEffect(AddTileEntityToTickableListEffect.getInstance())
.addEffect(TileOnLoadDuringAddToWorldEffect.getInstance())
.build();
return pipeline.processEffects(current, new PipelineCursor(tileEntity.getBlockState(), 0, immutable, tileEntity,
return pipeline.processEffects(current, new PipelineCursor(tileEntity.getBlockState(), 0, 0, immutable, tileEntity,
(Entity) null,
Constants.World.DEFAULT_BLOCK_CHANGE_LIMIT));
}
Expand Down Expand Up @@ -707,7 +708,8 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable
.addEffect(RemoveProposedTileEntitiesDuringSetIfWorldProcessingEffect.getInstance())
.addEffect(ReplaceTileEntityInWorldEffect.getInstance())
.build();
pipeline.processEffects(current, new PipelineCursor(proposed.getBlockState(), 0,immutable, proposed, (Entity) null, Constants.World.DEFAULT_BLOCK_CHANGE_LIMIT));
pipeline.processEffects(current, new PipelineCursor(proposed.getBlockState(), 0, 0, immutable, proposed, (Entity) null,
Constants.World.DEFAULT_BLOCK_CHANGE_LIMIT));
return;
}
}
Expand Down