Keep everything up to date

This commit is contained in:
grimmauld 2021-03-27 08:32:23 +01:00
commit 9bc25db615
25 changed files with 308 additions and 132 deletions

View file

@ -17,11 +17,13 @@ import net.minecraft.util.Direction;
public class HandCrankInstance extends SingleRotatingInstance implements IDynamicInstance { public class HandCrankInstance extends SingleRotatingInstance implements IDynamicInstance {
private final HandCrankTileEntity tile;
private InstanceKey<ModelData> crank; private InstanceKey<ModelData> crank;
private Direction facing; private Direction facing;
public HandCrankInstance(InstancedTileRenderer<?> modelManager, KineticTileEntity tile) { public HandCrankInstance(InstancedTileRenderer<?> modelManager, HandCrankTileEntity tile) {
super(modelManager, tile); super(modelManager, tile);
this.tile = tile;
Block block = blockState.getBlock(); Block block = blockState.getBlock();
AllBlockPartials renderedHandle = null; AllBlockPartials renderedHandle = null;
@ -33,16 +35,20 @@ public class HandCrankInstance extends SingleRotatingInstance implements IDynami
facing = blockState.get(BlockStateProperties.FACING); facing = blockState.get(BlockStateProperties.FACING);
InstancedModel<ModelData> model = renderedHandle.renderOnDirectionalSouthModel(modelManager, blockState, facing.getOpposite()); InstancedModel<ModelData> model = renderedHandle.renderOnDirectionalSouthModel(modelManager, blockState, facing.getOpposite());
crank = model.createInstance(); crank = model.createInstance();
rotateCrank();
} }
@Override @Override
public void beginFrame() { public void beginFrame() {
if (crank == null) return; if (crank == null) return;
HandCrankTileEntity crankTile = (HandCrankTileEntity) tile; rotateCrank();
}
private void rotateCrank() {
Direction.Axis axis = facing.getAxis(); Direction.Axis axis = facing.getAxis();
float angle = (crankTile.independentAngle + AnimationTickHolder.getPartialTicks() * crankTile.chasingVelocity) / 360; float angle = (tile.independentAngle + AnimationTickHolder.getPartialTicks() * tile.chasingVelocity) / 360;
MatrixStack ms = new MatrixStack(); MatrixStack ms = new MatrixStack();
MatrixStacker.of(ms) MatrixStacker.of(ms)

View file

@ -54,6 +54,8 @@ public class DeployerInstance extends ShaftInstance implements IDynamicInstance,
relight(pos, pole.getInstance()); relight(pos, pole.getInstance());
updateRotation(pole, hand, yRot, zRot, zRotPole); updateRotation(pole, hand, yRot, zRot, zRotPole);
beginFrame();
} }
@Override @Override

View file

@ -36,11 +36,8 @@ public class FlyWheelInstance extends KineticTileInstance<FlywheelTileEntity> im
protected InstanceKey<ModelData> upperSliding; protected InstanceKey<ModelData> upperSliding;
protected InstanceKey<ModelData> lowerSliding; protected InstanceKey<ModelData> lowerSliding;
protected float lastAngle = Float.NaN; protected float lastAngle = Float.NaN;
protected boolean firstFrame = true;
public FlyWheelInstance(InstancedTileRenderer<?> modelManager, FlywheelTileEntity tile) { public FlyWheelInstance(InstancedTileRenderer<?> modelManager, FlywheelTileEntity tile) {
super(modelManager, tile); super(modelManager, tile);
@ -69,6 +66,8 @@ public class FlyWheelInstance extends KineticTileInstance<FlywheelTileEntity> im
} else { } else {
connectors = Collections.emptyList(); connectors = Collections.emptyList();
} }
animate(tile.angle);
} }
@Override @Override
@ -79,8 +78,14 @@ public class FlyWheelInstance extends KineticTileInstance<FlywheelTileEntity> im
float speed = tile.visualSpeed.get(partialTicks) * 3 / 10f; float speed = tile.visualSpeed.get(partialTicks) * 3 / 10f;
float angle = tile.angle + speed * partialTicks; float angle = tile.angle + speed * partialTicks;
if (!firstFrame && Math.abs(angle - lastAngle) < 0.001) return; if (Math.abs(angle - lastAngle) < 0.001) return;
animate(angle);
lastAngle = angle;
}
private void animate(float angle) {
MatrixStack ms = new MatrixStack(); MatrixStack ms = new MatrixStack();
MatrixStacker msr = MatrixStacker.of(ms); MatrixStacker msr = MatrixStacker.of(ms);
@ -120,9 +125,6 @@ public class FlyWheelInstance extends KineticTileInstance<FlywheelTileEntity> im
.unCentre(); .unCentre();
wheel.getInstance().setTransform(ms); wheel.getInstance().setTransform(ms);
lastAngle = angle;
firstFrame = false;
} }
@Override @Override

View file

@ -14,25 +14,25 @@ import com.simibubi.create.foundation.utility.MatrixStacker;
public class PressInstance extends ShaftInstance implements IDynamicInstance { public class PressInstance extends ShaftInstance implements IDynamicInstance {
private final InstanceKey<ModelData> pressHead; private final InstanceKey<ModelData> pressHead;
private final MechanicalPressTileEntity press;
public PressInstance(InstancedTileRenderer<?> dispatcher, KineticTileEntity tile) { public PressInstance(InstancedTileRenderer<?> dispatcher, MechanicalPressTileEntity tile) {
super(dispatcher, tile); super(dispatcher, tile);
press = tile;
pressHead = AllBlockPartials.MECHANICAL_PRESS_HEAD.renderOnHorizontalModel(dispatcher, blockState).createInstance(); pressHead = AllBlockPartials.MECHANICAL_PRESS_HEAD.renderOnHorizontalModel(dispatcher, blockState).createInstance();
transformModels();
transformModels((MechanicalPressTileEntity) tile);
} }
@Override @Override
public void beginFrame() { public void beginFrame() {
MechanicalPressTileEntity press = (MechanicalPressTileEntity) tile;
if (!press.running) if (!press.running)
return; return;
transformModels(press); transformModels();
} }
private void transformModels(MechanicalPressTileEntity press) { private void transformModels() {
float renderedHeadOffset = getRenderedHeadOffset(press); float renderedHeadOffset = getRenderedHeadOffset(press);
MatrixStack ms = new MatrixStack(); MatrixStack ms = new MatrixStack();

View file

@ -31,6 +31,8 @@ public class StickerInstance extends TileEntityInstance<StickerTileEntity> imple
fakeWorld = tile.getWorld() != Minecraft.getInstance().world; fakeWorld = tile.getWorld() != Minecraft.getInstance().world;
facing = blockState.get(StickerBlock.FACING); facing = blockState.get(StickerBlock.FACING);
offset = blockState.get(StickerBlock.EXTENDED) ? 1 : 0; offset = blockState.get(StickerBlock.EXTENDED) ? 1 : 0;
animateHead(offset);
} }
@Override @Override
@ -43,6 +45,12 @@ public class StickerInstance extends TileEntityInstance<StickerTileEntity> imple
if (MathHelper.epsilonEquals(offset, lastOffset)) if (MathHelper.epsilonEquals(offset, lastOffset))
return; return;
animateHead(offset);
lastOffset = offset;
}
private void animateHead(float offset) {
MatrixStack stack = new MatrixStack(); MatrixStack stack = new MatrixStack();
MatrixStacker.of(stack) MatrixStacker.of(stack)
.translate(getInstancePosition()) .translate(getInstancePosition())
@ -55,8 +63,6 @@ public class StickerInstance extends TileEntityInstance<StickerTileEntity> imple
head.getInstance() head.getInstance()
.setTransform(stack); .setTransform(stack);
lastOffset = offset;
} }
@Override @Override

View file

