mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-15 10:53:44 +01:00
Mechanical Bearing
- The mechanical bearing now rotates attached structures
This commit is contained in:
parent
fb35aa7e10
commit
b7decf0d0f
7 changed files with 428 additions and 11 deletions
|
@ -3,10 +3,133 @@ package com.simibubi.create.modules.contraptions.receivers.constructs;
|
|||
import com.simibubi.create.AllTileEntities;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
|
||||
|
||||
public class MechanicalBearingTileEntity extends KineticTileEntity {
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.tileentity.ITickableTileEntity;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
||||
|
||||
public class MechanicalBearingTileEntity extends KineticTileEntity implements ITickableTileEntity {
|
||||
|
||||
protected RotationConstruct movingConstruct;
|
||||
protected float angle;
|
||||
protected boolean running;
|
||||
protected boolean assembleNextTick;
|
||||
|
||||
public MechanicalBearingTileEntity() {
|
||||
super(AllTileEntities.MECHANICAL_BEARING.type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AxisAlignedBB getRenderBoundingBox() {
|
||||
return INFINITE_EXTENT_AABB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundNBT write(CompoundNBT tag) {
|
||||
tag.putBoolean("Running", running);
|
||||
tag.putFloat("Angle", angle);
|
||||
if (running)
|
||||
tag.put("Construct", movingConstruct.writeNBT());
|
||||
|
||||
return super.write(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(CompoundNBT tag) {
|
||||
running = tag.getBoolean("Running");
|
||||
angle = tag.getFloat("Angle");
|
||||
if (running)
|
||||
movingConstruct = RotationConstruct.fromNBT(tag.getCompound("Construct"));
|
||||
|
||||
super.read(tag);
|
||||
}
|
||||
|
||||
public float getInterpolatedAngle(float partialTicks) {
|
||||
return MathHelper.lerp(partialTicks, angle, angle + getAngularSpeed());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeedChanged() {
|
||||
super.onSpeedChanged();
|
||||
assembleNextTick = true;
|
||||
}
|
||||
|
||||
public float getAngularSpeed() {
|
||||
return speed / 2048;
|
||||
}
|
||||
|
||||
public void assembleConstruct() {
|
||||
Direction direction = getBlockState().get(BlockStateProperties.FACING);
|
||||
|
||||
// Collect Construct
|
||||
movingConstruct = RotationConstruct.getAttachedForRotating(getWorld(), getPos(), direction);
|
||||
if (movingConstruct == null)
|
||||
return;
|
||||
|
||||
// Run
|
||||
running = true;
|
||||
angle = 0;
|
||||
sendData();
|
||||
|
||||
for (BlockInfo info : movingConstruct.blocks.values()) {
|
||||
getWorld().setBlockState(info.pos.add(pos), Blocks.AIR.getDefaultState(), 67);
|
||||
}
|
||||
}
|
||||
|
||||
public void disassembleConstruct() {
|
||||
if (!running)
|
||||
return;
|
||||
|
||||
for (BlockInfo block : movingConstruct.blocks.values()) {
|
||||
BlockPos targetPos = block.pos.add(pos);
|
||||
BlockState state = block.state;
|
||||
|
||||
for (Direction face : Direction.values())
|
||||
state = state.updatePostPlacement(face, world.getBlockState(targetPos.offset(face)), world, targetPos,
|
||||
targetPos.offset(face));
|
||||
|
||||
world.destroyBlock(targetPos, world.getBlockState(targetPos).getCollisionShape(world, targetPos).isEmpty());
|
||||
getWorld().setBlockState(targetPos, state, 3);
|
||||
TileEntity tileEntity = world.getTileEntity(targetPos);
|
||||
if (tileEntity != null && block.nbt != null) {
|
||||
((ChassisTileEntity) tileEntity).setRange(block.nbt.getInt("Range"));
|
||||
}
|
||||
}
|
||||
|
||||
running = false;
|
||||
movingConstruct = null;
|
||||
angle = 0;
|
||||
sendData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (!world.isRemote && assembleNextTick) {
|
||||
assembleNextTick = false;
|
||||
if (running) {
|
||||
if (speed == 0 && (Math.abs(angle) < Math.PI / 4f || Math.abs(angle) > 7 * Math.PI / 4f)) {
|
||||
disassembleConstruct();
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
assembleConstruct();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!running)
|
||||
return;
|
||||
|
||||
float angularSpeed = getAngularSpeed();
|
||||
float newAngle = angle + angularSpeed;
|
||||
angle = (float) (newAngle % (2 * Math.PI));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,22 +1,40 @@
|
|||
package com.simibubi.create.modules.contraptions.receivers.constructs;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.modules.contraptions.base.IRotate;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BlockModelRenderer;
|
||||
import net.minecraft.client.renderer.BlockRendererDispatcher;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
||||
import net.minecraftforge.client.model.animation.Animation;
|
||||
import net.minecraftforge.client.model.data.EmptyModelData;
|
||||
|
||||
public class MechanicalBearingTileEntityRenderer extends KineticTileEntityRenderer {
|
||||
|
||||
protected static Cache<RotationConstruct, RotationConstructVertexBuffer> cachedConstructs;
|
||||
|
||||
@Override
|
||||
public void renderTileEntityFast(KineticTileEntity te, double x, double y, double z, float partialTicks,
|
||||
int destroyStage, BufferBuilder buffer) {
|
||||
MechanicalBearingTileEntity bearingTe = (MechanicalBearingTileEntity) te;
|
||||
final Direction facing = te.getBlockState().get(BlockStateProperties.FACING);
|
||||
final BlockPos pos = te.getPos();
|
||||
float time = Animation.getWorldTime(Minecraft.getInstance().world, partialTicks);
|
||||
|
@ -33,9 +51,56 @@ public class MechanicalBearingTileEntityRenderer extends KineticTileEntityRender
|
|||
|
||||
angle += offset;
|
||||
angle = angle / 180f * (float) Math.PI;
|
||||
float interpolatedAngle = bearingTe.getInterpolatedAngle(partialTicks);
|
||||
|
||||
renderFromCache(buffer, shaftState, (float) x, (float) y, (float) z, pos, facing.getAxis(), angle);
|
||||
renderFromCache(buffer, capState, (float) x, (float) y, (float) z, pos, facing.getAxis(), angle);
|
||||
renderFromCache(buffer, capState, (float) x, (float) y, (float) z, pos, facing.getAxis(), interpolatedAngle);
|
||||
|
||||
if (!bearingTe.running)
|
||||
return;
|
||||
|
||||
cacheConstructIfMissing(bearingTe.movingConstruct);
|
||||
renderConstructFromCache(bearingTe.movingConstruct, bearingTe, x, y, z, partialTicks, buffer);
|
||||
}
|
||||
|
||||
protected void cacheConstructIfMissing(RotationConstruct c) {
|
||||
if (cachedConstructs == null)
|
||||
cachedConstructs = CacheBuilder.newBuilder().expireAfterAccess(1, TimeUnit.SECONDS).build();
|
||||
if (cachedConstructs.getIfPresent(c) != null)
|
||||
return;
|
||||
|
||||
BlockRendererDispatcher dispatcher = Minecraft.getInstance().getBlockRendererDispatcher();
|
||||
BlockModelRenderer blockRenderer = dispatcher.getBlockModelRenderer();
|
||||
Random random = new Random();
|
||||
BufferBuilder builder = new BufferBuilder(0);
|
||||
builder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK);
|
||||
builder.setTranslation(0, 255, 0);
|
||||
|
||||
for (BlockPos localPos : c.blocks.keySet()) {
|
||||
BlockInfo info = c.blocks.get(localPos);
|
||||
IBakedModel originalModel = dispatcher.getModelForState(info.state);
|
||||
blockRenderer.renderModel(getWorld(), originalModel, info.state, info.pos.down(255), builder, true, random,
|
||||
42, EmptyModelData.INSTANCE);
|
||||
}
|
||||
|
||||
builder.finishDrawing();
|
||||
cachedConstructs.put(c, new RotationConstructVertexBuffer(builder.getByteBuffer()));
|
||||
}
|
||||
|
||||
protected void renderConstructFromCache(RotationConstruct c, MechanicalBearingTileEntity te, double x, double y,
|
||||
double z, float partialTicks, BufferBuilder buffer) {
|
||||
float zfightBonus = 1 / 128f;
|
||||
Direction direction = te.getBlockState().get(BlockStateProperties.FACING);
|
||||
Vec3i vec = direction.getDirectionVec();
|
||||
buffer.putBulkData(cachedConstructs.getIfPresent(c).getTransformed(te, (float) (x) + vec.getX() * zfightBonus,
|
||||
(float) (y) + vec.getY() * zfightBonus, (float) (z) + vec.getZ() * zfightBonus,
|
||||
te.getInterpolatedAngle(partialTicks), direction.getAxis()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlockState getRenderedBlockState(KineticTileEntity te) {
|
||||
return AllBlocks.SHAFT.block.getDefaultState().with(BlockStateProperties.AXIS,
|
||||
((IRotate) te.getBlockState().getBlock()).getRotationAxis(te.getBlockState()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,11 +35,6 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
|
|||
super(AllTileEntities.MECHANICAL_PISTON.type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFastRenderer() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeedChanged() {
|
||||
super.onSpeedChanged();
|
||||
|
|
|
@ -26,7 +26,7 @@ import net.minecraftforge.client.model.data.EmptyModelData;
|
|||
|
||||
public class MechanicalPistonTileEntityRenderer extends KineticTileEntityRenderer {
|
||||
|
||||
protected static Cache<TranslationConstruct, ConstructVertexBuffer> cachedConstructs;
|
||||
protected static Cache<TranslationConstruct, TranslationConstructVertexBuffer> cachedConstructs;
|
||||
|
||||
@Override
|
||||
public void renderTileEntityFast(KineticTileEntity te, double x, double y, double z, float partialTicks,
|
||||
|
@ -64,7 +64,7 @@ public class MechanicalPistonTileEntityRenderer extends KineticTileEntityRendere
|
|||
}
|
||||
|
||||
builder.finishDrawing();
|
||||
cachedConstructs.put(c, new ConstructVertexBuffer(builder.getByteBuffer()));
|
||||
cachedConstructs.put(c, new TranslationConstructVertexBuffer(builder.getByteBuffer()));
|
||||
}
|
||||
|
||||
protected void renderConstructFromCache(TranslationConstruct c, MechanicalPistonTileEntity te, double x, double y, double z,
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
package com.simibubi.create.modules.contraptions.receivers.constructs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.PistonBlock;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
import net.minecraft.nbt.NBTUtil;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
||||
|
||||
public class RotationConstruct {
|
||||
|
||||
public static final int MAX_CHAINED_CHASSIS = 10;
|
||||
|
||||
protected Map<BlockPos, BlockInfo> blocks;
|
||||
|
||||
public RotationConstruct() {
|
||||
blocks = new HashMap<>();
|
||||
}
|
||||
|
||||
public static RotationConstruct getAttachedForRotating(World world, BlockPos pos, Direction direction) {
|
||||
RotationConstruct construct = new RotationConstruct();
|
||||
|
||||
if (!construct.collectAttached(world, pos, direction))
|
||||
return null;
|
||||
|
||||
return construct;
|
||||
}
|
||||
|
||||
protected boolean collectAttached(World world, BlockPos pos, Direction direction) {
|
||||
|
||||
// Find chassis
|
||||
List<BlockInfo> chassis = collectChassis(world, pos, direction);
|
||||
if (chassis == null)
|
||||
return false;
|
||||
|
||||
// Get single block
|
||||
if (chassis.isEmpty()) {
|
||||
BlockPos blockPos = pos.offset(direction);
|
||||
BlockState state = world.getBlockState(pos.offset(direction));
|
||||
|
||||
if (state.getMaterial().isReplaceable() || state.isAir(world, blockPos))
|
||||
return true;
|
||||
if (state.getCollisionShape(world, blockPos).isEmpty())
|
||||
return true;
|
||||
if (!canRotate(world, blockPos, direction))
|
||||
return false;
|
||||
|
||||
blocks.put(blockPos, new BlockInfo(blockPos.subtract(pos), state, null));
|
||||
|
||||
// Get attached blocks by chassis
|
||||
} else {
|
||||
List<BlockInfo> attachedBlocksByChassis = getAttachedBlocksByChassis(world, direction, chassis);
|
||||
if (attachedBlocksByChassis == null)
|
||||
return false;
|
||||
attachedBlocksByChassis.forEach(info -> {
|
||||
blocks.put(info.pos, new BlockInfo(info.pos.subtract(pos), info.state, info.nbt));
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private List<BlockInfo> getAttachedBlocksByChassis(World world, Direction direction, List<BlockInfo> chassis) {
|
||||
List<BlockInfo> blocks = new ArrayList<>();
|
||||
RotationChassisBlock def = (RotationChassisBlock) AllBlocks.ROTATION_CHASSIS.block;
|
||||
|
||||
for (BlockInfo chassisBlock : chassis) {
|
||||
blocks.add(chassisBlock);
|
||||
BlockState state = chassisBlock.state;
|
||||
BlockPos currentPos = chassisBlock.pos;
|
||||
TileEntity tileEntity = world.getTileEntity(currentPos);
|
||||
|
||||
if (!(tileEntity instanceof ChassisTileEntity))
|
||||
return null;
|
||||
|
||||
int chassisRange = ((ChassisTileEntity) tileEntity).getRange();
|
||||
Set<BlockPos> visited = new HashSet<>();
|
||||
|
||||
for (Direction facing : Direction.values()) {
|
||||
if (facing.getAxis() == direction.getAxis())
|
||||
continue;
|
||||
if (!state.get(def.getGlueableSide(state, facing)))
|
||||
continue;
|
||||
|
||||
BlockPos startPos = currentPos.offset(facing);
|
||||
List<BlockPos> frontier = new LinkedList<>();
|
||||
frontier.add(startPos);
|
||||
CompoundNBT nbt = new CompoundNBT();
|
||||
nbt.putInt("Range", chassisRange);
|
||||
|
||||
while (!frontier.isEmpty()) {
|
||||
BlockPos searchPos = frontier.remove(0);
|
||||
BlockState searchedState = world.getBlockState(searchPos);
|
||||
|
||||
if (visited.contains(searchPos))
|
||||
continue;
|
||||
if (!searchPos.withinDistance(currentPos, chassisRange + .5f))
|
||||
continue;
|
||||
if (searchedState.getMaterial().isReplaceable() || state.isAir(world, searchPos))
|
||||
continue;
|
||||
if (searchedState.getCollisionShape(world, searchPos).isEmpty())
|
||||
continue;
|
||||
if (!canRotate(world, searchPos, direction))
|
||||
return null;
|
||||
|
||||
visited.add(searchPos);
|
||||
|
||||
blocks.add(new BlockInfo(searchPos, searchedState,
|
||||
AllBlocks.ROTATION_CHASSIS.typeOf(searchedState) ? nbt : null));
|
||||
|
||||
for (Direction offset : Direction.values()) {
|
||||
if (offset.getAxis() == direction.getAxis())
|
||||
continue;
|
||||
if (searchPos.equals(currentPos) && offset != facing)
|
||||
continue;
|
||||
|
||||
frontier.add(searchPos.offset(offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
|
||||
private List<BlockInfo> collectChassis(World world, BlockPos pos, Direction direction) {
|
||||
List<BlockInfo> chassis = new ArrayList<>();
|
||||
for (int distance = 1; distance <= MAX_CHAINED_CHASSIS; distance++) {
|
||||
BlockPos currentPos = pos.offset(direction, distance);
|
||||
if (!world.isBlockPresent(currentPos))
|
||||
return chassis;
|
||||
|
||||
BlockState state = world.getBlockState(currentPos);
|
||||
if (!AllBlocks.ROTATION_CHASSIS.typeOf(state))
|
||||
return chassis;
|
||||
if (direction.getAxis() != state.get(BlockStateProperties.AXIS))
|
||||
return chassis;
|
||||
|
||||
chassis.add(new BlockInfo(currentPos, state, null));
|
||||
}
|
||||
return chassis;
|
||||
}
|
||||
|
||||
public CompoundNBT writeNBT() {
|
||||
CompoundNBT nbt = new CompoundNBT();
|
||||
ListNBT blocks = new ListNBT();
|
||||
for (BlockInfo block : this.blocks.values()) {
|
||||
CompoundNBT c = new CompoundNBT();
|
||||
c.put("Block", NBTUtil.writeBlockState(block.state));
|
||||
c.put("Pos", NBTUtil.writeBlockPos(block.pos));
|
||||
if (block.nbt != null)
|
||||
c.put("Data", block.nbt);
|
||||
blocks.add(c);
|
||||
}
|
||||
|
||||
nbt.put("Blocks", blocks);
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public static RotationConstruct fromNBT(CompoundNBT nbt) {
|
||||
RotationConstruct construct = new RotationConstruct();
|
||||
nbt.getList("Blocks", 10).forEach(c -> {
|
||||
CompoundNBT comp = (CompoundNBT) c;
|
||||
BlockInfo info = new BlockInfo(NBTUtil.readBlockPos(comp.getCompound("Pos")),
|
||||
NBTUtil.readBlockState(comp.getCompound("Block")),
|
||||
comp.contains("Data") ? comp.getCompound("Data") : null);
|
||||
construct.blocks.put(info.pos, info);
|
||||
});
|
||||
|
||||
return construct;
|
||||
}
|
||||
|
||||
private static boolean canRotate(World world, BlockPos pos, Direction direction) {
|
||||
return PistonBlock.canPush(world.getBlockState(pos), world, pos, direction, true, direction)
|
||||
|| AllBlocks.ROTATION_CHASSIS.typeOf(world.getBlockState(pos));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package com.simibubi.create.modules.contraptions.receivers.constructs;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.simibubi.create.foundation.utility.BufferManipulator;
|
||||
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
public class RotationConstructVertexBuffer extends BufferManipulator {
|
||||
|
||||
public RotationConstructVertexBuffer(ByteBuffer original) {
|
||||
super(original);
|
||||
}
|
||||
|
||||
public ByteBuffer getTransformed(TileEntity te, float x, float y, float z, float angle, Axis axis) {
|
||||
original.rewind();
|
||||
mutable.rewind();
|
||||
|
||||
float cos = MathHelper.cos(angle);
|
||||
float sin = MathHelper.sin(angle);
|
||||
|
||||
for (int vertex = 0; vertex < vertexCount(original); vertex++) {
|
||||
float xL = getX(original, vertex) -.5f;
|
||||
float yL = getY(original, vertex) -.5f;
|
||||
float zL = getZ(original, vertex) -.5f;
|
||||
|
||||
float xL2 = rotateX(xL, yL, zL, sin, cos, axis) + .5f;
|
||||
float yL2 = rotateY(xL, yL, zL, sin, cos, axis) + .5f;
|
||||
float zL2 = rotateZ(xL, yL, zL, sin, cos, axis) + .5f;
|
||||
|
||||
putPos(mutable, vertex, xL2 + x, yL2 + y, zL2 + z);
|
||||
BlockPos pos = new BlockPos(te.getPos().getX() + xL2, te.getPos().getY() + yL2, te.getPos().getZ() + zL2);
|
||||
putLight(mutable, vertex, te.getWorld().getCombinedLight(pos, 0));
|
||||
}
|
||||
|
||||
return mutable;
|
||||
}
|
||||
|
||||
}
|
|
@ -8,9 +8,9 @@ import net.minecraft.tileentity.TileEntity;
|
|||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public class ConstructVertexBuffer extends BufferManipulator {
|
||||
public class TranslationConstructVertexBuffer extends BufferManipulator {
|
||||
|
||||
public ConstructVertexBuffer(ByteBuffer original) {
|
||||
public TranslationConstructVertexBuffer(ByteBuffer original) {
|
||||
super(original);
|
||||
}
|
||||
|
Loading…
Reference in a new issue