Create/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplayTileEntity.java
simibubi 40f96b0038 You wrenched this? I wrenched this.
- Fix NPE in CarriageSyncData (Unknown cause)
- Fixed crash when applying text to display boards before they initialise
- Fixed incorrect itemstack remainders on Weighted Ejectors
- Other mods' wrenches now always behave like the Create wrench on IWrenchables
2023-02-02 12:14:25 +01:00

334 lines
9.2 KiB
Java

package com.simibubi.create.content.logistics.trains.management.display;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.google.gson.JsonElement;
import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.DyeHelper;
import com.simibubi.create.foundation.utility.DynamicComponent;
import com.simibubi.create.foundation.utility.NBTHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Vec3i;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth;
import net.minecraft.world.item.DyeColor;
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;
public class FlapDisplayTileEntity extends KineticTileEntity {
public List<FlapDisplayLayout> lines;
public boolean isController;
public boolean isRunning;
public int xSize, ySize;
public DyeColor[] colour;
public boolean[] glowingLines;
public boolean[] manualLines;
public FlapDisplayTileEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
setLazyTickRate(10);
isController = false;
xSize = 1;
ySize = 1;
colour = new DyeColor[2];
manualLines = new boolean[2];
glowingLines = new boolean[2];
}
@Override
public void initialize() {
super.initialize();
}
@Override
public void lazyTick() {
super.lazyTick();
updateControllerStatus();
}
public void updateControllerStatus() {
if (level.isClientSide)
return;
BlockState blockState = getBlockState();
if (!(blockState.getBlock() instanceof FlapDisplayBlock))
return;
Direction leftDirection = blockState.getValue(FlapDisplayBlock.HORIZONTAL_FACING)
.getClockWise();
boolean shouldBeController = !blockState.getValue(FlapDisplayBlock.UP)
&& level.getBlockState(worldPosition.relative(leftDirection)) != blockState;
int newXSize = 1;
int newYSize = 1;
if (shouldBeController) {
for (int xOffset = 1; xOffset < 32; xOffset++) {
if (level.getBlockState(worldPosition.relative(leftDirection.getOpposite(), xOffset)) != blockState)
break;
newXSize++;
}
for (int yOffset = 0; yOffset < 32; yOffset++) {
if (!level.getBlockState(worldPosition.relative(Direction.DOWN, yOffset))
.getOptionalValue(FlapDisplayBlock.DOWN)
.orElse(false))
break;
newYSize++;
}
}
if (isController == shouldBeController && newXSize == xSize && newYSize == ySize)
return;
isController = shouldBeController;
xSize = newXSize;
ySize = newYSize;
colour = Arrays.copyOf(colour, ySize * 2);
glowingLines = Arrays.copyOf(glowingLines, ySize * 2);
manualLines = new boolean[ySize * 2];
lines = null;
sendData();
}
@Override
public void tick() {
super.tick();
isRunning = super.isSpeedRequirementFulfilled();
if ((!level.isClientSide || !isRunning) && !isVirtual())
return;
int activeFlaps = 0;
for (FlapDisplayLayout line : lines)
for (FlapDisplaySection section : line.getSections())
activeFlaps += section.tick();
if (activeFlaps == 0)
return;
float volume = Mth.clamp(activeFlaps / 20f, 0.25f, 1.5f);
float bgVolume = Mth.clamp(activeFlaps / 40f, 0.25f, 1f);
BlockPos middle = worldPosition.relative(getDirection().getClockWise(), xSize / 2)
.relative(Direction.DOWN, ySize / 2);
AllSoundEvents.SCROLL_VALUE.playAt(level, middle, volume, 0.56f, false);
level.playLocalSound(middle.getX(), middle.getY(), middle.getZ(), SoundEvents.CALCITE_HIT, SoundSource.BLOCKS,
.35f * bgVolume, 1.95f, false);
}
@Override
protected boolean isNoisy() {
return false;
}
@Override
public boolean isSpeedRequirementFulfilled() {
return isRunning;
}
public void applyTextManually(int lineIndex, String rawComponentText) {
List<FlapDisplayLayout> lines = getLines();
if (lineIndex >= lines.size())
return;
FlapDisplayLayout layout = lines.get(lineIndex);
if (!layout.isLayout("Default"))
layout.loadDefault(getMaxCharCount());
List<FlapDisplaySection> sections = layout.getSections();
FlapDisplaySection flapDisplaySection = sections.get(0);
if (rawComponentText == null) {
manualLines[lineIndex] = false;
flapDisplaySection.setText(Components.immutableEmpty());
notifyUpdate();
return;
}
JsonElement json = DynamicComponent.getJsonFromString(rawComponentText);
if (json == null)
return;
manualLines[lineIndex] = true;
Component text = isVirtual() ? Component.Serializer.fromJson(rawComponentText)
: DynamicComponent.parseCustomText(level, worldPosition, json);
flapDisplaySection.setText(text);
if (isVirtual())
flapDisplaySection.refresh(true);
else
notifyUpdate();
}
public void setColour(int lineIndex, DyeColor color) {
colour[lineIndex] = color == DyeColor.WHITE ? null : color;
notifyUpdate();
}
public void setGlowing(int lineIndex) {
glowingLines[lineIndex] = true;
notifyUpdate();
}
public List<FlapDisplayLayout> getLines() {
if (lines == null)
initDefaultSections();
return lines;
}
public void initDefaultSections() {
lines = new ArrayList<>();
for (int i = 0; i < ySize * 2; i++)
lines.add(new FlapDisplayLayout(getMaxCharCount()));
}
public int getMaxCharCount() {
return getMaxCharCount(0);
}
public int getMaxCharCount(int gaps) {
return (int) ((xSize * 16f - 2f - 4f * gaps) / 3.5f);
}
@Override
protected void write(CompoundTag tag, boolean clientPacket) {
super.write(tag, clientPacket);
tag.putBoolean("Controller", isController);
tag.putInt("XSize", xSize);
tag.putInt("YSize", ySize);
for (int j = 0; j < manualLines.length; j++)
if (manualLines[j])
NBTHelper.putMarker(tag, "CustomLine" + j);
for (int j = 0; j < glowingLines.length; j++)
if (glowingLines[j])
NBTHelper.putMarker(tag, "GlowingLine" + j);
for (int j = 0; j < colour.length; j++)
if (colour[j] != null)
NBTHelper.writeEnum(tag, "Dye" + j, colour[j]);
List<FlapDisplayLayout> lines = getLines();
for (int i = 0; i < lines.size(); i++)
tag.put("Display" + i, lines.get(i)
.write());
}
@Override
protected void read(CompoundTag tag, boolean clientPacket) {
super.read(tag, clientPacket);
boolean wasActive = isController;
int prevX = xSize;
int prevY = ySize;
isController = tag.getBoolean("Controller");
xSize = tag.getInt("XSize");
ySize = tag.getInt("YSize");
manualLines = new boolean[ySize * 2];
for (int i = 0; i < ySize * 2; i++)
manualLines[i] = tag.contains("CustomLine" + i);
glowingLines = new boolean[ySize * 2];
for (int i = 0; i < ySize * 2; i++)
glowingLines[i] = tag.contains("GlowingLine" + i);
colour = new DyeColor[ySize * 2];
for (int i = 0; i < ySize * 2; i++)
colour[i] = tag.contains("Dye" + i) ? NBTHelper.readEnum(tag, "Dye" + i, DyeColor.class) : null;
if (clientPacket && wasActive != isController || prevX != xSize || prevY != ySize) {
invalidateRenderBoundingBox();
lines = null;
}
List<FlapDisplayLayout> lines = getLines();
for (int i = 0; i < lines.size(); i++)
lines.get(i)
.read(tag.getCompound("Display" + i));
}
public int getLineIndexAt(double yCoord) {
return (int) Mth.clamp(Math.floor(2 * (worldPosition.getY() - yCoord + 1)), 0, ySize * 2);
}
public FlapDisplayTileEntity getController() {
if (isController)
return this;
BlockState blockState = getBlockState();
if (!(blockState.getBlock() instanceof FlapDisplayBlock))
return null;
MutableBlockPos pos = getBlockPos().mutable();
Direction side = blockState.getValue(FlapDisplayBlock.HORIZONTAL_FACING)
.getClockWise();
for (int i = 0; i < 64; i++) {
BlockState other = level.getBlockState(pos);
if (other.getOptionalValue(FlapDisplayBlock.UP)
.orElse(false)) {
pos.move(Direction.UP);
continue;
}
if (!level.getBlockState(pos.relative(side))
.getOptionalValue(FlapDisplayBlock.UP)
.orElse(true)) {
pos.move(side);
continue;
}
BlockEntity found = level.getBlockEntity(pos);
if (found instanceof FlapDisplayTileEntity flap && flap.isController)
return flap;
break;
}
return null;
}
@Override
protected AABB createRenderBoundingBox() {
AABB aabb = new AABB(worldPosition);
if (!isController)
return aabb;
Vec3i normal = getDirection().getClockWise()
.getNormal();
return aabb.expandTowards(normal.getX() * xSize, -ySize, normal.getZ() * xSize);
}
public Direction getDirection() {
return getBlockState().getOptionalValue(FlapDisplayBlock.HORIZONTAL_FACING)
.orElse(Direction.SOUTH)
.getOpposite();
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {}
public int getLineColor(int line) {
DyeColor color = colour[line];
return color == null ? 0xFF_D3C6BA
: DyeHelper.DYE_TABLE.get(color)
.getFirst() | 0xFF_000000;
}
public boolean isLineGlowing(int line) {
return glowingLines[line];
}
}