@ -15,6 +15,7 @@ import com.simibubi.create.foundation.utility.MatrixStacker;
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.vector.Vector3f; import net.minecraft.util.math.vector.Vector3f;
import net.minecraft.util.math.MathHelper;
public class GantryCarriageInstance extends ShaftInstance implements IDynamicInstance { public class GantryCarriageInstance extends ShaftInstance implements IDynamicInstance {
@ -23,8 +24,11 @@ public class GantryCarriageInstance extends ShaftInstance implements IDynamicIns
final Direction facing; final Direction facing;
final Boolean alongFirst; final Boolean alongFirst;
final Direction.Axis rotationAxis; final Direction.Axis rotationAxis;
final float rotationMult;
final BlockPos visualPos; final BlockPos visualPos;
private float lastAngle = Float.NaN;
public GantryCarriageInstance(InstancedTileRenderer<?> dispatcher, KineticTileEntity tile) { public GantryCarriageInstance(InstancedTileRenderer<?> dispatcher, KineticTileEntity tile) {
super(dispatcher, tile); super(dispatcher, tile);
@ -36,27 +40,29 @@ public class GantryCarriageInstance extends ShaftInstance implements IDynamicIns
alongFirst = blockState.get(GantryCarriageBlock.AXIS_ALONG_FIRST_COORDINATE); alongFirst = blockState.get(GantryCarriageBlock.AXIS_ALONG_FIRST_COORDINATE);
rotationAxis = KineticTileEntityRenderer.getRotationAxisOf(tile); rotationAxis = KineticTileEntityRenderer.getRotationAxisOf(tile);
rotationMult = getRotationMultiplier(getGantryAxis(), facing);
visualPos = facing.getAxisDirection() == Direction.AxisDirection.POSITIVE ? tile.getPos() visualPos = facing.getAxisDirection() == Direction.AxisDirection.POSITIVE ? tile.getPos()
: tile.getPos() : tile.getPos()
.offset(facing.getOpposite()); .offset(facing.getOpposite());
animateCogs(getCogAngle());
} }
@Override @Override
public void beginFrame() { public void beginFrame() {
float angleForTe = GantryCarriageRenderer.getAngleForTe(tile, visualPos, rotationAxis); float cogAngle = getCogAngle();
Direction.Axis gantryAxis = Direction.Axis.X; if (MathHelper.epsilonEquals(cogAngle, lastAngle)) return;
for (Direction.Axis axis : Iterate.axes)
if (axis != rotationAxis && axis != facing.getAxis())
gantryAxis = axis;
if (gantryAxis == Direction.Axis.Z) animateCogs(cogAngle);
if (facing == Direction.DOWN) }
angleForTe *= -1;
if (gantryAxis == Direction.Axis.Y)
if (facing == Direction.NORTH || facing == Direction.EAST)
angleForTe *= -1;
private float getCogAngle() {
return GantryCarriageRenderer.getAngleForTe(tile, visualPos, rotationAxis) * rotationMult;
}
private void animateCogs(float cogAngle) {
MatrixStack ms = new MatrixStack(); MatrixStack ms = new MatrixStack();
MatrixStacker.of(ms) MatrixStacker.of(ms)
.translate(getInstancePosition()) .translate(getInstancePosition())
@ -65,13 +71,33 @@ public class GantryCarriageInstance extends ShaftInstance implements IDynamicIns
.rotateX(facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90) .rotateX(facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90)
.rotateY(alongFirst ^ facing.getAxis() == Direction.Axis.Z ? 90 : 0) .rotateY(alongFirst ^ facing.getAxis() == Direction.Axis.Z ? 90 : 0)
.translate(0, -9 / 16f, 0) .translate(0, -9 / 16f, 0)
.multiply(Vector3f.POSITIVE_X.getRadialQuaternion(-angleForTe)) .multiply(Vector3f.POSITIVE_X.getRadialQuaternion(-cogAngle))
.translate(0, 9 / 16f, 0) .translate(0, 9 / 16f, 0)
.unCentre(); .unCentre();
gantryCogs.getInstance().setTransform(ms); gantryCogs.getInstance().setTransform(ms);
} }
static float getRotationMultiplier(Direction.Axis gantryAxis, Direction facing) {
float multiplier = 1;
if (gantryAxis == Direction.Axis.Z)
if (facing == Direction.DOWN)
multiplier *= -1;
if (gantryAxis == Direction.Axis.Y)
if (facing == Direction.NORTH || facing == Direction.EAST)
multiplier *= -1;
return multiplier;
}
private Direction.Axis getGantryAxis() {
Direction.Axis gantryAxis = Direction.Axis.X;
for (Direction.Axis axis : Iterate.axes)
if (axis != rotationAxis && axis != facing.getAxis())
gantryAxis = axis;
return gantryAxis;
}
@Override @Override
public void updateLight() { public void updateLight() {
relight(pos, gantryCogs.getInstance(), rotatingModel.getInstance()); relight(pos, gantryCogs.getInstance(), rotatingModel.getInstance());

View file

@ -17,6 +17,8 @@ import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial;
import com.simibubi.create.foundation.render.backend.instancing.impl.OrientedModel; import com.simibubi.create.foundation.render.backend.instancing.impl.OrientedModel;
import com.simibubi.create.foundation.render.backend.instancing.impl.TransformedModel; import com.simibubi.create.foundation.render.backend.instancing.impl.TransformedModel;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.gen.feature.template.Template; import net.minecraft.world.gen.feature.template.Template;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
@ -46,14 +48,13 @@ public class ContraptionKineticRenderer extends InstancedTileRenderer<Contraptio
materials.put(KineticRenderMaterials.ACTORS, new RenderMaterial<>(this, AllProgramSpecs.C_ACTOR, ActorModel::new)); materials.put(KineticRenderMaterials.ACTORS, new RenderMaterial<>(this, AllProgramSpecs.C_ACTOR, ActorModel::new));
} }
@Override
public void tick() { public void tick() {
actors.forEach(ActorInstance::tick); actors.forEach(ActorInstance::tick);
} }
@Override @Override
public void beginFrame(double cameraX, double cameraY, double cameraZ) { public void beginFrame(ActiveRenderInfo info, double cameraX, double cameraY, double cameraZ) {
super.beginFrame(cameraX, cameraY, cameraZ); super.beginFrame(info, cameraX, cameraY, cameraZ);
actors.forEach(ActorInstance::beginFrame); actors.forEach(ActorInstance::beginFrame);
} }

View file

@ -38,6 +38,7 @@ import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.RenderTypeLookup; import net.minecraft.client.renderer.RenderTypeLookup;
import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
@ -93,9 +94,9 @@ public class ContraptionRenderDispatcher {
return contraption; return contraption;
} }
public static void beginFrame(double camX, double camY, double camZ) { public static void beginFrame(ActiveRenderInfo info, double camX, double camY, double camZ) {
for (RenderedContraption renderer : renderers.values()) { for (RenderedContraption renderer : renderers.values()) {
renderer.beginFrame(camX, camY, camZ); renderer.beginFrame(info, camX, camY, camZ);
} }
} }

View file

@ -88,8 +88,8 @@ public class RenderedContraption {
} }
} }
public void beginFrame(double camX, double camY, double camZ) { public void beginFrame(ActiveRenderInfo info, double camX, double camY, double camZ) {
kinetics.beginFrame(camX, camY, camZ); kinetics.beginFrame(info, camX, camY, camZ);
AbstractContraptionEntity entity = contraption.entity; AbstractContraptionEntity entity = contraption.entity;
float pt = AnimationTickHolder.getPartialTicks(); float pt = AnimationTickHolder.getPartialTicks();

View file

@ -1,15 +1,5 @@
package com.simibubi.create.content.contraptions.relays.advanced; package com.simibubi.create.content.contraptions.relays.advanced;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllShapes;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.base.HorizontalAxisKineticBlock;
import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock;
import com.simibubi.create.content.contraptions.relays.elementary.CogwheelBlockItem;
import com.simibubi.create.foundation.block.ITE;
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
import mcp.MethodsReturnNonnullByDefault; import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
@ -29,6 +19,16 @@ import net.minecraft.world.IBlockReader;
import net.minecraft.world.World; import net.minecraft.world.World;
import java.util.function.Predicate; import java.util.function.Predicate;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllShapes;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.base.HorizontalAxisKineticBlock;
import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock;
import com.simibubi.create.content.contraptions.relays.elementary.CogwheelBlockItem;
import com.simibubi.create.foundation.block.ITE;
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
public class SpeedControllerBlock extends HorizontalAxisKineticBlock implements ITE<SpeedControllerTileEntity> { public class SpeedControllerBlock extends HorizontalAxisKineticBlock implements ITE<SpeedControllerTileEntity> {
@ -100,8 +100,8 @@ public class SpeedControllerBlock extends HorizontalAxisKineticBlock implements
Axis newAxis = state.get(HORIZONTAL_AXIS) == Axis.X ? Axis.Z : Axis.X; Axis newAxis = state.get(HORIZONTAL_AXIS) == Axis.X ? Axis.Z : Axis.X;
if (CogwheelBlockItem.DiagonalCogHelper.hasLargeCogwheelNeighbor(world, newPos, newAxis) if (CogwheelBlockItem.hasLargeCogwheelNeighbor(world, newPos, newAxis)
|| CogwheelBlockItem.DiagonalCogHelper.hasSmallCogwheelNeighbor(world, newPos, newAxis)) || CogwheelBlockItem.hasSmallCogwheelNeighbor(world, newPos, newAxis))
return PlacementOffset.fail(); return PlacementOffset.fail();
return PlacementOffset.success(newPos, s -> s.with(CogWheelBlock.AXIS, newAxis)); return PlacementOffset.success(newPos, s -> s.with(CogWheelBlock.AXIS, newAxis));

View file

@ -1,15 +1,5 @@
package com.simibubi.create.content.contraptions.relays.elementary; package com.simibubi.create.content.contraptions.relays.elementary;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllShapes;
import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock;
import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock;
import com.simibubi.create.content.contraptions.base.IRotate;
import com.simibubi.create.foundation.advancement.AllTriggers;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
import mcp.MethodsReturnNonnullByDefault; import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
@ -27,6 +17,16 @@ import net.minecraft.world.World;
import java.util.List; import java.util.List;
import java.util.function.Predicate; import java.util.function.Predicate;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllShapes;
import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock;
import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock;
import com.simibubi.create.content.contraptions.base.IRotate;
import com.simibubi.create.foundation.advancement.AllTriggers;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
import static com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock.AXIS; import static com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock.AXIS;
@ -169,6 +169,10 @@ public class CogwheelBlockItem extends BlockItem {
for (Direction dir : directions) { for (Direction dir : directions) {
BlockPos newPos = pos.offset(dir) BlockPos newPos = pos.offset(dir)
.offset(side); .offset(side);
if (hasLargeCogwheelNeighbor(world, newPos, dir.getAxis()) || hasSmallCogwheelNeighbor(world, newPos, dir.getAxis()))
continue;
if (!world.getBlockState(newPos) if (!world.getBlockState(newPos)
.getMaterial() .getMaterial()
.isReplaceable()) .isReplaceable())
@ -225,30 +229,6 @@ public class CogwheelBlockItem extends BlockItem {
.subtract(ray.getHitVec() .subtract(ray.getHitVec()
.align(Iterate.axisSet))); .align(Iterate.axisSet)));
} }
static public boolean hasLargeCogwheelNeighbor(World world, BlockPos pos, Direction.Axis axis) {
for (Direction dir : Iterate.directions) {
if (dir.getAxis() == axis)
continue;
if (AllBlocks.LARGE_COGWHEEL.has(world.getBlockState(pos.offset(dir))))
return true;
}
return false;
}
static public boolean hasSmallCogwheelNeighbor(World world, BlockPos pos, Direction.Axis axis) {
for (Direction dir : Iterate.directions) {
if (dir.getAxis() == axis)
continue;
if (AllBlocks.COGWHEEL.has(world.getBlockState(pos.offset(dir))))
return true;
}
return false;
}
} }
@MethodsReturnNonnullByDefault @MethodsReturnNonnullByDefault
@ -294,8 +274,8 @@ public class CogwheelBlockItem extends BlockItem {
.isReplaceable()) .isReplaceable())
continue; continue;
if (DiagonalCogHelper.hasLargeCogwheelNeighbor(world, newPos, newAxis) if (hasLargeCogwheelNeighbor(world, newPos, newAxis)
|| DiagonalCogHelper.hasSmallCogwheelNeighbor(world, newPos, newAxis)) || hasSmallCogwheelNeighbor(world, newPos, newAxis))
return PlacementOffset.fail(); return PlacementOffset.fail();
return PlacementOffset.success(newPos, s -> s.with(CogWheelBlock.AXIS, newAxis)); return PlacementOffset.success(newPos, s -> s.with(CogWheelBlock.AXIS, newAxis));
@ -303,5 +283,29 @@ public class CogwheelBlockItem extends BlockItem {
return PlacementOffset.fail(); return PlacementOffset.fail();
} }
}
static public boolean hasLargeCogwheelNeighbor(World world, BlockPos pos, Axis axis) {
for (Direction dir : Iterate.directions) {
if (dir.getAxis() == axis)
continue;
if (AllBlocks.LARGE_COGWHEEL.has(world.getBlockState(pos.offset(dir))))
return true;
}
return false;
}
static public boolean hasSmallCogwheelNeighbor(World world, BlockPos pos, Axis axis) {
for (Direction dir : Iterate.directions) {
if (dir.getAxis() == axis)
continue;
if (AllBlocks.COGWHEEL.has(world.getBlockState(pos.offset(dir))))
return true;
}
return false;
} }
} }

