mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-29 08:27:03 +01:00
Crash-proof nixie tubes
- Add many checks when reading NBT to prevent crashes - Store rendered strings and only update when necessary - Reorganize some code and rename some members
This commit is contained in:
parent
c9f9be73ff
commit
0bc1a71558
3 changed files with 123 additions and 83 deletions
|
@ -154,7 +154,7 @@ public class NixieTubeBlock extends HorizontalBlock implements ITE<NixieTubeTile
|
||||||
return;
|
return;
|
||||||
withTileEntityDo(worldIn, pos, te -> {
|
withTileEntityDo(worldIn, pos, te -> {
|
||||||
if (te.reactsToRedstone())
|
if (te.reactsToRedstone())
|
||||||
te.displayRedstoneStrength(getPower(worldIn, pos));
|
te.updateRedstoneStrength(getPower(worldIn, pos));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ import net.minecraft.util.text.Style;
|
||||||
|
|
||||||
public class NixieTubeRenderer extends SafeTileEntityRenderer<NixieTubeTileEntity> {
|
public class NixieTubeRenderer extends SafeTileEntityRenderer<NixieTubeTileEntity> {
|
||||||
|
|
||||||
Random r = new Random();
|
private Random r = new Random();
|
||||||
|
|
||||||
public NixieTubeRenderer(TileEntityRendererDispatcher dispatcher) {
|
public NixieTubeRenderer(TileEntityRendererDispatcher dispatcher) {
|
||||||
super(dispatcher);
|
super(dispatcher);
|
||||||
|
@ -38,7 +38,7 @@ public class NixieTubeRenderer extends SafeTileEntityRenderer<NixieTubeTileEntit
|
||||||
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();
|
Couple<String> s = te.getDisplayedStrings();
|
||||||
|
|
||||||
ms.push();
|
ms.push();
|
||||||
ms.translate(-4 / 16f, 0, 0);
|
ms.translate(-4 / 16f, 0, 0);
|
||||||
|
|
|
@ -1,23 +1,20 @@
|
||||||
package com.simibubi.create.content.logistics.block.redstone;
|
package com.simibubi.create.content.logistics.block.redstone;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import com.simibubi.create.foundation.item.TooltipHelper;
|
|
||||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
import com.simibubi.create.foundation.utility.Couple;
|
import com.simibubi.create.foundation.utility.Couple;
|
||||||
import com.simibubi.create.foundation.utility.Pair;
|
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.command.CommandSource;
|
import net.minecraft.command.CommandSource;
|
||||||
import net.minecraft.command.ICommandSource;
|
import net.minecraft.command.ICommandSource;
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.nbt.CompoundNBT;
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
@ -28,19 +25,23 @@ import net.minecraft.util.text.ITextComponent;
|
||||||
import net.minecraft.util.text.StringTextComponent;
|
import net.minecraft.util.text.StringTextComponent;
|
||||||
import net.minecraft.util.text.TextComponentUtils;
|
import net.minecraft.util.text.TextComponentUtils;
|
||||||
import net.minecraft.world.server.ServerWorld;
|
import net.minecraft.world.server.ServerWorld;
|
||||||
|
import net.minecraftforge.common.util.Constants.NBT;
|
||||||
|
|
||||||
public class NixieTubeTileEntity extends SmartTileEntity {
|
public class NixieTubeTileEntity extends SmartTileEntity {
|
||||||
|
|
||||||
Optional<Pair<ITextComponent, Integer>> customText;
|
private static final Couple<String> EMPTY = Couple.create("", "");
|
||||||
JsonElement rawCustomText;
|
|
||||||
Couple<String> renderText;
|
|
||||||
|
|
||||||
int redstoneStrength;
|
private boolean hasCustomText;
|
||||||
|
private int redstoneStrength;
|
||||||
|
private JsonElement rawCustomText;
|
||||||
|
private int customTextIndex;
|
||||||
|
private ITextComponent parsedCustomText;
|
||||||
|
private Couple<String> displayedStrings;
|
||||||
|
|
||||||
public NixieTubeTileEntity(TileEntityType<?> tileEntityTypeIn) {
|
public NixieTubeTileEntity(TileEntityType<?> tileEntityTypeIn) {
|
||||||
super(tileEntityTypeIn);
|
super(tileEntityTypeIn);
|
||||||
|
hasCustomText = false;
|
||||||
redstoneStrength = 0;
|
redstoneStrength = 0;
|
||||||
customText = Optional.empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -48,117 +49,156 @@ public class NixieTubeTileEntity extends SmartTileEntity {
|
||||||
super.tick();
|
super.tick();
|
||||||
|
|
||||||
// Dynamic text components have to be ticked manually and re-sent to the client
|
// Dynamic text components have to be ticked manually and re-sent to the client
|
||||||
if (customText.isPresent() && world instanceof ServerWorld) {
|
if (world instanceof ServerWorld && hasCustomText) {
|
||||||
Pair<ITextComponent, Integer> textSection = customText.get();
|
Couple<String> currentStrings = displayedStrings;
|
||||||
textSection.setFirst(updateDynamicTextComponents(ITextComponent.Serializer.fromJson(rawCustomText)));
|
parsedCustomText = parseCustomText();
|
||||||
|
updateDisplayedStrings();
|
||||||
Couple<String> currentText = getVisibleText();
|
if (currentStrings == null || !currentStrings.equals(displayedStrings))
|
||||||
if (renderText != null && renderText.equals(currentText))
|
sendData();
|
||||||
return;
|
|
||||||
|
|
||||||
renderText = currentText;
|
|
||||||
sendData();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
if (world.isRemote)
|
||||||
|
updateDisplayedStrings();
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
public void clearCustomText() {
|
public boolean reactsToRedstone() {
|
||||||
if (!customText.isPresent())
|
return !hasCustomText;
|
||||||
return;
|
|
||||||
displayRedstoneStrength(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void displayCustomNameOf(ItemStack stack, int nixiePositionInRow) {
|
public Couple<String> getDisplayedStrings() {
|
||||||
CompoundNBT compoundnbt = stack.getChildTag("display");
|
if (displayedStrings == null)
|
||||||
if (compoundnbt != null && compoundnbt.contains("Name", 8)) {
|
return EMPTY;
|
||||||
JsonElement fromJson = getJsonFromString(compoundnbt.getString("Name"));
|
return displayedStrings;
|
||||||
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) {
|
public void updateRedstoneStrength(int signalStrength) {
|
||||||
customText = Optional.empty();
|
clearCustomText();
|
||||||
redstoneStrength = signalStrength;
|
redstoneStrength = signalStrength;
|
||||||
notifyUpdate();
|
notifyUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean reactsToRedstone() {
|
public void displayCustomNameOf(ItemStack stack, int nixiePositionInRow) {
|
||||||
return !customText.isPresent();
|
CompoundNBT compoundnbt = stack.getChildTag("display");
|
||||||
|
if (compoundnbt != null && compoundnbt.contains("Name", NBT.TAG_STRING)) {
|
||||||
|
hasCustomText = true;
|
||||||
|
rawCustomText = getJsonFromString(compoundnbt.getString("Name"));
|
||||||
|
customTextIndex = nixiePositionInRow;
|
||||||
|
parsedCustomText = parseCustomText();
|
||||||
|
notifyUpdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Couple<String> getVisibleText() {
|
public void updateDisplayedStrings() {
|
||||||
if (!customText.isPresent())
|
if (!hasCustomText) {
|
||||||
return Couple.create(redstoneStrength < 10 ? "0" : "1", redstoneStrength % 10 + "");
|
displayedStrings = Couple.create(redstoneStrength < 10 ? "0" : "1", String.valueOf(redstoneStrength % 10));
|
||||||
String fullText = TooltipHelper.getUnformattedDeepText(customText.get()
|
} else {
|
||||||
.getFirst());
|
String fullText = parsedCustomText.getString();
|
||||||
int index = customText.get()
|
int index = customTextIndex * 2;
|
||||||
.getSecond() * 2;
|
displayedStrings = Couple.create(charOrEmpty(fullText, index), charOrEmpty(fullText, index + 1));
|
||||||
return Couple.create(charOrEmpty(fullText, index), charOrEmpty(fullText, index + 1));
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearCustomText() {
|
||||||
|
hasCustomText = false;
|
||||||
|
rawCustomText = null;
|
||||||
|
customTextIndex = 0;
|
||||||
|
parsedCustomText = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void fromTag(BlockState state, CompoundNBT nbt, boolean clientPacket) {
|
protected void fromTag(BlockState state, 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.fromTag(state, nbt, clientPacket);
|
super.fromTag(state, nbt, clientPacket);
|
||||||
|
|
||||||
|
if (nbt.contains("RawCustomText", NBT.TAG_STRING)) {
|
||||||
|
rawCustomText = getJsonFromString(nbt.getString("RawCustomText"));
|
||||||
|
// Check if string forms valid JSON
|
||||||
|
if (rawCustomText != null && !rawCustomText.isJsonNull()) {
|
||||||
|
ITextComponent deserializedComponent = parseCustomText();
|
||||||
|
// Check if JSON forms valid component
|
||||||
|
if (deserializedComponent != null) {
|
||||||
|
try {
|
||||||
|
// Try to deserialize previously parsed component
|
||||||
|
parsedCustomText = ITextComponent.Serializer.fromJson(nbt.getString("CustomText"));
|
||||||
|
} catch (JsonParseException e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
if (parsedCustomText == null) {
|
||||||
|
// Use test component to ensure field isn't null
|
||||||
|
parsedCustomText = deserializedComponent;
|
||||||
|
}
|
||||||
|
hasCustomText = true;
|
||||||
|
customTextIndex = nbt.getInt("CustomTextIndex");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasCustomText) {
|
||||||
|
clearCustomText();
|
||||||
|
redstoneStrength = nbt.getInt("RedstoneStrength");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientPacket)
|
||||||
|
updateDisplayedStrings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected void write(CompoundNBT nbt, boolean clientPacket) {
|
protected void write(CompoundNBT nbt, boolean clientPacket) {
|
||||||
super.write(nbt, clientPacket);
|
super.write(nbt, clientPacket);
|
||||||
nbt.putInt("RedstoneStrength", redstoneStrength);
|
|
||||||
|
|
||||||
if (customText.isPresent()) {
|
if (hasCustomText) {
|
||||||
nbt.putString("RawCustomText", rawCustomText.toString());
|
nbt.putString("RawCustomText", rawCustomText.toString());
|
||||||
nbt.putString("CustomText", ITextComponent.Serializer.toJson(customText.get()
|
nbt.putInt("CustomTextIndex", customTextIndex);
|
||||||
.getFirst()));
|
nbt.putString("CustomText", ITextComponent.Serializer.toJson(parsedCustomText));
|
||||||
nbt.putInt("CustomTextIndex", customText.get()
|
} else {
|
||||||
.getSecond());
|
nbt.putInt("RedstoneStrength", redstoneStrength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsonElement getJsonFromString(String string) {
|
private JsonElement getJsonFromString(String string) {
|
||||||
return new JsonParser().parse(string);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ITextComponent updateDynamicTextComponents(ITextComponent customText) {
|
|
||||||
try {
|
try {
|
||||||
return TextComponentUtils.parse(this.getCommandSource(null), customText,
|
return new JsonParser().parse(string);
|
||||||
(Entity) null, 0);
|
} catch (JsonParseException e) {
|
||||||
} catch (CommandSyntaxException e) {
|
return null;
|
||||||
}
|
}
|
||||||
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 Vector3d((double) this.pos.getX() + 0.5D, (double) this.pos.getY() + 0.5D,
|
|
||||||
(double) this.pos.getZ() + 0.5D),
|
|
||||||
Vector2f.ZERO, (ServerWorld) this.world, 2, s, itextcomponent, this.world.getServer(), p_195539_1_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String charOrEmpty(String string, int index) {
|
private String charOrEmpty(String string, int index) {
|
||||||
return string.length() <= index ? " " : string.substring(index, index + 1);
|
return string.length() <= index ? " " : string.substring(index, index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ITextComponent parseCustomText() {
|
||||||
|
try {
|
||||||
|
return parseDynamicComponent(ITextComponent.Serializer.fromJson(rawCustomText));
|
||||||
|
} catch (JsonParseException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ITextComponent parseDynamicComponent(ITextComponent customText) {
|
||||||
|
if (world instanceof ServerWorld) {
|
||||||
|
try {
|
||||||
|
return TextComponentUtils.parse(getCommandSource(null), customText, null, 0);
|
||||||
|
} catch (CommandSyntaxException e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return customText;
|
||||||
|
}
|
||||||
|
|
||||||
|
// From SignTileEntity
|
||||||
|
public CommandSource getCommandSource(@Nullable ServerPlayerEntity p_195539_1_) {
|
||||||
|
String s = p_195539_1_ == null ? "Nixie Tube" : p_195539_1_.getName().getString();
|
||||||
|
ITextComponent itextcomponent = (ITextComponent)(p_195539_1_ == null ? new StringTextComponent("Nixie Tube") : p_195539_1_.getDisplayName());
|
||||||
|
return new CommandSource(ICommandSource.field_213139_a_, Vector3d.ofCenter(this.pos), Vector2f.ZERO, (ServerWorld)this.world, 2, s, itextcomponent, this.world.getServer(), p_195539_1_);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {}
|
public void addBehaviours(List<TileEntityBehaviour> behaviours) {}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue