271 lines
10 KiB
Java
271 lines
10 KiB
Java
package net.minecraft.world.level.block.entity;
|
|
|
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
|
import com.mojang.logging.LogUtils;
|
|
import com.mojang.serialization.DynamicOps;
|
|
import java.util.List;
|
|
import java.util.UUID;
|
|
import java.util.function.UnaryOperator;
|
|
import javax.annotation.Nullable;
|
|
import net.minecraft.commands.CommandSource;
|
|
import net.minecraft.commands.CommandSourceStack;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.HolderLookup;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.nbt.NbtOps;
|
|
import net.minecraft.nbt.Tag;
|
|
import net.minecraft.network.chat.ClickEvent;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.network.chat.ComponentUtils;
|
|
import net.minecraft.network.chat.Style;
|
|
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.server.network.FilteredText;
|
|
import net.minecraft.sounds.SoundEvent;
|
|
import net.minecraft.sounds.SoundEvents;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.block.SignBlock;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.phys.Vec2;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import org.slf4j.Logger;
|
|
|
|
public class SignBlockEntity extends BlockEntity {
|
|
private static final Logger LOGGER = LogUtils.getLogger();
|
|
private static final int MAX_TEXT_LINE_WIDTH = 90;
|
|
private static final int TEXT_LINE_HEIGHT = 10;
|
|
private static final boolean DEFAULT_IS_WAXED = false;
|
|
@Nullable
|
|
private UUID playerWhoMayEdit;
|
|
private SignText frontText;
|
|
private SignText backText;
|
|
private boolean isWaxed = false;
|
|
|
|
public SignBlockEntity(BlockPos p_155700_, BlockState p_155701_) {
|
|
this(BlockEntityType.SIGN, p_155700_, p_155701_);
|
|
}
|
|
|
|
public SignBlockEntity(BlockEntityType p_249609_, BlockPos p_248914_, BlockState p_249550_) {
|
|
super(p_249609_, p_248914_, p_249550_);
|
|
this.frontText = this.createDefaultSignText();
|
|
this.backText = this.createDefaultSignText();
|
|
}
|
|
|
|
protected SignText createDefaultSignText() {
|
|
return new SignText();
|
|
}
|
|
|
|
public boolean isFacingFrontText(Player p_277382_) {
|
|
if (this.getBlockState().getBlock() instanceof SignBlock signblock) {
|
|
Vec3 vec3 = signblock.getSignHitboxCenterPosition(this.getBlockState());
|
|
double d0 = p_277382_.getX() - (this.getBlockPos().getX() + vec3.x);
|
|
double d1 = p_277382_.getZ() - (this.getBlockPos().getZ() + vec3.z);
|
|
float f = signblock.getYRotationDegrees(this.getBlockState());
|
|
float f1 = (float)(Mth.atan2(d1, d0) * 180.0F / (float)Math.PI) - 90.0F;
|
|
return Mth.degreesDifferenceAbs(f, f1) <= 90.0F;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public SignText getText(boolean p_277918_) {
|
|
return p_277918_ ? this.frontText : this.backText;
|
|
}
|
|
|
|
public SignText getFrontText() {
|
|
return this.frontText;
|
|
}
|
|
|
|
public SignText getBackText() {
|
|
return this.backText;
|
|
}
|
|
|
|
public int getTextLineHeight() {
|
|
return 10;
|
|
}
|
|
|
|
public int getMaxTextLineWidth() {
|
|
return 90;
|
|
}
|
|
|
|
@Override
|
|
protected void saveAdditional(CompoundTag p_187515_, HolderLookup.Provider p_331864_) {
|
|
super.saveAdditional(p_187515_, p_331864_);
|
|
DynamicOps<Tag> dynamicops = p_331864_.createSerializationContext(NbtOps.INSTANCE);
|
|
p_187515_.store("front_text", SignText.DIRECT_CODEC, dynamicops, this.frontText);
|
|
p_187515_.store("back_text", SignText.DIRECT_CODEC, dynamicops, this.backText);
|
|
p_187515_.putBoolean("is_waxed", this.isWaxed);
|
|
}
|
|
|
|
@Override
|
|
protected void loadAdditional(CompoundTag p_329420_, HolderLookup.Provider p_336389_) {
|
|
super.loadAdditional(p_329420_, p_336389_);
|
|
DynamicOps<Tag> dynamicops = p_336389_.createSerializationContext(NbtOps.INSTANCE);
|
|
this.frontText = p_329420_.read("front_text", SignText.DIRECT_CODEC, dynamicops).map(this::loadLines).orElseGet(SignText::new);
|
|
this.backText = p_329420_.read("back_text", SignText.DIRECT_CODEC, dynamicops).map(this::loadLines).orElseGet(SignText::new);
|
|
this.isWaxed = p_329420_.getBooleanOr("is_waxed", false);
|
|
}
|
|
|
|
private SignText loadLines(SignText p_278305_) {
|
|
for (int i = 0; i < 4; i++) {
|
|
Component component = this.loadLine(p_278305_.getMessage(i, false));
|
|
Component component1 = this.loadLine(p_278305_.getMessage(i, true));
|
|
p_278305_ = p_278305_.setMessage(i, component, component1);
|
|
}
|
|
|
|
return p_278305_;
|
|
}
|
|
|
|
private Component loadLine(Component p_278307_) {
|
|
if (this.level instanceof ServerLevel serverlevel) {
|
|
try {
|
|
return ComponentUtils.updateForEntity(createCommandSourceStack(null, serverlevel, this.worldPosition), p_278307_, null, 0);
|
|
} catch (CommandSyntaxException commandsyntaxexception) {
|
|
}
|
|
}
|
|
|
|
return p_278307_;
|
|
}
|
|
|
|
public void updateSignText(Player p_278048_, boolean p_278103_, List<FilteredText> p_277990_) {
|
|
if (!this.isWaxed() && p_278048_.getUUID().equals(this.getPlayerWhoMayEdit()) && this.level != null) {
|
|
this.updateText(p_277776_ -> this.setMessages(p_278048_, p_277990_, p_277776_), p_278103_);
|
|
this.setAllowedPlayerEditor(null);
|
|
this.level.sendBlockUpdated(this.getBlockPos(), this.getBlockState(), this.getBlockState(), 3);
|
|
} else {
|
|
LOGGER.warn("Player {} just tried to change non-editable sign", p_278048_.getName().getString());
|
|
}
|
|
}
|
|
|
|
public boolean updateText(UnaryOperator<SignText> p_277877_, boolean p_277426_) {
|
|
SignText signtext = this.getText(p_277426_);
|
|
return this.setText(p_277877_.apply(signtext), p_277426_);
|
|
}
|
|
|
|
private SignText setMessages(Player p_277396_, List<FilteredText> p_277744_, SignText p_277359_) {
|
|
for (int i = 0; i < p_277744_.size(); i++) {
|
|
FilteredText filteredtext = p_277744_.get(i);
|
|
Style style = p_277359_.getMessage(i, p_277396_.isTextFilteringEnabled()).getStyle();
|
|
if (p_277396_.isTextFilteringEnabled()) {
|
|
p_277359_ = p_277359_.setMessage(i, Component.literal(filteredtext.filteredOrEmpty()).setStyle(style));
|
|
} else {
|
|
p_277359_ = p_277359_.setMessage(
|
|
i, Component.literal(filteredtext.raw()).setStyle(style), Component.literal(filteredtext.filteredOrEmpty()).setStyle(style)
|
|
);
|
|
}
|
|
}
|
|
|
|
return p_277359_;
|
|
}
|
|
|
|
public boolean setText(SignText p_277733_, boolean p_277720_) {
|
|
return p_277720_ ? this.setFrontText(p_277733_) : this.setBackText(p_277733_);
|
|
}
|
|
|
|
private boolean setBackText(SignText p_277777_) {
|
|
if (p_277777_ != this.backText) {
|
|
this.backText = p_277777_;
|
|
this.markUpdated();
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private boolean setFrontText(SignText p_278038_) {
|
|
if (p_278038_ != this.frontText) {
|
|
this.frontText = p_278038_;
|
|
this.markUpdated();
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public boolean canExecuteClickCommands(boolean p_278276_, Player p_278240_) {
|
|
return this.isWaxed() && this.getText(p_278276_).hasAnyClickCommands(p_278240_);
|
|
}
|
|
|
|
public boolean executeClickCommandsIfPresent(Player p_279304_, Level p_279201_, BlockPos p_278282_, boolean p_278254_) {
|
|
boolean flag = false;
|
|
|
|
for (Component component : this.getText(p_278254_).getMessages(p_279304_.isTextFilteringEnabled())) {
|
|
Style style = component.getStyle();
|
|
if (style.getClickEvent() instanceof ClickEvent.RunCommand(String s)) {
|
|
p_279304_.getServer().getCommands().performPrefixedCommand(createCommandSourceStack(p_279304_, p_279201_, p_278282_), s);
|
|
flag = true;
|
|
}
|
|
}
|
|
|
|
return flag;
|
|
}
|
|
|
|
private static CommandSourceStack createCommandSourceStack(@Nullable Player p_279428_, Level p_279359_, BlockPos p_279430_) {
|
|
String s = p_279428_ == null ? "Sign" : p_279428_.getName().getString();
|
|
Component component = (Component)(p_279428_ == null ? Component.literal("Sign") : p_279428_.getDisplayName());
|
|
return new CommandSourceStack(
|
|
CommandSource.NULL, Vec3.atCenterOf(p_279430_), Vec2.ZERO, (ServerLevel)p_279359_, 2, s, component, p_279359_.getServer(), p_279428_
|
|
);
|
|
}
|
|
|
|
public ClientboundBlockEntityDataPacket getUpdatePacket() {
|
|
return ClientboundBlockEntityDataPacket.create(this);
|
|
}
|
|
|
|
@Override
|
|
public CompoundTag getUpdateTag(HolderLookup.Provider p_333348_) {
|
|
return this.saveCustomOnly(p_333348_);
|
|
}
|
|
|
|
public void setAllowedPlayerEditor(@Nullable UUID p_155714_) {
|
|
this.playerWhoMayEdit = p_155714_;
|
|
}
|
|
|
|
@Nullable
|
|
public UUID getPlayerWhoMayEdit() {
|
|
return this.playerWhoMayEdit;
|
|
}
|
|
|
|
private void markUpdated() {
|
|
this.setChanged();
|
|
this.level.sendBlockUpdated(this.getBlockPos(), this.getBlockState(), this.getBlockState(), 3);
|
|
}
|
|
|
|
public boolean isWaxed() {
|
|
return this.isWaxed;
|
|
}
|
|
|
|
public boolean setWaxed(boolean p_277344_) {
|
|
if (this.isWaxed != p_277344_) {
|
|
this.isWaxed = p_277344_;
|
|
this.markUpdated();
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public boolean playerIsTooFarAwayToEdit(UUID p_277978_) {
|
|
Player player = this.level.getPlayerByUUID(p_277978_);
|
|
return player == null || !player.canInteractWithBlock(this.getBlockPos(), 4.0);
|
|
}
|
|
|
|
public static void tick(Level p_277662_, BlockPos p_278050_, BlockState p_277927_, SignBlockEntity p_277928_) {
|
|
UUID uuid = p_277928_.getPlayerWhoMayEdit();
|
|
if (uuid != null) {
|
|
p_277928_.clearInvalidPlayerWhoMayEdit(p_277928_, p_277662_, uuid);
|
|
}
|
|
}
|
|
|
|
private void clearInvalidPlayerWhoMayEdit(SignBlockEntity p_277656_, Level p_277853_, UUID p_277849_) {
|
|
if (p_277656_.playerIsTooFarAwayToEdit(p_277849_)) {
|
|
p_277656_.setAllowedPlayerEditor(null);
|
|
}
|
|
}
|
|
|
|
public SoundEvent getSignInteractionFailedSoundEvent() {
|
|
return SoundEvents.WAXED_SIGN_INTERACT_FAIL;
|
|
}
|
|
} |