Portable Deployers

- Server speed sync no longer goes nuts when server speed increased from low tps
- Flimsy attempts at better syncing a bearings' current angle
- Portable Storage abilities are (for now) available to the Barrel only
- Deployers can now be mounted on moving structures and will activate at every visited block position
This commit is contained in:
simibubi 2020-02-13 00:12:05 +01:00
parent e0b36a79c9
commit 7dd29e9ffd
18 changed files with 681 additions and 344 deletions

View file

@ -71,7 +71,7 @@ public class ServerSpeedProvider {
return;
}
float target = ((float) getSyncInterval()) / Math.max(clientTimer, 1);
modifier.target(target);
modifier.target(Math.min(target, 1));
clientTimer = 0;
});

View file

@ -150,17 +150,15 @@ public class Contraption {
return false;
for (int limit = 1000; limit > 0; limit--) {
if (frontier.isEmpty()) {
onAssembled(world, pos);
if (frontier.isEmpty())
return true;
}
if (!moveBlock(world, frontier.remove(0), direction, frontier, visited))
return false;
}
return false;
}
protected void onAssembled(World world, BlockPos pos) {
public void gatherStoredItems() {
List<IItemHandlerModifiable> list =
storage.values().stream().map(MountedStorage::getItemHandler).collect(Collectors.toList());
inventory = new CombinedInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class));
@ -504,7 +502,7 @@ public class Contraption {
nbt.getList("Actors", 10).forEach(c -> {
CompoundNBT comp = (CompoundNBT) c;
BlockInfo info = blocks.get(NBTUtil.readBlockPos(comp.getCompound("Pos")));
MovementContext context = MovementContext.readNBT(world, comp);
MovementContext context = MovementContext.readNBT(world, info, comp);
context.contraption = this;
getActors().add(MutablePair.of(info, context));
});
@ -549,6 +547,7 @@ public class Contraption {
for (MutablePair<BlockInfo, MovementContext> actor : getActors()) {
CompoundNBT compound = new CompoundNBT();
compound.put("Pos", NBTUtil.writeBlockPos(actor.left.pos));
getMovement(actor.left.state).writeExtraData(actor.right);
actor.right.writeToNBT(compound);
actorsNBT.add(compound);
}
@ -591,6 +590,7 @@ public class Contraption {
}
public void removeBlocksFromWorld(IWorld world, BlockPos offset, BiPredicate<BlockPos, BlockState> customRemoval) {
storage.values().forEach(MountedStorage::empty);
for (BlockInfo block : blocks.values()) {
BlockPos add = block.pos.add(anchor).add(offset);
if (customRemoval.test(add, block.state))
@ -635,10 +635,9 @@ public class Contraption {
public void initActors(World world) {
for (MutablePair<BlockInfo, MovementContext> pair : actors) {
BlockState blockState = pair.left.state;
MovementContext context = new MovementContext(world, blockState);
MovementContext context = new MovementContext(world, pair.left);
context.contraption = this;
getMovement(blockState).startMoving(context);
getMovement(pair.left.state).startMoving(context);
pair.setRight(context);
}
}

View file

@ -70,6 +70,8 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
this.prevYaw = initialAngle;
this.yaw = initialAngle;
this.targetYaw = initialAngle;
if (contraption != null)
contraption.gatherStoredItems();
}
public <T extends TileEntity & IControlContraption> ContraptionEntity controlledBy(T controller) {
@ -92,7 +94,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
Vec3d movementVector = e.getMotion();
Vec3d motion = movementVector.normalize();
if (motion.length() > 0) {
targetYaw = yawFromMotion(motion);
targetYaw = yawFromVector(motion);
targetPitch = (float) ((Math.atan(motion.y) * 73.0D) / Math.PI * 180);
if (targetYaw < 0)
targetYaw += 360;
@ -254,8 +256,12 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
disassemble();
}
public static float yawFromMotion(Vec3d motion) {
return (float) ((3 * Math.PI / 2 + Math.atan2(motion.z, motion.x)) / Math.PI * 180);
public static float yawFromVector(Vec3d vec) {
return (float) ((3 * Math.PI / 2 + Math.atan2(vec.z, vec.x)) / Math.PI * 180);
}
public static float pitchFromVector(Vec3d vec) {
return (float) ((Math.acos(vec.y)) / Math.PI * 180);
}
public float getYaw(float partialTicks) {

View file

@ -69,7 +69,7 @@ public class ContraptionRenderer {
context.world = world;
BlockInfo blockInfo = actor.getLeft();
SuperByteBuffer render = Contraption.getMovement(blockInfo.state).renderInContraption(context);
for (SuperByteBuffer render : Contraption.getMovement(blockInfo.state).renderListInContraption(context)) {
if (render == null)
continue;
@ -82,6 +82,7 @@ public class ContraptionRenderer {
render.light((lx, ly, lz) -> getLight(world, lx, ly, lz)).renderInto(buffer);
}
}
}
public static int getLight(World world, float lx, float ly, float lz) {
MutableBlockPos pos = new MutableBlockPos();

View file

@ -1,7 +1,5 @@
package com.simibubi.create.modules.contraptions.components.contraptions;
import com.simibubi.create.AllTileEntities;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.TileEntity;
@ -17,9 +15,14 @@ public class MountedStorage {
ItemStackHandler handler;
boolean working;
private TileEntity te;
public MountedStorage(TileEntity te) {
this.te = te;
handler = dummyHandler;
}
public void empty() {
if (te != null) {
IItemHandler teHandler =
te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).orElse(dummyHandler);
@ -68,11 +71,8 @@ public class MountedStorage {
if (te == null)
return false;
TileEntityType<?> type = te.getType();
if (type == TileEntityType.CHEST || type == TileEntityType.SHULKER_BOX || type == TileEntityType.BARREL)
if (type == TileEntityType.BARREL)
return true;
if (type == AllTileEntities.FLEXCRATE.type)
return true;
return false;
}

View file

@ -1,5 +1,8 @@
package com.simibubi.create.modules.contraptions.components.contraptions;
import java.util.Arrays;
import java.util.List;
import com.simibubi.create.foundation.utility.SuperByteBuffer;
import net.minecraft.entity.item.ItemEntity;
@ -45,8 +48,17 @@ public abstract class MovementBehaviour {
return null;
}
@OnlyIn(value = Dist.CLIENT)
public List<SuperByteBuffer> renderListInContraption(MovementContext context) {
return Arrays.asList(renderInContraption(context));
}
public void stopMoving(MovementContext context) {
}
public void writeExtraData(MovementContext context) {
}
}

View file

@ -4,9 +4,9 @@ import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
import net.minecraftforge.common.util.Constants.NBT;
public class MovementContext {
@ -17,14 +17,17 @@ public class MovementContext {
public Vec3d rotation;
public World world;
public BlockState state;
public CompoundNBT tileData;
public boolean stall;
public CompoundNBT data;
public Contraption contraption;
public Object temporaryData;
public MovementContext(World world, BlockState state) {
public MovementContext(World world, BlockInfo info) {
this.world = world;
this.state = state;
this.state = info.state;
this.tileData = info.nbt;
motion = Vec3d.ZERO;
relativeMotion = Vec3d.ZERO;
@ -44,9 +47,8 @@ public class MovementContext {
return (((int) (length * modifier + 100 * Math.signum(length))) / 100) * 100;
}
public static MovementContext readNBT(World world, CompoundNBT nbt) {
BlockState state = NBTUtil.readBlockState(nbt.getCompound("State"));
MovementContext context = new MovementContext(world, state);
public static MovementContext readNBT(World world, BlockInfo info, CompoundNBT nbt) {
MovementContext context = new MovementContext(world, info);
context.motion = VecHelper.readNBT(nbt.getList("Motion", NBT.TAG_DOUBLE));
context.relativeMotion = VecHelper.readNBT(nbt.getList("RelativeMotion", NBT.TAG_DOUBLE));
context.rotation = VecHelper.readNBT(nbt.getList("Rotation", NBT.TAG_DOUBLE));
@ -58,7 +60,6 @@ public class MovementContext {
}
public CompoundNBT writeToNBT(CompoundNBT nbt) {
nbt.put("State", NBTUtil.writeBlockState(state));
nbt.put("Motion", VecHelper.writeNBT(motion));
nbt.put("RelativeMotion", VecHelper.writeNBT(relativeMotion));
nbt.put("Rotation", VecHelper.writeNBT(rotation));

View file

@ -24,9 +24,12 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
protected boolean assembleNextTick;
protected boolean isWindmill;
protected float clientAngleDiff;
public MechanicalBearingTileEntity() {
super(AllTileEntities.MECHANICAL_BEARING.type);
isWindmill = false;
setLazyTickRate(3);
}
@Override
@ -92,6 +95,16 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
super.read(tag);
}
@Override
public void readClientUpdate(CompoundNBT tag) {
float angleBefore = angle;
super.readClientUpdate(tag);
clientAngleDiff = angle - angleBefore;
if (Math.abs(clientAngleDiff) > 20)
clientAngleDiff = 0;
angle = angleBefore;
}
public float getInterpolatedAngle(float partialTicks) {
if (movedContraption != null && movedContraption.isStalled())
partialTicks = 0;
@ -106,8 +119,10 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
public float getAngularSpeed() {
float speed = getSpeed() * 3 / 10f;
if (world.isRemote)
if (world.isRemote) {
speed *= ServerSpeedProvider.get();
speed += clientAngleDiff / 3f;
}
return speed;
}
@ -120,9 +135,9 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
return;
if (isWindmill && contraption.getSailBlocks() == 0)
return;
contraption.removeBlocksFromWorld(world, BlockPos.ZERO);
movedContraption = new ContraptionEntity(world, contraption, 0).controlledBy(this);
BlockPos anchor = pos.offset(direction);
contraption.removeBlocksFromWorld(world, BlockPos.ZERO);
movedContraption.setPosition(anchor.getX(), anchor.getY(), anchor.getZ());
world.addEntity(movedContraption);
@ -150,17 +165,20 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
public void tick() {
super.tick();
if (world.isRemote)
clientAngleDiff /= 2;
if (running && Contraption.isFrozen())
disassembleConstruct();
if (!world.isRemote && assembleNextTick) {
assembleNextTick = false;
if (running) {
if (movedContraption != null)
movedContraption.getContraption().stop(world);
boolean canDisassemble = Math.abs(angle) < 45 || Math.abs(angle) > 7 * 45;
if (speed == 0 && (canDisassemble || movedContraption == null
|| movedContraption.getContraption().blocks.isEmpty())) {
if (movedContraption != null)
movedContraption.getContraption().stop(world);
disassembleConstruct();
}
return;
@ -184,6 +202,13 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
applyRotation();
}
@Override
public void lazyTick() {
super.lazyTick();
if (movedContraption != null && !world.isRemote)
sendData();
}
private void applyRotation() {
if (movedContraption != null) {
Axis axis = getBlockState().get(BlockStateProperties.FACING).getAxis();

View file

@ -76,7 +76,7 @@ public class CartAssemblerBlock extends AbstractRailBlock {
if (contraption == null)
return;
ContraptionEntity entity = new ContraptionEntity(world, contraption,
ContraptionEntity.yawFromMotion(cart.getMotion()));
ContraptionEntity.yawFromVector(cart.getMotion()));
entity.setPosition(pos.getX(), pos.getY(), pos.getZ());
world.addEntity(entity);
entity.startRiding(cart);

View file

@ -93,6 +93,7 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ICo
if (!removed)
getWorld().setBlockState(pos, getBlockState().with(MechanicalPistonBlock.STATE, PistonState.EXTENDED), 3);
if (movedContraption != null)
movedContraption.disassemble();
running = false;
movedContraption = null;

View file

@ -6,9 +6,12 @@ import com.simibubi.create.foundation.utility.AllShapes;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.base.DirectionalAxisKineticBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.IPortableBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.material.PushReaction;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUseContext;
@ -25,7 +28,10 @@ import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
public class DeployerBlock extends DirectionalAxisKineticBlock implements IWithTileEntity<DeployerTileEntity> {
public class DeployerBlock extends DirectionalAxisKineticBlock
implements IWithTileEntity<DeployerTileEntity>, IPortableBlock {
public static MovementBehaviour MOVEMENT = new DeployerMovementBehaviour();
public DeployerBlock() {
super(Properties.from(Blocks.ANDESITE));
@ -41,6 +47,11 @@ public class DeployerBlock extends DirectionalAxisKineticBlock implements IWithT
return true;
}
@Override
public PushReaction getPushReaction(BlockState state) {
return PushReaction.PUSH_ONLY;
}
@Override
public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
return AllShapes.SHORT_CASING_12_VOXEL.get(state.get(FACING));
@ -60,8 +71,12 @@ public class DeployerBlock extends DirectionalAxisKineticBlock implements IWithT
public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) {
if (state.hasTileEntity() && state.getBlock() != newState.getBlock()) {
withTileEntityDo(worldIn, pos, te -> {
if (te.player != null && !isMoving) {
te.player.inventory.dropAllItems();
te.overflowItems.forEach(itemstack -> te.player.dropItem(itemstack, true, false));
te.player.remove();
te.player = null;
}
});
worldIn.removeTileEntity(pos);
@ -112,4 +127,9 @@ public class DeployerBlock extends DirectionalAxisKineticBlock implements IWithT
return new Vec3d(0, yRot, zRot);
}
@Override
public MovementBehaviour getMovementBehaviour() {
return MOVEMENT;
}
}

View file

@ -3,6 +3,8 @@ package com.simibubi.create.modules.contraptions.components.deployer;
import java.util.OptionalInt;
import java.util.UUID;
import org.apache.commons.lang3.tuple.Pair;
import com.mojang.authlib.GameProfile;
import com.simibubi.create.foundation.utility.Lang;
@ -12,12 +14,14 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.Pose;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.item.ItemStack;
import net.minecraft.network.IPacket;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.PacketDirection;
import net.minecraft.network.play.ServerPlayNetHandler;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.EntityDamageSource;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
@ -35,8 +39,10 @@ import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
public class DeployerFakePlayer extends FakePlayer {
private static final NetworkManager NETWORK_MANAGER = new NetworkManager(PacketDirection.CLIENTBOUND);
public static final GameProfile DEPLOYER_PROFILE = new GameProfile(
UUID.fromString("9e2faded-cafe-4ec2-c314-dad129ae971d"), "Deployer");
public static final GameProfile DEPLOYER_PROFILE =
new GameProfile(UUID.fromString("9e2faded-cafe-4ec2-c314-dad129ae971d"), "Deployer");
Pair<BlockPos, Float> blockBreakingProgress;
ItemStack spawnedItemEffects;
public DeployerFakePlayer(ServerWorld world) {
super(world, DEPLOYER_PROFILE);
@ -88,6 +94,13 @@ public class DeployerFakePlayer extends FakePlayer {
}
}
@Override
public void remove(boolean keepData) {
if (blockBreakingProgress != null && !world.isRemote)
world.sendBlockBreakProgress(getEntityId(), blockBreakingProgress.getKey(), -1);
super.remove(keepData);
}
@SubscribeEvent
public static void deployerKillsDoNotSpawnXP(LivingExperienceDropEvent event) {
if (event.getAttackingPlayer() instanceof DeployerFakePlayer)

View file

@ -0,0 +1,263 @@
package com.simibubi.create.modules.contraptions.components.deployer;
import static net.minecraftforge.eventbus.api.Event.Result.DENY;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.collect.Multimap;
import com.simibubi.create.foundation.utility.WrappedWorld;
import com.simibubi.create.modules.contraptions.components.deployer.DeployerTileEntity.Mode;
import com.simibubi.create.modules.curiosities.tools.SandPaperItem;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.material.Material;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.Fluids;
import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.item.BlockItem;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.BucketItem;
import net.minecraft.item.FlintAndSteelItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUseContext;
import net.minecraft.item.Items;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.ActionResult;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceContext;
import net.minecraft.util.math.RayTraceContext.BlockMode;
import net.minecraft.util.math.RayTraceContext.FluidMode;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickBlock;
import net.minecraftforge.event.entity.player.PlayerInteractEvent.RightClickBlock;
import net.minecraftforge.eventbus.api.Event.Result;
public class DeployerHandler {
private static final class ItemUseWorld extends WrappedWorld {
private final Direction face;
private final BlockPos pos;
boolean rayMode = false;
private ItemUseWorld(World world, Direction face, BlockPos pos) {
super(world);
this.face = face;
this.pos = pos;
}
@Override
public BlockRayTraceResult rayTraceBlocks(RayTraceContext context) {
rayMode = true;
BlockRayTraceResult rayTraceBlocks = super.rayTraceBlocks(context);
rayMode = false;
return rayTraceBlocks;
}
@Override
public BlockState getBlockState(BlockPos position) {
if (rayMode && (pos.offset(face.getOpposite(), 3).equals(position)
|| pos.offset(face.getOpposite(), 1).equals(position)))
return Blocks.BEDROCK.getDefaultState();
return world.getBlockState(position);
}
}
static boolean shouldActivate(ItemStack held, World world, BlockPos targetPos) {
if (held.getItem() instanceof BlockItem)
if (!world.getBlockState(targetPos).getMaterial().isReplaceable())
return false;
if (held.getItem() instanceof BucketItem) {
BucketItem bucketItem = (BucketItem) held.getItem();
Fluid fluid = bucketItem.getFluid();
if (fluid != Fluids.EMPTY && world.getFluidState(targetPos).getFluid() == fluid)
return false;
}
return true;
}
static void activate(DeployerFakePlayer player, Vec3d vec, BlockPos clickedPos, Vec3d extensionVector, Mode mode) {
Multimap<String, AttributeModifier> attributeModifiers =
player.getHeldItemMainhand().getAttributeModifiers(EquipmentSlotType.MAINHAND);
player.getAttributes().applyAttributeModifiers(attributeModifiers);
activateInner(player, vec, clickedPos, extensionVector, mode);
player.getAttributes().removeAttributeModifiers(attributeModifiers);
}
private static void activateInner(DeployerFakePlayer player, Vec3d vec, BlockPos clickedPos, Vec3d extensionVector,
Mode mode) {
Vec3d rayOrigin = vec.add(extensionVector.scale(3 / 2f + 1 / 64f));
Vec3d rayTarget = vec.add(extensionVector.scale(5 / 2f - 1 / 64f));
player.setPosition(rayOrigin.x, rayOrigin.y, rayOrigin.z);
BlockPos pos = new BlockPos(vec);
ItemStack stack = player.getHeldItemMainhand();
Item item = stack.getItem();
// Check for entities
final ServerWorld world = player.getServerWorld();
List<LivingEntity> entities = world.getEntitiesWithinAABB(LivingEntity.class, new AxisAlignedBB(clickedPos));
Hand hand = Hand.MAIN_HAND;
if (!entities.isEmpty()) {
LivingEntity entity = entities.get(world.rand.nextInt(entities.size()));
List<ItemEntity> capturedDrops = new ArrayList<>();
boolean success = false;
entity.captureDrops(capturedDrops);
// Use on entity
if (mode == Mode.USE) {
ActionResultType cancelResult = ForgeHooks.onInteractEntity(player, entity, hand);
if (cancelResult == ActionResultType.FAIL) {
entity.captureDrops(null);
return;
}
if (cancelResult == null) {
if (entity.processInitialInteract(player, hand))
success = true;
else if (stack.interactWithEntity(player, entity, hand))
success = true;
}
}
// Punch entity
if (mode == Mode.PUNCH) {
player.resetCooldown();
player.attackTargetEntityWithCurrentItem(entity);
success = true;
}
entity.captureDrops(null);
capturedDrops.forEach(e -> player.inventory.placeItemBackInInventory(world, e.getItem()));
if (success)
return;
}
// Shoot ray
RayTraceContext rayTraceContext =
new RayTraceContext(rayOrigin, rayTarget, BlockMode.OUTLINE, FluidMode.NONE, player);
BlockRayTraceResult result = world.rayTraceBlocks(rayTraceContext);
BlockState clickedState = world.getBlockState(clickedPos);
Direction face = result.getFace();
if (face == null)
face = Direction.getFacingFromVector(extensionVector.x, extensionVector.y, extensionVector.z).getOpposite();
// Left click
if (mode == Mode.PUNCH) {
LeftClickBlock event = ForgeHooks.onLeftClickBlock(player, clickedPos, face);
if (event.isCanceled())
return;
if (!world.isBlockModifiable(player, clickedPos))
return;
if (world.extinguishFire(player, clickedPos, face))
return;
if (clickedState.isAir(world, clickedPos)) {
player.blockBreakingProgress = null;
return;
}
if (event.getUseBlock() != Result.DENY)
clickedState.onBlockClicked(world, clickedPos, player);
if (stack.isEmpty())
return;
float progress = clickedState.getPlayerRelativeBlockHardness(player, world, clickedPos) * 16;
float before = 0;
Pair<BlockPos, Float> blockBreakingProgress = player.blockBreakingProgress;
if (blockBreakingProgress != null)
before = blockBreakingProgress.getValue();
progress += before;
if (progress >= 1) {
player.interactionManager.tryHarvestBlock(clickedPos);
world.sendBlockBreakProgress(player.getEntityId(), clickedPos, -1);
player.blockBreakingProgress = null;
return;
}
if ((int) (before * 10) != (int) (progress * 10))
world.sendBlockBreakProgress(player.getEntityId(), clickedPos, (int) (progress * 10));
player.blockBreakingProgress = Pair.of(clickedPos, progress);
return;
}
// Right click
ItemUseContext itemusecontext = new ItemUseContext(player, hand, result);
RightClickBlock event = ForgeHooks.onRightClickBlock(player, hand, clickedPos, face);
// Item has custom active use
if (event.getUseItem() != DENY) {
ActionResultType actionresult = stack.onItemUseFirst(itemusecontext);
if (actionresult != ActionResultType.PASS)
return;
}
boolean holdingSomething = !player.getHeldItemMainhand().isEmpty();
boolean flag1 =
!(player.isSneaking() && holdingSomething) || (stack.doesSneakBypassUse(world, clickedPos, player));
// Use on block
if (event.getUseBlock() != DENY && flag1 && clickedState.onBlockActivated(world, player, hand, result))
return;
if (stack.isEmpty())
return;
if (event.getUseItem() == DENY)
return;
if (item instanceof BlockItem && !clickedState.isReplaceable(new BlockItemUseContext(itemusecontext)))
return;
// Reposition fire placement for convenience
if (item == Items.FLINT_AND_STEEL) {
Direction newFace = result.getFace();
BlockPos newPos = result.getPos();
if (!FlintAndSteelItem.canSetFire(clickedState, world, clickedPos))
newFace = Direction.UP;
if (clickedState.getMaterial() == Material.AIR)
newPos = newPos.offset(face.getOpposite());
result = new BlockRayTraceResult(result.getHitVec(), newFace, newPos, result.isInside());
itemusecontext = new ItemUseContext(player, hand, result);
}
// 'Inert' item use behaviour & block placement
ActionResultType onItemUse = stack.onItemUse(itemusecontext);
if (onItemUse == ActionResultType.SUCCESS)
return;
if (item == Items.ENDER_PEARL)
return;
// buckets create their own ray, We use a fake wall to contain the active area
World itemUseWorld = world;
if (item instanceof BucketItem || item instanceof SandPaperItem)
itemUseWorld = new ItemUseWorld(world, face, pos);
ActionResult<ItemStack> onItemRightClick = item.onItemRightClick(itemUseWorld, player, hand);
player.setHeldItem(hand, onItemRightClick.getResult());
CompoundNBT tag = stack.getOrCreateTag();
if (stack.getItem() instanceof SandPaperItem && tag.contains("Polishing"))
player.spawnedItemEffects = ItemStack.read(tag.getCompound("Polishing"));
if (stack.isFood())
player.spawnedItemEffects = stack.copy();
if (!player.getActiveItemStack().isEmpty())
player.setHeldItem(hand, stack.onItemUseFinish(world, player));
player.resetActiveHand();
}
}

View file

@ -0,0 +1,175 @@
package com.simibubi.create.modules.contraptions.components.deployer;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.foundation.item.ItemHelper;
import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext;
import com.simibubi.create.modules.contraptions.components.deployer.DeployerTileEntity.Mode;
import com.simibubi.create.modules.logistics.item.filter.FilterItem;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.Constants.NBT;
public class DeployerMovementBehaviour extends MovementBehaviour {
@Override
public Vec3d getActiveAreaOffset(MovementContext context) {
return new Vec3d(context.state.get(DeployerBlock.FACING).getDirectionVec()).scale(2);
}
@Override
public void visitNewPosition(MovementContext context, BlockPos pos) {
if (context.world.isRemote)
return;
tryGrabbingItem(context);
DeployerFakePlayer player = getPlayer(context);
Mode mode = getMode(context);
if (mode == Mode.USE && !DeployerHandler.shouldActivate(player.getHeldItemMainhand(), context.world, pos))
return;
activate(context, pos, player, mode);
tryDisposeOfExcess(context);
context.stall = player.blockBreakingProgress != null;
}
public void activate(MovementContext context, BlockPos pos, DeployerFakePlayer player, Mode mode) {
Vec3d facingVec = new Vec3d(context.state.get(DeployerBlock.FACING).getDirectionVec());
facingVec = VecHelper.rotate(facingVec, context.rotation.x, context.rotation.y, context.rotation.z);
Vec3d vec = context.position.subtract(facingVec.scale(2));
player.rotationYaw = ContraptionEntity.yawFromVector(facingVec);
player.rotationPitch = ContraptionEntity.pitchFromVector(facingVec) - 90;
DeployerHandler.activate(player, vec, pos, facingVec, mode);
}
@Override
public void tick(MovementContext context) {
if (context.world.isRemote)
return;
if (!context.stall)
return;
DeployerFakePlayer player = getPlayer(context);
Mode mode = getMode(context);
Pair<BlockPos, Float> blockBreakingProgress = player.blockBreakingProgress;
if (blockBreakingProgress != null) {
int timer = context.data.getInt("Timer");
if (timer < 20) {
timer++;
context.data.putInt("Timer", timer);
return;
}
context.data.remove("Timer");
activate(context, blockBreakingProgress.getKey(), player, mode);
tryDisposeOfExcess(context);
}
context.stall = player.blockBreakingProgress != null;
}
@Override
public void stopMoving(MovementContext context) {
if (context.world.isRemote)
return;
tryDisposeOfEverything(context);
}
private void tryGrabbingItem(MovementContext context) {
DeployerFakePlayer player = getPlayer(context);
if (player == null)
return;
if (player.getHeldItemMainhand().isEmpty()) {
ItemStack held = ItemHelper.extract(context.contraption.inventory,
stack -> FilterItem.test(stack, getFilter(context)), 1, false);
player.setHeldItem(Hand.MAIN_HAND, held);
}
}
private void tryDisposeOfEverything(MovementContext context) {
DeployerFakePlayer player = getPlayer(context);
if (player == null)
return;
ItemStack held = player.getHeldItemMainhand();
if (!held.isEmpty()) {
dropItem(context, held);
player.setHeldItem(Hand.MAIN_HAND, ItemStack.EMPTY);
}
tryDisposeOfExcess(context);
}
private void tryDisposeOfExcess(MovementContext context) {
DeployerFakePlayer player = getPlayer(context);
if (player == null)
return;
PlayerInventory inv = player.inventory;
ItemStack filter = getFilter(context);
for (List<ItemStack> list : Arrays.asList(inv.armorInventory, inv.offHandInventory, inv.mainInventory)) {
for (int i = 0; i < list.size(); ++i) {
ItemStack itemstack = list.get(i);
if (itemstack.isEmpty())
continue;
if (list == inv.mainInventory && i == inv.currentItem && FilterItem.test(itemstack, filter))
continue;
dropItem(context, itemstack);
list.set(i, ItemStack.EMPTY);
}
}
}
@Override
public void writeExtraData(MovementContext context) {
DeployerFakePlayer player = getPlayer(context);
if (player == null)
return;
context.data.put("HeldItem", player.getHeldItemMainhand().serializeNBT());
}
private DeployerFakePlayer getPlayer(MovementContext context) {
if (!(context.temporaryData instanceof DeployerFakePlayer) && context.world instanceof ServerWorld) {
DeployerFakePlayer deployerFakePlayer = new DeployerFakePlayer((ServerWorld) context.world);
deployerFakePlayer.inventory.read(context.tileData.getList("Inventory", NBT.TAG_COMPOUND));
if (context.data.contains("HeldItem"))
deployerFakePlayer.setHeldItem(Hand.MAIN_HAND, ItemStack.read(context.data.getCompound("HeldItem")));
context.tileData.remove("Inventory");
context.temporaryData = deployerFakePlayer;
}
return (DeployerFakePlayer) context.temporaryData;
}
private ItemStack getFilter(MovementContext context) {
return ItemStack.read(context.tileData.getCompound("Filter"));
}
private Mode getMode(MovementContext context) {
return NBTHelper.readEnum(context.tileData.getString("Mode"), Mode.class);
}
@Override
@OnlyIn(Dist.CLIENT)
public List<SuperByteBuffer> renderListInContraption(MovementContext context) {
return DeployerTileEntityRenderer.renderListInContraption(context);
}
}

View file

@ -1,7 +1,6 @@
package com.simibubi.create.modules.contraptions.components.deployer;
import static com.simibubi.create.modules.contraptions.base.DirectionalKineticBlock.FACING;
import static net.minecraftforge.eventbus.api.Event.Result.DENY;
import java.util.ArrayList;
import java.util.Arrays;
@ -9,15 +8,12 @@ import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import com.simibubi.create.foundation.advancement.AllCriterionTriggers;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.tileentity.TileEntity;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.collect.Multimap;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.foundation.advancement.AllCriterionTriggers;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
import com.simibubi.create.foundation.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.behaviour.filtering.FilteringBehaviour.SlotPositioning;
@ -25,32 +21,16 @@ import com.simibubi.create.foundation.behaviour.inventory.ExtractingBehaviour;
import com.simibubi.create.foundation.item.ItemHelper;
import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.foundation.utility.WrappedWorld;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.modules.curiosities.tools.SandPaperItem;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.material.Material;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.Fluids;
import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.item.BlockItem;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.BucketItem;
import net.minecraft.item.FlintAndSteelItem;
import net.minecraft.item.Item;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUseContext;
import net.minecraft.item.Items;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.util.ActionResult;
import net.minecraft.util.ActionResultType;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.AxisAlignedBB;
@ -61,13 +41,8 @@ import net.minecraft.util.math.RayTraceContext;
import net.minecraft.util.math.RayTraceContext.BlockMode;
import net.minecraft.util.math.RayTraceContext.FluidMode;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickBlock;
import net.minecraftforge.event.entity.player.PlayerInteractEvent.RightClickBlock;
import net.minecraftforge.eventbus.api.Event.Result;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
@ -86,10 +61,7 @@ public class DeployerTileEntity extends KineticTileEntity {
protected float reach;
protected boolean boop = false;
protected List<ItemStack> overflowItems = new ArrayList<>();
protected Pair<BlockPos, Float> blockBreakingProgress;
private ListNBT deferredInventoryList;
private ItemStack spawnItemEffects;
enum State {
WAITING, EXPANDING, RETRACTING, DUMPING;
@ -152,10 +124,10 @@ public class DeployerTileEntity extends KineticTileEntity {
if (getSpeed() == 0)
return;
if (!world.isRemote && blockBreakingProgress != null) {
if (world.isAirBlock(blockBreakingProgress.getKey())) {
world.sendBlockBreakProgress(player.getEntityId(), blockBreakingProgress.getKey(), -1);
blockBreakingProgress = null;
if (!world.isRemote && player != null && player.blockBreakingProgress != null) {
if (world.isAirBlock(player.blockBreakingProgress.getKey())) {
world.sendBlockBreakProgress(player.getEntityId(), player.blockBreakingProgress.getKey(), -1);
player.blockBreakingProgress = null;
}
}
if (timer > 0) {
@ -191,50 +163,21 @@ public class DeployerTileEntity extends KineticTileEntity {
extracting.extract(1);
Direction facing = getBlockState().get(FACING);
if (stack.getItem() instanceof BlockItem) {
if (!world.getBlockState(pos.offset(facing, 2)).getMaterial().isReplaceable()) {
if (mode == Mode.USE && !DeployerHandler.shouldActivate(stack, world, pos.offset(facing, 2))) {
timer = getTimerSpeed() * 10;
return;
}
}
if (stack.getItem() instanceof BucketItem) {
BucketItem bucketItem = (BucketItem) stack.getItem();
Fluid fluid = bucketItem.getFluid();
if (fluid != Fluids.EMPTY && world.getFluidState(pos.offset(facing, 2)).getFluid() == fluid) {
timer = getTimerSpeed() * 10;
// Check for advancement conditions
if (mode == Mode.PUNCH && !boop && startBoop(facing))
return;
}
}
//Check for advancement conditions
if (mode == Mode.PUNCH && !boop) {
if (world.isAirBlock(pos.offset(facing,1)) && world.isAirBlock(pos.offset(facing,2))) {
BlockPos otherDeployer = pos.offset(facing, 4);
if (world.isBlockPresent(otherDeployer)){
TileEntity otherTile = world.getTileEntity(otherDeployer);
if (otherTile instanceof DeployerTileEntity){
DeployerTileEntity deployerTile = (DeployerTileEntity) otherTile;
if (world.getBlockState(otherDeployer).get(FACING).getOpposite() == facing && deployerTile.mode == Mode.PUNCH) {
//two facing deployer
boop = true;
reach = 1f;
timer = 1000;
state = State.EXPANDING;
sendData();
return;
}
}
}
}
}
state = State.EXPANDING;
Vec3d movementVector = getMovementVector();
Vec3d rayOrigin = VecHelper.getCenterOf(pos).add(movementVector.scale(3 / 2f));
Vec3d rayTarget = VecHelper.getCenterOf(pos).add(movementVector.scale(5 / 2f));
RayTraceContext rayTraceContext = new RayTraceContext(rayOrigin, rayTarget, BlockMode.OUTLINE,
FluidMode.NONE, player);
RayTraceContext rayTraceContext =
new RayTraceContext(rayOrigin, rayTarget, BlockMode.OUTLINE, FluidMode.NONE, player);
BlockRayTraceResult result = world.rayTraceBlocks(rayTraceContext);
reach = (float) (.5f + Math.min(result.getHitVec().subtract(rayOrigin).length(), .75f));
@ -244,37 +187,10 @@ public class DeployerTileEntity extends KineticTileEntity {
}
if (state == State.EXPANDING) {
if (boop){
TileEntity otherTile = world.getTileEntity(pos.offset(getBlockState().get(FACING),4));
if (otherTile instanceof DeployerTileEntity){
DeployerTileEntity deployerTile = (DeployerTileEntity) otherTile;
if (deployerTile.boop && deployerTile.state == State.EXPANDING){
if(deployerTile.timer <= 0){
//everything should be met
boop = false;
state = State.RETRACTING;
timer = 1000;
deployerTile.boop = false;
deployerTile.state = State.RETRACTING;
deployerTile.timer = 1000;
deployerTile.sendData();
sendData();
//award nearby players
List<ServerPlayerEntity> players = world.getEntitiesWithinAABB(ServerPlayerEntity.class, new AxisAlignedBB(pos).grow(9));
players.forEach(AllCriterionTriggers.DEPLOYER_BOOP::trigger);
}
}
}
return;
}
Multimap<String, AttributeModifier> attributeModifiers = stack
.getAttributeModifiers(EquipmentSlotType.MAINHAND);
player.getAttributes().applyAttributeModifiers(attributeModifiers);
if (boop)
triggerBoop();
else
activate();
player.getAttributes().removeAttributeModifiers(attributeModifiers);
heldItem = player.getHeldItemMainhand();
state = State.RETRACTING;
timer = 1000;
@ -292,183 +208,61 @@ public class DeployerTileEntity extends KineticTileEntity {
}
public boolean startBoop(Direction facing) {
if (!world.isAirBlock(pos.offset(facing, 1)) || !world.isAirBlock(pos.offset(facing, 2)))
return false;
BlockPos otherDeployer = pos.offset(facing, 4);
if (!world.isBlockPresent(otherDeployer))
return false;
TileEntity otherTile = world.getTileEntity(otherDeployer);
if (!(otherTile instanceof DeployerTileEntity))
return false;
DeployerTileEntity deployerTile = (DeployerTileEntity) otherTile;
if (world.getBlockState(otherDeployer).get(FACING).getOpposite() != facing || deployerTile.mode != Mode.PUNCH)
return false;
boop = true;
reach = 1f;
timer = 1000;
state = State.EXPANDING;
sendData();
return true;
}
public void triggerBoop() {
TileEntity otherTile = world.getTileEntity(pos.offset(getBlockState().get(FACING), 4));
if (!(otherTile instanceof DeployerTileEntity))
return;
DeployerTileEntity deployerTile = (DeployerTileEntity) otherTile;
if (!deployerTile.boop || deployerTile.state != State.EXPANDING)
return;
if (deployerTile.timer > 0)
return;
// everything should be met
boop = false;
deployerTile.boop = false;
deployerTile.state = State.RETRACTING;
deployerTile.timer = 1000;
deployerTile.sendData();
// award nearby players
List<ServerPlayerEntity> players =
world.getEntitiesWithinAABB(ServerPlayerEntity.class, new AxisAlignedBB(pos).grow(9));
players.forEach(AllCriterionTriggers.DEPLOYER_BOOP::trigger);
}
protected void activate() {
// Update player position and angle
Vec3d movementVector = getMovementVector();
Direction direction = getBlockState().get(FACING);
Vec3d center = VecHelper.getCenterOf(pos);
Vec3d rayOrigin = center.add(movementVector.scale(3 / 2f + 1 / 64f));
Vec3d rayTarget = center.add(movementVector.scale(5 / 2f - 1 / 64f));
BlockPos clickedPos = pos.offset(direction, 2);
player.rotationYaw = direction.getHorizontalAngle();
player.rotationPitch = direction == Direction.UP ? -90 : direction == Direction.DOWN ? 90 : 0;
player.setPosition(rayOrigin.x, rayOrigin.y, rayOrigin.z);
ItemStack stack = player.getHeldItemMainhand();
Item item = stack.getItem();
// Check for entities
World world = this.world;
List<LivingEntity> entities = world.getEntitiesWithinAABB(LivingEntity.class, new AxisAlignedBB(clickedPos));
Hand hand = Hand.MAIN_HAND;
if (!entities.isEmpty()) {
LivingEntity entity = entities.get(world.rand.nextInt(entities.size()));
List<ItemEntity> capturedDrops = new ArrayList<>();
boolean success = false;
entity.captureDrops(capturedDrops);
// Use on entity
if (mode == Mode.USE) {
ActionResultType cancelResult = ForgeHooks.onInteractEntity(player, entity, hand);
if (cancelResult == ActionResultType.FAIL) {
entity.captureDrops(null);
return;
}
if (cancelResult == null) {
if (entity.processInitialInteract(player, hand))
success = true;
else if (stack.interactWithEntity(player, entity, hand))
success = true;
}
}
// Punch entity
if (mode == Mode.PUNCH) {
player.resetCooldown();
player.attackTargetEntityWithCurrentItem(entity);
success = true;
}
entity.captureDrops(null);
capturedDrops.forEach(e -> player.inventory.placeItemBackInInventory(this.world, e.getItem()));
if (success)
return;
}
// Shoot ray
RayTraceContext rayTraceContext = new RayTraceContext(rayOrigin, rayTarget, BlockMode.OUTLINE, FluidMode.NONE,
player);
BlockRayTraceResult result = world.rayTraceBlocks(rayTraceContext);
BlockState clickedState = world.getBlockState(clickedPos);
// Left click
if (mode == Mode.PUNCH) {
LeftClickBlock event = ForgeHooks.onLeftClickBlock(player, clickedPos, direction.getOpposite());
if (event.isCanceled())
return;
if (!world.isBlockModifiable(player, clickedPos))
return;
if (world.extinguishFire(player, clickedPos, direction.getOpposite()))
return;
if (clickedState.isAir(world, clickedPos))
return;
if (event.getUseBlock() != Result.DENY)
clickedState.onBlockClicked(world, clickedPos, player);
if (stack.isEmpty())
return;
float progress = clickedState.getPlayerRelativeBlockHardness(player, world, clickedPos) * 16;
float before = 0;
if (blockBreakingProgress != null)
before = blockBreakingProgress.getValue();
progress += before;
if (progress >= 1) {
player.interactionManager.tryHarvestBlock(clickedPos);
world.sendBlockBreakProgress(player.getEntityId(), clickedPos, -1);
blockBreakingProgress = null;
return;
}
if ((int) (before * 10) != (int) (progress * 10))
world.sendBlockBreakProgress(player.getEntityId(), clickedPos, (int) (progress * 10));
blockBreakingProgress = Pair.of(clickedPos, progress);
return;
}
// Right click
ItemUseContext itemusecontext = new ItemUseContext(player, hand, result);
RightClickBlock event = ForgeHooks.onRightClickBlock(player, hand, clickedPos, direction.getOpposite());
// Item has custom active use
if (event.getUseItem() != DENY) {
ActionResultType actionresult = stack.onItemUseFirst(itemusecontext);
if (actionresult != ActionResultType.PASS)
return;
}
boolean holdingSomething = !player.getHeldItemMainhand().isEmpty();
boolean flag1 = !(player.isSneaking() && holdingSomething)
|| (stack.doesSneakBypassUse(world, clickedPos, player));
// Use on block
if (event.getUseBlock() != DENY && flag1 && clickedState.onBlockActivated(world, player, hand, result))
return;
if (stack.isEmpty())
return;
if (event.getUseItem() == DENY)
return;
if (item instanceof BlockItem && !clickedState.isReplaceable(new BlockItemUseContext(itemusecontext)))
return;
// Reposition fire placement for convenience
if (item == Items.FLINT_AND_STEEL) {
Direction newFace = result.getFace();
BlockPos newPos = result.getPos();
if (!FlintAndSteelItem.canSetFire(clickedState, world, clickedPos))
newFace = Direction.UP;
if (clickedState.getMaterial() == Material.AIR)
newPos = newPos.offset(direction);
result = new BlockRayTraceResult(result.getHitVec(), newFace, newPos, result.isInside());
itemusecontext = new ItemUseContext(player, hand, result);
}
// 'Inert' item use behaviour & block placement
ActionResultType onItemUse = stack.onItemUse(itemusecontext);
if (onItemUse == ActionResultType.SUCCESS)
return;
if (item == Items.ENDER_PEARL)
return;
// buckets create their own ray, We use a fake wall to contain the active area
if (item instanceof BucketItem || item instanceof SandPaperItem) {
world = new WrappedWorld(world) {
boolean rayMode = false;
@Override
public BlockRayTraceResult rayTraceBlocks(RayTraceContext context) {
rayMode = true;
BlockRayTraceResult rayTraceBlocks = super.rayTraceBlocks(context);
rayMode = false;
return rayTraceBlocks;
};
@Override
public BlockState getBlockState(BlockPos position) {
if (rayMode
&& (pos.offset(direction, 3).equals(position) || pos.offset(direction, 1).equals(position)))
return Blocks.BEDROCK.getDefaultState();
return world.getBlockState(position);
}
};
}
ActionResult<ItemStack> onItemRightClick = item.onItemRightClick(world, player, hand);
player.setHeldItem(hand, onItemRightClick.getResult());
CompoundNBT tag = stack.getOrCreateTag();
if (stack.getItem() instanceof SandPaperItem && tag.contains("Polishing"))
spawnItemEffects = ItemStack.read(tag.getCompound("Polishing"));
if (stack.isFood())
spawnItemEffects = stack.copy();
if (!player.getActiveItemStack().isEmpty())
player.setHeldItem(hand, stack.onItemUseFinish(world, player));
player.resetActiveHand();
DeployerHandler.activate(player, center, clickedPos, movementVector, mode);
heldItem = player.getHeldItemMainhand();
}
protected void returnAndDeposit() {
@ -556,11 +350,12 @@ public class DeployerTileEntity extends KineticTileEntity {
@Override
public CompoundNBT writeToClient(CompoundNBT compound) {
compound.putFloat("Reach", reach);
if (player != null)
if (player != null) {
compound.put("HeldItem", player.getHeldItemMainhand().serializeNBT());
if (spawnItemEffects != null) {
compound.put("Particle", spawnItemEffects.serializeNBT());
spawnItemEffects = null;
if (player.spawnedItemEffects != null) {
compound.put("Particle", player.spawnedItemEffects.serializeNBT());
player.spawnedItemEffects = null;
}
}
return super.writeToClient(compound);
}
@ -584,14 +379,6 @@ public class DeployerTileEntity extends KineticTileEntity {
return false;
}
@Override
public void remove() {
if (!world.isRemote && blockBreakingProgress != null)
world.sendBlockBreakProgress(player.getEntityId(), blockBreakingProgress.getKey(), -1);
super.remove();
player = null;
}
public AllBlockPartials getHandPose() {
return mode == Mode.PUNCH ? AllBlockPartials.DEPLOYER_HAND_PUNCHING
: heldItem.isEmpty() ? AllBlockPartials.DEPLOYER_HAND_POINTING : AllBlockPartials.DEPLOYER_HAND_HOLDING;

View file

@ -4,18 +4,23 @@ import static com.simibubi.create.modules.contraptions.base.DirectionalAxisKinet
import static com.simibubi.create.modules.contraptions.base.DirectionalKineticBlock.FACING;
import static net.minecraft.state.properties.BlockStateProperties.AXIS;
import java.util.Arrays;
import java.util.List;
import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.behaviour.filtering.FilteringRenderer;
import com.simibubi.create.foundation.block.SafeTileEntityRenderer;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.TessellatorHelper;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.base.IRotate;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext;
import com.simibubi.create.modules.contraptions.components.deployer.DeployerTileEntity.Mode;
import com.simibubi.create.modules.contraptions.components.deployer.DeployerTileEntity.State;
@ -33,12 +38,14 @@ import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
@SuppressWarnings("deprecation")
public class DeployerTileEntityRenderer extends SafeTileEntityRenderer<DeployerTileEntity> {
@Override
public void renderWithGL(DeployerTileEntity te, double x, double y, double z, float partialTicks, int destroyStage) {
public void renderWithGL(DeployerTileEntity te, double x, double y, double z, float partialTicks,
int destroyStage) {
renderItem(te, x, y, z, partialTicks);
FilteringRenderer.renderOnTileEntity(te, x, y, z, partialTicks, destroyStage);
renderComponents(te, x, y, z, partialTicks);
@ -64,8 +71,8 @@ public class DeployerTileEntityRenderer extends SafeTileEntityRenderer<DeployerT
GlStateManager.translatef(0, 1 / 8f, -1 / 16f);
ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer();
boolean isBlockItem = (te.heldItem.getItem() instanceof BlockItem)
&& itemRenderer.getModelWithOverrides(te.heldItem).isGui3d();
boolean isBlockItem =
(te.heldItem.getItem() instanceof BlockItem) && itemRenderer.getModelWithOverrides(te.heldItem).isGui3d();
float scale = punching ? .75f : isBlockItem ? .75f - 1 / 64f : .5f;
GlStateManager.scaled(scale, scale, scale);
TransformType transform = punching ? TransformType.THIRD_PERSON_RIGHT_HAND : TransformType.FIXED;
@ -84,8 +91,8 @@ public class DeployerTileEntityRenderer extends SafeTileEntityRenderer<DeployerT
BlockState blockState = te.getBlockState();
BlockPos pos = te.getPos();
SuperByteBuffer pole = renderAndTransform(AllBlockPartials.DEPLOYER_POLE, blockState, pos, true);
SuperByteBuffer hand = renderAndTransform(te.getHandPose(), blockState, pos, false);
SuperByteBuffer pole = renderAndTransform(getWorld(), AllBlockPartials.DEPLOYER_POLE, blockState, pos, true);
SuperByteBuffer hand = renderAndTransform(getWorld(), te.getHandPose(), blockState, pos, false);
Vec3d offset = getHandOffset(te, partialTicks, blockState);
pole.translate(x + offset.x, y + offset.y, z + offset.z).renderInto(buffer);
@ -115,21 +122,44 @@ public class DeployerTileEntityRenderer extends SafeTileEntityRenderer<DeployerT
return AllBlocks.SHAFT.block.getDefaultState().with(AXIS, ((IRotate) state.getBlock()).getRotationAxis(state));
}
private SuperByteBuffer renderAndTransform(AllBlockPartials renderBlock, BlockState deployerState, BlockPos pos,
boolean axisDirectionMatters) {
private static SuperByteBuffer renderAndTransform(World world, AllBlockPartials renderBlock,
BlockState deployerState, BlockPos pos, boolean axisDirectionMatters) {
SuperByteBuffer buffer = renderBlock.renderOn(deployerState);
Direction facing = deployerState.get(FACING);
float zRotFirst = axisDirectionMatters
&& (deployerState.get(AXIS_ALONG_FIRST_COORDINATE) ^ facing.getAxis() == Axis.Z) ? 90 : 0;
float zRotFirst =
axisDirectionMatters && (deployerState.get(AXIS_ALONG_FIRST_COORDINATE) ^ facing.getAxis() == Axis.Z) ? 90
: 0;
float yRot = AngleHelper.horizontalAngle(facing);
float zRot = facing == Direction.UP ? 270 : facing == Direction.DOWN ? 90 : 0;
buffer.rotateCentered(Axis.Z, (float) ((zRotFirst) / 180 * Math.PI));
buffer.rotateCentered(Axis.Y, (float) ((yRot) / 180 * Math.PI));
buffer.rotateCentered(Axis.Z, (float) ((zRot) / 180 * Math.PI));
buffer.light(deployerState.getPackedLightmapCoords(getWorld(), pos));
buffer.light(deployerState.getPackedLightmapCoords(world, pos));
return buffer;
}
public static List<SuperByteBuffer> renderListInContraption(MovementContext context) {
BlockState blockState = context.state;
BlockPos pos = BlockPos.ZERO;
Mode mode = NBTHelper.readEnum(context.tileData.getString("Mode"), Mode.class);
World world = context.world;
AllBlockPartials handPose =
mode == Mode.PUNCH ? AllBlockPartials.DEPLOYER_HAND_PUNCHING : AllBlockPartials.DEPLOYER_HAND_POINTING;
SuperByteBuffer pole = renderAndTransform(world, AllBlockPartials.DEPLOYER_POLE, blockState, pos, true);
SuperByteBuffer hand = renderAndTransform(world, handPose, blockState, pos, false);
Vec3d center = VecHelper.getCenterOf(new BlockPos(context.position));
double distance = context.position.distanceTo(center);
double nextDistance = context.position.add(context.motion).distanceTo(center);
Vec3d offset = new Vec3d(blockState.get(FACING).getDirectionVec())
.scale(.5f - MathHelper.lerp(Minecraft.getInstance().getRenderPartialTicks(), distance, nextDistance));
pole.translate(offset.x, offset.y, offset.z);
hand.translate(offset.x, offset.y, offset.z);
return Arrays.asList(pole, hand);
}
}

View file

@ -138,6 +138,7 @@ public class FlexcrateBlock extends ProperDirectionalBlock {
if (state.hasTileEntity() && state.getBlock() != newState.getBlock()) {
FlexcrateTileEntity te = (FlexcrateTileEntity) worldIn.getTileEntity(pos);
if (!isMoving)
te.onDestroyed();
worldIn.removeTileEntity(pos);
}

View file

@ -157,6 +157,9 @@ public class FilterItem extends Item implements INamedContainerProvider {
}
private static boolean test(ItemStack stack, ItemStack filter, boolean matchNBT) {
if (filter.isEmpty())
return true;
if (!(filter.getItem() instanceof FilterItem))
return (matchNBT ? ItemHandlerHelper.canItemStacksStack(filter, stack)
: ItemStack.areItemsEqual(filter, stack));