diff --git a/src/main/java/com/simibubi/create/AllEntityTypes.java b/src/main/java/com/simibubi/create/AllEntityTypes.java index 8f9fc0c2b..1f893325f 100644 --- a/src/main/java/com/simibubi/create/AllEntityTypes.java +++ b/src/main/java/com/simibubi/create/AllEntityTypes.java @@ -6,7 +6,6 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Con import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntityRenderer; import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.glue.GlueInstance; import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueRenderer; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionEntityRenderer; @@ -34,25 +33,20 @@ import net.minecraft.world.entity.MobCategory; public class AllEntityTypes { public static final EntityEntry ORIENTED_CONTRAPTION = contraption("contraption", - OrientedContraptionEntity::new, () -> OrientedContraptionEntityRenderer::new, 5, 3, true) - .register(); + OrientedContraptionEntity::new, () -> OrientedContraptionEntityRenderer::new, 5, 3, true).register(); public static final EntityEntry CONTROLLED_CONTRAPTION = contraption("stationary_contraption", ControlledContraptionEntity::new, () -> ContraptionEntityRenderer::new, - 20, 40, false) - .register(); + 20, 40, false).register(); public static final EntityEntry GANTRY_CONTRAPTION = contraption("gantry_contraption", - GantryContraptionEntity::new, () -> ContraptionEntityRenderer::new, 10, 40, false) - .register(); + GantryContraptionEntity::new, () -> ContraptionEntityRenderer::new, 10, 40, false).register(); public static final EntityEntry CARRIAGE_CONTRAPTION = contraption("carriage_contraption", CarriageContraptionEntity::new, - () -> CarriageContraptionEntityRenderer::new, 15, 3, true) - .instance(() -> CarriageContraptionInstance::new) - .register(); + () -> CarriageContraptionEntityRenderer::new, 15, 3, true).instance(() -> CarriageContraptionInstance::new) + .register(); public static final EntityEntry SUPER_GLUE = register("super_glue", SuperGlueEntity::new, () -> SuperGlueRenderer::new, MobCategory.MISC, 10, - Integer.MAX_VALUE, false, true, SuperGlueEntity::build).instance(() -> GlueInstance::new, false) - .register(); + Integer.MAX_VALUE, false, true, SuperGlueEntity::build).register(); public static final EntityEntry CRAFTING_BLUEPRINT = register("crafting_blueprint", BlueprintEntity::new, () -> BlueprintRenderer::new, MobCategory.MISC, 10, diff --git a/src/main/java/com/simibubi/create/AllSpecialTextures.java b/src/main/java/com/simibubi/create/AllSpecialTextures.java index 30f923f0b..f697d04d6 100644 --- a/src/main/java/com/simibubi/create/AllSpecialTextures.java +++ b/src/main/java/com/simibubi/create/AllSpecialTextures.java @@ -12,6 +12,7 @@ public enum AllSpecialTextures { CUTOUT_CHECKERED("cutout_checkerboard.png"), HIGHLIGHT_CHECKERED("highlighted_checkerboard.png"), SELECTION("selection.png"), + GLUE("glue.png"), ; diff --git a/src/main/java/com/simibubi/create/Create.java b/src/main/java/com/simibubi/create/Create.java index 3dbe5ba3a..fa35898f1 100644 --- a/src/main/java/com/simibubi/create/Create.java +++ b/src/main/java/com/simibubi/create/Create.java @@ -11,7 +11,6 @@ import com.simibubi.create.api.behaviour.BlockSpoutingBehaviour; import com.simibubi.create.content.CreateItemGroup; import com.simibubi.create.content.contraptions.TorquePropagator; import com.simibubi.create.content.contraptions.components.flywheel.engine.FurnaceEngineInteractions; -import com.simibubi.create.content.contraptions.components.structureMovement.glue.GlueQueue; import com.simibubi.create.content.curiosities.weapons.BuiltinPotatoProjectileTypes; import com.simibubi.create.content.logistics.RedstoneLinkNetworkHandler; import com.simibubi.create.content.logistics.block.data.AllDataGathererBehaviours; @@ -77,7 +76,6 @@ public class Create { public static final TorquePropagator TORQUE_PROPAGATOR = new TorquePropagator(); public static final GlobalRailwayManager RAILWAYS = new GlobalRailwayManager(); public static final ServerLagger LAGGER = new ServerLagger(); - public static final GlueQueue GLUE_QUEUE = new GlueQueue(); public static final Random RANDOM = new Random(); private static final NonNullSupplier REGISTRATE = CreateRegistrate.lazy(ID); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java index 11302a44c..2ec35d58f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java @@ -42,7 +42,6 @@ import com.simibubi.create.content.contraptions.components.structureMovement.cha import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerBlock; import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageBlock; import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueHandler; import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsBlock; import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock; import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.PistonState; @@ -101,6 +100,7 @@ import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.ChestType; import net.minecraft.world.level.block.state.properties.PistonType; import net.minecraft.world.level.chunk.HashMapPalette; +import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.Fluids; @@ -137,12 +137,12 @@ public abstract class Contraption { protected Map fluidStorage; protected List> actors; protected Map interactors; - protected Set> superglue; + protected List superglue; protected List seats; protected Map seatMapping; protected Map stabilizedSubContraptions; - private List glueToRemove; + private Set glueToRemove; private Map initialPassengers; private List pendingSubContraptions; @@ -161,10 +161,10 @@ public abstract class Contraption { seats = new ArrayList<>(); actors = new ArrayList<>(); interactors = new HashMap<>(); - superglue = new HashSet<>(); + superglue = new ArrayList<>(); seatMapping = new HashMap<>(); fluidStorage = new HashMap<>(); - glueToRemove = new ArrayList<>(); + glueToRemove = new HashSet<>(); initialPassengers = new HashMap<>(); presentTileEntities = new HashMap<>(); maybeInstancedTileEntities = new ArrayList<>(); @@ -389,8 +389,6 @@ public abstract class Contraption { if (!visited.contains(posDown) && AllBlocks.CART_ASSEMBLER.has(stateBelow)) frontier.add(posDown); - Map superglue = SuperGlueHandler.gatherGlue(world, pos); - // Slime blocks and super glue drag adjacent blocks if possible for (Direction offset : Iterate.directions) { BlockPos offsetPos = pos.relative(offset); @@ -404,7 +402,7 @@ public abstract class Contraption { } boolean wasVisited = visited.contains(offsetPos); - boolean faceHasGlue = superglue.containsKey(offset); + boolean faceHasGlue = SuperGlueEntity.isGlued(world, pos, offset, glueToRemove); boolean blockAttachedTowardsFace = BlockMovementChecks.isBlockAttachedTowards(blockState, world, offsetPos, offset.getOpposite()); boolean brittle = BlockMovementChecks.isBrittle(blockState); @@ -425,8 +423,6 @@ public abstract class Contraption { if (!wasVisited && (canStick || blockAttachedTowardsFace || faceHasGlue || (offset == forcedDirection && !BlockMovementChecks.isNotSupportive(state, forcedDirection)))) frontier.add(offsetPos); - if (faceHasGlue) - addGlue(superglue.get(offset)); } addBlock(pos, capture(world, pos)); @@ -678,13 +674,6 @@ public abstract class Contraption { return nbt; } - protected void addGlue(SuperGlueEntity entity) { - BlockPos pos = entity.getHangingPosition(); - Direction direction = entity.getFacingDirection(); - this.superglue.add(Pair.of(toLocalPos(pos), direction)); - glueToRemove.add(entity); - } - protected BlockPos toLocalPos(BlockPos globalPos) { return globalPos.subtract(anchor); } @@ -718,8 +707,8 @@ public abstract class Contraption { }); superglue.clear(); - NBTHelper.iterateCompoundList(nbt.getList("Superglue", Tag.TAG_COMPOUND), c -> superglue.add( - Pair.of(NbtUtils.readBlockPos(c.getCompound("Pos")), Direction.from3DDataValue(c.getByte("Direction"))))); + NBTHelper.iterateCompoundList(nbt.getList("Superglue", Tag.TAG_COMPOUND), + c -> superglue.add(SuperGlueEntity.readBoundingBox(c))); seats.clear(); NBTHelper.iterateCompoundList(nbt.getList("Seats", Tag.TAG_COMPOUND), c -> seats.add(NbtUtils.readBlockPos(c))); @@ -802,11 +791,9 @@ public abstract class Contraption { ListTag superglueNBT = new ListTag(); ListTag storageNBT = new ListTag(); if (!spawnPacket) { - for (Pair glueEntry : superglue) { + for (AABB glueEntry : superglue) { CompoundTag c = new CompoundTag(); - c.put("Pos", NbtUtils.writeBlockPos(glueEntry.getKey())); - c.putByte("Direction", (byte) glueEntry.getValue() - .get3DDataValue()); + SuperGlueEntity.writeBoundingBox(c, glueEntry); superglueNBT.add(c); } @@ -978,7 +965,17 @@ public abstract class Contraption { .forEach(MountedStorage::removeStorageFromWorld); fluidStorage.values() .forEach(MountedFluidStorage::removeStorageFromWorld); - glueToRemove.forEach(SuperGlueEntity::discard); + + glueToRemove.forEach(glue -> { + superglue.add(glue.getBoundingBox() + .move(Vec3.atLowerCornerOf(offset.offset(anchor)) + .scale(-1))); + glue.discard(); + }); + + List minimisedGlue = new ArrayList<>(); + for (int i = 0; i < superglue.size(); i++) + minimisedGlue.add(null); for (boolean brittles : Iterate.trueAndFalse) { for (Iterator iterator = blocks.values() @@ -987,6 +984,18 @@ public abstract class Contraption { if (brittles != BlockMovementChecks.isBrittle(block.state)) continue; + for (int i = 0; i < superglue.size(); i++) { + AABB aabb = superglue.get(i); + if (aabb == null + || !aabb.contains(block.pos.getX() + .5, block.pos.getY() + .5, block.pos.getZ() + .5)) + continue; + if (minimisedGlue.get(i) == null) + minimisedGlue.set(i, new BoundingBox(block.pos)); + else + minimisedGlue.get(i) + .encapsulate(block.pos); + } + BlockPos add = block.pos.offset(anchor) .offset(offset); if (customBlockRemoval(world, add, block.state)) @@ -1008,6 +1017,16 @@ public abstract class Contraption { world.setBlock(add, Blocks.AIR.defaultBlockState(), flags); } } + + superglue.clear(); + for (BoundingBox box : minimisedGlue) { + if (box == null) + continue; + AABB bb = new AABB(box.minX(), box.minY(), box.minZ(), box.maxX() + 1, box.maxY() + 1, box.maxZ() + 1); + if (bb.getSize() > 1.01) + superglue.add(bb); + } + for (StructureBlockInfo block : blocks.values()) { BlockPos add = block.pos.offset(anchor) .offset(offset); @@ -1074,10 +1093,10 @@ public abstract class Contraption { } world.destroyBlock(targetPos, true); - + if (AllBlocks.SHAFT.has(state)) state = ShaftBlock.pickCorrectShaftType(state, world, targetPos); - + world.setBlock(targetPos, state, Block.UPDATE_MOVE_BY_PISTON | Block.UPDATE_ALL); boolean verticalRotation = transform.rotationAxis == null || transform.rotationAxis.isHorizontal(); @@ -1137,15 +1156,11 @@ public abstract class Contraption { for (int i = 0; i < fluidInventory.getTanks(); i++) fluidInventory.drain(fluidInventory.getFluidInTank(i), FluidAction.EXECUTE); - for (Pair pair : superglue) { - BlockPos targetPos = transform.apply(pair.getKey()); - Direction targetFacing = transform.transformFacing(pair.getValue()); - - SuperGlueEntity entity = new SuperGlueEntity(world, targetPos, targetFacing); - if (entity.onValidSurface()) { - if (!world.isClientSide) - world.addFreshEntity(entity); - } + for (AABB box : superglue) { + box = new AABB(transform.apply(new Vec3(box.minX, box.minY, box.minZ)), + transform.apply(new Vec3(box.maxX, box.maxY, box.maxZ))); + if (!world.isClientSide) + world.addFreshEntity(new SuperGlueEntity(world, box)); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueInstance.java deleted file mode 100644 index 7282da1e1..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueInstance.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.glue; - -import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.api.MaterialGroup; -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.api.instance.TickableInstance; -import com.jozufozu.flywheel.backend.instancing.entity.EntityInstance; -import com.jozufozu.flywheel.core.Materials; -import com.jozufozu.flywheel.core.instancing.ConditionalInstance; -import com.jozufozu.flywheel.core.materials.oriented.OrientedData; -import com.mojang.math.Quaternion; -import com.simibubi.create.AllItems; -import com.simibubi.create.Create; -import com.simibubi.create.foundation.utility.AngleHelper; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.LightLayer; - -public class GlueInstance extends EntityInstance implements TickableInstance { - - private static final ResourceLocation TEXTURE = Create.asResource("textures/entity/super_glue/slime.png"); - - private final Quaternion rotation; - protected ConditionalInstance model; - - public GlueInstance(MaterialManager materialManager, SuperGlueEntity entity) { - super(materialManager, entity); - - Instancer instancer = getInstancer(materialManager, entity); - - Direction face = entity.getFacingDirection(); - rotation = new Quaternion(AngleHelper.verticalAngle(face), AngleHelper.horizontalAngle(face), 0, true); - - model = new ConditionalInstance<>(instancer) - .withCondition(this::shouldShow) - .withSetupFunc(this::positionModel) - .update(); - } - - private Instancer getInstancer(MaterialManager materialManager, SuperGlueEntity entity) { - MaterialGroup group = GlueModel.USE_ATLAS ? materialManager.defaultCutout() : materialManager.cutout(RenderType.entityCutout(TEXTURE)); - - return group.material(Materials.ORIENTED).model(entity.getType(), GlueModel::get); - } - - @Override - public void tick() { - model.update(); - } - - @Override - public void remove() { - model.delete(); - } - - private void positionModel(OrientedData model) { - - model.setPosition(getInstancePosition()) - .setPivot(0, 0, 0) - .setRotation(rotation); - - updateLight(model); - } - - @Override - public void updateLight() { - model.get().ifPresent(this::updateLight); - } - - private void updateLight(OrientedData model) { - BlockPos pos = entity.getHangingPosition(); - model.setBlockLight(world.getBrightness(LightLayer.BLOCK, pos)) - .setSkyLight(world.getBrightness(LightLayer.SKY, pos)); - } - - private boolean shouldShow() { - Player player = Minecraft.getInstance().player; - - return entity.isVisible() - || AllItems.SUPER_GLUE.isIn(player.getMainHandItem()) - || AllItems.SUPER_GLUE.isIn(player.getOffhandItem()); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueModel.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueModel.java deleted file mode 100644 index 0c279a640..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueModel.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.glue; - -import com.jozufozu.flywheel.api.vertex.VertexList; -import com.jozufozu.flywheel.core.Formats; -import com.jozufozu.flywheel.core.model.Model; -import com.jozufozu.flywheel.core.vertex.PosTexNormalWriterUnsafe; -import com.mojang.blaze3d.platform.MemoryTracker; -import com.simibubi.create.AllStitchedTextures; -import com.simibubi.create.foundation.utility.VecHelper; - -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.core.Direction; -import net.minecraft.world.phys.Vec3; - -public class GlueModel implements Model { - - public static final GlueModel INSTANCE = new GlueModel(); - static final boolean USE_ATLAS = false; - - public static GlueModel get() { - return INSTANCE; - } - - private final VertexList reader; - - private GlueModel() { - PosTexNormalWriterUnsafe writer = Formats.POS_TEX_NORMAL.createWriter(MemoryTracker.create(size())); - createGlueModel(writer); - reader = writer.intoReader(); - } - - @Override - public String name() { - return "glue"; - } - - @Override - public int vertexCount() { - return 8; - } - - @Override - public VertexList getReader() { - return reader; - } - - public static void createGlueModel(PosTexNormalWriterUnsafe buffer) { - Vec3 diff = Vec3.atLowerCornerOf(Direction.SOUTH.getNormal()); - Vec3 extension = diff.normalize() - .scale(1 / 32f - 1 / 128f); - - Vec3 plane = VecHelper.axisAlingedPlaneOf(diff); - Direction.Axis axis = Direction.getNearest(diff.x, diff.y, diff.z) - .getAxis(); - - Vec3 start = Vec3.ZERO.subtract(extension); - Vec3 end = Vec3.ZERO.add(extension); - - plane = plane.scale(1 / 2f); - Vec3 a1 = plane.add(start); - Vec3 b1 = plane.add(end); - plane = VecHelper.rotate(plane, -90, axis); - Vec3 a2 = plane.add(start); - Vec3 b2 = plane.add(end); - plane = VecHelper.rotate(plane, -90, axis); - Vec3 a3 = plane.add(start); - Vec3 b3 = plane.add(end); - plane = VecHelper.rotate(plane, -90, axis); - Vec3 a4 = plane.add(start); - Vec3 b4 = plane.add(end); - - float minU; - float maxU; - float minV; - float maxV; - - if (USE_ATLAS) { - TextureAtlasSprite sprite = AllStitchedTextures.SUPER_GLUE.get(); - minU = sprite.getU0(); - maxU = sprite.getU1(); - minV = sprite.getV0(); - maxV = sprite.getV1(); - } else { - minU = minV = 0; - maxU = maxV = 1; - } - - // inside quad - buffer.putVertex((float) a1.x, (float) a1.y, (float) a1.z, 0, 0, -1, maxU, minV); - buffer.putVertex((float) a2.x, (float) a2.y, (float) a2.z, 0, 0, -1, maxU, maxV); - buffer.putVertex((float) a3.x, (float) a3.y, (float) a3.z, 0, 0, -1, minU, maxV); - buffer.putVertex((float) a4.x, (float) a4.y, (float) a4.z, 0, 0, -1, minU, minV); - // outside quad - buffer.putVertex((float) b4.x, (float) b4.y, (float) b4.z, 0, 0, 1f, minU, minV); - buffer.putVertex((float) b3.x, (float) b3.y, (float) b3.z, 0, 0, 1f, minU, maxV); - buffer.putVertex((float) b2.x, (float) b2.y, (float) b2.z, 0, 0, 1f, maxU, maxV); - buffer.putVertex((float) b1.x, (float) b1.y, (float) b1.z, 0, 0, 1f, maxU, minV); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueQueue.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueQueue.java deleted file mode 100644 index 5d71b43d3..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueQueue.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.glue; - -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; - -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.utility.BlockFace; -import com.simibubi.create.foundation.utility.WorldAttached; - -import net.minecraft.util.Mth; -import net.minecraft.world.level.Level; -import net.minecraftforge.network.PacketDistributor; - -public class GlueQueue { - - private WorldAttached> QUEUED_GLUE = new WorldAttached<>(level -> new LinkedList<>()); - - public void tick(Level level) { - List list = QUEUED_GLUE.get(level); - if (list.isEmpty()) - return; - BlockFace next = list.remove(0); - if (!level.isLoaded(next.getPos())) - return; - - SuperGlueEntity entity = new SuperGlueEntity(level, next.getPos(), next.getFace()); - level.addFreshEntity(entity); - AllSoundEvents.SLIME_ADDED.playFrom(entity, 0.125F, Mth.clamp(8f / (list.size() + 1), 0.75f, 1f)); - - AllPackets.channel.send(PacketDistributor.ALL.noArg(), - new GlueEffectPacket(entity.getHangingPosition(), entity.getFacingDirection() - .getOpposite(), false)); - } - - public void add(Level level, Collection entries) { - QUEUED_GLUE.get(level) - .addAll(entries); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java index a063a53ff..46899b9ae 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java @@ -1,8 +1,6 @@ package com.simibubi.create.content.contraptions.components.structureMovement.glue; -import javax.annotation.Nullable; - -import org.apache.commons.lang3.Validate; +import java.util.Set; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllEntityTypes; @@ -15,23 +13,19 @@ import com.simibubi.create.content.contraptions.components.structureMovement.cha import com.simibubi.create.content.schematics.ISpecialEntityItemRequirement; import com.simibubi.create.content.schematics.ItemRequirement; import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.utility.AnimationTickHolder; -import com.simibubi.create.foundation.utility.BlockFace; -import com.simibubi.create.foundation.utility.worldWrappers.WrappedWorld; +import com.simibubi.create.foundation.utility.Iterate; +import com.simibubi.create.foundation.utility.VecHelper; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.core.particles.ParticleTypes; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.protocol.Packet; import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.util.Mth; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.damagesource.DamageSource; @@ -39,14 +33,11 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityDimensions; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LightningBolt; -import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.MoverType; import net.minecraft.world.entity.Pose; -import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.GameRules; import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.DirectionalBlock; import net.minecraft.world.level.block.Mirror; @@ -54,145 +45,51 @@ import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.HitResult.Type; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.entity.IEntityAdditionalSpawnData; -import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.network.NetworkHooks; -import net.minecraftforge.network.PacketDistributor; -public class SuperGlueEntity extends Entity - implements IEntityAdditionalSpawnData, ISpecialEntityItemRequirement { +public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnData, ISpecialEntityItemRequirement { - private int validationTimer; - protected BlockPos hangingPosition; - protected Direction facingDirection = Direction.SOUTH; + public static AABB span(BlockPos startPos, BlockPos endPos) { + return new AABB(startPos, endPos).expandTowards(1, 1, 1); + } + + public static boolean isGlued(LevelAccessor level, BlockPos blockPos, Direction direction, + Set cached) { + BlockPos targetPos = blockPos.relative(direction); + if (cached != null) + for (SuperGlueEntity glueEntity : cached) + if (glueEntity.contains(blockPos) && glueEntity.contains(targetPos)) + return true; + for (SuperGlueEntity glueEntity : level.getEntitiesOfClass(SuperGlueEntity.class, span(blockPos, targetPos))) { + if (!glueEntity.contains(blockPos) || !glueEntity.contains(targetPos)) + continue; + if (cached != null) + cached.add(glueEntity); + return true; + } + return false; + } public SuperGlueEntity(EntityType type, Level world) { super(type, world); } - public SuperGlueEntity(Level world, BlockPos pos, Direction direction) { + public SuperGlueEntity(Level world, AABB boundingBox) { this(AllEntityTypes.SUPER_GLUE.get(), world); - hangingPosition = pos; - facingDirection = direction; - updateFacingWithBoundingBox(); + setBoundingBox(boundingBox); + resetPositionToBB(); + } + + public void resetPositionToBB() { + AABB bb = getBoundingBox(); + setPosRaw(bb.getCenter().x, bb.minY, bb.getCenter().z); } @Override protected void defineSynchedData() {} - public int getWidthPixels() { - return 12; - } - - public int getHeightPixels() { - return 12; - } - - public void onBroken(@Nullable Entity breaker) { - playSound(SoundEvents.SLIME_SQUISH_SMALL, 1.0F, 1.0F); - if (onValidSurface()) { - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this), - new GlueEffectPacket(getHangingPosition(), getFacingDirection().getOpposite(), false)); - AllSoundEvents.SLIME_ADDED.playFrom(this, 0.5F, 0.5F); - } - } - - public void playPlaceSound() { - AllSoundEvents.SLIME_ADDED.playFrom(this, 0.5F, 0.75F); - } - - protected void updateFacingWithBoundingBox() { - Validate.notNull(getFacingDirection()); - if (getFacingDirection().getAxis() - .isHorizontal()) { - setXRot(0); - setYRot(getFacingDirection().get2DDataValue() * 90); - } else { - setXRot(-90 * getFacingDirection().getAxisDirection() - .getStep()); - setYRot(0); - } - - this.xRotO = this.getXRot(); - this.yRotO = this.getYRot(); - this.updateBoundingBox(); - } - - protected void updateBoundingBox() { - if (this.getFacingDirection() != null) { - double offset = 0.5 - 1 / 256d; - double x = hangingPosition.getX() + 0.5 - facingDirection.getStepX() * offset; - double y = hangingPosition.getY() + 0.5 - facingDirection.getStepY() * offset; - double z = hangingPosition.getZ() + 0.5 - facingDirection.getStepZ() * offset; - this.setPosRaw(x, y, z); - double w = getWidthPixels(); - double h = getHeightPixels(); - double l = getWidthPixels(); - Axis axis = this.getFacingDirection() - .getAxis(); - double depth = 2 - 1 / 128f; - - switch (axis) { - case X -> w = depth; - case Y -> h = depth; - case Z -> l = depth; - } - - w = w / 32.0D; - h = h / 32.0D; - l = l / 32.0D; - this.setBoundingBox(new AABB(x - w, y - h, z - l, x + w, y + h, z + l)); - } - } - - @Override - public void tick() { - if (this.validationTimer++ == 10 && !this.level.isClientSide) { - this.validationTimer = 0; - if (isAlive() && !this.onValidSurface()) { - kill(); - onBroken(null); - } - } - - } - - public boolean isVisible() { - if (!isAlive()) - return false; - if (level instanceof WrappedWorld) - return true; - - BlockPos pos = hangingPosition; - BlockPos pos2 = pos.relative(getFacingDirection().getOpposite()); - return isValidFace(level, pos2, getFacingDirection()) != isValidFace(level, pos, - getFacingDirection().getOpposite()); - } - - public boolean onValidSurface() { - BlockPos pos = hangingPosition; - BlockPos pos2 = hangingPosition.relative(getFacingDirection().getOpposite()); - if (level.isOutsideBuildHeight(pos2)) - return false; - if (!level.isLoaded(pos) || !level.isLoaded(pos2)) - return true; - if (!isValidFace(level, pos2, getFacingDirection()) - && !isValidFace(level, pos, getFacingDirection().getOpposite())) - return false; - if (isSideSticky(level, pos2, getFacingDirection()) - || isSideSticky(level, pos, getFacingDirection().getOpposite())) - return false; - return level.getEntities(this, getBoundingBox(), e -> e instanceof SuperGlueEntity) - .isEmpty(); - } - public static boolean isValidFace(Level world, BlockPos pos, Direction direction) { BlockState state = world.getBlockState(pos); if (BlockMovementChecks.isBlockAttachedTowards(state, world, pos, direction)) @@ -237,61 +134,36 @@ public class SuperGlueEntity extends Entity return false; } - @Override - public boolean isPickable() { - return true; - } - - @Override - public boolean skipAttackInteraction(Entity entity) { - return entity instanceof Player ? hurt(DamageSource.playerAttack((Player) entity), 0) : false; - } - - @Override - public Direction getDirection() { - return this.getFacingDirection(); - } - @Override public boolean hurt(DamageSource source, float amount) { - if (this.isInvulnerableTo(source)) - return false; + return false; + } - boolean mobGriefing = level.getGameRules() - .getBoolean(GameRules.RULE_MOBGRIEFING); - Entity trueSource = source.getEntity(); - if (!mobGriefing && trueSource instanceof Mob) - return false; + @Override + public void tick() { + super.tick(); + if (getBoundingBox().getXsize() == 0) + discard(); + } - Entity immediateSource = source.getDirectEntity(); - if (!isVisible() && immediateSource instanceof Player) { - if (!AllItems.SUPER_GLUE.isIn(((Player) immediateSource).getMainHandItem())) - return true; - } - - if (isAlive() && !level.isClientSide) { - onBroken(source.getEntity()); - kill(); - markHurt(); - } - - return true; + @Override + public void setPos(double x, double y, double z) { + setPosRaw(x, y, z); + getBoundingBox().move(getBoundingBox().getCenter() + .scale(-1) + .add(x, y, z)); } @Override public void move(MoverType typeIn, Vec3 pos) { - if (!level.isClientSide && isAlive() && pos.lengthSqr() > 0.0D) { + if (!level.isClientSide && isAlive() && pos.lengthSqr() > 0.0D) discard(); - onBroken(null); - } } @Override public void push(double x, double y, double z) { - if (!level.isClientSide && isAlive() && x * x + y * y + z * z > 0.0D) { + if (!level.isClientSide && isAlive() && x * x + y * y + z * z > 0.0D) discard(); - onBroken(null); - } } @Override @@ -299,9 +171,8 @@ public class SuperGlueEntity extends Entity return 0.0F; } - @Override - public ItemStack getPickedResult(HitResult target) { - return AllItems.SUPER_GLUE.asStack(); + public void playPlaceSound() { + AllSoundEvents.SLIME_ADDED.playFrom(this, 0.5F, 0.75F); } @Override @@ -311,79 +182,30 @@ public class SuperGlueEntity extends Entity @Override public InteractionResult interact(Player player, InteractionHand hand) { - if (player instanceof FakePlayer) - return InteractionResult.PASS; - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { - triggerPlaceBlock(player, hand); - }); - return InteractionResult.CONSUME; - } - - @OnlyIn(Dist.CLIENT) - private void triggerPlaceBlock(Player player, InteractionHand hand) { - if (!(player instanceof LocalPlayer)) - return; - if (!(player.level instanceof ClientLevel)) - return; - - LocalPlayer cPlayer = (LocalPlayer) player; - Minecraft mc = Minecraft.getInstance(); - HitResult ray = cPlayer.pick(mc.gameMode.getPickRange(), AnimationTickHolder.getPartialTicks(), false); - - if (!(ray instanceof BlockHitResult)) - return; - if (ray.getType() == Type.MISS) - return; - BlockHitResult blockRay = (BlockHitResult) ray; - BlockFace rayFace = new BlockFace(blockRay.getBlockPos(), blockRay.getDirection()); - BlockFace hangingFace = new BlockFace(getHangingPosition(), getFacingDirection().getOpposite()); - if (!rayFace.isEquivalent(hangingFace)) - return; - - for (InteractionHand handIn : InteractionHand.values()) { - ItemStack itemstack = cPlayer.getItemInHand(handIn); - int countBefore = itemstack.getCount(); - InteractionResult actionResultType = - mc.gameMode.useItemOn(cPlayer, (ClientLevel) cPlayer.level, handIn, blockRay); - if (actionResultType != InteractionResult.SUCCESS) - return; - - cPlayer.swing(handIn); - if (!itemstack.isEmpty() && (itemstack.getCount() != countBefore || mc.gameMode.hasInfiniteItems())) - mc.gameRenderer.itemInHandRenderer.itemUsed(handIn); - return; - } + return InteractionResult.PASS; } @Override public void addAdditionalSaveData(CompoundTag compound) { - compound.putByte("Facing", (byte) this.getFacingDirection() - .get3DDataValue()); - BlockPos blockpos = this.getHangingPosition(); - compound.putInt("TileX", blockpos.getX()); - compound.putInt("TileY", blockpos.getY()); - compound.putInt("TileZ", blockpos.getZ()); + Vec3 position = position(); + writeBoundingBox(compound, getBoundingBox().move(position.scale(-1))); } @Override public void readAdditionalSaveData(CompoundTag compound) { - this.hangingPosition = - new BlockPos(compound.getInt("TileX"), compound.getInt("TileY"), compound.getInt("TileZ")); - this.facingDirection = Direction.from3DDataValue(compound.getByte("Facing")); - updateFacingWithBoundingBox(); + Vec3 position = position(); + setBoundingBox(readBoundingBox(compound).move(position)); } - @Override - public ItemEntity spawnAtLocation(ItemStack stack, float yOffset) { - float xOffset = (float) this.getFacingDirection() - .getStepX() * 0.15F; - float zOffset = (float) this.getFacingDirection() - .getStepZ() * 0.15F; - ItemEntity itementity = - new ItemEntity(this.level, this.getX() + xOffset, this.getY() + yOffset, this.getZ() + zOffset, stack); - itementity.setDefaultPickUpDelay(); - this.level.addFreshEntity(itementity); - return itementity; + public static void writeBoundingBox(CompoundTag compound, AABB bb) { + compound.put("From", VecHelper.writeNBT(new Vec3(bb.minX, bb.minY, bb.minZ))); + compound.put("To", VecHelper.writeNBT(new Vec3(bb.maxX, bb.maxY, bb.maxZ))); + } + + public static AABB readBoundingBox(CompoundTag compound) { + Vec3 from = VecHelper.readNBT(compound.getList("From", Tag.TAG_DOUBLE)); + Vec3 to = VecHelper.readNBT(compound.getList("To", Tag.TAG_DOUBLE)); + return new AABB(from, to); } @Override @@ -391,51 +213,17 @@ public class SuperGlueEntity extends Entity return false; } - @Override - public void setPos(double x, double y, double z) { - hangingPosition = new BlockPos(x, y, z); - updateBoundingBox(); - hasImpulse = true; - } - @Override public float rotate(Rotation transformRotation) { - if (this.getFacingDirection() - .getAxis() != Direction.Axis.Y) { - switch (transformRotation) { - case CLOCKWISE_180: - facingDirection = facingDirection.getOpposite(); - break; - case COUNTERCLOCKWISE_90: - facingDirection = facingDirection.getCounterClockWise(); - break; - case CLOCKWISE_90: - facingDirection = facingDirection.getClockWise(); - default: - break; - } - } - - float f = Mth.wrapDegrees(this.getYRot()); - return switch (transformRotation) { - case CLOCKWISE_180 -> f + 180.0F; - case COUNTERCLOCKWISE_90 -> f + 90.0F; - case CLOCKWISE_90 -> f + 270.0F; - default -> f; - }; - } - - public BlockPos getHangingPosition() { - return this.hangingPosition; + AABB bb = getBoundingBox().move(position().scale(-1)); + if (transformRotation == Rotation.CLOCKWISE_90 || transformRotation == Rotation.COUNTERCLOCKWISE_90) + setBoundingBox(new AABB(bb.minZ, bb.minY, bb.minX, bb.maxZ, bb.maxY, bb.maxX).move(position())); + return super.rotate(transformRotation); } @Override public float mirror(Mirror transformMirror) { - return this.rotate(transformMirror.getRotation(this.getFacingDirection())); - } - - public Direction getAttachedDirection(BlockPos pos) { - return !pos.equals(hangingPosition) ? getFacingDirection() : getFacingDirection().getOpposite(); + return super.mirror(transformMirror); } @Override @@ -467,10 +255,6 @@ public class SuperGlueEntity extends Entity readAdditionalSaveData(additionalData.readNbt()); } - public Direction getFacingDirection() { - return facingDirection; - } - @Override public ItemRequirement getRequiredItems() { return new ItemRequirement(ItemUseType.DAMAGE, AllItems.SUPER_GLUE.get()); @@ -480,4 +264,53 @@ public class SuperGlueEntity extends Entity public boolean isIgnoringBlockTriggers() { return true; } + + public boolean contains(BlockPos pos) { + return getBoundingBox().contains(Vec3.atCenterOf(pos)); + } + + public void spawnParticles() { + AABB bb = getBoundingBox(); + Vec3 origin = new Vec3(bb.minX, bb.minY, bb.minZ); + Vec3 extents = new Vec3(bb.getXsize(), bb.getYsize(), bb.getZsize()); + + if (!(level instanceof ServerLevel slevel)) + return; + + for (Axis axis : Iterate.axes) { + AxisDirection positive = AxisDirection.POSITIVE; + double max = axis.choose(extents.x, extents.y, extents.z); + Vec3 normal = Vec3.atLowerCornerOf(Direction.fromAxisAndDirection(axis, positive) + .getNormal()); + for (Axis axis2 : Iterate.axes) { + if (axis2 == axis) + continue; + double max2 = axis2.choose(extents.x, extents.y, extents.z); + Vec3 normal2 = Vec3.atLowerCornerOf(Direction.fromAxisAndDirection(axis2, positive) + .getNormal()); + for (Axis axis3 : Iterate.axes) { + if (axis3 == axis2 || axis3 == axis) + continue; + double max3 = axis3.choose(extents.x, extents.y, extents.z); + Vec3 normal3 = Vec3.atLowerCornerOf(Direction.fromAxisAndDirection(axis3, positive) + .getNormal()); + + for (int i = 0; i <= max * 2; i++) { + for (int o1 : Iterate.zeroAndOne) { + for (int o2 : Iterate.zeroAndOne) { + Vec3 v = origin.add(normal.scale(i / 2f)) + .add(normal2.scale(max2 * o1)) + .add(normal3.scale(max3 * o2)); + + slevel.sendParticles(ParticleTypes.ITEM_SLIME, v.x, v.y, v.z, 1, 0, 0, 0, 0); + + } + } + } + break; + } + break; + } + } + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueHandler.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueHandler.java index 7d062dee7..66ed67c86 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueHandler.java @@ -1,11 +1,12 @@ package com.simibubi.create.content.contraptions.components.structureMovement.glue; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.HashSet; +import java.util.Set; import com.simibubi.create.AllItems; +import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementChecks; import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.placement.IPlacementHelper; import com.simibubi.create.foundation.utility.worldWrappers.RayTraceWorld; @@ -21,7 +22,6 @@ import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult.Type; import net.minecraft.world.phys.Vec3; @@ -34,14 +34,6 @@ import net.minecraftforge.network.PacketDistributor; @EventBusSubscriber public class SuperGlueHandler { - public static Map gatherGlue(LevelAccessor world, BlockPos pos) { - List entities = world.getEntitiesOfClass(SuperGlueEntity.class, new AABB(pos)); - Map map = new HashMap<>(); - for (SuperGlueEntity entity : entities) - map.put(entity.getAttachedDirection(pos), entity); - return map; - } - @SubscribeEvent public static void glueListensForBlockPlacement(EntityPlaceEvent event) { LevelAccessor world = event.getWorld(); @@ -53,10 +45,14 @@ public class SuperGlueHandler { if (world.isClientSide()) return; - Map gatheredGlue = gatherGlue(world, pos); - for (Direction direction : gatheredGlue.keySet()) - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> entity), - new GlueEffectPacket(pos, direction, true)); + Set cached = new HashSet<>(); + for (Direction direction : Iterate.directions) { + BlockPos relative = pos.relative(direction); + if (SuperGlueEntity.isGlued(world, pos, direction, cached) + && BlockMovementChecks.isMovementNecessary(world.getBlockState(relative), entity.level, relative)) + AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> entity), + new GlueEffectPacket(pos, direction, true)); + } if (entity instanceof Player) glueInOffHandAppliesOnBlockPlace(event, pos, (Player) entity); @@ -80,31 +76,33 @@ public class SuperGlueHandler { RayTraceWorld rayTraceWorld = new RayTraceWorld(world, (p, state) -> p.equals(pos) ? Blocks.AIR.defaultBlockState() : state); - BlockHitResult ray = rayTraceWorld.clip( - new ClipContext(start, end, ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, placer)); + BlockHitResult ray = + rayTraceWorld.clip(new ClipContext(start, end, ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, placer)); Direction face = ray.getDirection(); if (face == null || ray.getType() == Type.MISS) return; - if (!ray.getBlockPos() - .relative(face) + BlockPos gluePos = ray.getBlockPos(); + if (!gluePos.relative(face) .equals(pos)) { event.setCanceled(true); return; } - SuperGlueEntity entity = new SuperGlueEntity(world, ray.getBlockPos(), face.getOpposite()); + if (SuperGlueEntity.isGlued(world, gluePos, face, null)) + return; + + SuperGlueEntity entity = new SuperGlueEntity(world, SuperGlueEntity.span(gluePos, gluePos.relative(face))); CompoundTag compoundnbt = itemstack.getTag(); if (compoundnbt != null) EntityType.updateCustomEntityTag(world, placer, entity, compoundnbt); - if (entity.onValidSurface()) { + if (SuperGlueEntity.isValidFace(world, gluePos, face)) { if (!world.isClientSide) { - entity.playPlaceSound(); world.addFreshEntity(entity); AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> entity), - new GlueEffectPacket(ray.getBlockPos(), face, true)); + new GlueEffectPacket(gluePos, face, true)); } itemstack.hurtAndBreak(1, placer, SuperGlueItem::onBroken); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueItem.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueItem.java index 151a9024e..feacc0e42 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueItem.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueItem.java @@ -7,15 +7,11 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.particles.ItemParticleOption; import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.nbt.CompoundTag; import net.minecraft.util.Mth; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; -import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; @@ -49,47 +45,17 @@ public class SuperGlueItem extends Item { super(properties); } + @Override + public boolean canAttackBlock(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer) { + return false; + } + @Override public boolean canBeDepleted() { return true; } - @Override - public InteractionResult useOn(UseOnContext context) { - BlockPos blockpos = context.getClickedPos(); - Direction direction = context.getClickedFace(); - BlockPos blockpos1 = blockpos.relative(direction); - Player playerentity = context.getPlayer(); - ItemStack itemstack = context.getItemInHand(); - - if (playerentity == null || !this.canPlace(playerentity, direction, itemstack, blockpos1)) - return InteractionResult.FAIL; - - Level world = context.getLevel(); - SuperGlueEntity entity = new SuperGlueEntity(world, blockpos1, direction); - CompoundTag compoundnbt = itemstack.getTag(); - if (compoundnbt != null) - EntityType.updateCustomEntityTag(world, playerentity, entity, compoundnbt); - - if (!entity.onValidSurface()) - return InteractionResult.FAIL; - - if (!world.isClientSide) { - entity.playPlaceSound(); - world.addFreshEntity(entity); - } - itemstack.hurtAndBreak(1, playerentity, SuperGlueItem::onBroken); - - return InteractionResult.SUCCESS; - } - - public static void onBroken(Player player) { - - } - - protected boolean canPlace(Player entity, Direction facing, ItemStack stack, BlockPos pos) { - return !entity.level.isOutsideBuildHeight(pos) && entity.mayUseItemAt(pos, facing, stack); - } + public static void onBroken(Player player) {} @OnlyIn(Dist.CLIENT) public static void spawnParticles(Level world, BlockPos pos, Direction direction, boolean fullBlock) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueRemovalPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueRemovalPacket.java new file mode 100644 index 000000000..cab9c41cd --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueRemovalPacket.java @@ -0,0 +1,53 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.glue; + +import java.util.function.Supplier; + +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraftforge.network.NetworkEvent.Context; + +public class SuperGlueRemovalPacket extends SimplePacketBase { + + private int entityId; + private BlockPos soundSource; + + public SuperGlueRemovalPacket(int id, BlockPos soundSource) { + entityId = id; + this.soundSource = soundSource; + } + + public SuperGlueRemovalPacket(FriendlyByteBuf buffer) { + entityId = buffer.readInt(); + soundSource = buffer.readBlockPos(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(entityId); + buffer.writeBlockPos(soundSource); + } + + @Override + public void handle(Supplier context) { + Context ctx = context.get(); + ctx.enqueueWork(() -> { + ServerPlayer player = ctx.getSender(); + Entity entity = player.level.getEntity(entityId); + if (!(entity instanceof SuperGlueEntity superGlue)) + return; + double range = 32; + if (player.distanceToSqr(superGlue.position()) > range * range) + return; + AllSoundEvents.SLIME_ADDED.play(player.level, null, soundSource, 0.5F, 0.5F); + superGlue.spawnParticles(); + entity.discard(); + }); + ctx.setPacketHandled(true); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueRenderer.java index adbea90be..8c6beab89 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueRenderer.java @@ -1,146 +1,27 @@ package com.simibubi.create.content.contraptions.components.structureMovement.glue; -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.PoseStack.Pose; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllItems; -import com.simibubi.create.Create; -import com.simibubi.create.foundation.utility.AngleHelper; -import com.simibubi.create.foundation.utility.VecHelper; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.culling.Frustum; import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.client.renderer.entity.EntityRendererProvider; -import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.Vec3; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @OnlyIn(Dist.CLIENT) public class SuperGlueRenderer extends EntityRenderer { - private ResourceLocation regular = Create.asResource("textures/entity/super_glue/slime.png"); - - private float[] insideQuad; - private float[] outsideQuad; - public SuperGlueRenderer(EntityRendererProvider.Context context) { super(context); - initQuads(); } @Override public ResourceLocation getTextureLocation(SuperGlueEntity entity) { - return regular; + return null; } @Override public boolean shouldRender(SuperGlueEntity entity, Frustum frustum, double x, double y, double z) { - if (super.shouldRender(entity, frustum, x, y, z)) { - Player player = Minecraft.getInstance().player; - boolean visible = entity.isVisible(); - boolean holdingGlue = AllItems.SUPER_GLUE.isIn(player.getMainHandItem()) - || AllItems.SUPER_GLUE.isIn(player.getOffhandItem()); - - if (visible || holdingGlue) - return true; - } return false; } - @Override - public void render(SuperGlueEntity entity, float yaw, float partialTicks, PoseStack ms, - MultiBufferSource buffer, int light) { - super.render(entity, yaw, partialTicks, ms, buffer, light); - - VertexConsumer builder = buffer.getBuffer(RenderType.entityCutout(getTextureLocation(entity))); - light = getBrightnessForRender(entity); - Direction face = entity.getFacingDirection(); - - ms.pushPose(); - TransformStack.cast(ms) - .rotateY(AngleHelper.horizontalAngle(face)) - .rotateX(AngleHelper.verticalAngle(face)); - Pose peek = ms.last(); - - renderQuad(builder, peek, insideQuad, light, -1); - renderQuad(builder, peek, outsideQuad, light, 1); - - ms.popPose(); - } - - private void initQuads() { - Vec3 diff = Vec3.atLowerCornerOf(Direction.SOUTH.getNormal()); - Vec3 extension = diff.normalize() - .scale(1 / 32f - 1 / 128f); - - Vec3 plane = VecHelper.axisAlingedPlaneOf(diff); - Axis axis = Direction.getNearest(diff.x, diff.y, diff.z) - .getAxis(); - - Vec3 start = Vec3.ZERO.subtract(extension); - Vec3 end = Vec3.ZERO.add(extension); - - plane = plane.scale(1 / 2f); - Vec3 a1 = plane.add(start); - Vec3 b1 = plane.add(end); - plane = VecHelper.rotate(plane, -90, axis); - Vec3 a2 = plane.add(start); - Vec3 b2 = plane.add(end); - plane = VecHelper.rotate(plane, -90, axis); - Vec3 a3 = plane.add(start); - Vec3 b3 = plane.add(end); - plane = VecHelper.rotate(plane, -90, axis); - Vec3 a4 = plane.add(start); - Vec3 b4 = plane.add(end); - - insideQuad = new float[] { - (float) a1.x, (float) a1.y, (float) a1.z, 1, 0, - (float) a2.x, (float) a2.y, (float) a2.z, 1, 1, - (float) a3.x, (float) a3.y, (float) a3.z, 0, 1, - (float) a4.x, (float) a4.y, (float) a4.z, 0, 0, - }; - outsideQuad = new float[] { - (float) b4.x, (float) b4.y, (float) b4.z, 0, 0, - (float) b3.x, (float) b3.y, (float) b3.z, 0, 1, - (float) b2.x, (float) b2.y, (float) b2.z, 1, 1, - (float) b1.x, (float) b1.y, (float) b1.z, 1, 0, - }; - } - - private int getBrightnessForRender(SuperGlueEntity entity) { - BlockPos blockpos = entity.getHangingPosition(); - BlockPos blockpos2 = blockpos.relative(entity.getFacingDirection() - .getOpposite()); - - Level world = entity.getCommandSenderWorld(); - int light = world.isLoaded(blockpos) ? LevelRenderer.getLightColor(world, blockpos) : 15; - int light2 = world.isLoaded(blockpos2) ? LevelRenderer.getLightColor(world, blockpos2) : 15; - return Math.max(light, light2); - } - - // Vertex format: pos x, pos y, pos z, u, v - private void renderQuad(VertexConsumer builder, Pose matrix, float[] data, int light, float normalZ) { - for (int i = 0; i < 4; i++) { - builder.vertex(matrix.pose(), data[5 * i], data[5 * i + 1], data[5 * i + 2]) - .color(255, 255, 255, 255) - .uv(data[5 * i + 3], data[5 * i + 4]) - .overlayCoords(OverlayTexture.NO_OVERLAY) - .uv2(light) - .normal(matrix.normal(), 0.0f, 0.0f, normalZ) - .endVertex(); - } - } - } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionHandler.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionHandler.java index a5cca8d75..fa387da25 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionHandler.java @@ -1,42 +1,53 @@ package com.simibubi.create.content.contraptions.components.structureMovement.glue; import java.util.List; +import java.util.Optional; import java.util.Set; import com.google.common.base.Objects; +import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSpecialTextures; import com.simibubi.create.CreateClient; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.AbstractChassisBlock; import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.utility.BlockFace; import com.simibubi.create.foundation.utility.Lang; -import com.simibubi.create.foundation.utility.Pair; -import com.simibubi.create.foundation.utility.outliner.Outline.OutlineParams; +import com.simibubi.create.foundation.utility.RaycastHelper; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult.Type; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.ForgeMod; public class SuperGlueSelectionHandler { - private static final int SUCCESS = 0x68c586; + private static final int PASSIVE = 0x4D9162; + private static final int HIGHLIGHT = 0x68c586; private static final int FAIL = 0xc5b548; private Object clusterOutlineSlot = new Object(); private Object bbOutlineSlot = new Object(); + private int clusterCooldown; private BlockPos firstPos; private BlockPos hoveredPos; private Set currentCluster; private int glueRequired; + private SuperGlueEntity selected; + private BlockPos soundSourceForRemoval; + public void tick() { Minecraft mc = Minecraft.getInstance(); LocalPlayer player = mc.player; @@ -49,6 +60,51 @@ public class SuperGlueSelectionHandler { return; } + if (clusterCooldown > 0) { + if (clusterCooldown == 25) + player.displayClientMessage(TextComponent.EMPTY, true); + CreateClient.OUTLINER.keep(clusterOutlineSlot); + clusterCooldown--; + } + + AABB scanArea = player.getBoundingBox() + .inflate(32, 16, 32); + + List glueNearby = mc.level.getEntitiesOfClass(SuperGlueEntity.class, scanArea); + + selected = null; + if (firstPos == null) { + double range = player.getAttribute(ForgeMod.REACH_DISTANCE.get()) + .getValue() + 1; + Vec3 traceOrigin = RaycastHelper.getTraceOrigin(player); + Vec3 traceTarget = RaycastHelper.getTraceTarget(player, range, traceOrigin); + + double bestDistance = Double.MAX_VALUE; + for (SuperGlueEntity glueEntity : glueNearby) { + Optional clip = glueEntity.getBoundingBox() + .clip(traceOrigin, traceTarget); + if (clip.isEmpty()) + continue; + Vec3 vec3 = clip.get(); + double distanceToSqr = vec3.distanceToSqr(traceOrigin); + if (distanceToSqr > bestDistance) + continue; + selected = glueEntity; + soundSourceForRemoval = new BlockPos(vec3); + bestDistance = distanceToSqr; + } + + for (SuperGlueEntity glueEntity : glueNearby) { + boolean h = clusterCooldown == 0 && glueEntity == selected; + AllSpecialTextures faceTex = h ? AllSpecialTextures.GLUE : null; + CreateClient.OUTLINER.showAABB(glueEntity, glueEntity.getBoundingBox()) + .colored(h ? HIGHLIGHT : PASSIVE) + .withFaceTextures(faceTex, faceTex) + .disableNormals() + .lineWidth(h ? 1 / 16f : 1 / 64f); + } + } + HitResult hitResult = mc.hitResult; if (hitResult != null && hitResult.getType() == Type.BLOCK) hovered = ((BlockHitResult) hitResult).getBlockPos(); @@ -83,33 +139,29 @@ public class SuperGlueSelectionHandler { else if (cancel) Lang.sendStatus(player, FAIL, "super_glue.click_to_discard"); else - Lang.sendStatus(player, SUCCESS, "super_glue.click_to_confirm"); + Lang.sendStatus(player, HIGHLIGHT, "super_glue.click_to_confirm"); + + if (currentSelectionBox != null) + CreateClient.OUTLINER.showAABB(bbOutlineSlot, currentSelectionBox) + .colored(canReach && canAfford && !cancel ? HIGHLIGHT : FAIL) + .withFaceTextures(AllSpecialTextures.GLUE, AllSpecialTextures.GLUE) + .disableNormals() + .lineWidth(1 / 16f); CreateClient.OUTLINER.showCluster(clusterOutlineSlot, currentCluster) - .colored(canReach && canAfford && !cancel ? SUCCESS : FAIL) - .withFaceTextures(AllSpecialTextures.CHECKERED, AllSpecialTextures.HIGHLIGHT_CHECKERED) - .lineWidth(1 / 16f); - } - if (currentSelectionBox != null) { - OutlineParams params = - firstPos == null ? CreateClient.OUTLINER.showAABB(bbOutlineSlot, currentSelectionBox) - : CreateClient.OUTLINER.chaseAABB(bbOutlineSlot, currentSelectionBox); - params.colored(0x111111) + .colored(0x4D9162) .disableNormals() - .lineWidth(1 / 128f); + .lineWidth(1 / 64f); } + return; } hoveredPos = hovered; - Pair, List> pair = - SuperGlueSelectionHelper.searchGlueGroup(mc.level, firstPos, hoveredPos); - - currentCluster = pair == null ? null : pair.getFirst(); - glueRequired = pair == null ? 0 - : pair.getSecond() - .size(); + Set cluster = SuperGlueSelectionHelper.searchGlueGroup(mc.level, firstPos, hoveredPos, true); + currentCluster = cluster; + glueRequired = 1; } private boolean isGlue(ItemStack stack) { @@ -120,7 +172,7 @@ public class SuperGlueSelectionHandler { return firstPos == null || hoveredPos == null ? null : new AABB(firstPos, hoveredPos).expandTowards(1, 1, 1); } - public boolean onMouseInput() { + public boolean onMouseInput(boolean attack) { Minecraft mc = Minecraft.getInstance(); LocalPlayer player = mc.player; ClientLevel level = mc.level; @@ -128,6 +180,15 @@ public class SuperGlueSelectionHandler { if (!isGlue(player.getMainHandItem())) return false; + if (attack) { + if (selected == null) + return false; + AllPackets.channel.sendToServer(new SuperGlueRemovalPacket(selected.getId(), soundSourceForRemoval)); + selected = null; + clusterCooldown = 0; + return true; + } + if (player.isSteppingCarefully()) { if (firstPos != null) { discard(); @@ -139,7 +200,9 @@ public class SuperGlueSelectionHandler { if (hoveredPos == null) return false; + Direction face = null; if (mc.hitResult instanceof BlockHitResult bhr) { + face = bhr.getDirection(); BlockState blockState = level.getBlockState(hoveredPos); if (blockState.getBlock()instanceof AbstractChassisBlock cb) if (cb.getGlueableSide(blockState, bhr.getDirection()) != null) @@ -158,7 +221,11 @@ public class SuperGlueSelectionHandler { } firstPos = hoveredPos; + if (face != null) + SuperGlueItem.spawnParticles(level, firstPos, face, true); Lang.sendStatus(player, "super_glue.first_pos"); + AllSoundEvents.SLIME_ADDED.playAt(level, firstPos, 0.5F, 0.85F, false); + level.playSound(player, firstPos, SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, 0.75f, 1); return true; } @@ -167,13 +234,25 @@ public class SuperGlueSelectionHandler { currentCluster = null; firstPos = null; Lang.sendStatus(player, "super_glue.abort"); + clusterCooldown = 0; } public void confirm() { LocalPlayer player = Minecraft.getInstance().player; AllPackets.channel.sendToServer(new SuperGlueSelectionPacket(firstPos, hoveredPos)); + AllSoundEvents.SLIME_ADDED.playAt(player.level, hoveredPos, 0.5F, 0.95F, false); + player.level.playSound(player, hoveredPos, SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, 0.75f, 1); + + if (currentCluster != null) + CreateClient.OUTLINER.showCluster(clusterOutlineSlot, currentCluster) + .colored(0xB5F2C6) + .withFaceTextures(AllSpecialTextures.GLUE, AllSpecialTextures.HIGHLIGHT_CHECKERED) + .disableNormals() + .lineWidth(1 / 24f); + discard(); Lang.sendStatus(player, "super_glue.sucess"); + clusterCooldown = 40; } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionHelper.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionHelper.java index 7c9e426f0..4089269d5 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionHelper.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionHelper.java @@ -3,13 +3,10 @@ package com.simibubi.create.content.contraptions.components.structureMovement.gl import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementChecks; -import com.simibubi.create.foundation.utility.BlockFace; import com.simibubi.create.foundation.utility.Iterate; -import com.simibubi.create.foundation.utility.Pair; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -22,17 +19,16 @@ import net.minecraft.world.phys.Vec3; public class SuperGlueSelectionHelper { - public static Pair, List> searchGlueGroup(Level level, BlockPos startPos, - BlockPos endPos) { + public static Set searchGlueGroup(Level level, BlockPos startPos, BlockPos endPos, boolean includeOther) { if (endPos == null || startPos == null) return null; - AABB bb = new AABB(startPos, endPos).expandTowards(1, 1, 1); + AABB bb = SuperGlueEntity.span(startPos, endPos); List frontier = new ArrayList<>(); Set visited = new HashSet<>(); Set attached = new HashSet<>(); - List glue = new ArrayList<>(); + Set cachedOther = new HashSet<>(); visited.add(startPos); frontier.add(startPos); @@ -41,11 +37,10 @@ public class SuperGlueSelectionHelper { BlockPos currentPos = frontier.remove(0); attached.add(currentPos); - Map gatheredGlue = SuperGlueHandler.gatherGlue(level, currentPos); for (Direction d : Iterate.directions) { BlockPos offset = currentPos.relative(d); - boolean gluePresent = gatheredGlue.containsKey(d); - boolean alreadySticky = SuperGlueEntity.isSideSticky(level, currentPos, d) + boolean gluePresent = includeOther && SuperGlueEntity.isGlued(level, currentPos, d, cachedOther); + boolean alreadySticky = includeOther && SuperGlueEntity.isSideSticky(level, currentPos, d) || SuperGlueEntity.isSideSticky(level, offset, d.getOpposite()); if (!alreadySticky && !gluePresent && !bb.contains(Vec3.atCenterOf(offset))) @@ -56,20 +51,15 @@ public class SuperGlueSelectionHelper { || !SuperGlueEntity.isValidFace(level, offset, d.getOpposite())) continue; - boolean glueNecessary = !gluePresent && !alreadySticky; - - if (visited.add(offset)) { + if (visited.add(offset)) frontier.add(offset); - if (glueNecessary) - glue.add(new BlockFace(offset, d)); - } } } if (attached.size() < 2 && attached.contains(endPos)) return null; - return Pair.of(attached, glue); + return attached; } public static boolean collectGlueFromInventory(Player player, int requiredAmount, boolean simulate) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionPacket.java index 15420a95a..2d4c9faa4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionPacket.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionPacket.java @@ -1,17 +1,14 @@ package com.simibubi.create.content.contraptions.components.structureMovement.glue; -import java.util.List; import java.util.Set; import java.util.function.Supplier; -import com.simibubi.create.Create; import com.simibubi.create.foundation.networking.SimplePacketBase; -import com.simibubi.create.foundation.utility.BlockFace; -import com.simibubi.create.foundation.utility.Pair; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.ForgeMod; import net.minecraftforge.network.NetworkEvent.Context; @@ -50,19 +47,19 @@ public class SuperGlueSelectionPacket extends SimplePacketBase { if (!to.closerThan(from, 25)) return; - Pair, List> group = - SuperGlueSelectionHelper.searchGlueGroup(player.level, from, to); + Set group = SuperGlueSelectionHelper.searchGlueGroup(player.level, from, to, false); if (group == null) return; - if (!group.getFirst() - .contains(to)) + if (!group.contains(to)) return; - List glue = group.getSecond(); - if (!SuperGlueSelectionHelper.collectGlueFromInventory(player, glue.size(), true)) + if (!SuperGlueSelectionHelper.collectGlueFromInventory(player, 1, true)) return; - - SuperGlueSelectionHelper.collectGlueFromInventory(player, glue.size(), false); - Create.GLUE_QUEUE.add(player.level, glue); + + AABB bb = SuperGlueEntity.span(from, to); + SuperGlueSelectionHelper.collectGlueFromInventory(player, 1, false); + SuperGlueEntity entity = new SuperGlueEntity(player.level, bb); + player.level.addFreshEntity(entity); + entity.spawnParticles(); }); ctx.setPacketHandled(true); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/package-info.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/package-info.java deleted file mode 100644 index 18cc22daf..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -package com.simibubi.create.content.contraptions.components.structureMovement.glue; - -import javax.annotation.ParametersAreNonnullByDefault; - -import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/simibubi/create/events/CommonEvents.java b/src/main/java/com/simibubi/create/events/CommonEvents.java index 720916cee..57582f7a0 100644 --- a/src/main/java/com/simibubi/create/events/CommonEvents.java +++ b/src/main/java/com/simibubi/create/events/CommonEvents.java @@ -122,7 +122,6 @@ public class CommonEvents { LinkedControllerServerHandler.tick(world); ControlsServerHandler.tick(world); Create.RAILWAYS.tick(world); - Create.GLUE_QUEUE.tick(world); } @SubscribeEvent diff --git a/src/main/java/com/simibubi/create/events/InputEvents.java b/src/main/java/com/simibubi/create/events/InputEvents.java index fa30d1fdf..25eb34b58 100644 --- a/src/main/java/com/simibubi/create/events/InputEvents.java +++ b/src/main/java/com/simibubi/create/events/InputEvents.java @@ -8,6 +8,7 @@ import com.simibubi.create.content.logistics.trains.track.CurvedTrackInteraction import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringHandler; import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueHandler; +import net.minecraft.client.KeyMapping; import net.minecraft.client.Minecraft; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.InputEvent.ClickInputEvent; @@ -68,12 +69,14 @@ public class InputEvents { return; } - if (event.getKeyMapping() == mc.options.keyUse) { - if (CreateClient.GLUE_HANDLER.onMouseInput()) + KeyMapping key = event.getKeyMapping(); + + if (key == mc.options.keyUse || key == mc.options.keyAttack) { + if (CreateClient.GLUE_HANDLER.onMouseInput(key == mc.options.keyAttack)) event.setCanceled(true); } - if (event.getKeyMapping() == mc.options.keyPickItem) { + if (key == mc.options.keyPickItem) { if (ToolboxHandlerClient.onPickItem()) event.setCanceled(true); return; diff --git a/src/main/java/com/simibubi/create/foundation/command/CloneCommand.java b/src/main/java/com/simibubi/create/foundation/command/CloneCommand.java index 3a848952b..524c78b3f 100644 --- a/src/main/java/com/simibubi/create/foundation/command/CloneCommand.java +++ b/src/main/java/com/simibubi/create/foundation/command/CloneCommand.java @@ -92,19 +92,19 @@ public class CloneCommand { List glue = world.getEntitiesOfClass(SuperGlueEntity.class, AABB.of(sourceArea)); List> newGlue = Lists.newArrayList(); - for (SuperGlueEntity g : glue) { - BlockPos pos = g.getHangingPosition(); - Direction direction = g.getFacingDirection(); - newGlue.add(Pair.of(pos.offset(diffToTarget), direction)); - } - - for (Pair p : newGlue) { - SuperGlueEntity g = new SuperGlueEntity(world, p.getFirst(), p.getSecond()); - if (g.onValidSurface()) { - world.addFreshEntity(g); - gluePastes++; - } - } +// for (SuperGlueEntity g : glue) {TODO +// BlockPos pos = g.getHangingPosition(); +// Direction direction = g.getFacingDirection(); +// newGlue.add(Pair.of(pos.offset(diffToTarget), direction)); +// } +// +// for (Pair p : newGlue) { +// SuperGlueEntity g = new SuperGlueEntity(world, p.getFirst(), p.getSecond()); +// if (g.onValidSurface()) { +// world.addFreshEntity(g); +// gluePastes++; +// } +// } return gluePastes; } diff --git a/src/main/java/com/simibubi/create/foundation/command/GlueCommand.java b/src/main/java/com/simibubi/create/foundation/command/GlueCommand.java index 61c56712c..461fff603 100644 --- a/src/main/java/com/simibubi/create/foundation/command/GlueCommand.java +++ b/src/main/java/com/simibubi/create/foundation/command/GlueCommand.java @@ -7,26 +7,26 @@ import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.commands.arguments.coordinates.BlockPosArgument; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; public class GlueCommand { public static ArgumentBuilder register() { return Commands.literal("glue") - .requires(cs -> cs.hasPermission(2)) - .then(Commands.argument("pos", BlockPosArgument.blockPos()) - //.then(Commands.argument("direction", EnumArgument.enumArgument(Direction.class)) - .executes(ctx -> { - BlockPos pos = BlockPosArgument.getLoadedBlockPos(ctx, "pos"); + .requires(cs -> cs.hasPermission(2)) + .then(Commands.argument("from", BlockPosArgument.blockPos()) + .then(Commands.argument("to", BlockPosArgument.blockPos()) + .executes(ctx -> { + BlockPos from = BlockPosArgument.getLoadedBlockPos(ctx, "from"); + BlockPos to = BlockPosArgument.getLoadedBlockPos(ctx, "to"); - ServerLevel world = ctx.getSource().getLevel(); - SuperGlueEntity entity = new SuperGlueEntity(world, pos, Direction.UP); + ServerLevel world = ctx.getSource() + .getLevel(); - entity.playPlaceSound(); - world.addFreshEntity(entity); - - return 1; - })); + SuperGlueEntity entity = new SuperGlueEntity(world, SuperGlueEntity.span(from, to)); + entity.playPlaceSound(); + world.addFreshEntity(entity); + return 1; + }))); } } diff --git a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java index 3d88c566f..d86b30875 100644 --- a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java +++ b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java @@ -12,6 +12,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Con import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionStallPacket; import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryContraptionUpdatePacket; import com.simibubi.create.content.contraptions.components.structureMovement.glue.GlueEffectPacket; +import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueRemovalPacket; import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueSelectionPacket; import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsInputPacket; import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsStopControllingPacket; @@ -130,6 +131,7 @@ public enum AllPackets { SELECT_CURVED_TRACK(CurvedTrackSelectionPacket.class, CurvedTrackSelectionPacket::new, PLAY_TO_SERVER), PLACE_CURVED_TRACK(PlaceExtendedCurvePacket.class, PlaceExtendedCurvePacket::new, PLAY_TO_SERVER), GLUE_IN_AREA(SuperGlueSelectionPacket.class, SuperGlueSelectionPacket::new, PLAY_TO_SERVER), + GLUE_REMOVED(SuperGlueRemovalPacket.class, SuperGlueRemovalPacket::new, PLAY_TO_SERVER), // Server to Client SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new, PLAY_TO_CLIENT), diff --git a/src/main/java/com/simibubi/create/foundation/ponder/SceneBuilder.java b/src/main/java/com/simibubi/create/foundation/ponder/SceneBuilder.java index 3e4fa29bb..ec1d521de 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/SceneBuilder.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/SceneBuilder.java @@ -13,7 +13,6 @@ import com.simibubi.create.content.contraptions.base.KineticBlock; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.components.crafter.ConnectedInputHandler; import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueItem; import com.simibubi.create.content.contraptions.fluids.PumpTileEntity; import com.simibubi.create.content.contraptions.particle.RotationIndicatorParticleData; @@ -661,11 +660,6 @@ public class SceneBuilder { }); } - public ElementLink createGlueEntity(BlockPos pos, Direction face) { - effects.superGlue(pos, face, false); - return createEntity(world -> new SuperGlueEntity(world, pos, face.getOpposite())); - } - public void createItemOnBeltLike(BlockPos location, Direction insertionSide, ItemStack stack) { addInstruction(scene -> { PonderWorld world = scene.getWorld(); diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/ChassisScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/ChassisScenes.java index 6799f54b3..d3e283f94 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/content/ChassisScenes.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/ChassisScenes.java @@ -253,7 +253,7 @@ public class ChassisScenes { scene.overlay.showControls(new InputWindowElement(glueSurface, Pointing.DOWN).rightClick() .withItem(AllItems.SUPER_GLUE.asStack()), 30); scene.idle(7); - ElementLink glueEntity = scene.world.createGlueEntity(chassisPos.west(), Direction.NORTH); +// ElementLink glueEntity = scene.world.createGlueEntity(chassisPos.west(), Direction.NORTH);TODO scene.idle(20); ElementLink gluedPlank = scene.world.showIndependentSection(util.select.position(3, 3, 1), Direction.SOUTH); @@ -262,7 +262,7 @@ public class ChassisScenes { scene.effects.superGlue(chassisPos.west(), Direction.NORTH, true); scene.idle(20); - scene.world.modifyEntity(glueEntity, Entity::discard); +// scene.world.modifyEntity(glueEntity, Entity::discard); scene.world.hideIndependentSection(glassSection, Direction.UP); scene.world.hideIndependentSection(gluedPlank, Direction.UP); scene.world.hideIndependentSection(topGlassSection, Direction.UP); @@ -499,7 +499,7 @@ public class ChassisScenes { scene.overlay.showControls(new InputWindowElement(blockSurface, Pointing.DOWN).rightClick() .withItem(AllItems.SUPER_GLUE.asStack()), 40); scene.idle(7); - ElementLink glueEntity = scene.world.createGlueEntity(central, Direction.NORTH); +// ElementLink glueEntity = scene.world.createGlueEntity(central, Direction.NORTH);TODO scene.idle(10); scene.overlay.showText(60) .pointAt(blockSurface) @@ -510,7 +510,7 @@ public class ChassisScenes { scene.world.glueBlockOnto(central.north(), Direction.SOUTH, plank); scene.idle(20); - scene.world.modifyEntity(glueEntity, Entity::discard); +// scene.world.modifyEntity(glueEntity, Entity::discard); BlockPos bearingPos = util.grid.at(2, 1, 2); scene.world.configureCenterOfRotation(plank, util.vector.centerOf(bearingPos)); @@ -553,13 +553,13 @@ public class ChassisScenes { scene.world.rotateSection(plank, 0, 360, 0, 80); scene.idle(90); - glueEntity = scene.world.createGlueEntity(central, Direction.UP); +// glueEntity = scene.world.createGlueEntity(central, Direction.UP);TODO scene.world.destroyBlock(central.above()); scene.idle(20); scene.addKeyframe(); scene.overlay.showControls(new InputWindowElement(util.vector.topOf(central), Pointing.DOWN).leftClick(), 40); scene.idle(7); - scene.world.modifyEntity(glueEntity, Entity::discard); +// scene.world.modifyEntity(glueEntity, Entity::discard); scene.effects.superGlue(central, Direction.UP, false); scene.idle(10); scene.overlay.showText(60) diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/BlockClusterOutline.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/BlockClusterOutline.java index fb914f2cb..0f005a5bb 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/outliner/BlockClusterOutline.java +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/BlockClusterOutline.java @@ -55,27 +55,47 @@ public class BlockClusterOutline extends Outline { }); } + static Vec3 xyz = new Vec3(-.5, -.5, -.5); + static Vec3 Xyz = new Vec3(.5, -.5, -.5); + static Vec3 xYz = new Vec3(-.5, .5, -.5); + static Vec3 XYz = new Vec3(.5, .5, -.5); + static Vec3 xyZ = new Vec3(-.5, -.5, .5); + static Vec3 XyZ = new Vec3(.5, -.5, .5); + static Vec3 xYZ = new Vec3(-.5, .5, .5); + static Vec3 XYZ = new Vec3(.5, .5, .5); + protected void renderBlockFace(PoseStack ms, VertexConsumer builder, BlockPos pos, Direction face) { Vec3 center = VecHelper.getCenterOf(pos); Vec3 offset = Vec3.atLowerCornerOf(face.getNormal()); - Vec3 plane = VecHelper.axisAlingedPlaneOf(offset); - Axis axis = face.getAxis(); + offset = offset.scale(1 / 128d); + center = center.add(offset); - offset = offset.scale(1 / 2f + 1 / 128d); - plane = plane.scale(1 / 2f) - .add(offset); + ms.pushPose(); + ms.translate(center.x, center.y, center.z); - int deg = face.getAxisDirection() - .getStep() * 90; - Vec3 a1 = plane.add(center); - plane = VecHelper.rotate(plane, deg, axis); - Vec3 a2 = plane.add(center); - plane = VecHelper.rotate(plane, deg, axis); - Vec3 a3 = plane.add(center); - plane = VecHelper.rotate(plane, deg, axis); - Vec3 a4 = plane.add(center); + switch (face) { + case DOWN: + putQuad(ms, builder, xyz, Xyz, XyZ, xyZ, face); + break; + case EAST: + putQuad(ms, builder, XYz, XYZ, XyZ, Xyz, face); + break; + case NORTH: + putQuad(ms, builder, xYz, XYz, Xyz, xyz, face); + break; + case SOUTH: + putQuad(ms, builder, XYZ, xYZ, xyZ, XyZ, face); + break; + case UP: + putQuad(ms, builder, xYZ, XYZ, XYz, xYz, face); + break; + case WEST: + putQuad(ms, builder, xYZ, xYz, xyz, xyZ, face); + default: + break; + } - putQuad(ms, builder, a1, a2, a3, a4, face); + ms.popPose(); } private static class Cluster { diff --git a/src/main/resources/assets/create/textures/special/glue.png b/src/main/resources/assets/create/textures/special/glue.png new file mode 100644 index 000000000..7060f03f8 Binary files /dev/null and b/src/main/resources/assets/create/textures/special/glue.png differ