Refactor multi-pos block destruction

- Replace DestroyProgressMixin with BlockDestructionProgressMixin and
LevelRendererMixin
- Replace DestroyProgressRenderingHandler with
MultiPosDestructionHandler
This commit is contained in:
PepperCode1 2022-11-09 16:52:22 -08:00
parent b77388a8e4
commit cf87508276
13 changed files with 156 additions and 78 deletions

View file

@ -1,8 +1,10 @@
package com.simibubi.create.content.contraptions.relays.belt;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import org.apache.commons.lang3.mutable.MutableBoolean;
@ -25,13 +27,12 @@ import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement;
import com.simibubi.create.content.schematics.ItemRequirement;
import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType;
import com.simibubi.create.foundation.block.ITE;
import com.simibubi.create.foundation.block.render.DestroyProgressRenderingHandler;
import com.simibubi.create.foundation.block.render.MultiPosDestructionHandler;
import com.simibubi.create.foundation.block.render.ReducedDestroyEffects;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
@ -475,7 +476,6 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE<BeltTileEnt
BlockPos currentPos = nextSegmentPosition(state, pos, forward);
if (currentPos == null)
continue;
world.destroyBlockProgress(currentPos.hashCode(), currentPos, -1);
BlockState currentState = world.getBlockState(currentPos);
if (!AllBlocks.BELT.has(currentState))
continue;
@ -695,17 +695,14 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE<BeltTileEnt
return false;
}
public static class RenderProperties extends ReducedDestroyEffects implements DestroyProgressRenderingHandler {
public static class RenderProperties extends ReducedDestroyEffects implements MultiPosDestructionHandler {
@Override
public boolean renderDestroyProgress(ClientLevel level, LevelRenderer renderer, int breakerId, BlockPos pos,
int progress, BlockState blockState) {
public Set<BlockPos> getExtraPositions(ClientLevel level, BlockPos pos, BlockState blockState, int progress) {
BlockEntity blockEntity = level.getBlockEntity(pos);
if (blockEntity instanceof BeltTileEntity belt) {
for (BlockPos beltPos : BeltBlock.getBeltChain(level, belt.getController())) {
renderer.destroyBlockProgress(beltPos.hashCode(), beltPos, progress);
}
return new HashSet<>(BeltBlock.getBeltChain(level, belt.getController()));
}
return false;
return null;
}
}

View file

@ -1,12 +1,17 @@
package com.simibubi.create.content.logistics.trains;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
public class CameraDistanceModifier {
private static final LerpedFloat multiplier = LerpedFloat.linear().startWithValue(1);
public static float getMultiplier() {
return getMultiplier(AnimationTickHolder.getPartialTicks());
}
public static float getMultiplier(float partialTicks) {
return multiplier.getValue(partialTicks);
}

View file

@ -32,7 +32,7 @@ public class TrackPropagator {
}
public static void onRailRemoved(LevelAccessor reader, BlockPos pos, BlockState state) {
if (!(state.getBlock()instanceof ITrackBlock track))
if (!(state.getBlock() instanceof ITrackBlock track))
return;
Collection<DiscoveredLocation> ends = track.getConnected(reader, pos, state, false, null);

View file

@ -11,12 +11,16 @@ import static com.simibubi.create.AllShapes.TRACK_ORTHO_LONG;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.function.Consumer;
import org.jetbrains.annotations.Nullable;
import com.google.common.base.Predicates;
import com.jozufozu.flywheel.core.PartialModel;
import com.jozufozu.flywheel.util.transform.TransformStack;
@ -41,7 +45,7 @@ import com.simibubi.create.content.schematics.ItemRequirement;
import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType;
import com.simibubi.create.foundation.block.ITE;
import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
import com.simibubi.create.foundation.block.render.DestroyProgressRenderingHandler;
import com.simibubi.create.foundation.block.render.MultiPosDestructionHandler;
import com.simibubi.create.foundation.block.render.ReducedDestroyEffects;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.BlockFace;
@ -53,7 +57,6 @@ import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.ChatFormatting;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
@ -773,15 +776,16 @@ public class TrackBlock extends Block
return new ItemRequirement(ItemUseType.CONSUME, stacks);
}
public static class RenderProperties extends ReducedDestroyEffects implements DestroyProgressRenderingHandler {
public static class RenderProperties extends ReducedDestroyEffects implements MultiPosDestructionHandler {
@Override
public boolean renderDestroyProgress(ClientLevel level, LevelRenderer renderer, int breakerId, BlockPos pos,
int progress, BlockState blockState) {
@Nullable
public Set<BlockPos> getExtraPositions(ClientLevel level, BlockPos pos, BlockState blockState,
int progress) {
BlockEntity blockEntity = level.getBlockEntity(pos);
if (blockEntity instanceof TrackTileEntity track)
for (BlockPos trackPos : track.connections.keySet())
renderer.destroyBlockProgress(pos.hashCode(), trackPos, progress);
return false;
if (blockEntity instanceof TrackTileEntity track) {
return new HashSet<>(track.connections.keySet());
}
return null;
}
}

View file

@ -0,0 +1,14 @@
package com.simibubi.create.foundation.block.render;
import java.util.Set;
import org.jetbrains.annotations.Nullable;
import net.minecraft.core.BlockPos;
public interface BlockDestructionProgressExtension {
@Nullable
Set<BlockPos> getExtraPositions();
void setExtraPositions(@Nullable Set<BlockPos> positions);
}

View file

@ -1,16 +0,0 @@
package com.simibubi.create.foundation.block.render;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.IBlockRenderProperties;
public interface DestroyProgressRenderingHandler extends IBlockRenderProperties {
/**
* Called before the default block breaking progress overlay is rendered.
*
* @return if the default rendering should be cancelled or not
*/
boolean renderDestroyProgress(ClientLevel level, LevelRenderer renderer, int breakerId, BlockPos pos, int progress, BlockState blockState);
}

View file

@ -0,0 +1,17 @@
package com.simibubi.create.foundation.block.render;
import java.util.Set;
import org.jetbrains.annotations.Nullable;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.state.BlockState;
public interface MultiPosDestructionHandler {
/**
* Returned set must be mutable and must not be changed after it is returned.
*/
@Nullable
Set<BlockPos> getExtraPositions(ClientLevel level, BlockPos pos, BlockState blockState, int progress);
}

View file

@ -0,0 +1,27 @@
package com.simibubi.create.foundation.mixin;
import java.util.Set;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import com.simibubi.create.foundation.block.render.BlockDestructionProgressExtension;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.BlockDestructionProgress;
@Mixin(BlockDestructionProgress.class)
public class BlockDestructionProgressMixin implements BlockDestructionProgressExtension {
@Unique
private Set<BlockPos> extraPositions;
@Override
public Set<BlockPos> getExtraPositions() {
return extraPositions;
}
@Override
public void setExtraPositions(Set<BlockPos> positions) {
extraPositions = positions;
}
}

View file

@ -5,7 +5,6 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import com.simibubi.create.content.logistics.trains.CameraDistanceModifier;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import net.minecraft.client.Camera;
@ -17,6 +16,6 @@ public abstract class CameraMixin {
index = 0
)
public double modifyCameraOffset(double originalValue) {
return originalValue * CameraDistanceModifier.getMultiplier(AnimationTickHolder.getPartialTicks());
return originalValue * CameraDistanceModifier.getMultiplier();
}
}

View file

@ -1,37 +0,0 @@
package com.simibubi.create.foundation.mixin;
import org.spongepowered.asm.mixin.Final;
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 com.simibubi.create.foundation.block.render.DestroyProgressRenderingHandler;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.IBlockRenderProperties;
import net.minecraftforge.client.RenderProperties;
@Mixin(ClientLevel.class)
public class DestroyProgressMixin {
@Shadow
@Final
private LevelRenderer levelRenderer;
@Inject(at = @At("HEAD"), method = "destroyBlockProgress(ILnet/minecraft/core/BlockPos;I)V", cancellable = true)
private void onDestroyBlockProgress(int breakerId, BlockPos pos, int progress, CallbackInfo ci) {
ClientLevel self = (ClientLevel) (Object) this;
BlockState state = self.getBlockState(pos);
IBlockRenderProperties properties = RenderProperties.get(state);
if (properties instanceof DestroyProgressRenderingHandler handler) {
if (handler.renderDestroyProgress(self, levelRenderer, breakerId, pos, progress, state)) {
ci.cancel();
}
} else if (progress == -1)
levelRenderer.destroyBlockProgress(pos.hashCode(), pos, -1);
}
}

View file

@ -15,11 +15,9 @@ import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
@Mixin(GameRenderer.class)
public class GameRendererMixin {
@Inject(at = @At("TAIL"), method = "pick")
private void bigShapePick(CallbackInfo ci) {
BigOutlines.pick();
TrackBlockOutline.pickCurves();
}
}

View file

@ -0,0 +1,69 @@
package com.simibubi.create.foundation.mixin;
import java.util.Set;
import java.util.SortedSet;
import org.spongepowered.asm.mixin.Final;
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.At.Shift;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import com.google.common.collect.Sets;
import com.simibubi.create.foundation.block.render.BlockDestructionProgressExtension;
import com.simibubi.create.foundation.block.render.MultiPosDestructionHandler;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.BlockDestructionProgress;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.IBlockRenderProperties;
import net.minecraftforge.client.RenderProperties;
@Mixin(LevelRenderer.class)
public class LevelRendererMixin {
@Shadow
private ClientLevel level;
@Shadow
@Final
private Long2ObjectMap<SortedSet<BlockDestructionProgress>> destructionProgress;
@Inject(method = "destroyBlockProgress(ILnet/minecraft/core/BlockPos;I)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/BlockDestructionProgress;updateTick(I)V", shift = Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD)
private void onDestroyBlockProgress(int breakerId, BlockPos pos, int progress, CallbackInfo ci, BlockDestructionProgress progressObj) {
BlockState state = level.getBlockState(pos);
IBlockRenderProperties properties = RenderProperties.get(state);
if (properties instanceof MultiPosDestructionHandler handler) {
Set<BlockPos> extraPositions = handler.getExtraPositions(level, pos, state, progress);
if (extraPositions != null) {
extraPositions.remove(pos);
((BlockDestructionProgressExtension) progressObj).setExtraPositions(extraPositions);
for (BlockPos extraPos : extraPositions) {
destructionProgress.computeIfAbsent(extraPos.asLong(), l -> Sets.newTreeSet()).add(progressObj);
}
}
}
}
@Inject(method = "removeProgress(Lnet/minecraft/server/level/BlockDestructionProgress;)V", at = @At("RETURN"))
private void onRemoveProgress(BlockDestructionProgress progress, CallbackInfo ci) {
Set<BlockPos> extraPositions = ((BlockDestructionProgressExtension) progress).getExtraPositions();
if (extraPositions != null) {
for (BlockPos extraPos : extraPositions) {
long l = extraPos.asLong();
Set<BlockDestructionProgress> set = destructionProgress.get(l);
if (set != null) {
set.remove(progress);
if (set.isEmpty()) {
destructionProgress.remove(l);
}
}
}
}
}
}

View file

@ -17,12 +17,13 @@
"accessor.ServerLevelAccessor"
],
"client": [
"BlockDestructionProgressMixin",
"CameraMixin",
"DestroyProgressMixin",
"EntityContraptionInteractionMixin",
"FixNormalScalingMixin",
"GameRendererMixin",
"HeavyBootsOnPlayerMixin",
"LevelRendererMixin",
"MapRendererMapInstanceMixin",
"ModelDataRefreshMixin",
"WindowResizeMixin",