Better Acting

- Contraption actors can now expose a few more properties and behaviours.
- Contraption actors can save data within the context
- Redstone Contacts now work when being rotated
- Fixed harvester and drill offsets and their motion-aware animation
- Fixed Mounted contraptions calculating their yaw inconsistently (again)
This commit is contained in:
simibubi 2019-12-09 13:32:39 +01:00
parent f991c88fc2
commit 5db014c45b
11 changed files with 188 additions and 110 deletions

View file

@ -4,6 +4,7 @@ import java.util.Random;
import net.minecraft.nbt.DoubleNBT; import net.minecraft.nbt.DoubleNBT;
import net.minecraft.nbt.ListNBT; import net.minecraft.nbt.ListNBT;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@ -11,9 +12,15 @@ import net.minecraft.util.math.Vec3i;
public class VecHelper { public class VecHelper {
public static Vec3d rotate(Vec3d vec, float deg, Axis axis) { public static Vec3d rotate(Vec3d vec, double xRot, double yRot, double zRot) {
float angle = (float) (deg / 180f * Math.PI); return rotate(rotate(rotate(vec, xRot, Axis.X), yRot, Axis.Y), zRot, Axis.Z);
}
public static Vec3d rotate(Vec3d vec, double deg, Axis axis) {
if (deg == 0)
return vec;
float angle = (float) (deg / 180f * Math.PI);
double sin = MathHelper.sin(angle); double sin = MathHelper.sin(angle);
double cos = MathHelper.cos(angle); double cos = MathHelper.cos(angle);
double x = vec.x; double x = vec.x;
@ -29,6 +36,10 @@ public class VecHelper {
return vec; return vec;
} }
public static boolean isVecPointingTowards(Vec3d vec, Direction direction) {
return new Vec3d(direction.getDirectionVec()).distanceTo(vec.normalize()) < .75;
}
public static Vec3d getCenterOf(Vec3i pos) { public static Vec3d getCenterOf(Vec3i pos) {
return new Vec3d(pos).add(.5f, .5f, .5f); return new Vec3d(pos).add(.5f, .5f, .5f);
} }

View file

@ -5,6 +5,7 @@ import java.util.List;
import com.simibubi.create.foundation.block.IRenderUtilityBlock; import com.simibubi.create.foundation.block.IRenderUtilityBlock;
import com.simibubi.create.foundation.block.IWithTileEntity; import com.simibubi.create.foundation.block.IWithTileEntity;
import com.simibubi.create.foundation.utility.SuperByteBuffer; import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.foundation.utility.VoxelShapers; import com.simibubi.create.foundation.utility.VoxelShapers;
import com.simibubi.create.modules.contraptions.base.DirectionalKineticBlock; import com.simibubi.create.modules.contraptions.base.DirectionalKineticBlock;
import com.simibubi.create.modules.contraptions.receivers.contraptions.IHaveMovementBehavior; import com.simibubi.create.modules.contraptions.receivers.contraptions.IHaveMovementBehavior;
@ -85,18 +86,22 @@ public class DrillBlock extends DirectionalKineticBlock
} }
@Override @Override
public void visitPosition(MovementContext context) { public boolean isActive(MovementContext context) {
Direction movement = context.getMovementDirection(); return !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.get(FACING).getOpposite());
}
// BlockState block = context.state; @Override
// if (movement == block.get(FACING).getOpposite()) public Vec3d getActiveAreaOffset(MovementContext context) {
// return; return new Vec3d(context.state.get(FACING).getDirectionVec()).scale(.65f);
}
@Override
public void visitNewPosition(MovementContext context, BlockPos pos) {
World world = context.world; World world = context.world;
BlockPos pos = context.currentGridPos;
// pos = pos.offset(movement);
BlockState stateVisited = world.getBlockState(pos); BlockState stateVisited = world.getBlockState(pos);
if (world.isRemote)
return;
if (stateVisited.getCollisionShape(world, pos).isEmpty()) if (stateVisited.getCollisionShape(world, pos).isEmpty())
return; return;
if (stateVisited.getBlockHardness(world, pos) == -1) if (stateVisited.getBlockHardness(world, pos) == -1)
@ -108,8 +113,7 @@ public class DrillBlock extends DirectionalKineticBlock
for (ItemStack stack : drops) { for (ItemStack stack : drops) {
ItemEntity itemEntity = new ItemEntity(world, pos.getX() + .5f, pos.getY() + .25f, pos.getZ() + .5f, stack); ItemEntity itemEntity = new ItemEntity(world, pos.getX() + .5f, pos.getY() + .25f, pos.getZ() + .5f, stack);
itemEntity.setMotion( itemEntity.setMotion(context.motion.add(0, 0.5f, 0).scale(world.rand.nextFloat() * .3f));
new Vec3d(movement.getDirectionVec()).add(0, 0.5f, 0).scale(world.rand.nextFloat() * .3f));
world.addEntity(itemEntity); world.addEntity(itemEntity);
} }
} }