View file

@ -33,8 +33,6 @@ public class SplitShaftInstance extends KineticTileInstance<SplitShaftTileEntity
keys.add(setup(half.createInstance(), splitSpeed)); keys.add(setup(half.createInstance(), splitSpeed));
} }
updateLight();
} }
@Override @Override

View file

@ -28,7 +28,6 @@ public class EjectorInstance extends ShaftInstance implements IDynamicInstance {
plate = getTransformMaterial().getModel(AllBlockPartials.EJECTOR_TOP, blockState).createInstance(); plate = getTransformMaterial().getModel(AllBlockPartials.EJECTOR_TOP, blockState).createInstance();
pivotPlate(); pivotPlate();
updateLight();
} }
@Override @Override

View file

@ -3,7 +3,6 @@ package com.simibubi.create.content.logistics.block.mechanicalArm;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.base.RotatingData; import com.simibubi.create.content.contraptions.base.RotatingData;
import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; import com.simibubi.create.content.contraptions.base.SingleRotatingInstance;
import com.simibubi.create.foundation.render.backend.instancing.*; import com.simibubi.create.foundation.render.backend.instancing.*;
@ -30,10 +29,11 @@ public class ArmInstance extends SingleRotatingInstance implements IDynamicInsta
private final ArrayList<InstanceKey<ModelData>> clawGrips; private final ArrayList<InstanceKey<ModelData>> clawGrips;
private final ArrayList<InstanceKey<ModelData>> models; private final ArrayList<InstanceKey<ModelData>> models;
private final ArmTileEntity arm;
private boolean firstTick = true; private boolean firstTick = true;
public ArmInstance(InstancedTileRenderer<?> modelManager, KineticTileEntity tile) { public ArmInstance(InstancedTileRenderer<?> modelManager, ArmTileEntity tile) {
super(modelManager, tile); super(modelManager, tile);
RenderMaterial<?, InstancedModel<ModelData>> mat = getTransformMaterial(); RenderMaterial<?, InstancedModel<ModelData>> mat = getTransformMaterial();
@ -50,33 +50,35 @@ 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;
animateArm(false);
} }
@Override @Override
public void beginFrame() { public void beginFrame() {
ArmTileEntity arm = (ArmTileEntity) tile;
boolean settled = arm.baseAngle.settled() && arm.lowerArmAngle.settled() && arm.upperArmAngle.settled() && arm.headAngle.settled(); boolean settled = arm.baseAngle.settled() && arm.lowerArmAngle.settled() && arm.upperArmAngle.settled() && arm.headAngle.settled();
boolean rave = arm.phase == ArmTileEntity.Phase.DANCING; boolean rave = arm.phase == ArmTileEntity.Phase.DANCING;
if (!settled || rave || firstTick) if (!settled || rave || firstTick)
transformModels(arm, rave); animateArm(rave);
if (settled) if (settled)
firstTick = false; firstTick = false;
} }
private void transformModels(ArmTileEntity arm, boolean rave) { private void animateArm(boolean rave) {
float pt = AnimationTickHolder.getPartialTicks(); float pt = AnimationTickHolder.getPartialTicks();
int color = 0xFFFFFF; int color = 0xFFFFFF;
float baseAngle = arm.baseAngle.get(pt); float baseAngle = this.arm.baseAngle.get(pt);
float lowerArmAngle = arm.lowerArmAngle.get(pt) - 135; float lowerArmAngle = this.arm.lowerArmAngle.get(pt) - 135;
float upperArmAngle = arm.upperArmAngle.get(pt) - 90; float upperArmAngle = this.arm.upperArmAngle.get(pt) - 90;
float headAngle = arm.headAngle.get(pt); float headAngle = this.arm.headAngle.get(pt);
if (rave) { if (rave) {
float renderTick = AnimationTickHolder.getRenderTime(arm.getWorld()) + (tile.hashCode() % 64); float renderTick = AnimationTickHolder.getRenderTime(this.arm.getWorld()) + (tile.hashCode() % 64);
baseAngle = (renderTick * 10) % 360; baseAngle = (renderTick * 10) % 360;
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);
@ -84,7 +86,6 @@ public class ArmInstance extends SingleRotatingInstance implements IDynamicInsta
color = ColorHelper.rainbowColor(AnimationTickHolder.getTicks() * 100); color = ColorHelper.rainbowColor(AnimationTickHolder.getTicks() * 100);
} }
MatrixStack msLocal = new MatrixStack(); MatrixStack msLocal = new MatrixStack();
MatrixStacker msr = MatrixStacker.of(msLocal); MatrixStacker msr = MatrixStacker.of(msLocal);
msr.translate(getInstancePosition()); msr.translate(getInstancePosition());
@ -115,7 +116,7 @@ public class ArmInstance extends SingleRotatingInstance implements IDynamicInsta
claw.getInstance() claw.getInstance()
.setTransform(msLocal); .setTransform(msLocal);
ItemStack item = arm.heldItem; ItemStack item = this.arm.heldItem;
ItemRenderer itemRenderer = Minecraft.getInstance() ItemRenderer itemRenderer = Minecraft.getInstance()
.getItemRenderer(); .getItemRenderer();
boolean hasItem = !item.isEmpty(); boolean hasItem = !item.isEmpty();

View file

@ -31,16 +31,16 @@ public class AnalogLeverInstance extends TileEntityInstance<AnalogLeverTileEntit
rX = face == AttachFace.FLOOR ? 0 : face == AttachFace.WALL ? 90 : 180; rX = face == AttachFace.FLOOR ? 0 : face == AttachFace.WALL ? 90 : 180;
rY = AngleHelper.horizontalAngle(blockState.get(AnalogLeverBlock.HORIZONTAL_FACING)); rY = AngleHelper.horizontalAngle(blockState.get(AnalogLeverBlock.HORIZONTAL_FACING));
setupModel(); animateLever();
} }
@Override @Override
public void beginFrame() { public void beginFrame() {
if (!tile.clientState.settled()) if (!tile.clientState.settled())
setupModel(); animateLever();
} }
protected void setupModel() { protected void animateLever() {
MatrixStack ms = new MatrixStack(); MatrixStack ms = new MatrixStack();
MatrixStacker msr = MatrixStacker.of(ms); MatrixStacker msr = MatrixStacker.of(ms);

View file

@ -20,6 +20,8 @@ public class SchematicannonInstance extends TileEntityInstance<SchematicannonTil
connector = mat.getModel(AllBlockPartials.SCHEMATICANNON_CONNECTOR, blockState).createInstance(); connector = mat.getModel(AllBlockPartials.SCHEMATICANNON_CONNECTOR, blockState).createInstance();
pipe = mat.getModel(AllBlockPartials.SCHEMATICANNON_PIPE, blockState).createInstance(); pipe = mat.getModel(AllBlockPartials.SCHEMATICANNON_PIPE, blockState).createInstance();
beginFrame();
} }
@Override @Override

