Custom Nixies

- Rows of nixie tubes will now display text from a name tag used on them
- Nixie tubes will dynamically update score/selector/nbt components in the displayed text
This commit is contained in:
simibubi 2020-10-11 17:50:48 +02:00
parent 22ed233969
commit 1b84bbf16f
4 changed files with 254 additions and 61 deletions

View file

@ -8,7 +8,6 @@ import java.util.Set;
import org.apache.commons.lang3.mutable.MutableObject; import org.apache.commons.lang3.mutable.MutableObject;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.contraptions.fluids.pipes.AxisPipeBlock; import com.simibubi.create.content.contraptions.fluids.pipes.AxisPipeBlock;
import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock; import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock;
import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.AllConfigs;
@ -27,13 +26,10 @@ import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IBlockReader; import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld; import net.minecraft.world.IWorld;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fml.DistExecutor;
public class FluidPropagator { public class FluidPropagator {
@ -136,20 +132,21 @@ public class FluidPropagator {
return AllConfigs.SERVER.fluids.mechanicalPumpRange.get(); return AllConfigs.SERVER.fluids.mechanicalPumpRange.get();
} }
@Deprecated // Remove after pipes are fixed; comment out for production
public static OutlineParams showBlockFace(BlockFace face) { public static OutlineParams showBlockFace(BlockFace face) {
MutableObject<OutlineParams> params = new MutableObject<>(new OutlineParams()); MutableObject<OutlineParams> params = new MutableObject<>(new OutlineParams());
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { // DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> {
Vec3d directionVec = new Vec3d(face.getFace() // Vec3d directionVec = new Vec3d(face.getFace()
.getDirectionVec()); // .getDirectionVec());
Vec3d scaleVec = directionVec.scale(-.25f * face.getFace() // Vec3d scaleVec = directionVec.scale(-.25f * face.getFace()
.getAxisDirection() // .getAxisDirection()
.getOffset()); // .getOffset());
directionVec = directionVec.scale(.5f); // directionVec = directionVec.scale(.5f);
params.setValue(CreateClient.outliner.showAABB(face, // params.setValue(CreateClient.outliner.showAABB(face,
FluidPropagator.smallCenter.offset(directionVec.add(new Vec3d(face.getPos()))) // FluidPropagator.smallCenter.offset(directionVec.add(new Vec3d(face.getPos())))
.grow(scaleVec.x, scaleVec.y, scaleVec.z) // .grow(scaleVec.x, scaleVec.y, scaleVec.z)
.grow(1 / 16f))); // .grow(1 / 16f)));
}); // });
return params.getValue(); return params.getValue();
} }

View file

