package com.jozufozu.flywheel.vanilla; import com.jozufozu.flywheel.backend.instancing.IDynamicInstance; import com.jozufozu.flywheel.backend.instancing.MaterialManager; import com.jozufozu.flywheel.backend.instancing.tile.TileEntityInstance; import com.jozufozu.flywheel.backend.model.BufferedModel; import com.jozufozu.flywheel.core.Materials; import com.jozufozu.flywheel.core.materials.OrientedData; import com.jozufozu.flywheel.core.model.ModelPart; import com.jozufozu.flywheel.util.AnimationTickHolder; import com.jozufozu.flywheel.util.vec.Vec3; import com.jozufozu.flywheel.util.vec.Vec4; import com.mojang.blaze3d.matrix.MatrixStack; import it.unimi.dsi.fastutil.floats.Float2FloatFunction; import net.minecraft.block.Block; import net.minecraft.block.ChestBlock; import net.minecraft.client.renderer.Atlases; import net.minecraft.client.renderer.model.RenderMaterial; import net.minecraft.state.properties.ChestType; import net.minecraft.tileentity.ChestTileEntity; import net.minecraft.tileentity.IChestLid; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityMerger; import net.minecraft.util.math.vector.Quaternion; import net.minecraft.util.math.vector.Vector3f; import net.minecraft.util.math.vector.Vector4f; import javax.annotation.Nonnull; import java.util.Calendar; public class ChestInstance extends TileEntityInstance implements IDynamicInstance { private final OrientedData body; private final OrientedData lid; private final Float2FloatFunction lidProgress; private final RenderMaterial renderMaterial; @Nonnull private final ChestType chestType; private final Quaternion baseRotation; public ChestInstance(MaterialManager materialManager, T tile) { super(materialManager, tile); Block block = blockState.getBlock(); chestType = blockState.contains(ChestBlock.TYPE) ? blockState.get(ChestBlock.TYPE) : ChestType.SINGLE; renderMaterial = Atlases.getChestTexture(tile, chestType, isChristmas()); body = baseInstance() .setPosition(getInstancePosition()); lid = lidInstance() .setPosition(getInstancePosition()) .nudge(0, 9f/16f, 0); if (block instanceof ChestBlock) { // MatrixStack stack = new MatrixStack(); // // stack.push(); float horizontalAngle = blockState.get(ChestBlock.FACING).getHorizontalAngle(); baseRotation = Vector3f.POSITIVE_Y.getDegreesQuaternion(-horizontalAngle); body.setRotation(baseRotation); ChestBlock chestBlock = (ChestBlock) block; TileEntityMerger.ICallbackWrapper wrapper = chestBlock.getBlockEntitySource(blockState, world, getWorldPosition(), true); this.lidProgress = wrapper.apply(ChestBlock.getAnimationProgressRetriever(tile)); } else { baseRotation = Quaternion.IDENTITY; lidProgress = $ -> 0f; } } @Override public void beginFrame() { float progress = lidProgress.get(AnimationTickHolder.getPartialTicks()); progress = 1.0F - progress; progress = 1.0F - progress * progress * progress; float angleX = -(progress * ((float) Math.PI / 2F)); Vec3 axis = Vec3.POSITIVE_X.copy(); Vec3 pivot = new Vec3(0, 0, 1f / 16f); pivot.add(0.5f, 0.5f, 0.5f) .multiply(baseRotation) .sub(0.5f, 0.5f, 0.5f); axis.multiply(baseRotation); Quaternion quaternion = new Quaternion(axis.convert(), angleX, false); quaternion.multiply(baseRotation); lid.setRotation(quaternion) .setPosition(getInstancePosition()) .nudge(0, 9f/16f, 0) .setPivot(pivot); } @Override public void updateLight() { relight(getWorldPosition(), body, lid); } @Override public void remove() { body.delete(); lid.delete(); } private OrientedData baseInstance() { return materialManager.getMaterial(Materials.ORIENTED, renderMaterial.getAtlasId()) .get("base_" + renderMaterial.getTextureId(), this::getBaseModel) .createInstance(); } private OrientedData lidInstance() { return materialManager.getMaterial(Materials.ORIENTED, renderMaterial.getAtlasId()) .get("lid_" + renderMaterial.getTextureId(), this::getLidModel) .createInstance(); } private BufferedModel getBaseModel() { switch (chestType) { case LEFT: return ModelPart.builder(64, 64) .sprite(renderMaterial.getSprite()) .cuboid() .textureOffset(0, 19) .start(0, 0, 1) .size(15, 10, 14) .endCuboid() .build(); case RIGHT: return ModelPart.builder(64, 64) .sprite(renderMaterial.getSprite()) .cuboid() .textureOffset(0, 19) .start(1, 0, 1) .size(15, 10, 14) .endCuboid() .build(); } return ModelPart.builder(64, 64) .sprite(renderMaterial.getSprite()) .cuboid() .textureOffset(0, 19) .start(1, 0, 1) .end(15, 10, 15) .endCuboid() .build(); } private BufferedModel getLidModel() { switch (chestType) { case LEFT: return ModelPart.builder(64, 64) .sprite(renderMaterial.getSprite()) .cuboid() .textureOffset(0, 0) .start(0, 0, 1) .size(15, 5, 14) .endCuboid() .cuboid() .start(0, -2, 15) .size(1, 4, 1) .endCuboid() .build(); case RIGHT: return ModelPart.builder(64, 64) .sprite(renderMaterial.getSprite()) .cuboid() .textureOffset(0, 0) .start(1, 0, 1) .size(15, 5, 14) .endCuboid() .cuboid() .start(15, -2, 15) .size(1, 4, 1) .endCuboid() .build(); } return ModelPart.builder(64, 64) .sprite(renderMaterial.getSprite()) .cuboid() .textureOffset(0, 0) .start(1, 0, 1) .size(14, 5, 14) .endCuboid() .cuboid() .start(7, -2, 15) .size(2, 4, 1) .endCuboid() .build(); } public static boolean isChristmas() { Calendar calendar = Calendar.getInstance(); return calendar.get(Calendar.MONTH) + 1 == 12 && calendar.get(Calendar.DATE) >= 24 && calendar.get(Calendar.DATE) <= 26; } }