View file

@ -59,8 +59,8 @@ public class RenderHooksMixin {
double camY = cameraPos.getY(); double camY = cameraPos.getY();
double camZ = cameraPos.getZ(); double camZ = cameraPos.getZ();
CreateClient.kineticRenderer.get(world).beginFrame(camX, camY, camZ); CreateClient.kineticRenderer.get(world).beginFrame(info, camX, camY, camZ);
ContraptionRenderDispatcher.beginFrame(camX, camY, camZ); ContraptionRenderDispatcher.beginFrame(info, camX, camY, camZ);
} }
@Inject(at = @At("TAIL"), method = "scheduleBlockRerenderIfNeeded") @Inject(at = @At("TAIL"), method = "scheduleBlockRerenderIfNeeded")

View file

@ -15,6 +15,7 @@ import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial;
import com.simibubi.create.foundation.render.backend.instancing.impl.OrientedModel; import com.simibubi.create.foundation.render.backend.instancing.impl.OrientedModel;
import com.simibubi.create.foundation.render.backend.instancing.impl.TransformedModel; import com.simibubi.create.foundation.render.backend.instancing.impl.TransformedModel;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@ -42,7 +43,7 @@ public class KineticRenderer extends InstancedTileRenderer<BasicProgram> {
} }
@Override @Override
public void beginFrame(double cameraX, double cameraY, double cameraZ) { public void beginFrame(ActiveRenderInfo info, double cameraX, double cameraY, double cameraZ) {
int cX = MathHelper.floor(cameraX); int cX = MathHelper.floor(cameraX);
int cY = MathHelper.floor(cameraY); int cY = MathHelper.floor(cameraY);
int cZ = MathHelper.floor(cameraZ); int cZ = MathHelper.floor(cameraZ);
@ -62,7 +63,7 @@ public class KineticRenderer extends InstancedTileRenderer<BasicProgram> {
instancedTiles.forEach(this::add); instancedTiles.forEach(this::add);
} }
super.beginFrame(cameraX, cameraY, cameraZ); super.beginFrame(info, cameraX, cameraY, cameraZ);
} }
@Override @Override