View file

@ -6,6 +6,7 @@ import com.simibubi.create.AllBlocks;
import com.simibubi.create.CreateClient; import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.SuperByteBuffer; import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.base.IRotate; import com.simibubi.create.modules.contraptions.base.IRotate;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity; import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer;
@ -29,7 +30,9 @@ public class DrillTileEntityRenderer extends KineticTileEntityRenderer {
BlockState state = context.state; BlockState state = context.state;
SuperByteBuffer buffer = CreateClient.bufferCache.renderBlockState(KINETIC_TILE, getRenderedBlockState(state)); SuperByteBuffer buffer = CreateClient.bufferCache.renderBlockState(KINETIC_TILE, getRenderedBlockState(state));
float speed = (float) (context.getMovementDirection() == state.get(FACING) ? context.getAnimationSpeed() : 0); float speed = (float) (!VecHelper.isVecPointingTowards(context.relativeMotion, state.get(FACING).getOpposite())
? context.getAnimationSpeed()
: 0);
Axis axis = ((IRotate) state.getBlock()).getRotationAxis(state); Axis axis = ((IRotate) state.getBlock()).getRotationAxis(state);
float time = AnimationTickHolder.getRenderTick(); float time = AnimationTickHolder.getRenderTick();
float angle = (float) (((time * speed) % 360) / 180 * (float) Math.PI); float angle = (float) (((time * speed) % 360) / 180 * (float) Math.PI);

View file

@ -5,6 +5,7 @@ import java.util.List;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.block.IRenderUtilityBlock; import com.simibubi.create.foundation.block.IRenderUtilityBlock;
import com.simibubi.create.foundation.utility.SuperByteBuffer; import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.foundation.utility.VoxelShaper; import com.simibubi.create.foundation.utility.VoxelShaper;
import com.simibubi.create.modules.contraptions.receivers.contraptions.IHaveMovementBehavior; import com.simibubi.create.modules.contraptions.receivers.contraptions.IHaveMovementBehavior;
@ -107,18 +108,25 @@ public class HarvesterBlock extends HorizontalBlock implements IHaveMovementBeha
} }
@Override @Override
public void visitPosition(MovementContext context) { public boolean isActive(MovementContext context) {
Direction movement = context.getMovementDirection(); return !VecHelper.isVecPointingTowards(context.relativeMotion,
context.state.get(HORIZONTAL_FACING).getOpposite());
}
@Override
public Vec3d getActiveAreaOffset(MovementContext context) {
return new Vec3d(context.state.get(HORIZONTAL_FACING).getDirectionVec()).scale(.5);
}
@Override
public void visitNewPosition(MovementContext context, BlockPos pos) {
World world = context.world; World world = context.world;
BlockState block = context.state;
BlockPos pos = context.currentGridPos;
// if (movement != block.get(HORIZONTAL_FACING))
// return;
BlockState stateVisited = world.getBlockState(pos); BlockState stateVisited = world.getBlockState(pos);
boolean notCropButCuttable = false; boolean notCropButCuttable = false;
if (world.isRemote)
return;
if (stateVisited.getBlock() == Blocks.SUGAR_CANE) { if (stateVisited.getBlock() == Blocks.SUGAR_CANE) {
notCropButCuttable = true; notCropButCuttable = true;
pos = pos.up(); pos = pos.up();
@ -143,8 +151,7 @@ public class HarvesterBlock extends HorizontalBlock implements IHaveMovementBeha
seedSubtracted = true; seedSubtracted = true;
} }
ItemEntity itemEntity = new ItemEntity(world, pos.getX() + .5f, pos.getY() + .25f, pos.getZ() + .5f, stack); ItemEntity itemEntity = new ItemEntity(world, pos.getX() + .5f, pos.getY() + .25f, pos.getZ() + .5f, stack);
itemEntity.setMotion( itemEntity.setMotion(context.motion.add(0, 0.5f, 0).scale(world.rand.nextFloat() * .3f));
new Vec3d(movement.getDirectionVec()).add(0, 0.5f, 0).scale(world.rand.nextFloat() * .3f));
world.addEntity(itemEntity); world.addEntity(itemEntity);
} }
} }