@ -8,12 +8,18 @@ import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.HorizontalBlock; import net.minecraft.block.HorizontalBlock;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.state.BooleanProperty; import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer.Builder; import net.minecraft.state.StateContainer.Builder;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShape;
@ -29,6 +35,60 @@ public class NixieTubeBlock extends HorizontalBlock implements ITE<NixieTubeTile
setDefaultState(getDefaultState().with(CEILING, false)); setDefaultState(getDefaultState().with(CEILING, false));
} }
@Override
public ActionResultType onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand,
BlockRayTraceResult ray) {
try {
ItemStack heldItem = player.getHeldItem(hand);
NixieTubeTileEntity nixie = getTileEntity(world, pos);
if (player.isSneaking())
return ActionResultType.PASS;
if (heldItem.isEmpty()) {
if (nixie.reactsToRedstone())
return ActionResultType.PASS;
nixie.clearCustomText();
updateDisplayedRedstoneValue(state, world, pos);
return ActionResultType.SUCCESS;
}
if (heldItem.getItem() == Items.NAME_TAG && heldItem.hasDisplayName()) {
Direction left = state.get(HORIZONTAL_FACING)
.rotateY();
Direction right = left.getOpposite();
if (world.isRemote)
return ActionResultType.SUCCESS;
BlockPos currentPos = pos;
while (true) {
BlockPos nextPos = currentPos.offset(left);
if (world.getBlockState(nextPos) != state)
break;
currentPos = nextPos;
}
int index = 0;
while (true) {
final int rowPosition = index;
withTileEntityDo(world, currentPos, te -> te.displayCustomNameOf(heldItem, rowPosition));
BlockPos nextPos = currentPos.offset(right);
if (world.getBlockState(nextPos) != state)
break;
currentPos = nextPos;
index++;
}
}
} catch (TileEntityException e) {
}
return ActionResultType.PASS;
}
@Override @Override
protected void fillStateContainer(Builder<Block, BlockState> builder) { protected void fillStateContainer(Builder<Block, BlockState> builder) {
super.fillStateContainer(builder.add(CEILING, HORIZONTAL_FACING)); super.fillStateContainer(builder.add(CEILING, HORIZONTAL_FACING));
@ -57,12 +117,12 @@ public class NixieTubeBlock extends HorizontalBlock implements ITE<NixieTubeTile
@Override @Override
public void neighborChanged(BlockState p_220069_1_, World p_220069_2_, BlockPos p_220069_3_, Block p_220069_4_, public void neighborChanged(BlockState p_220069_1_, World p_220069_2_, BlockPos p_220069_3_, Block p_220069_4_,
BlockPos p_220069_5_, boolean p_220069_6_) { BlockPos p_220069_5_, boolean p_220069_6_) {
updateDisplayedValue(p_220069_1_, p_220069_2_, p_220069_3_); updateDisplayedRedstoneValue(p_220069_1_, p_220069_2_, p_220069_3_);
} }
@Override @Override
public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) { public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) {
updateDisplayedValue(state, worldIn, pos); updateDisplayedRedstoneValue(state, worldIn, pos);
} }
@Override @Override
@ -75,12 +135,13 @@ public class NixieTubeBlock extends HorizontalBlock implements ITE<NixieTubeTile
return true; return true;
} }
private void updateDisplayedValue(BlockState state, World worldIn, BlockPos pos) { private void updateDisplayedRedstoneValue(BlockState state, World worldIn, BlockPos pos) {
if (worldIn.isRemote) if (worldIn.isRemote)
return; return;
int power = getPower(worldIn, pos); withTileEntityDo(worldIn, pos, te -> {
String display = (power < 10 ? "0" : "") + power; if (te.reactsToRedstone())
withTileEntityDo(worldIn, pos, te -> te.display(display.charAt(0), display.charAt(1))); te.displayRedstoneStrength(getPower(worldIn, pos));
});
} }
static boolean isValidBlock(IBlockReader world, BlockPos pos, boolean above) { static boolean isValidBlock(IBlockReader world, BlockPos pos, boolean above) {

View file

@ -6,6 +6,7 @@ import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.ColorHelper; import com.simibubi.create.foundation.utility.ColorHelper;
import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.MatrixStacker;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
@ -25,35 +26,35 @@ public class NixieTubeRenderer extends SafeTileEntityRenderer<NixieTubeTileEntit
@Override @Override
protected void renderSafe(NixieTubeTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, protected void renderSafe(NixieTubeTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
int light, int overlay) { int light, int overlay) {
ms.push(); ms.push();
BlockState blockState = te.getBlockState(); BlockState blockState = te.getBlockState();
MatrixStacker.of(ms) MatrixStacker.of(ms)
.centre() .centre()
.rotateY(AngleHelper.horizontalAngle(blockState .rotateY(AngleHelper.horizontalAngle(blockState.get(NixieTubeBlock.HORIZONTAL_FACING)));
.get(NixieTubeBlock.HORIZONTAL_FACING)));
float height = blockState.get(NixieTubeBlock.CEILING) ? 2 : 6; float height = blockState.get(NixieTubeBlock.CEILING) ? 2 : 6;
float scale = 1 / 20f; float scale = 1 / 20f;
Couple<String> s = te.getVisibleText();
ms.push(); ms.push();
ms.translate(-4/16f, 0, 0); ms.translate(-4 / 16f, 0, 0);
ms.scale(scale, -scale, scale); ms.scale(scale, -scale, scale);
drawTube(ms, buffer, te.tube1, height); drawTube(ms, buffer, s.getFirst(), height);
ms.pop(); ms.pop();
ms.push(); ms.push();
ms.translate(4/16f, 0, 0); ms.translate(4 / 16f, 0, 0);
ms.scale(scale, -scale, scale); ms.scale(scale, -scale, scale);
drawTube(ms, buffer, te.tube2, height); drawTube(ms, buffer, s.getSecond(), height);
ms.pop(); ms.pop();
ms.pop(); ms.pop();
} }
private void drawTube(MatrixStack ms, IRenderTypeBuffer buffer, char c, float height) { private void drawTube(MatrixStack ms, IRenderTypeBuffer buffer, String c, float height) {
FontRenderer fontRenderer = Minecraft.getInstance().fontRenderer; FontRenderer fontRenderer = Minecraft.getInstance().fontRenderer;
float charWidth = fontRenderer.getCharWidth(c); float charWidth = fontRenderer.getStringWidth(c);
float shadowOffset = .5f; float shadowOffset = .5f;
float flicker = r.nextFloat(); float flicker = r.nextFloat();
int brightColor = 0xFF982B; int brightColor = 0xFF982B;
@ -64,7 +65,7 @@ public class NixieTubeRenderer extends SafeTileEntityRenderer<NixieTubeTileEntit
ms.translate((charWidth - shadowOffset) / -2f, -height, 0); ms.translate((charWidth - shadowOffset) / -2f, -height, 0);
drawChar(ms, buffer, c, flickeringBrightColor); drawChar(ms, buffer, c, flickeringBrightColor);
ms.push(); ms.push();
ms.translate(shadowOffset, shadowOffset, -1/16f); ms.translate(shadowOffset, shadowOffset, -1 / 16f);
drawChar(ms, buffer, c, darkColor); drawChar(ms, buffer, c, darkColor);
ms.pop(); ms.pop();
ms.pop(); ms.pop();
@ -74,15 +75,15 @@ public class NixieTubeRenderer extends SafeTileEntityRenderer<NixieTubeTileEntit
ms.translate((charWidth - shadowOffset) / -2f, -height, 0); ms.translate((charWidth - shadowOffset) / -2f, -height, 0);
drawChar(ms, buffer, c, darkColor); drawChar(ms, buffer, c, darkColor);
ms.push(); ms.push();
ms.translate(-shadowOffset, shadowOffset, -1/16f); ms.translate(-shadowOffset, shadowOffset, -1 / 16f);
drawChar(ms, buffer, c, 0x99180F); drawChar(ms, buffer, c, 0x99180F);
ms.pop(); ms.pop();
ms.pop(); ms.pop();
} }
private static void drawChar(MatrixStack ms, IRenderTypeBuffer buffer, char c, int color) { private static void drawChar(MatrixStack ms, IRenderTypeBuffer buffer, String c, int color) {
FontRenderer fontRenderer = Minecraft.getInstance().fontRenderer; FontRenderer fontRenderer = Minecraft.getInstance().fontRenderer;
fontRenderer.draw(String.valueOf(c), 0, 0, color, false, ms.peek() fontRenderer.draw(c, 0, 0, color, false, ms.peek()
.getModel(), buffer, false, 0, 15728880); .getModel(), buffer, false, 0, 15728880);
} }

View file

@ -1,41 +1,175 @@
package com.simibubi.create.content.logistics.block.redstone; package com.simibubi.create.content.logistics.block.redstone;
import com.simibubi.create.foundation.tileEntity.SyncedTileEntity; import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import javax.annotation.Nullable;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Pair;
import net.minecraft.command.CommandSource;
import net.minecraft.command.ICommandSource;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.TileEntityType; import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.math.Vec2f;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextComponentUtils;
import net.minecraft.world.server.ServerWorld;
public class NixieTubeTileEntity extends SyncedTileEntity { public class NixieTubeTileEntity extends SmartTileEntity {
char tube1; Optional<Pair<ITextComponent, Integer>> customText;
char tube2; JsonElement rawCustomText;
Couple<String> renderText;
int redstoneStrength;
public NixieTubeTileEntity(TileEntityType<?> tileEntityTypeIn) { public NixieTubeTileEntity(TileEntityType<?> tileEntityTypeIn) {
super(tileEntityTypeIn); super(tileEntityTypeIn);
tube1 = '0'; redstoneStrength = 0;
tube2 = '0'; customText = Optional.empty();
} }
@Override @Override
public CompoundNBT write(CompoundNBT nbt) { public void tick() {
super.write(nbt); super.tick();
nbt.putInt("tube1", tube1);
nbt.putInt("tube2", tube2);
return nbt;
}
public void display(char tube1, char tube2) { // Dynamic text components have to be ticked manually and re-sent to the client
this.tube1 = tube1; if (customText.isPresent() && world instanceof ServerWorld) {
this.tube2 = tube2; Pair<ITextComponent, Integer> textSection = customText.get();
markDirty(); textSection.setFirst(updateDynamicTextComponents(ITextComponent.Serializer.fromJson(rawCustomText)));
Couple<String> currentText = getVisibleText();
if (renderText != null && renderText.equals(currentText))
return;
renderText = currentText;
sendData(); sendData();
} }
@Override
public void read(CompoundNBT nbt) {
tube1 = (char) nbt.getInt("tube1");
tube2 = (char) nbt.getInt("tube2");
super.read(nbt);
} }
//
public void clearCustomText() {
if (!customText.isPresent())
return;
displayRedstoneStrength(0);
}
public void displayCustomNameOf(ItemStack stack, int nixiePositionInRow) {
CompoundNBT compoundnbt = stack.getChildTag("display");
if (compoundnbt != null && compoundnbt.contains("Name", 8)) {
JsonElement fromJson = getJsonFromString(compoundnbt.getString("Name"));
ITextComponent displayed = ITextComponent.Serializer.fromJson(fromJson);
if (this.world instanceof ServerWorld)
displayed = updateDynamicTextComponents(displayed);
this.customText = Optional.of(Pair.of(displayed, nixiePositionInRow));
this.rawCustomText = fromJson;
notifyUpdate();
}
}
public void displayRedstoneStrength(int signalStrength) {
customText = Optional.empty();
redstoneStrength = signalStrength;
notifyUpdate();
}
public boolean reactsToRedstone() {
return !customText.isPresent();
}
public Couple<String> getVisibleText() {
if (!customText.isPresent())
return Couple.create(redstoneStrength < 10 ? "0" : "1", redstoneStrength % 10 + "");
String fullText = createStringFromComponentText(customText.get()
.getFirst());
int index = customText.get()
.getSecond() * 2;
return Couple.create(charOrEmpty(fullText, index), charOrEmpty(fullText, index + 1));
}
//
@Override
protected void read(CompoundNBT nbt, boolean clientPacket) {
customText = Optional.empty();
redstoneStrength = nbt.getInt("RedstoneStrength");
if (nbt.contains("CustomText")) {
ITextComponent displayed = ITextComponent.Serializer.fromJson(nbt.getString("CustomText"));
rawCustomText = getJsonFromString(nbt.getString("RawCustomText"));
customText = Optional.of(Pair.of(displayed, nbt.getInt("CustomTextIndex")));
}
super.read(nbt, clientPacket);
}
@Override
protected void write(CompoundNBT nbt, boolean clientPacket) {
super.write(nbt, clientPacket);
nbt.putInt("RedstoneStrength", redstoneStrength);
if (customText.isPresent()) {
nbt.putString("RawCustomText", rawCustomText.toString());
nbt.putString("CustomText", ITextComponent.Serializer.toJson(customText.get()
.getFirst()));
nbt.putInt("CustomTextIndex", customText.get()
.getSecond());
}
}
private JsonElement getJsonFromString(String string) {
return new JsonParser().parse(string);
}
protected ITextComponent updateDynamicTextComponents(ITextComponent customText) {
try {
return TextComponentUtils.updateForEntity(this.getCommandSource((ServerPlayerEntity) null), customText,
(Entity) null, 0);
} catch (CommandSyntaxException e) {
}
return customText;
}
// From SignTileEntity
protected CommandSource getCommandSource(@Nullable ServerPlayerEntity p_195539_1_) {
String s = p_195539_1_ == null ? "Sign"
: p_195539_1_.getName()
.getString();
ITextComponent itextcomponent =
(ITextComponent) (p_195539_1_ == null ? new StringTextComponent("Sign") : p_195539_1_.getDisplayName());
return new CommandSource(ICommandSource.field_213139_a_,
new Vec3d((double) this.pos.getX() + 0.5D, (double) this.pos.getY() + 0.5D,
(double) this.pos.getZ() + 0.5D),
Vec2f.ZERO, (ServerWorld) this.world, 2, s, itextcomponent, this.world.getServer(), p_195539_1_);
}
protected String createStringFromComponentText(ITextComponent iTextComponent) {
StringBuilder stringbuilder = new StringBuilder();
Iterator<ITextComponent> iterator = iTextComponent.stream()
.iterator();
while (iterator.hasNext())
stringbuilder.append(iterator.next()
.getUnformattedComponentText());
return stringbuilder.toString();
}
private String charOrEmpty(String string, int index) {
return string.length() <= index ? " " : string.substring(index, index + 1);
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {}
} }