View file

@ -15,6 +15,7 @@ import net.minecraft.client.entity.player.ClientPlayerEntity;
import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.world.ClientWorld; import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity;
import net.minecraft.potion.Effects; import net.minecraft.potion.Effects;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
@ -37,10 +38,13 @@ public class FastRenderDispatcher {
} }
public static void tick() { public static void tick() {
ClientWorld world = Minecraft.getInstance().world; Minecraft mc = Minecraft.getInstance();
ClientWorld world = mc.world;
KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(world); KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(world);
kineticRenderer.tick();
Entity renderViewEntity = mc.renderViewEntity;
kineticRenderer.tick(renderViewEntity.getX(), renderViewEntity.getY(), renderViewEntity.getZ());
ConcurrentHashMap.KeySetView<TileEntity, Boolean> map = queuedUpdates.get(world); ConcurrentHashMap.KeySetView<TileEntity, Boolean> map = queuedUpdates.get(world);
map map

View file

@ -9,9 +9,22 @@ package com.simibubi.create.foundation.render.backend.instancing;
* <br><br> If your goal is offloading work to shaders, but you're unsure exactly how you need * <br><br> If your goal is offloading work to shaders, but you're unsure exactly how you need
* to parameterize the instances, you're encouraged to implement this for prototyping. * to parameterize the instances, you're encouraged to implement this for prototyping.
*/ */
public interface IDynamicInstance { public interface IDynamicInstance extends IInstance {
/** /**
* Called every frame. * Called every frame.
*/ */
void beginFrame(); void beginFrame();
/**
* As a further optimization, dynamic instances that are far away are ticked less often.
* This behavior can be disabled by returning false.
*
* <br> You might want to opt out of this if you want your animations to remain smooth
* even when far away from the camera. It is recommended to keep this as is, however.
*
* @return <code>true</code> if your instance should be slow ticked.
*/
default boolean decreaseFramerateWithDistance() {
return true;
}
} }

View file

@ -0,0 +1,13 @@
package com.simibubi.create.foundation.render.backend.instancing;
import net.minecraft.util.math.BlockPos;
/**
* A general interface providing information about any type of thing that could use
* Flywheel's instanced rendering. Right now, that's only {@link InstancedTileRenderer},
* but there could be an entity equivalent in the future.
*/
public interface IInstance {
BlockPos getWorldPosition();
}

View file

@ -16,10 +16,23 @@ package com.simibubi.create.foundation.render.backend.instancing;
* </li> * </li>
* </ul> * </ul>
*/ */
public interface ITickableInstance { public interface ITickableInstance extends IInstance {
/** /**
* Called every tick. * Called every tick.
*/ */
void tick(); void tick();
/**
* As a further optimization, tickable instances that are far away are ticked less often.
* This behavior can be disabled by returning false.
*
* <br> You might want to opt out of this if you want your animations to remain smooth
* even when far away from the camera. It is recommended to keep this as is, however.
*
* @return <code>true</code> if your instance should be slow ticked.
*/
default boolean decreaseTickRateWithDistance() {
return true;
}
} }

View file

@ -10,13 +10,14 @@ import com.simibubi.create.foundation.render.backend.gl.BasicProgram;
import com.simibubi.create.foundation.render.backend.gl.shader.ShaderCallback; import com.simibubi.create.foundation.render.backend.gl.shader.ShaderCallback;
import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData; import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData;
import com.simibubi.create.foundation.render.backend.instancing.impl.OrientedData; import com.simibubi.create.foundation.render.backend.instancing.impl.OrientedData;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.*;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Matrix4f; import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.math.vector.Vector3f;
import net.minecraft.world.IBlockReader; import net.minecraft.world.IBlockReader;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -30,6 +31,8 @@ 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 InstancedTileRenderer() { protected InstancedTileRenderer() {
registerMaterials(); registerMaterials();
} }
@ -38,15 +41,74 @@ public abstract class InstancedTileRenderer<P extends BasicProgram> {
public abstract void registerMaterials(); public abstract void registerMaterials();
public void tick() { public void tick(double cameraX, double cameraY, double cameraZ) {
if (tickableInstances.size() > 0) // integer camera pos
tickableInstances.values().forEach(ITickableInstance::tick); int cX = (int) cameraX;
int cY = (int) cameraY;
int cZ = (int) cameraZ;
if (tickableInstances.size() > 0) {
for (ITickableInstance instance : tickableInstances.values()) {
if (!instance.decreaseTickRateWithDistance()) {
instance.tick();
continue;
} }
public void beginFrame(double cameraX, double cameraY, double cameraZ) { BlockPos pos = instance.getWorldPosition();
int dX = pos.getX() - cX;
int dY = pos.getY() - cY;
int dZ = pos.getZ() - cZ;
int dSq = dX * dX + dY * dY + dZ * dZ;
int divisor = (dSq / 1024) + 1;
if (frame % divisor == 0)
instance.tick();
}
}
}
public void beginFrame(ActiveRenderInfo info, double cameraX, double cameraY, double cameraZ) {
frame++;
processQueuedAdditions(); processQueuedAdditions();
if (dynamicInstances.size() > 0)
dynamicInstances.values().forEach(IDynamicInstance::beginFrame); Vector3f look = info.getHorizontalPlane();
float lookX = look.getX();
float lookY = look.getY();
float lookZ = look.getZ();
// integer camera pos
int cX = (int) cameraX;
int cY = (int) cameraY;
int cZ = (int) cameraZ;
if (dynamicInstances.size() > 0) {
for (IDynamicInstance dyn : dynamicInstances.values()) {
if (!dyn.decreaseFramerateWithDistance()) {
dyn.beginFrame();
continue;
}
BlockPos pos = dyn.getWorldPosition();
int dX = pos.getX() - cX;
int dY = pos.getY() - cY;
int dZ = pos.getZ() - cZ;
float dot = dX * lookX + dY * lookY + dZ * lookZ;
if (dot < 0) continue; // is it behind the camera?
int dSq = dX * dX + dY * dY + dZ * dZ;
int divisor = (dSq / 1024) + 1; // https://www.desmos.com/calculator/aaycpludsy
if (frame % divisor == 0)
dyn.beginFrame();
}
}
} }
public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ) { public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ) {

View file

@ -30,12 +30,13 @@ import java.util.stream.Stream;
* *
* @param <T> The type of {@link TileEntity} your class is an instance of. * @param <T> The type of {@link TileEntity} your class is an instance of.
*/ */
public abstract class TileEntityInstance<T extends TileEntity> { public abstract class TileEntityInstance<T extends TileEntity> implements IInstance {
protected final InstancedTileRenderer<?> renderer; protected final InstancedTileRenderer<?> renderer;
protected final T tile; protected final T tile;
protected final World world; protected final World world;
protected final BlockPos pos; protected final BlockPos pos;
protected final BlockPos instancePos;
protected final BlockState blockState; protected final BlockState blockState;
public TileEntityInstance(InstancedTileRenderer<?> renderer, T tile) { public TileEntityInstance(InstancedTileRenderer<?> renderer, T tile) {
@ -44,6 +45,7 @@ public abstract class TileEntityInstance<T extends TileEntity> {
this.world = tile.getWorld(); this.world = tile.getWorld();
this.pos = tile.getPos(); this.pos = tile.getPos();
this.blockState = tile.getBlockState(); this.blockState = tile.getBlockState();
this.instancePos = pos.subtract(renderer.getOriginCoordinate());
} }
/** /**
@ -89,7 +91,12 @@ public abstract class TileEntityInstance<T extends TileEntity> {
* represents should be rendered at to appear in the correct location. * represents should be rendered at to appear in the correct location.
*/ */
public BlockPos getInstancePosition() { public BlockPos getInstancePosition() {
return pos.subtract(renderer.getOriginCoordinate()); return instancePos;
}
@Override
public BlockPos getWorldPosition() {
return pos;
} }
protected void relight(BlockPos pos, IFlatLight<?>... models) { protected void relight(BlockPos pos, IFlatLight<?>... models) {

View file

@ -18,7 +18,9 @@ import net.minecraftforge.items.CapabilityItemHandler;
public abstract class SmartTileEntity extends SyncedTileEntity implements ITickableTileEntity { public abstract class SmartTileEntity extends SyncedTileEntity implements ITickableTileEntity {
private Map<BehaviourType<?>, TileEntityBehaviour> behaviours; private final Map<BehaviourType<?>, TileEntityBehaviour> behaviours;
// Internally maintained to be identical to behaviorMap.values() in order to improve iteration performance.
private final List<TileEntityBehaviour> behaviourList;
private boolean initialized; private boolean initialized;
private boolean firstNbtRead; private boolean firstNbtRead;
private int lazyTickRate; private int lazyTickRate;
@ -37,6 +39,9 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
ArrayList<TileEntityBehaviour> list = new ArrayList<>(); ArrayList<TileEntityBehaviour> list = new ArrayList<>();
addBehaviours(list); addBehaviours(list);
list.forEach(b -> behaviours.put(b.getType(), b)); list.forEach(b -> behaviours.put(b.getType(), b));
behaviourList = new ArrayList<>(list.size());
updateBehaviorList();
} }
public abstract void addBehaviours(List<TileEntityBehaviour> behaviours); public abstract void addBehaviours(List<TileEntityBehaviour> behaviours);
@ -59,13 +64,11 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
lazyTick(); lazyTick();
} }
behaviours.values() behaviourList.forEach(TileEntityBehaviour::tick);
.forEach(TileEntityBehaviour::tick);
} }
public void initialize() { public void initialize() {
behaviours.values() behaviourList.forEach(TileEntityBehaviour::initialize);
.forEach(TileEntityBehaviour::initialize);
lazyTick(); lazyTick();
} }
@ -100,10 +103,11 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
ArrayList<TileEntityBehaviour> list = new ArrayList<>(); ArrayList<TileEntityBehaviour> list = new ArrayList<>();
addBehavioursDeferred(list); addBehavioursDeferred(list);
list.forEach(b -> behaviours.put(b.getType(), b)); list.forEach(b -> behaviours.put(b.getType(), b));
updateBehaviorList();
} }
super.fromTag(state, compound); super.fromTag(state, compound);
behaviours.values() behaviourList.forEach(tb -> tb.read(compound, clientPacket));
.forEach(tb -> tb.read(compound, clientPacket));
} }
/** /**
@ -111,8 +115,7 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
*/ */
protected void write(CompoundNBT compound, boolean clientPacket) { protected void write(CompoundNBT compound, boolean clientPacket) {
super.write(compound); super.write(compound);
behaviours.values() behaviourList.forEach(tb -> tb.write(compound, clientPacket));
.forEach(tb -> tb.write(compound, clientPacket));
} }
@Override @Override
@ -131,19 +134,31 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
} }
protected void forEachBehaviour(Consumer<TileEntityBehaviour> action) { protected void forEachBehaviour(Consumer<TileEntityBehaviour> action) {
behaviours.values() behaviourList.forEach(action);
.forEach(action);
} }
protected void attachBehaviourLate(TileEntityBehaviour behaviour) { protected void attachBehaviourLate(TileEntityBehaviour behaviour) {
behaviours.put(behaviour.getType(), behaviour); behaviours.put(behaviour.getType(), behaviour);
behaviour.initialize(); behaviour.initialize();
updateBehaviorList();
} }
protected void removeBehaviour(BehaviourType<?> type) { protected void removeBehaviour(BehaviourType<?> type) {
TileEntityBehaviour remove = behaviours.remove(type); TileEntityBehaviour remove = behaviours.remove(type);
if (remove != null) if (remove != null) {
remove.remove(); remove.remove();
updateBehaviorList();
}
}
// We don't trust the input to the API will be sane, so we
// update all the contents whenever something changes. It's
// simpler than trying to manipulate the list one element at
// a time.
private void updateBehaviorList() {
behaviourList.clear();
behaviourList.addAll(behaviours.values());
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")