View file

@ -7,6 +7,7 @@ import com.simibubi.create.AllBlocks;
import com.simibubi.create.CreateClient; import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.SuperByteBuffer; import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.receivers.contraptions.IHaveMovementBehavior.MovementContext; import com.simibubi.create.modules.contraptions.receivers.contraptions.IHaveMovementBehavior.MovementContext;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
@ -28,13 +29,9 @@ public class HarvesterTileEntityRenderer extends TileEntityRenderer<HarvesterTil
public static SuperByteBuffer renderInContraption(MovementContext context) { public static SuperByteBuffer renderInContraption(MovementContext context) {
BlockState state = context.state; BlockState state = context.state;
Direction facing = context.getMovementDirection(); float speed = (float) (!VecHelper.isVecPointingTowards(context.relativeMotion, state.get(HORIZONTAL_FACING).getOpposite())
float speed = -500 * state.get(HORIZONTAL_FACING).getAxisDirection().getOffset(); ? context.getAnimationSpeed() * state.get(HORIZONTAL_FACING).getAxisDirection().getOffset()
// float speed = (float) (facing != state.get(HORIZONTAL_FACING) : 0);
// ? context.getAnimationSpeed() * facing.getAxisDirection().getOffset()
// : 0);
// if (facing.getAxis() == Axis.X)
// speed = -speed;
float time = AnimationTickHolder.getRenderTick(); float time = AnimationTickHolder.getRenderTick();
float angle = (float) (((time * speed) % 360) / 180 * (float) Math.PI); float angle = (float) (((time * speed) % 360) / 180 * (float) Math.PI);

View file

@ -45,7 +45,6 @@ import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IWorld; import net.minecraft.world.IWorld;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo; import net.minecraft.world.gen.feature.template.Template.BlockInfo;
@ -597,10 +596,9 @@ public class Contraption {
public void initActors(World world) { public void initActors(World world) {
for (MutablePair<BlockInfo, MovementContext> pair : actors) { for (MutablePair<BlockInfo, MovementContext> pair : actors) {
MovementContext context = new MovementContext(world, pair.left.state); BlockState blockState = pair.left.state;
context.world = world; MovementContext context = new MovementContext(world, blockState);
context.motion = Vec3d.ZERO; ((IHaveMovementBehavior) blockState.getBlock()).startMoving(context);
context.currentGridPos = BlockPos.ZERO;
pair.setRight(context); pair.setRight(context);
} }
} }

View file

@ -1,5 +1,7 @@
package com.simibubi.create.modules.contraptions.receivers.contraptions; package com.simibubi.create.modules.contraptions.receivers.contraptions;
import org.apache.commons.lang3.tuple.MutablePair;
import com.simibubi.create.AllEntities; import com.simibubi.create.AllEntities;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.receivers.contraptions.IHaveMovementBehavior.MovementContext; import com.simibubi.create.modules.contraptions.receivers.contraptions.IHaveMovementBehavior.MovementContext;
@ -11,25 +13,25 @@ import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil; import net.minecraft.nbt.NBTUtil;
import net.minecraft.network.IPacket; import net.minecraft.network.IPacket;
import net.minecraft.network.PacketBuffer; import net.minecraft.network.PacketBuffer;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
import net.minecraft.world.server.ServerWorld; import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
import net.minecraftforge.fml.network.NetworkHooks; import net.minecraftforge.fml.network.NetworkHooks;
public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnData { public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnData {
private Contraption contraption; protected Contraption contraption;
protected float initialAngle; protected float initialAngle;
protected BlockPos controllerPos; protected BlockPos controllerPos;
protected IControlContraption controllerTE; protected IControlContraption controllerTE;
public float movementSpeedModifier;
public float prevYaw; public float prevYaw;
public float prevPitch; public float prevPitch;
public float prevRoll; public float prevRoll;
@ -57,6 +59,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
this.prevYaw = initialAngle; this.prevYaw = initialAngle;
this.yaw = initialAngle; this.yaw = initialAngle;
this.targetYaw = initialAngle; this.targetYaw = initialAngle;
movementSpeedModifier = 1;
} }
public <T extends TileEntity & IControlContraption> ContraptionEntity controlledBy(T controller) { public <T extends TileEntity & IControlContraption> ContraptionEntity controlledBy(T controller) {
@ -82,11 +85,17 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
yaw += 360; yaw += 360;
} }
if (Math.abs(getShortestAngleDiff(yaw, targetYaw)) >= 175) {
initialAngle += 180;
yaw += 180;
prevYaw = yaw;
} else {
float speed = 0.2f; float speed = 0.2f;
prevYaw = yaw; prevYaw = yaw;
yaw = angleLerp(speed, yaw, targetYaw); yaw = angleLerp(speed, yaw, targetYaw);
prevPitch = pitch; prevPitch = pitch;
pitch = angleLerp(speed, pitch, targetPitch); pitch = angleLerp(speed, pitch, targetPitch);
}
tickActors(movementVector); tickActors(movementVector);
super.tick(); super.tick();
@ -102,31 +111,48 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
} }
public void tickActors(Vec3d movementVector) { public void tickActors(Vec3d movementVector) {
getContraption().getActors().forEach(pair -> { movementSpeedModifier = 1;
MovementContext context = pair.right;
float deg = (getRidingEntity() != null ? yaw + 180 : yaw) + initialAngle;
context.motion = VecHelper.rotate(movementVector, deg, Axis.Y);
if (context.world == null)
context.world = world;
float anglePitch = getPitch(1);
float angleYaw = getYaw(1);
float angleRoll = getRoll(1);
Vec3d rotationVec = new Vec3d(angleRoll, angleYaw, anglePitch);
Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO); Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO);
Vec3d offset = new Vec3d(pair.left.pos);
offset = VecHelper.rotate(offset, deg, Axis.Y);
offset = offset.add(rotationOffset);
offset = offset.add(posX, posY, posZ);
if (world.isRemote) for (MutablePair<BlockInfo, MovementContext> pair : contraption.actors) {
return; MovementContext context = pair.right;
BlockInfo blockInfo = pair.left;
IHaveMovementBehavior actor = (IHaveMovementBehavior) blockInfo.state.getBlock();
BlockPos gridPos = new BlockPos(offset); Vec3d actorPosition = new Vec3d(blockInfo.pos);
if (context.currentGridPos.equals(gridPos)) actorPosition = actorPosition.add(actor.getActiveAreaOffset(context));
return; actorPosition = VecHelper.rotate(actorPosition, angleRoll, angleYaw, anglePitch);
context.currentGridPos = gridPos; actorPosition = actorPosition.add(rotationOffset).add(posX, posY, posZ);
IHaveMovementBehavior actor = (IHaveMovementBehavior) pair.left.state.getBlock(); Vec3d previousPosition = context.position;
actor.visitPosition(context); BlockPos gridPosition = new BlockPos(actorPosition);
}); boolean newPosVisited = true;
if (previousPosition != null) {
context.motion = actorPosition.subtract(previousPosition);
Vec3d relativeMotion = context.motion;
relativeMotion = VecHelper.rotate(relativeMotion, -angleRoll, -angleYaw, -anglePitch);
context.relativeMotion = relativeMotion;
newPosVisited = !new BlockPos(previousPosition).equals(gridPosition);
}
context.rotation = rotationVec;
context.position = actorPosition;
if (actor.isActive(context)) {
if (newPosVisited)
actor.visitNewPosition(context, gridPosition);
actor.tick(context);
}
if (movementSpeedModifier > context.movementSpeedModifier)
movementSpeedModifier = context.movementSpeedModifier;
}
} }
public void moveTo(double x, double y, double z) { public void moveTo(double x, double y, double z) {
@ -182,11 +208,12 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
} }
public static float yawFromMotion(Vec3d motion) { public static float yawFromMotion(Vec3d motion) {
return (float) ((Math.PI / 2 - Math.atan2(motion.z, motion.x)) / Math.PI * 180); return (float) ((3 * Math.PI / 2 + Math.atan2(motion.z, motion.x)) / Math.PI * 180);
} }
public float getYaw(float partialTicks) { public float getYaw(float partialTicks) {
return (partialTicks == 1.0F ? yaw : angleLerp(partialTicks, prevYaw, yaw)) - initialAngle; return (getRidingEntity() == null ? 1 : -1)
* (partialTicks == 1.0F ? yaw : angleLerp(partialTicks, prevYaw, yaw)) + initialAngle;
} }
public float getPitch(float partialTicks) { public float getPitch(float partialTicks) {

View file

@ -36,6 +36,13 @@ public class ContraptionEntityRenderer extends EntityRenderer<ContraptionEntity>
return; return;
GlStateManager.pushMatrix(); GlStateManager.pushMatrix();
long randomBits = (long) entity.getEntityId() * 493286711L;
randomBits = randomBits * randomBits * 4392167121L + randomBits * 98761L;
float xNudge = (((float) (randomBits >> 16 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F;
float yNudge = (((float) (randomBits >> 20 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F;
float zNudge = (((float) (randomBits >> 24 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F;
GlStateManager.translatef(xNudge, yNudge, zNudge);
float angleYaw = (float) (entity.getYaw(partialTicks) / 180 * Math.PI); float angleYaw = (float) (entity.getYaw(partialTicks) / 180 * Math.PI);
float anglePitch = (float) (entity.getPitch(partialTicks) / 180 * Math.PI); float anglePitch = (float) (entity.getPitch(partialTicks) / 180 * Math.PI);
float angleRoll = (float) (entity.getRoll(partialTicks) / 180 * Math.PI); float angleRoll = (float) (entity.getRoll(partialTicks) / 180 * Math.PI);
@ -44,20 +51,12 @@ public class ContraptionEntityRenderer extends EntityRenderer<ContraptionEntity>
if (ridingEntity != null && ridingEntity instanceof AbstractMinecartEntity) { if (ridingEntity != null && ridingEntity instanceof AbstractMinecartEntity) {
AbstractMinecartEntity cart = (AbstractMinecartEntity) ridingEntity; AbstractMinecartEntity cart = (AbstractMinecartEntity) ridingEntity;
long i = (long) entity.getEntityId() * 493286711L;
i = i * i * 4392167121L + i * 98761L;
float f = (((float) (i >> 16 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F;
float f1 = (((float) (i >> 20 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F;
float f2 = (((float) (i >> 24 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F;
GlStateManager.translatef(f, f1, f2);
double cartX = MathHelper.lerp((double) partialTicks, cart.lastTickPosX, cart.posX); double cartX = MathHelper.lerp((double) partialTicks, cart.lastTickPosX, cart.posX);
double cartY = MathHelper.lerp((double) partialTicks, cart.lastTickPosY, cart.posY); double cartY = MathHelper.lerp((double) partialTicks, cart.lastTickPosY, cart.posY);
double cartZ = MathHelper.lerp((double) partialTicks, cart.lastTickPosZ, cart.posZ); double cartZ = MathHelper.lerp((double) partialTicks, cart.lastTickPosZ, cart.posZ);
Vec3d cartPos = cart.getPos(cartX, cartY, cartZ); Vec3d cartPos = cart.getPos(cartX, cartY, cartZ);
if (cartPos != null) { if (cartPos != null) {
Vec3d cartPosFront = cart.getPosOffset(cartX, cartY, cartZ, (double) 0.3F); Vec3d cartPosFront = cart.getPosOffset(cartX, cartY, cartZ, (double) 0.3F);
Vec3d cartPosBack = cart.getPosOffset(cartX, cartY, cartZ, (double) -0.3F); Vec3d cartPosBack = cart.getPosOffset(cartX, cartY, cartZ, (double) -0.3F);
if (cartPosFront == null) if (cartPosFront == null)
@ -73,10 +72,7 @@ public class ContraptionEntityRenderer extends EntityRenderer<ContraptionEntity>
} }
} }
// BlockPos anchor = entity.getContraption().getAnchor();
Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO); Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO);
// Vec3d offset = VecHelper.getCenterOf(anchor).scale(-1);
TessellatorHelper.prepareFastRender(); TessellatorHelper.prepareFastRender();
TessellatorHelper.begin(DefaultVertexFormats.BLOCK); TessellatorHelper.begin(DefaultVertexFormats.BLOCK);
ContraptionRenderer.render(entity.world, entity.getContraption(), superByteBuffer -> { ContraptionRenderer.render(entity.world, entity.getContraption(), superByteBuffer -> {

View file

@ -2,12 +2,10 @@ package com.simibubi.create.modules.contraptions.receivers.contraptions;
import com.simibubi.create.foundation.utility.SuperByteBuffer; import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.receivers.contraptions.piston.MechanicalPistonTileEntity;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil; import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -17,60 +15,82 @@ import net.minecraftforge.common.util.Constants.NBT;
public interface IHaveMovementBehavior { public interface IHaveMovementBehavior {
public enum MoverType {
PISTON, BEARING, MINECART;
}
default void visitPosition(MovementContext context) {
}
default void tick(MechanicalPistonTileEntity piston) {
}
default boolean hasSpecialRenderer() {
return false;
}
public class MovementContext { public class MovementContext {
public BlockPos currentGridPos; public Vec3d position;
public Vec3d motion; public Vec3d motion;
public float movementSpeedModifier = 1; public Vec3d relativeMotion;
public Vec3d rotation;
public World world; public World world;
public BlockState state; public BlockState state;
public float movementSpeedModifier;
public CompoundNBT data;
public MovementContext(World world, BlockState state) { public MovementContext(World world, BlockState state) {
this.world = world; this.world = world;
this.state = state; this.state = state;
}
public Direction getMovementDirection() { motion = Vec3d.ZERO;
return Direction.getFacingFromVector(motion.x, motion.y, motion.z); relativeMotion = Vec3d.ZERO;
rotation = Vec3d.ZERO;
position = null;
data = new CompoundNBT();
movementSpeedModifier = 1;
} }
public float getAnimationSpeed() { public float getAnimationSpeed() {
int modifier = 1000; int modifier = 1000;
return ((int) (motion.length() * modifier)) / 100 * 100; double length = -motion.length();
if (Math.abs(length) < 1 / 512f)
return 0;
return (((int) (length * modifier + 100 * Math.signum(length))) / 100) * 100;
} }
public static MovementContext readNBT(World world, CompoundNBT nbt) { public static MovementContext readNBT(World world, CompoundNBT nbt) {
MovementContext context = new MovementContext(world, NBTUtil.readBlockState(nbt.getCompound("State"))); BlockState state = NBTUtil.readBlockState(nbt.getCompound("State"));
MovementContext context = new MovementContext(world, state);
context.motion = VecHelper.readNBT(nbt.getList("Motion", NBT.TAG_DOUBLE)); 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));
if (nbt.contains("Position"))
context.position = VecHelper.readNBT(nbt.getList("Position", NBT.TAG_DOUBLE));
context.movementSpeedModifier = nbt.getFloat("SpeedModifier"); context.movementSpeedModifier = nbt.getFloat("SpeedModifier");
context.currentGridPos = NBTUtil.readBlockPos(nbt.getCompound("GridPos")); context.data = nbt.getCompound("Data");
return context; return context;
} }
public CompoundNBT writeToNBT(CompoundNBT nbt) { public CompoundNBT writeToNBT(CompoundNBT nbt) {
nbt.put("State", NBTUtil.writeBlockState(state)); nbt.put("State", NBTUtil.writeBlockState(state));
nbt.put("Motion", VecHelper.writeNBT(motion)); nbt.put("Motion", VecHelper.writeNBT(motion));
nbt.put("RelativeMotion", VecHelper.writeNBT(relativeMotion));
nbt.put("Rotation", VecHelper.writeNBT(rotation));
if (position != null)
nbt.put("Position", VecHelper.writeNBT(position));
nbt.putFloat("SpeedModifier", movementSpeedModifier); nbt.putFloat("SpeedModifier", movementSpeedModifier);
nbt.put("GridPos", NBTUtil.writeBlockPos(currentGridPos)); nbt.put("Data", data);
return nbt; return nbt;
} }
} }
default boolean isActive(MovementContext context) {
return true;
}
default void tick(MovementContext context) {
}
default void startMoving(MovementContext context) {
}
default void visitNewPosition(MovementContext context, BlockPos pos) {
}
default Vec3d getActiveAreaOffset(MovementContext context) {
return Vec3d.ZERO;
}
@OnlyIn(value = Dist.CLIENT) @OnlyIn(value = Dist.CLIENT)
default SuperByteBuffer renderInContraption(MovementContext context) { default SuperByteBuffer renderInContraption(MovementContext context) {
return null; return null;

View file

@ -170,7 +170,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
if (movedContraption != null) { if (movedContraption != null) {
Direction direction = getBlockState().get(BlockStateProperties.FACING); Direction direction = getBlockState().get(BlockStateProperties.FACING);
Vec3d vec = new Vec3d(1, 1, 1).scale(angle * 180 / Math.PI).mul(new Vec3d(direction.getDirectionVec())); Vec3d vec = new Vec3d(1, 1, 1).scale(angle * 180 / Math.PI).mul(new Vec3d(direction.getDirectionVec()));
movedContraption.rotateTo(-vec.x, vec.y, -vec.z); movedContraption.rotateTo(vec.x, vec.y, -vec.z);
} }
} }

View file

@ -4,6 +4,7 @@ import java.util.Random;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.block.ProperDirectionalBlock; import com.simibubi.create.foundation.block.ProperDirectionalBlock;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.receivers.contraptions.IHaveMovementBehavior; import com.simibubi.create.modules.contraptions.receivers.contraptions.IHaveMovementBehavior;
import net.minecraft.block.Block; import net.minecraft.block.Block;
@ -15,6 +16,7 @@ import net.minecraft.state.StateContainer.Builder;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IBlockReader; import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld; import net.minecraft.world.IWorld;
import net.minecraft.world.TickPriority; import net.minecraft.world.TickPriority;
@ -100,19 +102,32 @@ public class ContactBlock extends ProperDirectionalBlock implements IHaveMovemen
} }
@Override @Override
public void visitPosition(MovementContext context) { public Vec3d getActiveAreaOffset(MovementContext context) {
return new Vec3d(context.state.get(FACING).getDirectionVec()).scale(.65f);
}
@Override
public void visitNewPosition(MovementContext context, BlockPos pos) {
BlockState block = context.state; BlockState block = context.state;
World world = context.world; World world = context.world;
BlockPos pos = context.currentGridPos;
Direction direction = block.get(FACING); if (world.isRemote)
if (!hasValidContact(world, pos, direction))
return; return;
int ticksToStayActive = (int) Math BlockState visitedState = world.getBlockState(pos);
.ceil(1 / Math.abs(context.motion.length())); if (!AllBlocks.CONTACT.typeOf(visitedState))
world.setBlockState(pos.offset(direction), world.getBlockState(pos.offset(direction)).with(POWERED, true)); return;
world.getPendingBlockTicks().scheduleTick(pos.offset(direction), this, ticksToStayActive, TickPriority.NORMAL);
Vec3d contact = new Vec3d(block.get(FACING).getDirectionVec());
contact = VecHelper.rotate(contact, context.rotation.x, context.rotation.y, context.rotation.z);
Direction direction = Direction.getFacingFromVector(contact.x, contact.y, contact.z);
if (!hasValidContact(world, pos.offset(direction.getOpposite()), direction))
return;
int ticksToStayActive = 4;
world.setBlockState(pos, visitedState.with(POWERED, true));
world.getPendingBlockTicks().scheduleTick(pos, this, ticksToStayActive, TickPriority.NORMAL);
return; return;
} }