Merge remote-tracking branch 'origin/mc1.15/dev' into mc1.16/dev

# Conflicts:
#	src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java
#	src/main/java/com/simibubi/create/content/curiosities/TreeFertilizerItem.java
This commit is contained in:
JozsefA 2021-03-31 21:17:01 -07:00
commit 78fbb52ddc
15 changed files with 306 additions and 108 deletions

View file

@ -50,10 +50,7 @@ import com.simibubi.create.content.contraptions.components.press.PressInstance;
import com.simibubi.create.content.contraptions.components.saw.SawInstance; import com.simibubi.create.content.contraptions.components.saw.SawInstance;
import com.simibubi.create.content.contraptions.components.saw.SawRenderer; import com.simibubi.create.content.contraptions.components.saw.SawRenderer;
import com.simibubi.create.content.contraptions.components.saw.SawTileEntity; import com.simibubi.create.content.contraptions.components.saw.SawTileEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.bearing.BearingRenderer; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.*;
import com.simibubi.create.content.contraptions.components.structureMovement.bearing.ClockworkBearingTileEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.bearing.MechanicalBearingTileEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.bearing.WindmillBearingTileEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.chassis.ChassisTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.ChassisTileEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerInstance; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerInstance;
import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerRenderer; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerRenderer;
@ -380,21 +377,21 @@ public class AllTileEntities {
public static final TileEntityEntry<WindmillBearingTileEntity> WINDMILL_BEARING = Create.registrate() public static final TileEntityEntry<WindmillBearingTileEntity> WINDMILL_BEARING = Create.registrate()
.tileEntity("windmill_bearing", WindmillBearingTileEntity::new) .tileEntity("windmill_bearing", WindmillBearingTileEntity::new)
.instance(() -> BackHalfShaftInstance::new) .instance(() -> BearingInstance::new)
.validBlocks(AllBlocks.WINDMILL_BEARING) .validBlocks(AllBlocks.WINDMILL_BEARING)
.renderer(() -> BearingRenderer::new) .renderer(() -> BearingRenderer::new)
.register(); .register();
public static final TileEntityEntry<MechanicalBearingTileEntity> MECHANICAL_BEARING = Create.registrate() public static final TileEntityEntry<MechanicalBearingTileEntity> MECHANICAL_BEARING = Create.registrate()
.tileEntity("mechanical_bearing", MechanicalBearingTileEntity::new) .tileEntity("mechanical_bearing", MechanicalBearingTileEntity::new)
.instance(() -> BackHalfShaftInstance::new) .instance(() -> BearingInstance::new)
.validBlocks(AllBlocks.MECHANICAL_BEARING) .validBlocks(AllBlocks.MECHANICAL_BEARING)
.renderer(() -> BearingRenderer::new) .renderer(() -> BearingRenderer::new)
.register(); .register();
public static final TileEntityEntry<ClockworkBearingTileEntity> CLOCKWORK_BEARING = Create.registrate() public static final TileEntityEntry<ClockworkBearingTileEntity> CLOCKWORK_BEARING = Create.registrate()
.tileEntity("clockwork_bearing", ClockworkBearingTileEntity::new) .tileEntity("clockwork_bearing", ClockworkBearingTileEntity::new)
.instance(() -> BackHalfShaftInstance::new) .instance(() -> BearingInstance::new)
.validBlocks(AllBlocks.CLOCKWORK_BEARING) .validBlocks(AllBlocks.CLOCKWORK_BEARING)
.renderer(() -> BearingRenderer::new) .renderer(() -> BearingRenderer::new)
.register(); .register();

View file

@ -13,6 +13,7 @@ import org.apache.commons.lang3.mutable.MutableInt;
import org.apache.commons.lang3.mutable.MutableObject; import org.apache.commons.lang3.mutable.MutableObject;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableSet;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.AllMovementBehaviours;
import com.simibubi.create.content.contraptions.components.actors.BlockBreakingMovementBehaviour; import com.simibubi.create.content.contraptions.components.actors.BlockBreakingMovementBehaviour;
@ -221,6 +222,7 @@ public class ContraptionCollider {
totalResponse = VecHelper.rotate(totalResponse, yawOffset, Axis.Y); totalResponse = VecHelper.rotate(totalResponse, yawOffset, Axis.Y);
collisionNormal = rotationMatrix.transform(collisionNormal); collisionNormal = rotationMatrix.transform(collisionNormal);
collisionNormal = VecHelper.rotate(collisionNormal, yawOffset, Axis.Y); collisionNormal = VecHelper.rotate(collisionNormal, yawOffset, Axis.Y);
collisionNormal = collisionNormal.normalize();
collisionLocation = rotationMatrix.transform(collisionLocation); collisionLocation = rotationMatrix.transform(collisionLocation);
collisionLocation = VecHelper.rotate(collisionLocation, yawOffset, Axis.Y); collisionLocation = VecHelper.rotate(collisionLocation, yawOffset, Axis.Y);
rotationMatrix.transpose(); rotationMatrix.transpose();
@ -248,16 +250,11 @@ public class ContraptionCollider {
boolean hasNormal = !collisionNormal.equals(Vector3d.ZERO); boolean hasNormal = !collisionNormal.equals(Vector3d.ZERO);
boolean anyCollision = hardCollision || temporalCollision; boolean anyCollision = hardCollision || temporalCollision;
if (bounce > 0 && hasNormal && anyCollision) { if (bounce > 0 && hasNormal && anyCollision && bounceEntity(entity, collisionNormal, contraptionEntity, bounce)) {
collisionNormal = collisionNormal.normalize(); entity.world.playSound(playerType == PlayerType.CLIENT ? (PlayerEntity) entity : null,
Vector3d newNormal = collisionNormal.crossProduct(collisionNormal.crossProduct(entityMotionNoTemporal)) entity.getX(), entity.getY(), entity.getZ(), SoundEvents.BLOCK_SLIME_BLOCK_FALL,
.normalize(); SoundCategory.BLOCKS, .5f, 1);
if (bounceEntity(entity, newNormal, contraptionEntity, bounce)) { continue;
entity.world.playSound(playerType == PlayerType.CLIENT ? (PlayerEntity) entity : null,
entity.getX(), entity.getY(), entity.getZ(), SoundEvents.BLOCK_SLIME_BLOCK_FALL,
SoundCategory.BLOCKS, .5f, 1);
continue;
}
} }
if (temporalCollision) { if (temporalCollision) {
@ -288,7 +285,6 @@ public class ContraptionCollider {
} }
if (bounce == 0 && slide > 0 && hasNormal && anyCollision && rotation.hasVerticalRotation()) { if (bounce == 0 && slide > 0 && hasNormal && anyCollision && rotation.hasVerticalRotation()) {
collisionNormal = collisionNormal.normalize();
Vector3d motionIn = entityMotionNoTemporal.mul(0, 1, 0) Vector3d motionIn = entityMotionNoTemporal.mul(0, 1, 0)
.add(0, -.01f, 0); .add(0, -.01f, 0);
Vector3d slideNormal = collisionNormal.crossProduct(motionIn.crossProduct(collisionNormal)) Vector3d slideNormal = collisionNormal.crossProduct(motionIn.crossProduct(collisionNormal))
@ -346,35 +342,14 @@ public class ContraptionCollider {
return false; return false;
if (entity.bypassesLandingEffects()) if (entity.bypassesLandingEffects())
return false; return false;
if (normal.equals(Vector3d.ZERO))
return false;
Vector3d contraptionVec = Vector3d.ZERO;
Vector3d contactPointMotion = contraption.getContactPointMotion(entity.getPositionVec()); Vector3d contactPointMotion = contraption.getContactPointMotion(entity.getPositionVec());
Vector3d motion = entity.getMotion() Vector3d motion = entity.getMotion().subtract(contactPointMotion);
.subtract(contactPointMotion); Vector3d deltav = normal.scale(factor*2*motion.dotProduct(normal));
if (deltav.dotProduct(deltav) < 0.1f)
Vector3d v2 = motion.crossProduct(normal) return false;
.normalize(); entity.setMotion(entity.getMotion().subtract(deltav));
if (v2 != Vector3d.ZERO) return true;
contraptionVec = normal.scale(contraptionVec.dotProduct(normal))
.add(v2.scale(contraptionVec.dotProduct(v2)));
else
v2 = normal.crossProduct(normal.add(Math.random(), Math.random(), Math.random()))
.normalize();
Vector3d v3 = normal.crossProduct(v2);
motion = motion.subtract(contraptionVec);
Vector3d lr = new Vector3d(factor * motion.dotProduct(normal), -motion.dotProduct(v2), -motion.dotProduct(v3));
if (lr.dotProduct(lr) > 1 / 16f) {
Vector3d newMot = contactPointMotion.add(normal.x * lr.x + v2.x * lr.y + v3.x * lr.z,
normal.y * lr.x + v2.y * lr.y + v3.y * lr.z, normal.z * lr.x + v2.z * lr.y + v3.z * lr.z);
entity.setMotion(newMot);
return true;
}
return false;
} }
public static Vector3d getWorldToLocalTranslation(Entity entity, AbstractContraptionEntity contraptionEntity) { public static Vector3d getWorldToLocalTranslation(Entity entity, AbstractContraptionEntity contraptionEntity) {

View file

@ -8,15 +8,6 @@ public class NonStationaryLighter<C extends Contraption> extends ContraptionLigh
super(contraption); super(contraption);
} }
@Override
protected GridAlignedBB contraptionBoundsToVolume(GridAlignedBB bounds) {
bounds.grow(2); // so we have at least enough data on the edges to avoid artifacts and have smooth lighting
bounds.minY = Math.max(bounds.minY, 0);
bounds.maxY = Math.min(bounds.maxY, 255);
return bounds;
}
@Override @Override
public void tick(RenderedContraption owner) { public void tick(RenderedContraption owner) {
super.tick(owner); super.tick(owner);

View file

@ -0,0 +1,77 @@
package com.simibubi.create.content.contraptions.components.structureMovement.bearing;
import net.minecraft.client.renderer.Quaternion;
import net.minecraft.client.renderer.Vector3f;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.Direction;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.base.BackHalfShaftInstance;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.foundation.render.backend.core.OrientedData;
import com.simibubi.create.foundation.render.backend.instancing.IDynamicInstance;
import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
public class BearingInstance<B extends KineticTileEntity & IBearingTileEntity> extends BackHalfShaftInstance implements IDynamicInstance {
final B bearing;
final OrientedData topInstance;
final Vector3f rotationAxis;
final Quaternion blockOrientation;
public BearingInstance(InstancedTileRenderer<?> modelManager, B tile) {
super(modelManager, tile);
this.bearing = tile;
Direction facing = blockState.get(BlockStateProperties.FACING);
rotationAxis = Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector();
blockOrientation = getBlockStateOrientation(facing);
AllBlockPartials top =
bearing.isWoodenTop() ? AllBlockPartials.BEARING_TOP_WOODEN : AllBlockPartials.BEARING_TOP;
topInstance = getOrientedMaterial().getModel(top, blockState).createInstance();
topInstance.setPosition(getInstancePosition()).setRotation(blockOrientation);
}
@Override
public void beginFrame() {
float interpolatedAngle = bearing.getInterpolatedAngle(AnimationTickHolder.getPartialTicks() - 1);
Quaternion rot = rotationAxis.getDegreesQuaternion(interpolatedAngle);
rot.multiply(blockOrientation);
topInstance.setRotation(rot);
}
@Override
public void updateLight() {
super.updateLight();
relight(pos, topInstance);
}
@Override
public void remove() {
super.remove();
topInstance.delete();
}
static Quaternion getBlockStateOrientation(Direction facing) {
Quaternion orientation;
if (facing.getAxis().isHorizontal()) {
orientation = Vector3f.POSITIVE_Y.getDegreesQuaternion(AngleHelper.horizontalAngle(facing.getOpposite()));
} else {
orientation = Quaternion.IDENTITY.copy();
}
orientation.multiply(Vector3f.POSITIVE_X.getDegreesQuaternion(-90 - AngleHelper.verticalAngle(facing)));
return orientation;
}
}

View file

@ -5,6 +5,7 @@ import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.render.SuperByteBuffer;
import com.simibubi.create.foundation.render.backend.FastRenderDispatcher;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer;
@ -22,6 +23,9 @@ public class BearingRenderer extends KineticTileEntityRenderer {
@Override @Override
protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
int light, int overlay) { int light, int overlay) {
if (FastRenderDispatcher.available(te.getWorld())) return;
super.renderSafe(te, partialTicks, ms, buffer, light, overlay); super.renderSafe(te, partialTicks, ms, buffer, light, overlay);
IBearingTileEntity bearingTe = (IBearingTileEntity) te; IBearingTileEntity bearingTe = (IBearingTileEntity) te;

View file

@ -0,0 +1,51 @@
package com.simibubi.create.content.contraptions.components.structureMovement.bearing;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.Quaternion;
import net.minecraft.client.renderer.Vector3f;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.Direction;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionKineticRenderer;
import com.simibubi.create.foundation.render.backend.core.OrientedData;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
public class StabilizedBearingInstance extends ActorInstance {
final OrientedData topInstance;
final Direction facing;
final Vector3f rotationAxis;
final Quaternion blockOrientation;
public StabilizedBearingInstance(ContraptionKineticRenderer modelManager, MovementContext context) {
super(modelManager, context);
BlockState blockState = context.state;
facing = blockState.get(BlockStateProperties.FACING);
rotationAxis = Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, facing.getAxis()).getUnitVector();
blockOrientation = BearingInstance.getBlockStateOrientation(facing);
topInstance = modelManager.getOrientedMaterial().getModel(AllBlockPartials.BEARING_TOP, blockState).createInstance();
topInstance.setPosition(context.localPos)
.setRotation(blockOrientation)
.setBlockLight(localBlockLight());
}
@Override
public void beginFrame() {
float counterRotationAngle = StabilizedBearingMovementBehaviour.getCounterRotationAngle(context, facing, AnimationTickHolder.getPartialTicks());
Quaternion rotation = rotationAxis.getDegreesQuaternion(counterRotationAngle);
rotation.multiply(blockOrientation);
topInstance.setRotation(rotation);
}
}

View file

@ -7,12 +7,16 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Con
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionKineticRenderer;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher;
import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.render.SuperByteBuffer;
import com.simibubi.create.foundation.render.backend.FastRenderDispatcher;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.AnimationTickHolder;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.Quaternion;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
@ -20,27 +24,56 @@ import net.minecraft.util.Direction.Axis;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.Nullable;
public class StabilizedBearingMovementBehaviour extends MovementBehaviour { public class StabilizedBearingMovementBehaviour extends MovementBehaviour {
@Override @Override
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
public void renderInContraption(MovementContext context, MatrixStack ms, MatrixStack msLocal, public void renderInContraption(MovementContext context, MatrixStack ms, MatrixStack msLocal,
IRenderTypeBuffer buffer) { IRenderTypeBuffer buffer) {
if (FastRenderDispatcher.available()) return;
Direction facing = context.state.get(BlockStateProperties.FACING); Direction facing = context.state.get(BlockStateProperties.FACING);
AllBlockPartials top = AllBlockPartials.BEARING_TOP; AllBlockPartials top = AllBlockPartials.BEARING_TOP;
SuperByteBuffer superBuffer = top.renderOn(context.state); SuperByteBuffer superBuffer = top.renderOn(context.state);
float renderPartialTicks = AnimationTickHolder.getPartialTicks(); float renderPartialTicks = AnimationTickHolder.getPartialTicks();
// rotate to match blockstate // rotate to match blockstate
Axis axis = facing.getAxis(); Quaternion orientation = BearingInstance.getBlockStateOrientation(facing);
if (axis.isHorizontal())
superBuffer.rotateCentered(Direction.UP,
AngleHelper.rad(AngleHelper.horizontalAngle(facing.getOpposite())));
superBuffer.rotateCentered(Direction.EAST, AngleHelper.rad(-90 - AngleHelper.verticalAngle(facing)));
// rotate against parent // rotate against parent
float angle = getCounterRotationAngle(context, facing, renderPartialTicks) * facing.getAxisDirection().getOffset();
Quaternion rotation = facing.getUnitVector().getDegreesQuaternion(angle);
rotation.multiply(orientation);
orientation = rotation;
superBuffer.rotateCentered(orientation);
// render
superBuffer.light(msLocal.peek()
.getModel(), ContraptionRenderDispatcher.getLightOnContraption(context));
superBuffer.renderInto(ms, buffer.getBuffer(RenderType.getSolid()));
}
@Override
public boolean hasSpecialInstancedRendering() {
return true;
}
@Nullable
@Override
public ActorInstance createInstance(ContraptionKineticRenderer kr, MovementContext context) {
return new StabilizedBearingInstance(kr, context);
}
static float getCounterRotationAngle(MovementContext context, Direction facing, float renderPartialTicks) {
float offset = 0; float offset = 0;
int offsetMultiplier = facing.getAxisDirection().getOffset();
Axis axis = facing.getAxis();
AbstractContraptionEntity entity = context.contraption.entity; AbstractContraptionEntity entity = context.contraption.entity;
if (entity instanceof ControlledContraptionEntity) { if (entity instanceof ControlledContraptionEntity) {
@ -54,17 +87,12 @@ public class StabilizedBearingMovementBehaviour extends MovementBehaviour {
offset = -orientedCE.getYaw(renderPartialTicks); offset = -orientedCE.getYaw(renderPartialTicks);
else { else {
if (orientedCE.isInitialOrientationPresent() && orientedCE.getInitialOrientation() if (orientedCE.isInitialOrientationPresent() && orientedCE.getInitialOrientation()
.getAxis() == axis) .getAxis() == axis)
offset = -orientedCE.getPitch(renderPartialTicks); offset = -orientedCE.getPitch(renderPartialTicks);
} }
} }
if (offset != 0) return offset;
superBuffer.rotateCentered(Direction.UP, AngleHelper.rad(offset * offsetMultiplier));
// render
superBuffer.light(msLocal.peek()
.getModel(), ContraptionRenderDispatcher.getLightOnContraption(context));
superBuffer.renderInto(ms, buffer.getBuffer(RenderType.getSolid()));
} }
} }

View file

@ -31,8 +31,8 @@ public class TreeFertilizerItem extends Item {
return ActionResultType.SUCCESS; return ActionResultType.SUCCESS;
} }
TreesDreamWorld world = new TreesDreamWorld((ServerWorld) context.getWorld(), context.getPos());
BlockPos saplingPos = context.getPos(); BlockPos saplingPos = context.getPos();
TreesDreamWorld world = new TreesDreamWorld((ServerWorld) context.getWorld(), saplingPos);
for (BlockPos pos : BlockPos.getAllInBoxMutable(-1, 0, -1, 1, 0, 1)) { for (BlockPos pos : BlockPos.getAllInBoxMutable(-1, 0, -1, 1, 0, 1)) {
if (context.getWorld() if (context.getWorld()
@ -45,8 +45,8 @@ public class TreeFertilizerItem extends Item {
state.with(SaplingBlock.STAGE, 1)); state.with(SaplingBlock.STAGE, 1));
for (BlockPos pos : world.blocksAdded.keySet()) { for (BlockPos pos : world.blocksAdded.keySet()) {
BlockPos actualPos = pos.add(saplingPos) BlockPos actualPos = pos.add(saplingPos).down(10);
.down(10); BlockState newState = world.blocksAdded.get(pos);
// Don't replace Bedrock // Don't replace Bedrock
if (context.getWorld() if (context.getWorld()
@ -54,21 +54,15 @@ public class TreeFertilizerItem extends Item {
.getBlockHardness(context.getWorld(), actualPos) == -1) .getBlockHardness(context.getWorld(), actualPos) == -1)
continue; continue;
// Don't replace solid blocks with leaves // Don't replace solid blocks with leaves
if (!world.getBlockState(pos) if (!newState.isNormalCube(world, pos)
.isNormalCube(world, pos)
&& !context.getWorld() && !context.getWorld()
.getBlockState(actualPos) .getBlockState(actualPos)
.getCollisionShape(context.getWorld(), actualPos) .getCollisionShape(context.getWorld(), actualPos)
.isEmpty()) .isEmpty())
continue; continue;
if (world.getBlockState(pos)
.getBlock() == Blocks.GRASS_BLOCK
|| world.getBlockState(pos)
.getBlock() == Blocks.PODZOL)
continue;
context.getWorld() context.getWorld()
.setBlockState(actualPos, world.getBlockState(pos)); .setBlockState(actualPos, newState);
} }
if (context.getPlayer() != null && !context.getPlayer() if (context.getPlayer() != null && !context.getPlayer()
@ -84,21 +78,27 @@ public class TreeFertilizerItem extends Item {
private class TreesDreamWorld extends PlacementSimulationServerWorld { private class TreesDreamWorld extends PlacementSimulationServerWorld {
private final BlockPos saplingPos; private final BlockPos saplingPos;
private final BlockState soil;
protected TreesDreamWorld(ServerWorld wrapped, BlockPos saplingPos) { protected TreesDreamWorld(ServerWorld wrapped, BlockPos saplingPos) {
super(wrapped); super(wrapped);
this.saplingPos = saplingPos; this.saplingPos = saplingPos;
soil = wrapped.getBlockState(saplingPos.down());
} }
@Override @Override
public BlockState getBlockState(BlockPos pos) { public BlockState getBlockState(BlockPos pos) {
if (pos.getY() <= 9) if (pos.getY() <= 9)
return world.getBlockState(saplingPos.down()); return soil;
return super.getBlockState(pos); return super.getBlockState(pos);
} }
@Override
public boolean setBlockState(BlockPos pos, BlockState newState, int flags) {
if (newState.getBlock() == Blocks.PODZOL)
return true;
return super.setBlockState(pos, newState, flags);
}
} }
} }

View file

@ -30,9 +30,15 @@ public class ArmInstance extends SingleRotatingInstance implements IDynamicInsta
private final ArrayList<ModelData> models; private final ArrayList<ModelData> models;
private final ArmTileEntity arm; private final ArmTileEntity arm;
private final Boolean ceiling;
private boolean firstTick = true; private boolean firstTick = true;
private float baseAngle = Float.NaN;
private float lowerArmAngle = Float.NaN;
private float upperArmAngle = Float.NaN;
private float headAngle = Float.NaN;
public ArmInstance(InstancedTileRenderer<?> modelManager, ArmTileEntity tile) { public ArmInstance(InstancedTileRenderer<?> modelManager, ArmTileEntity tile) {
super(modelManager, tile); super(modelManager, tile);
@ -51,31 +57,49 @@ public class ArmInstance extends SingleRotatingInstance implements IDynamicInsta
clawGrips = Lists.newArrayList(clawGrip1, clawGrip2); clawGrips = Lists.newArrayList(clawGrip1, clawGrip2);
models = Lists.newArrayList(base, lowerBody, upperBody, head, claw, clawGrip1, clawGrip2); models = Lists.newArrayList(base, lowerBody, upperBody, head, claw, clawGrip1, clawGrip2);
arm = tile; arm = tile;
ceiling = blockState.get(ArmBlock.CEILING);
animateArm(false); animateArm(false);
} }
@Override @Override
public void beginFrame() { public void beginFrame() {
if (arm.phase == ArmTileEntity.Phase.DANCING) {
animateArm(true);
return;
}
boolean settled = arm.baseAngle.settled() && arm.lowerArmAngle.settled() && arm.upperArmAngle.settled() && arm.headAngle.settled(); float pt = AnimationTickHolder.getPartialTicks();
boolean rave = arm.phase == ArmTileEntity.Phase.DANCING;
if (!settled || rave || firstTick) float baseAngleNow = this.arm.baseAngle.get(pt);
animateArm(rave); float lowerArmAngleNow = this.arm.lowerArmAngle.get(pt);
float upperArmAngleNow = this.arm.upperArmAngle.get(pt);
float headAngleNow = this.arm.headAngle.get(pt);
boolean settled = MathHelper.epsilonEquals(baseAngle, baseAngleNow)
&& MathHelper.epsilonEquals(lowerArmAngle, lowerArmAngleNow)
&& MathHelper.epsilonEquals(upperArmAngle, upperArmAngleNow)
&& MathHelper.epsilonEquals(headAngle, headAngleNow);
this.baseAngle = baseAngleNow;
this.lowerArmAngle = lowerArmAngleNow;
this.upperArmAngle = upperArmAngleNow;
this.headAngle = headAngleNow;
if (!settled || firstTick)
animateArm(false);
if (settled) if (settled)
firstTick = false; firstTick = false;
} }
private void animateArm(boolean rave) { private void animateArm(boolean rave) {
float pt = AnimationTickHolder.getPartialTicks();
int color = 0xFFFFFF;
float baseAngle = this.arm.baseAngle.get(pt); int color;
float lowerArmAngle = this.arm.lowerArmAngle.get(pt) - 135; float baseAngle;
float upperArmAngle = this.arm.upperArmAngle.get(pt) - 90; float lowerArmAngle;
float headAngle = this.arm.headAngle.get(pt); float upperArmAngle;
float headAngle;
if (rave) { if (rave) {
float renderTick = AnimationTickHolder.getRenderTime(this.arm.getWorld()) + (tile.hashCode() % 64); float renderTick = AnimationTickHolder.getRenderTime(this.arm.getWorld()) + (tile.hashCode() % 64);
@ -83,7 +107,15 @@ public class ArmInstance extends SingleRotatingInstance implements IDynamicInsta
lowerArmAngle = MathHelper.lerp((MathHelper.sin(renderTick / 4) + 1) / 2, -45, 15); lowerArmAngle = MathHelper.lerp((MathHelper.sin(renderTick / 4) + 1) / 2, -45, 15);
upperArmAngle = MathHelper.lerp((MathHelper.sin(renderTick / 8) + 1) / 4, -45, 95); upperArmAngle = MathHelper.lerp((MathHelper.sin(renderTick / 8) + 1) / 4, -45, 95);
headAngle = -lowerArmAngle; headAngle = -lowerArmAngle;
color = ColorHelper.rainbowColor(AnimationTickHolder.getTicks() * 100); color = ColorHelper.rainbowColor(AnimationTickHolder.getTicks() * 100);
} else {
baseAngle = this.baseAngle;
lowerArmAngle = this.lowerArmAngle - 135;
upperArmAngle = this.upperArmAngle - 90;
headAngle = this.headAngle;
color = 0xFFFFFF;
} }
MatrixStack msLocal = new MatrixStack(); MatrixStack msLocal = new MatrixStack();
@ -91,7 +123,7 @@ public class ArmInstance extends SingleRotatingInstance implements IDynamicInsta
msr.translate(getInstancePosition()); msr.translate(getInstancePosition());
msr.centre(); msr.centre();
if (blockState.get(ArmBlock.CEILING)) if (ceiling)
msr.rotateX(180); msr.rotateX(180);
ArmRenderer.transformBase(msr, baseAngle); ArmRenderer.transformBase(msr, baseAngle);

View file

@ -196,11 +196,21 @@ public class SuperByteBuffer extends TemplateBuffer {
return this; return this;
} }
public SuperByteBuffer rotate(Quaternion q) {
transforms.multiply(q);
return this;
}
public SuperByteBuffer rotateCentered(Direction axis, float radians) { public SuperByteBuffer rotateCentered(Direction axis, float radians) {
return translate(.5f, .5f, .5f).rotate(axis, radians) return translate(.5f, .5f, .5f).rotate(axis, radians)
.translate(-.5f, -.5f, -.5f); .translate(-.5f, -.5f, -.5f);
} }
public SuperByteBuffer rotateCentered(Quaternion q) {
return translate(.5f, .5f, .5f).rotate(q)
.translate(-.5f, -.5f, -.5f);
}
public SuperByteBuffer shiftUV(SpriteShiftEntry entry) { public SuperByteBuffer shiftUV(SpriteShiftEntry entry) {
this.spriteShiftFunc = (builder, u, v) -> { this.spriteShiftFunc = (builder, u, v) -> {
float targetU = entry.getTarget().getInterpolatedU((getUnInterpolatedU(entry.getOriginal(), u))); float targetU = entry.getTarget().getInterpolatedU((getUnInterpolatedU(entry.getOriginal(), u)));

View file

@ -1,19 +1,17 @@
package com.simibubi.create.foundation.render.backend; package com.simibubi.create.foundation.render.backend;
import java.nio.FloatBuffer;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.simibubi.create.foundation.render.backend.gl.GlFog; import com.simibubi.create.foundation.render.backend.gl.GlFog;
import com.simibubi.create.foundation.render.backend.gl.shader.*; import com.simibubi.create.foundation.render.backend.gl.shader.*;
import com.simibubi.create.foundation.render.backend.gl.versioned.GlFeatureCompat; import com.simibubi.create.foundation.render.backend.gl.versioned.GlCompat;
import com.simibubi.create.foundation.render.backend.instancing.IFlywheelWorld; import com.simibubi.create.foundation.render.backend.instancing.IFlywheelWorld;
import net.minecraft.world.World; import net.minecraft.world.World;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GLCapabilities; import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.system.MemoryUtil;
import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.AllConfigs;
@ -28,7 +26,7 @@ public class Backend {
public static final Logger log = LogManager.getLogger(Backend.class); public static final Logger log = LogManager.getLogger(Backend.class);
public static GLCapabilities capabilities; public static GLCapabilities capabilities;
public static GlFeatureCompat compat; public static GlCompat compat;
private static boolean instancingAvailable; private static boolean instancingAvailable;
private static boolean enabled; private static boolean enabled;
@ -97,7 +95,7 @@ public class Backend {
public static void refresh() { public static void refresh() {
capabilities = GL.createCapabilities(); capabilities = GL.createCapabilities();
compat = new GlFeatureCompat(capabilities); compat = new GlCompat(capabilities);
instancingAvailable = compat.vertexArrayObjectsSupported() && instancingAvailable = compat.vertexArrayObjectsSupported() &&
compat.drawInstancedSupported() && compat.drawInstancedSupported() &&

View file

@ -1,17 +1,16 @@
package com.simibubi.create.foundation.render.backend; package com.simibubi.create.foundation.render.backend;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.simibubi.create.foundation.render.backend.gl.GlFogMode; import com.simibubi.create.foundation.render.backend.gl.GlFogMode;
import com.simibubi.create.foundation.render.backend.gl.shader.*; import com.simibubi.create.foundation.render.backend.gl.shader.*;
import com.simibubi.create.foundation.render.backend.gl.versioned.GlFeatureCompat;
import net.minecraft.resources.IResource; import net.minecraft.resources.IResource;
import net.minecraft.resources.IResourceManager; import net.minecraft.resources.IResourceManager;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraftforge.resource.IResourceType; import net.minecraftforge.resource.IResourceType;
import net.minecraftforge.resource.VanillaResourceType; import net.minecraftforge.resource.VanillaResourceType;
import org.lwjgl.opengl.GL;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
import java.io.*; import java.io.*;

View file

@ -4,6 +4,7 @@ import org.lwjgl.opengl.GL20;
import com.simibubi.create.foundation.render.backend.Backend; import com.simibubi.create.foundation.render.backend.Backend;
import com.simibubi.create.foundation.render.backend.gl.GlObject; import com.simibubi.create.foundation.render.backend.gl.GlObject;
import com.simibubi.create.foundation.render.backend.gl.versioned.GlCompat;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
@ -17,7 +18,7 @@ public class GlShader extends GlObject {
this.name = name; this.name = name;
int handle = GL20.glCreateShader(type.glEnum); int handle = GL20.glCreateShader(type.glEnum);
GL20.glShaderSource(handle, source); GlCompat.safeShaderSource(handle, source);
GL20.glCompileShader(handle); GL20.glCompileShader(handle);
String log = GL20.glGetShaderInfoLog(handle); String log = GL20.glGetShaderInfoLog(handle);

View file

@ -1,6 +1,10 @@
package com.simibubi.create.foundation.render.backend.gl.versioned; package com.simibubi.create.foundation.render.backend.gl.versioned;
import org.lwjgl.PointerBuffer;
import org.lwjgl.opengl.GL20C;
import org.lwjgl.opengl.GLCapabilities; import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
@ -13,7 +17,7 @@ import java.util.function.Consumer;
* Each field stores an enum variant that provides access to the * Each field stores an enum variant that provides access to the
* most appropriate version of a feature for the current system. * most appropriate version of a feature for the current system.
*/ */
public class GlFeatureCompat { public class GlCompat {
public final MapBuffer mapBuffer; public final MapBuffer mapBuffer;
public final VertexArrayObject vertexArrayObject; public final VertexArrayObject vertexArrayObject;
@ -22,7 +26,7 @@ public class GlFeatureCompat {
public final RGPixelFormat pixelFormat; public final RGPixelFormat pixelFormat;
public GlFeatureCompat(GLCapabilities caps) { public GlCompat(GLCapabilities caps) {
mapBuffer = getLatest(MapBuffer.class, caps); mapBuffer = getLatest(MapBuffer.class, caps);
vertexArrayObject = getLatest(VertexArrayObject.class, caps); vertexArrayObject = getLatest(VertexArrayObject.class, caps);
@ -85,5 +89,33 @@ public class GlFeatureCompat {
return Arrays.stream(constants).filter(it -> it.supported(caps)).findFirst().get(); return Arrays.stream(constants).filter(it -> it.supported(caps)).findFirst().get();
} }
/**
* Copied from:
* <br> https://github.com/grondag/canvas/commit/820bf754092ccaf8d0c169620c2ff575722d7d96
*
* <p>Identical in function to {@link GL20C#glShaderSource(int, CharSequence)} but
* passes a null pointer for string length to force the driver to rely on the null
* terminator for string length. This is a workaround for an apparent flaw with some
* AMD drivers that don't receive or interpret the length correctly, resulting in
* an access violation when the driver tries to read past the string memory.
*
* <p>Hat tip to fewizz for the find and the fix.
*/
public static void safeShaderSource(int glId, CharSequence source) {
final MemoryStack stack = MemoryStack.stackGet();
final int stackPointer = stack.getPointer();
try {
final ByteBuffer sourceBuffer = MemoryUtil.memUTF8(source, true);
final PointerBuffer pointers = stack.mallocPointer(1);
pointers.put(sourceBuffer);
GL20C.nglShaderSource(glId, 1, pointers.address0(), 0);
org.lwjgl.system.APIUtil.apiArrayFree(pointers.address0(), 1);
} finally {
stack.setPointer(stackPointer);
}
}
} }

View file

@ -33,6 +33,7 @@ public abstract class InstancedTileRenderer<P extends BasicProgram> {
protected Map<MaterialType<?>, RenderMaterial<P, ?>> materials = new HashMap<>(); protected Map<MaterialType<?>, RenderMaterial<P, ?>> materials = new HashMap<>();
protected int frame; protected int frame;
protected int tick;
protected InstancedTileRenderer() { protected InstancedTileRenderer() {
registerMaterials(); registerMaterials();
@ -43,6 +44,8 @@ public abstract class InstancedTileRenderer<P extends BasicProgram> {
public abstract void registerMaterials(); public abstract void registerMaterials();
public void tick(double cameraX, double cameraY, double cameraZ) { public void tick(double cameraX, double cameraY, double cameraZ) {
tick++;
// integer camera pos // integer camera pos
int cX = (int) cameraX; int cX = (int) cameraX;
int cY = (int) cameraY; int cY = (int) cameraY;
@ -61,7 +64,7 @@ public abstract class InstancedTileRenderer<P extends BasicProgram> {
int dY = pos.getY() - cY; int dY = pos.getY() - cY;
int dZ = pos.getZ() - cZ; int dZ = pos.getZ() - cZ;
if ((frame % getUpdateDivisor(dX, dY, dZ)) == 0) if ((tick % getUpdateDivisor(dX, dY, dZ)) == 0)
instance.tick(); instance.tick();
} }
} }
@ -198,9 +201,9 @@ public abstract class InstancedTileRenderer<P extends BasicProgram> {
int dY = worldPos.getY() - cY; int dY = worldPos.getY() - cY;
int dZ = worldPos.getZ() - cZ; int dZ = worldPos.getZ() - cZ;
float dot = dX * lookX + dY * lookY + dZ * lookZ; float dot = (dX + lookX * 2) * lookX + (dY + lookY * 2) * lookY + (dZ + lookZ * 2) * lookZ;
if (dot < 0) return false; // is it behind the camera? if (dot < 0) return false; // is it more than 2 blocks behind the camera?
return (frame % getUpdateDivisor(dX, dY, dZ)) == 0; return (frame % getUpdateDivisor(dX, dY, dZ)) == 0;
} }