Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.simibubi.create.api.behaviour.movement;

import org.jetbrains.annotations.NotNull;

import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;

public record ContraptionHandoffContainer(ListeningMovementBehaviour behaviour, ContraptionHandoffContext context) {

public static ContraptionHandoffContainer of(@NotNull ListeningMovementBehaviour behaviour, @NotNull BlockState state, BlockEntity blockEntity, BlockPos structurePos, BlockPos realPos) {
return new ContraptionHandoffContainer(behaviour, new ContraptionHandoffContext(state, blockEntity, structurePos, realPos));
}

public static record ContraptionHandoffContext(@NotNull BlockState state, BlockEntity blockEntity, BlockPos structurePos, BlockPos realPos) {
@Override
public final String toString() {
String be = blockEntity == null ? " (No BlockEntity)" : (" '" + blockEntity.getClass().getSimpleName() + "'");
return "ContraptionHandoffContext[" + state + be + " at (" + realPos.getX() + ", " + realPos.getY() + ", " + realPos.getZ() + "), (" + structurePos.getX() + ", " + structurePos.getY() + ", " + structurePos.getZ() + ")";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.simibubi.create.api.behaviour.movement;

import com.simibubi.create.api.behaviour.movement.ContraptionHandoffContainer.ContraptionHandoffContext;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.Contraption;

import net.minecraft.world.level.LevelAccessor;

/**
* A {@link MovementBehaviour} which allows actors to
* define custom assembly and disassembly behaviours.
*/
public interface ListeningMovementBehaviour extends MovementBehaviour {

/**
* Called when a contraption has been initialized that had previously
* destroyed a Block registered with this behaviour.
* At the time of invocation, any Blocks or BlockEntities that may
* have existed will have already been removed, so the BlockEntity
* instance in the container is stale.
* @param world
* @param ace
* @param contraption
* @param ctx {@link ContraptionHandoffContext} containing a stale BlockEntity reference
*/
public default void onAddedToContraption(LevelAccessor world, AbstractContraptionEntity ace, Contraption contraption, ContraptionHandoffContext ctx) {}

/**
* Called as an {@link AbstractContraptionEntity} is disassembling.
* This method is called after all blocks have been placed back into the world
* and the contraption entity has been removed.
* @param world
* @param contraption caller
* @param ctx {@link ContraptionHandoffContext} containing the now re-instantiated BlockEntity reference
*/
public default void onRemovedFromContraption(LevelAccessor world, AbstractContraptionEntity ace, Contraption contraption, ContraptionHandoffContext ctx) {}
}
21 changes: 21 additions & 0 deletions src/main/java/com/simibubi/create/api/event/ContraptionEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.simibubi.create.api.event;

import com.simibubi.create.content.contraptions.AbstractContraptionEntity;

import net.neoforged.neoforge.event.entity.EntityEvent;

public abstract class ContraptionEvent extends EntityEvent {
public ContraptionEvent(AbstractContraptionEntity entity) {
super(entity);
}
public static class Assemble extends ContraptionEvent {
public Assemble(AbstractContraptionEntity entity) {
super(entity);
}
}
public static class Disassemble extends ContraptionEvent {
public Disassemble(AbstractContraptionEntity entity) {
super(entity);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.simibubi.create.AllItems;
import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.api.event.ContraptionEvent;
import com.simibubi.create.content.contraptions.actors.psi.PortableStorageInterfaceMovement;
import com.simibubi.create.content.contraptions.actors.seat.SeatBlock;
import com.simibubi.create.content.contraptions.actors.seat.SeatEntity;
Expand Down Expand Up @@ -73,9 +74,9 @@
import net.minecraft.world.level.material.PushReaction;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;

import net.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.entity.IEntityWithComplexSpawn;

public abstract class AbstractContraptionEntity extends Entity implements IEntityWithComplexSpawn {
Expand Down Expand Up @@ -281,7 +282,7 @@ public boolean control(BlockPos controlsLocalPos, Collection<Integer> heldContro

public void stopControlling(BlockPos controlsLocalPos) {
getControllingPlayer().map(level()::getPlayerByUUID)
.map(p -> (p instanceof ServerPlayer) ? ((ServerPlayer) p) : null)
.map(p -> (p instanceof ServerPlayer s) ? s : null)
.ifPresent(p -> CatnipServices.NETWORK.sendToClient(p, ControlsStopControllingPacket.INSTANCE));
setControllingPlayer(null);
}
Expand Down Expand Up @@ -651,6 +652,7 @@ protected void readAdditional(CompoundTag compound, boolean spawnData) {
}

public void disassemble() {

if (!isAlive())
return;
if (contraption == null)
Expand Down Expand Up @@ -681,6 +683,10 @@ public void disassemble() {

ejectPassengers();
moveCollidedEntitiesOnDisassembly(transform);

contraption.consumeHandoffContainers(this, false);
NeoForge.EVENT_BUS.post(new ContraptionEvent.Disassemble(this));

AllSoundEvents.CONTRAPTION_DISASSEMBLE.playOnServer(level(), blockPosition());
}

Expand Down Expand Up @@ -830,6 +836,7 @@ public Vec3 getContactPointMotion(Vec3 globalContactPoint) {
return contraptionLocalMovement.add(contraptionAnchorMovement);
}

@Override
public boolean canCollideWith(Entity e) {
if (e instanceof Player && e.isSpectator())
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTags.AllContraptionTypeTags;
import com.simibubi.create.api.behaviour.interaction.MovingInteractionBehaviour;
import com.simibubi.create.api.behaviour.movement.ContraptionHandoffContainer;
import com.simibubi.create.api.behaviour.movement.ListeningMovementBehaviour;
import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.api.contraption.BlockMovementChecks;
import com.simibubi.create.api.contraption.ContraptionType;
import com.simibubi.create.api.event.ContraptionEvent;
import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement;
import com.simibubi.create.content.contraptions.actors.harvester.HarvesterMovementBehaviour;
import com.simibubi.create.content.contraptions.actors.seat.SeatBlock;
Expand Down Expand Up @@ -76,6 +79,7 @@
import com.simibubi.create.foundation.utility.BlockHelper;
import com.simibubi.create.infrastructure.config.AllConfigs;

import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.createmod.catnip.data.Iterate;
import net.createmod.catnip.data.UniqueLinkedList;
import net.createmod.catnip.math.BBHelper;
Expand Down Expand Up @@ -128,8 +132,8 @@
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;

import net.neoforged.neoforge.client.model.data.ModelData;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.registries.GameData;

public abstract class Contraption {
Expand Down Expand Up @@ -162,6 +166,8 @@ public abstract class Contraption {

private CompletableFuture<Void> simplifiedEntityColliderProvider;

private @Nullable List<ContraptionHandoffContainer> handoffers;

// Client
public Map<BlockPos, ModelData> modelData;
public Map<BlockPos, BlockEntity> presentBlockEntities;
Expand Down Expand Up @@ -303,6 +309,9 @@ public void onEntityInitialize(Level world, AbstractContraptionEntity contraptio
continue;
contraptionEntity.addSittingPassenger(passenger, seatIndex);
}

NeoForge.EVENT_BUS.post(new ContraptionEvent.Assemble(contraptionEntity));
consumeHandoffContainers(contraptionEntity, true);
}

/**
Expand Down Expand Up @@ -1103,7 +1112,16 @@ public void removeBlocksFromWorld(Level world, BlockPos offset) {
blockMismatch &= !AllBlocks.POWERED_SHAFT.is(blockIn) || !AllBlocks.SHAFT.has(block.state());
if (blockMismatch)
iterator.remove();

MovementBehaviour actor = MovementBehaviour.REGISTRY.get(block.state());
if (actor instanceof ListeningMovementBehaviour lmb) {
if (handoffers == null) handoffers = new ObjectArrayList<>(11);
BlockEntity be = world.getBlockEntity(add);
handoffers.add(ContraptionHandoffContainer.of(lmb, block.state(), be, block.pos(), add));
}

world.removeBlockEntity(add);

int flags = Block.UPDATE_MOVE_BY_PISTON | Block.UPDATE_SUPPRESS_DROPS | Block.UPDATE_KNOWN_SHAPE
| Block.UPDATE_CLIENTS | Block.UPDATE_IMMEDIATE;
if (blockIn instanceof SimpleWaterloggedBlock && oldState.hasProperty(BlockStateProperties.WATERLOGGED)
Expand Down Expand Up @@ -1253,8 +1271,13 @@ public void addBlocksToWorld(Level world, StructureTransform transform) {

storage.unmount(world, block, targetPos, blockEntity);

if (blockEntity != null) {
if (blockEntity != null)
transform.apply(blockEntity);

MovementBehaviour actor = MovementBehaviour.REGISTRY.get(block.state());
if (actor instanceof ListeningMovementBehaviour lmb) {
if (handoffers == null) handoffers = new ObjectArrayList<>(11);
handoffers.add(ContraptionHandoffContainer.of(lmb, blockState, blockEntity, block.pos(), targetPos));
}
}
}
Expand All @@ -1275,6 +1298,15 @@ public void addBlocksToWorld(Level world, StructureTransform transform) {
}
}

protected void consumeHandoffContainers(AbstractContraptionEntity entity, boolean add) {
if (handoffers == null) return;
for(ContraptionHandoffContainer container : handoffers) {
if (add) container.behaviour().onAddedToContraption(world, entity, this, container.context());
else container.behaviour().onRemovedFromContraption(world, entity, this, container.context());
}
handoffers = null;
}

protected void translateMultiblockControllers(StructureTransform transform) {
if (transform.rotationAxis != null && transform.rotationAxis != Axis.Y && transform.rotation != Rotation.NONE) {
capturedMultiblocks.values().forEach(info -> {
Expand Down