mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-15 21:03:41 +01:00
Beziterating
- Instanced tracks - Cleaner bezier connection iteration
This commit is contained in:
parent
87bdd8d586
commit
962975a09d
8 changed files with 308 additions and 57 deletions
|
@ -19,7 +19,7 @@ parchment_version = 2022.01.23
|
|||
|
||||
# dependency versions
|
||||
registrate_version = MC1.18-1.0.21
|
||||
flywheel_version = 1.18-0.6.1.56
|
||||
flywheel_version = 1.18-0.6.1.57
|
||||
jei_minecraft_version = 1.18.1
|
||||
jei_version = 9.2.1.69
|
||||
|
||||
|
|
|
@ -171,6 +171,7 @@ import com.simibubi.create.content.logistics.trains.IBogeyTileEntityRenderer;
|
|||
import com.simibubi.create.content.logistics.trains.management.StationRenderer;
|
||||
import com.simibubi.create.content.logistics.trains.management.StationTileEntity;
|
||||
import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackInstance;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackRenderer;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackTileEntity;
|
||||
import com.simibubi.create.content.schematics.block.SchematicTableTileEntity;
|
||||
|
@ -730,6 +731,7 @@ public class AllTileEntities {
|
|||
|
||||
public static final BlockEntityEntry<TrackTileEntity> TRACK = Create.registrate()
|
||||
.tileEntity("track", TrackTileEntity::new)
|
||||
.instance(() -> TrackInstance::new)
|
||||
.renderer(() -> TrackRenderer::new)
|
||||
.validBlocks(AllBlocks.TRACK)
|
||||
.register();
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.simibubi.create.content.logistics.trains;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.jozufozu.flywheel.repack.joml.Math;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
@ -13,7 +15,7 @@ import net.minecraft.network.FriendlyByteBuf;
|
|||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class BezierConnection {
|
||||
public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
||||
|
||||
public Couple<BlockPos> tePositions;
|
||||
public Couple<Boolean> trackEnds;
|
||||
|
@ -126,6 +128,10 @@ public class BezierConnection {
|
|||
return handleLength;
|
||||
}
|
||||
|
||||
public float getSegmentT(int index) {
|
||||
return index == segments ? 1 : index * stepLUT[index] / segments;
|
||||
}
|
||||
|
||||
public double incrementT(double currentT, double distance) {
|
||||
resolve();
|
||||
double dx =
|
||||
|
@ -250,4 +256,73 @@ public class BezierConnection {
|
|||
handleLength = 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Segment> iterator() {
|
||||
resolve();
|
||||
var offset = Vec3.atLowerCornerOf(tePositions.getFirst())
|
||||
.scale(-1)
|
||||
.add(0, 3 / 16f, 0);
|
||||
return new Bezierator(this, offset);
|
||||
}
|
||||
|
||||
public static class Segment {
|
||||
public int index;
|
||||
public Vec3 position;
|
||||
public Vec3 derivative;
|
||||
public Vec3 faceNormal;
|
||||
public Vec3 normal;
|
||||
}
|
||||
|
||||
private static class Bezierator implements Iterator<Segment> {
|
||||
|
||||
private final BezierConnection bc;
|
||||
private final Segment segment;
|
||||
private final Vec3 end1;
|
||||
private final Vec3 end2;
|
||||
private final Vec3 finish1;
|
||||
private final Vec3 finish2;
|
||||
private final Vec3 faceNormal1;
|
||||
private final Vec3 faceNormal2;
|
||||
|
||||
private Bezierator(BezierConnection bc, Vec3 offset) {
|
||||
bc.resolve();
|
||||
this.bc = bc;
|
||||
|
||||
end1 = bc.starts.getFirst()
|
||||
.add(offset);
|
||||
end2 = bc.starts.getSecond()
|
||||
.add(offset);
|
||||
|
||||
finish1 = bc.axes.getFirst()
|
||||
.scale(bc.handleLength)
|
||||
.add(end1);
|
||||
finish2 = bc.axes.getSecond()
|
||||
.scale(bc.handleLength)
|
||||
.add(end2);
|
||||
|
||||
faceNormal1 = bc.normals.getFirst();
|
||||
faceNormal2 = bc.normals.getSecond();
|
||||
segment = new Segment();
|
||||
segment.index = -1; // will get incremented to 0 in #next()
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return segment.index + 1 <= bc.segments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Segment next() {
|
||||
segment.index++;
|
||||
float t = this.bc.getSegmentT(segment.index);
|
||||
segment.position = VecHelper.bezier(end1, end2, finish1, finish2, t);
|
||||
segment.derivative = VecHelper.bezierDerivative(end1, end2, finish1, finish2, t)
|
||||
.normalize();
|
||||
segment.faceNormal = faceNormal1.equals(faceNormal2) ? faceNormal1 : VecHelper.slerp(t, faceNormal1, faceNormal2);
|
||||
segment.normal = segment.faceNormal.cross(segment.derivative)
|
||||
.normalize();
|
||||
return segment;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
|
||||
import com.jozufozu.flywheel.core.Materials;
|
||||
import com.jozufozu.flywheel.core.materials.model.ModelData;
|
||||
import com.jozufozu.flywheel.light.LightUpdater;
|
||||
import com.jozufozu.flywheel.util.FlwUtil;
|
||||
import com.jozufozu.flywheel.util.box.GridAlignedBB;
|
||||
import com.jozufozu.flywheel.util.box.ImmutableBox;
|
||||
import com.jozufozu.flywheel.util.transform.TransformStack;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.AllBlockPartials;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class TrackInstance extends BlockEntityInstance<TrackTileEntity> {
|
||||
|
||||
private List<BezierInstance> instances;
|
||||
|
||||
public TrackInstance(MaterialManager materialManager, TrackTileEntity track) {
|
||||
super(materialManager, track);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
if (blockEntity.connections.stream().allMatch(Map::isEmpty)) {
|
||||
return;
|
||||
}
|
||||
|
||||
instances = blockEntity.connections.stream()
|
||||
.flatMap(FlwUtil::mapValues)
|
||||
.map(this::createInstance)
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
LightUpdater.get(world).addListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableBox getVolume() {
|
||||
List<BlockPos> out = new ArrayList<>();
|
||||
out.addAll(blockEntity.connections.getFirst()
|
||||
.keySet());
|
||||
out.addAll(blockEntity.connections.getSecond()
|
||||
.keySet());
|
||||
return GridAlignedBB.containingAll(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLight() {
|
||||
if (instances == null) return;
|
||||
instances.forEach(BezierInstance::updateLight);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private BezierInstance createInstance(BezierConnection bc) {
|
||||
if (!bc.isPrimary()) return null;
|
||||
return new BezierInstance(bc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (instances == null) return;
|
||||
instances.forEach(BezierInstance::delete);
|
||||
}
|
||||
|
||||
private class BezierInstance {
|
||||
|
||||
private final ModelData[] ties;
|
||||
private final ModelData[] left;
|
||||
private final ModelData[] right;
|
||||
private final BlockPos[] tiesLightPos;
|
||||
private final BlockPos[] leftLightPos;
|
||||
private final BlockPos[] rightLightPos;
|
||||
|
||||
private BezierInstance(BezierConnection bc) {
|
||||
BlockPos tePosition = bc.tePositions.getFirst();
|
||||
|
||||
PoseStack pose = new PoseStack();
|
||||
TransformStack.cast(pose)
|
||||
.translate(getInstancePosition())
|
||||
.nudge((int) bc.tePositions.getFirst()
|
||||
.asLong());
|
||||
|
||||
var mat = materialManager.defaultSolid()
|
||||
.material(Materials.TRANSFORMED);
|
||||
|
||||
int segCount = bc.getSegmentCount();
|
||||
ties = new ModelData[segCount];
|
||||
left = new ModelData[segCount];
|
||||
right = new ModelData[segCount];
|
||||
tiesLightPos = new BlockPos[segCount];
|
||||
leftLightPos = new BlockPos[segCount];
|
||||
rightLightPos = new BlockPos[segCount];
|
||||
|
||||
mat.getModel(AllBlockPartials.TRACK_TIE)
|
||||
.createInstances(ties);
|
||||
mat.getModel(AllBlockPartials.TRACK_SEGMENT_LEFT)
|
||||
.createInstances(left);
|
||||
mat.getModel(AllBlockPartials.TRACK_SEGMENT_RIGHT)
|
||||
.createInstances(right);
|
||||
|
||||
Vec3 leftPrevious = null;
|
||||
Vec3 rightPrevious = null;
|
||||
|
||||
for (BezierConnection.Segment segment : bc) {
|
||||
Vec3 left = segment.position.add(segment.normal.scale(.97f));
|
||||
Vec3 right = segment.position.subtract(segment.normal.scale(.97f));
|
||||
|
||||
if (leftPrevious != null) {
|
||||
var modelIndex = segment.index - 1;
|
||||
{
|
||||
// Tie
|
||||
Vec3 railMiddle = left.add(right)
|
||||
.scale(.5);
|
||||
Vec3 prevMiddle = leftPrevious.add(rightPrevious)
|
||||
.scale(.5);
|
||||
|
||||
var tie = ties[modelIndex].setTransform(pose);
|
||||
Vec3 diff = railMiddle.subtract(prevMiddle);
|
||||
Vec3 angles = TrackRenderer.getModelAngles(segment.normal, diff);
|
||||
|
||||
tie.translate(prevMiddle)
|
||||
.rotateYRadians(angles.y)
|
||||
.rotateXRadians(angles.x)
|
||||
.rotateZRadians(angles.z)
|
||||
.translate(-1 / 2f, -2 / 16f - 1 / 1024f, 0);
|
||||
tiesLightPos[modelIndex] = new BlockPos(railMiddle).offset(tePosition);
|
||||
}
|
||||
|
||||
// Rails
|
||||
for (boolean first : Iterate.trueAndFalse) {
|
||||
Vec3 railI = first ? left : right;
|
||||
Vec3 prevI = first ? leftPrevious : rightPrevious;
|
||||
|
||||
var rail = (first ? this.left : this.right)[modelIndex].setTransform(pose);
|
||||
Vec3 diff = railI.subtract(prevI);
|
||||
Vec3 angles = TrackRenderer.getModelAngles(segment.normal, diff);
|
||||
|
||||
rail.translate(prevI)
|
||||
.rotateYRadians(angles.y)
|
||||
.rotateXRadians(angles.x)
|
||||
.rotateZRadians(angles.z)
|
||||
.translate(0, -2 / 16f + (segment.index % 2 == 0 ? 1 : -1) / 2048f - 1 / 1024f, 0)
|
||||
.scale(1, 1, (float) diff.length() * 2.1f);
|
||||
(first ? leftLightPos : rightLightPos)[modelIndex] = new BlockPos(prevI).offset(tePosition);
|
||||
}
|
||||
}
|
||||
|
||||
leftPrevious = left;
|
||||
rightPrevious = right;
|
||||
}
|
||||
|
||||
updateLight();
|
||||
}
|
||||
|
||||
void delete() {
|
||||
for (ModelData d : ties) d.delete();
|
||||
for (ModelData d : left) d.delete();
|
||||
for (ModelData d : right) d.delete();
|
||||
}
|
||||
|
||||
void updateLight() {
|
||||
for (int i = 0; i < ties.length; i++) {
|
||||
ties[i].updateLight(world, tiesLightPos[i]);
|
||||
}
|
||||
for (int i = 0; i < left.length; i++) {
|
||||
left[i].updateLight(world, leftLightPos[i]);
|
||||
}
|
||||
for (int i = 0; i < right.length; i++) {
|
||||
right[i].updateLight(world, rightLightPos[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.repack.joml.Math;
|
||||
import com.jozufozu.flywheel.util.transform.MatrixTransformStack;
|
||||
import com.jozufozu.flywheel.util.transform.TransformStack;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.simibubi.create.AllBlockPartials;
|
||||
|
@ -31,6 +32,8 @@ public class TrackRenderer extends SafeTileEntityRenderer<TrackTileEntity> {
|
|||
@Override
|
||||
protected void renderSafe(TrackTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light,
|
||||
int overlay) {
|
||||
if (Backend.isOn()) return;
|
||||
|
||||
VertexConsumer vb = buffer.getBuffer(RenderType.solid());
|
||||
te.connections.forEach(map -> map.values()
|
||||
.forEach(bc -> renderBezierTurn(bc, ms, vb)));
|
||||
|
@ -41,49 +44,19 @@ public class TrackRenderer extends SafeTileEntityRenderer<TrackTileEntity> {
|
|||
return;
|
||||
|
||||
ms.pushPose();
|
||||
new MatrixTransformStack(ms).nudge((int) bc.tePositions.getFirst()
|
||||
.asLong());
|
||||
|
||||
BlockPos tePosition = bc.tePositions.getFirst();
|
||||
Vec3 end1 = bc.starts.getFirst()
|
||||
.subtract(Vec3.atLowerCornerOf(tePosition))
|
||||
.add(0, 3 / 16f, 0);
|
||||
Vec3 end2 = bc.starts.getSecond()
|
||||
.subtract(Vec3.atLowerCornerOf(tePosition))
|
||||
.add(0, 3 / 16f, 0);
|
||||
Vec3 axis1 = bc.axes.getFirst();
|
||||
Vec3 axis2 = bc.axes.getSecond();
|
||||
|
||||
double handleLength = bc.getHandleLength();
|
||||
TransformStack.cast(ms)
|
||||
.nudge((int) tePosition.asLong());
|
||||
|
||||
Vec3 finish1 = axis1.scale(handleLength)
|
||||
.add(end1);
|
||||
Vec3 finish2 = axis2.scale(handleLength)
|
||||
.add(end2);
|
||||
|
||||
Vec3 faceNormal1 = bc.normals.getFirst();
|
||||
Vec3 faceNormal2 = bc.normals.getSecond();
|
||||
Vec3 previous1 = null;
|
||||
Vec3 previous2 = null;
|
||||
|
||||
int segCount = bc.getSegmentCount();
|
||||
float[] lut = bc.getStepLUT();
|
||||
|
||||
for (int i = 0; i <= segCount; i++) {
|
||||
float t = i == segCount ? 1 : i * lut[i] / segCount;
|
||||
|
||||
Vec3 result = VecHelper.bezier(end1, end2, finish1, finish2, t);
|
||||
Vec3 derivative = VecHelper.bezierDerivative(end1, end2, finish1, finish2, t)
|
||||
.normalize();
|
||||
Vec3 faceNormal =
|
||||
faceNormal1.equals(faceNormal2) ? faceNormal1 : VecHelper.slerp(t, faceNormal1, faceNormal2);
|
||||
Vec3 normal = faceNormal.cross(derivative)
|
||||
.normalize();
|
||||
Vec3 rail1 = result.add(normal.scale(.97f));
|
||||
Vec3 rail2 = result.subtract(normal.scale(.97f));
|
||||
for (BezierConnection.Segment segment : bc) {
|
||||
Vec3 rail1 = segment.position.add(segment.normal.scale(.97f));
|
||||
Vec3 rail2 = segment.position.subtract(segment.normal.scale(.97f));
|
||||
|
||||
if (previous1 != null) {
|
||||
ms.pushPose();
|
||||
{
|
||||
// Tie
|
||||
Vec3 railMiddle = rail1.add(rail2)
|
||||
|
@ -91,7 +64,7 @@ public class TrackRenderer extends SafeTileEntityRenderer<TrackTileEntity> {
|
|||
Vec3 prevMiddle = previous1.add(previous2)
|
||||
.scale(.5);
|
||||
Vec3 diff = railMiddle.subtract(prevMiddle);
|
||||
Vec3 angles = getModelAngles(normal, diff);
|
||||
Vec3 angles = getModelAngles(segment.normal, diff);
|
||||
|
||||
SuperByteBuffer sbb =
|
||||
CachedBufferer.partial(AllBlockPartials.TRACK_TIE, Blocks.AIR.defaultBlockState());
|
||||
|
@ -106,16 +79,13 @@ public class TrackRenderer extends SafeTileEntityRenderer<TrackTileEntity> {
|
|||
new BlockPos(railMiddle).offset(tePosition)));
|
||||
sbb.renderInto(ms, vb);
|
||||
}
|
||||
ms.popPose();
|
||||
|
||||
// Rails
|
||||
for (boolean first : Iterate.trueAndFalse) {
|
||||
ms.pushPose();
|
||||
|
||||
Vec3 railI = first ? rail1 : rail2;
|
||||
Vec3 prevI = first ? previous1 : previous2;
|
||||
Vec3 diff = railI.subtract(prevI);
|
||||
Vec3 angles = getModelAngles(normal, diff);
|
||||
Vec3 angles = getModelAngles(segment.normal, diff);
|
||||
|
||||
SuperByteBuffer sbb = CachedBufferer.partial(
|
||||
first ? AllBlockPartials.TRACK_SEGMENT_LEFT : AllBlockPartials.TRACK_SEGMENT_RIGHT,
|
||||
|
@ -125,14 +95,12 @@ public class TrackRenderer extends SafeTileEntityRenderer<TrackTileEntity> {
|
|||
.rotateYRadians(angles.y)
|
||||
.rotateXRadians(angles.x)
|
||||
.rotateZRadians(angles.z)
|
||||
.translate(0, -2 / 16f + (i % 2 == 0 ? 1 : -1) / 2048f - 1 / 1024f, 0)
|
||||
.translate(0, -2 / 16f + (segment.index % 2 == 0 ? 1 : -1) / 2048f - 1 / 1024f, 0)
|
||||
.scale(1, 1, (float) diff.length() * 2.1f);
|
||||
|
||||
sbb.light(LevelRenderer.getLightColor(Minecraft.getInstance().level,
|
||||
new BlockPos(prevI).offset(tePosition)));
|
||||
sbb.renderInto(ms, vb);
|
||||
|
||||
ms.popPose();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection;
|
||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||
|
@ -16,6 +17,8 @@ import net.minecraft.world.level.block.entity.BlockEntity;
|
|||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
|
||||
public class TrackTileEntity extends SmartTileEntity {
|
||||
|
||||
|
@ -94,6 +97,8 @@ public class TrackTileEntity extends SmartTileEntity {
|
|||
BezierConnection connection = new BezierConnection((CompoundTag) t);
|
||||
map.put(connection.getKey(), connection);
|
||||
}));
|
||||
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -3,10 +3,8 @@ package com.simibubi.create.foundation.render;
|
|||
import com.jozufozu.flywheel.api.vertex.VertexList;
|
||||
import com.jozufozu.flywheel.backend.OptifineHandler;
|
||||
import com.jozufozu.flywheel.core.vertex.BlockVertexList;
|
||||
import com.jozufozu.flywheel.util.transform.Rotate;
|
||||
import com.jozufozu.flywheel.util.transform.Scale;
|
||||
import com.jozufozu.flywheel.util.transform.TStack;
|
||||
import com.jozufozu.flywheel.util.transform.Translate;
|
||||
import com.jozufozu.flywheel.util.transform.Transform;
|
||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
@ -31,7 +29,7 @@ import net.minecraft.util.Mth;
|
|||
import net.minecraft.world.level.Level;
|
||||
import net.minecraftforge.client.model.pipeline.LightUtil;
|
||||
|
||||
public class SuperByteBuffer implements Scale<SuperByteBuffer>, Translate<SuperByteBuffer>, Rotate<SuperByteBuffer>, TStack<SuperByteBuffer> {
|
||||
public class SuperByteBuffer implements Transform<SuperByteBuffer>, TStack<SuperByteBuffer> {
|
||||
|
||||
private final VertexList template;
|
||||
|
||||
|
@ -241,6 +239,22 @@ public class SuperByteBuffer implements Scale<SuperByteBuffer>, Translate<SuperB
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuperByteBuffer mulPose(Matrix4f pose) {
|
||||
transforms.last()
|
||||
.pose()
|
||||
.multiply(pose);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuperByteBuffer mulNormal(Matrix3f normal) {
|
||||
transforms.last()
|
||||
.normal()
|
||||
.mul(normal);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuperByteBuffer transform(PoseStack stack) {
|
||||
transforms.last()
|
||||
.pose()
|
||||
|
|
|
@ -6,9 +6,9 @@ import java.util.function.BiConsumer;
|
|||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
@ -16,7 +16,7 @@ import net.minecraft.nbt.ListTag;
|
|||
|
||||
public class Couple<T> extends Pair<T, T> implements Iterable<T> {
|
||||
|
||||
private static Couple<Boolean> TRUE_AND_FALSE = Couple.create(true, false);
|
||||
private static final Couple<Boolean> TRUE_AND_FALSE = Couple.create(true, false);
|
||||
|
||||
protected Couple(T first, T second) {
|
||||
super(first, second);
|
||||
|
|
Loading…
Reference in a new issue