|
1 | 1 | package com.cak.pattern_schematics.mixin;
|
2 | 2 |
|
| 3 | +import com.cak.pattern_schematics.foundation.mixin_accessors.MovementContextAccessor; |
| 4 | +import com.cak.pattern_schematics.registry.PatternSchematicsRegistry; |
3 | 5 | import com.simibubi.create.AllBlocks;
|
4 | 6 | import com.simibubi.create.Create;
|
5 | 7 | import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
|
6 | 8 | import com.simibubi.create.content.contraptions.Contraption;
|
7 | 9 | import com.simibubi.create.content.contraptions.behaviour.MovementContext;
|
| 10 | +import com.simibubi.create.content.kinetics.deployer.DeployerBlock; |
| 11 | +import com.simibubi.create.content.logistics.filter.FilterItemStack; |
| 12 | +import net.minecraft.client.gui.screens.Screen; |
8 | 13 | import net.minecraft.core.BlockPos;
|
9 | 14 | import net.minecraft.core.Direction;
|
| 15 | +import net.minecraft.nbt.CompoundTag; |
| 16 | +import net.minecraft.network.chat.Component; |
10 | 17 | import net.minecraft.world.InteractionHand;
|
11 | 18 | import net.minecraft.world.entity.player.Player;
|
| 19 | +import net.minecraft.world.item.ItemStack; |
| 20 | +import net.minecraft.world.level.block.Block; |
12 | 21 | import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
|
| 22 | +import org.apache.commons.lang3.tuple.MutablePair; |
13 | 23 | import org.apache.commons.lang3.tuple.Pair;
|
14 | 24 | import org.spongepowered.asm.mixin.Mixin;
|
15 | 25 | import org.spongepowered.asm.mixin.Shadow;
|
| 26 | +import org.spongepowered.asm.mixin.Unique; |
16 | 27 | import org.spongepowered.asm.mixin.injection.At;
|
17 | 28 | import org.spongepowered.asm.mixin.injection.Inject;
|
18 | 29 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
19 | 30 |
|
| 31 | +import java.awt.*; |
| 32 | +import java.util.Arrays; |
| 33 | +import java.util.HashMap; |
| 34 | +import java.util.HashSet; |
| 35 | +import java.util.Set; |
| 36 | +import java.util.stream.Collectors; |
| 37 | + |
20 | 38 | /**
|
21 | 39 | * Adding interaction for applying schematics onto deployers that are in assembled schematics
|
22 |
| - * */ |
| 40 | + */ |
23 | 41 | @Mixin(value = AbstractContraptionEntity.class, remap = false)
|
24 | 42 | public class AbstractContraptionEntityMixin {
|
25 | 43 |
|
26 |
| -// @Shadow protected Contraption contraption; |
27 |
| -// |
28 |
| -// @Inject(method = "handlePlayerInteraction", at = @At("HEAD"), cancellable = true) |
29 |
| -// public void handlePlayerInteraction( |
30 |
| -// Player player, BlockPos localPos, Direction side, |
31 |
| -// InteractionHand interactionHand, CallbackInfoReturnable<Boolean> cir |
32 |
| -// ) { |
33 |
| -// Pair<StructureTemplate.StructureBlockInfo, MovementContext> actor = contraption.getActorAt(localPos); |
34 |
| -// if (actor != null && actor.getLeft().state().is(AllBlocks.DEPLOYER.get())) { |
35 |
| -// Create.LOGGER.info("Found deployer"); |
36 |
| -// cir.setReturnValue(true); |
37 |
| -// } |
38 |
| -// } |
| 44 | + @Shadow |
| 45 | + protected Contraption contraption; |
| 46 | + |
| 47 | + @Inject(method = "handlePlayerInteraction", at = @At("HEAD"), cancellable = true) |
| 48 | + public void handlePlayerInteraction( |
| 49 | + Player player, BlockPos localPos, Direction side, |
| 50 | + InteractionHand interactionHand, CallbackInfoReturnable<Boolean> cir |
| 51 | + ) { |
| 52 | + if (player.level().isClientSide || !player.isShiftKeyDown() || !player.getItemInHand(interactionHand).is(PatternSchematicsRegistry.PATTERN_SCHEMATIC.get())) |
| 53 | + return; |
| 54 | + |
| 55 | + Pair<StructureTemplate.StructureBlockInfo, MovementContext> actor = contraption.getActorAt(localPos); |
| 56 | + |
| 57 | + if (actor == null || !actor.getLeft().state().is(AllBlocks.DEPLOYER.get())) |
| 58 | + return; |
| 59 | + |
| 60 | + int appliedCount = pattern_schematics$performBulkSchematicApply(actor.getLeft().state().getValue(DeployerBlock.FACING), actor.getRight().localPos, player.getItemInHand(interactionHand)); |
| 61 | + |
| 62 | + player.displayClientMessage( |
| 63 | + Component.translatable("create_pattern_schematics.contraption_application.applied_to") |
| 64 | + .append(Component.literal(String.valueOf(appliedCount))) |
| 65 | + .append(Component.translatable("create_pattern_schematics.contraption_application.deployers")), |
| 66 | + true |
| 67 | + ); |
| 68 | + |
| 69 | + cir.setReturnValue(true); |
| 70 | + } |
| 71 | + |
| 72 | + @Unique |
| 73 | + private int pattern_schematics$performBulkSchematicApply(Direction facingDirection, BlockPos localPos, ItemStack item) { |
| 74 | + Set<MovementContext> deployerActors = pattern_schematics$collectDeployerSurface(facingDirection, localPos); |
| 75 | + |
| 76 | + FilterItemStack newFilter = FilterItemStack.of(item); |
| 77 | + CompoundTag newFilterTag = newFilter.serializeNBT(); |
| 78 | + |
| 79 | + for (MovementContext context : deployerActors) { |
| 80 | + context.blockEntityData.put("Filter", newFilterTag.copy()); |
| 81 | + ((MovementContextAccessor) context).pattern_schematics$setFilter(newFilter); |
| 82 | + } |
| 83 | + return deployerActors.size(); |
| 84 | + } |
| 85 | + |
| 86 | + @Unique |
| 87 | + private Set<MovementContext> pattern_schematics$collectDeployerSurface(Direction facingDirection, BlockPos localPos) { |
| 88 | + Set<MovementContext> allDeployers = contraption.getActors().stream() |
| 89 | + .filter(actor -> |
| 90 | + actor.getLeft().state().is(AllBlocks.DEPLOYER.get()) |
| 91 | + && actor.getLeft().state().getValue(DeployerBlock.FACING) == facingDirection |
| 92 | + ) |
| 93 | + .map(MutablePair::getRight).collect(Collectors.toSet()); |
| 94 | + |
| 95 | + return pattern_schematics$getConnectedDeployers(facingDirection, localPos, allDeployers); |
| 96 | + } |
| 97 | + |
| 98 | + @Unique |
| 99 | + private Set<MovementContext> pattern_schematics$getConnectedDeployers( |
| 100 | + Direction facingDirection, BlockPos localPos, Set<MovementContext> allDeployers |
| 101 | + ) { |
| 102 | + HashMap<BlockPos, MovementContext> deployerPositions = new HashMap<>(); |
| 103 | + allDeployers.forEach(context -> deployerPositions.put(context.localPos, context)); |
| 104 | + |
| 105 | + Set<BlockPos> frontier = new HashSet<>(); |
| 106 | + pattern_schematics$searchForConnected(pattern_schematics$getSearchDirections(facingDirection), localPos, deployerPositions, frontier); |
| 107 | + |
| 108 | +// Create.LOGGER.info("Found {} connected deployers", frontier.size()); |
| 109 | + |
| 110 | + Set<MovementContext> validDeployers = new HashSet<>(); |
| 111 | + for (BlockPos pos : frontier) { |
| 112 | + validDeployers.add(deployerPositions.get(pos)); |
| 113 | + } |
| 114 | + return validDeployers; |
| 115 | + } |
| 116 | + |
| 117 | + @Unique |
| 118 | + private void pattern_schematics$searchForConnected(Set<Direction> directions, BlockPos currentPos, HashMap<BlockPos, MovementContext> deployerPositions, Set<BlockPos> frontier) { |
| 119 | + if (frontier.contains(currentPos) || !deployerPositions.containsKey(currentPos) || frontier.size() > 512) return; |
| 120 | + |
| 121 | + //This block is a deployer |
| 122 | + frontier.add(currentPos); |
| 123 | + for (Direction direction : directions) { |
| 124 | + pattern_schematics$searchForConnected(directions, currentPos.offset(direction.getNormal()), deployerPositions, frontier); |
| 125 | + } |
| 126 | + } |
| 127 | + |
| 128 | + @Unique |
| 129 | + private Set<Direction> pattern_schematics$getSearchDirections(Direction facingDirection) { |
| 130 | + return Arrays.stream(Direction.values()).filter(direction -> direction.getAxis() != facingDirection.getAxis()).collect(Collectors.toSet()); |
| 131 | + } |
39 | 132 |
|
40 | 133 | }
|
0 commit comments