ChatComponent.java
net.minecraft.client.gui.components.ChatComponent
信息
- 全限定名:net.minecraft.client.gui.components.ChatComponent
- 类型:public class
- 包:net.minecraft.client.gui.components
- 源码路径:src/main/java/net/minecraft/client/gui/components/ChatComponent.java
- 起始行号:L46
- 职责:
TODO
字段/常量
-
LOGGER- 类型:
Logger - 修饰符:
private static final - 源码定位:
L47 - 说明:
TODO
- 类型:
-
MAX_CHAT_HISTORY- 类型:
int - 修饰符:
private static final - 源码定位:
L48 - 说明:
TODO
- 类型:
-
MESSAGE_INDENT- 类型:
int - 修饰符:
private static final - 源码定位:
L49 - 说明:
TODO
- 类型:
-
BOTTOM_MARGIN- 类型:
int - 修饰符:
private static final - 源码定位:
L50 - 说明:
TODO
- 类型:
-
TOOLTIP_MAX_WIDTH- 类型:
int - 修饰符:
private static final - 源码定位:
L51 - 说明:
TODO
- 类型:
-
TIME_BEFORE_MESSAGE_DELETION- 类型:
int - 修饰符:
private static final - 源码定位:
L52 - 说明:
TODO
- 类型:
-
DELETED_CHAT_MESSAGE- 类型:
Component - 修饰符:
private static final - 源码定位:
L53 - 说明:
TODO
- 类型:
-
MESSAGE_BOTTOM_TO_MESSAGE_TOP- 类型:
int - 修饰符:
public static final - 源码定位:
L54 - 说明:
TODO
- 类型:
-
QUEUE_EXPAND_ID- 类型:
Identifier - 修饰符:
public static final - 源码定位:
L55 - 说明:
TODO
- 类型:
-
QUEUE_EXPAND_TEXT_STYLE- 类型:
Style - 修饰符:
private static final - 源码定位:
L56 - 说明:
TODO
- 类型:
-
GO_TO_RESTRICTIONS_SCREEN- 类型:
Identifier - 修饰符:
public static final - 源码定位:
L59 - 说明:
TODO
- 类型:
-
RESTRICTED_CHAT_MESSAGE- 类型:
Component - 修饰符:
private static final - 源码定位:
L60 - 说明:
TODO
- 类型:
-
RESTRICTED_CHAT_MESSAGE_WITH_HOVER- 类型:
Component - 修饰符:
private static final - 源码定位:
L64 - 说明:
TODO
- 类型:
-
minecraft- 类型:
Minecraft - 修饰符:
private final - 源码定位:
L67 - 说明:
TODO
- 类型:
-
recentChat- 类型:
ArrayListDeque<String> - 修饰符:
private final - 源码定位:
L68 - 说明:
TODO
- 类型:
-
allMessages- 类型:
List<GuiMessage> - 修饰符:
private final - 源码定位:
L69 - 说明:
TODO
- 类型:
-
trimmedMessages- 类型:
List<GuiMessage.Line> - 修饰符:
private final - 源码定位:
L70 - 说明:
TODO
- 类型:
-
chatScrollbarPos- 类型:
int - 修饰符:
private - 源码定位:
L71 - 说明:
TODO
- 类型:
-
newMessageSinceScroll- 类型:
boolean - 修饰符:
private - 源码定位:
L72 - 说明:
TODO
- 类型:
-
latestDraft- 类型:
ChatComponent.Draft - 修饰符:
private - 源码定位:
L73 - 说明:
TODO
- 类型:
-
preservedScreen- 类型:
ChatScreen - 修饰符:
private - 源码定位:
L74 - 说明:
TODO
- 类型:
-
messageDeletionQueue- 类型:
List<ChatComponent.DelayedMessageDeletion> - 修饰符:
private final - 源码定位:
L75 - 说明:
TODO
- 类型:
-
visibleMessageFilter- 类型:
Predicate<GuiMessage> - 修饰符:
private - 源码定位:
L76 - 说明:
TODO
- 类型:
内部类/嵌套类型
-
net.minecraft.client.gui.components.ChatComponent.AlphaCalculator- 类型:
interface - 修饰符:
private - 源码定位:
L482 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.components.ChatComponent.ChatGraphicsAccess- 类型:
interface - 修饰符:
public - 源码定位:
L501 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.components.ChatComponent.ChatMethod- 类型:
enum - 修饰符:
public static - 源码定位:
L514 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.components.ChatComponent.ClickableTextOnlyGraphicsAccess- 类型:
class - 修饰符:
private static - 源码定位:
L542 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.components.ChatComponent.DelayedMessageDeletion- 类型:
record - 修饰符:
private - 源码定位:
L577 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.components.ChatComponent.DisplayMode- 类型:
enum - 修饰符:
public static - 源码定位:
L581 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.components.ChatComponent.Draft- 类型:
record - 修饰符:
public - 源码定位:
L596 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.components.ChatComponent.DrawingBackgroundGraphicsAccess- 类型:
class - 修饰符:
private static - 源码定位:
L600 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.components.ChatComponent.DrawingFocusedGraphicsAccess- 类型:
class - 修饰符:
private static - 源码定位:
L640 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.components.ChatComponent.LineConsumer- 类型:
interface - 修饰符:
private - 源码定位:
L729 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.components.ChatComponent.State- 类型:
class - 修饰符:
public static - 源码定位:
L734 - 说明:
TODO
- 类型:
构造器
public ChatComponent(Minecraft minecraft) @ L78
- 构造器名:ChatComponent
- 源码定位:L78
- 修饰符:public
参数:
- minecraft: Minecraft
说明:
TODO
方法
下面的方法块按源码顺序生成。
public void tick() @ L83
- 方法名:tick
- 源码定位:L83
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public void setVisibleMessageFilter(Predicate<GuiMessage> visibleMessageFilter) @ L89
- 方法名:setVisibleMessageFilter
- 源码定位:L89
- 返回类型:void
- 修饰符:public
参数:
- visibleMessageFilter: Predicate
说明:
TODO
private int forEachLine(ChatComponent.AlphaCalculator alphaCalculator, ChatComponent.LineConsumer lineConsumer) @ L94
- 方法名:forEachLine
- 源码定位:L94
- 返回类型:int
- 修饰符:private
参数:
- alphaCalculator: ChatComponent.AlphaCalculator
- lineConsumer: ChatComponent.LineConsumer
说明:
TODO
public void extractRenderState(GuiGraphicsExtractor graphics, Font font, int ticks, int mouseX, int mouseY, ChatComponent.DisplayMode displayMode, boolean changeCursorOnInsertions) @ L111
- 方法名:extractRenderState
- 源码定位:L111
- 返回类型:void
- 修饰符:public
参数:
- graphics: GuiGraphicsExtractor
- font: Font
- ticks: int
- mouseX: int
- mouseY: int
- displayMode: ChatComponent.DisplayMode
- changeCursorOnInsertions: boolean
说明:
TODO
public void captureClickableText(ActiveTextCollector activeTextCollector, int screenHeight, int ticks, ChatComponent.DisplayMode displayMode) @ L126
- 方法名:captureClickableText
- 源码定位:L126
- 返回类型:void
- 修饰符:public
参数:
- activeTextCollector: ActiveTextCollector
- screenHeight: int
- ticks: int
- displayMode: ChatComponent.DisplayMode
说明:
TODO
private void extractRenderState(ChatComponent.ChatGraphicsAccess graphics, int screenHeight, int ticks, ChatComponent.DisplayMode displayMode) @ L130
- 方法名:extractRenderState
- 源码定位:L130
- 返回类型:void
- 修饰符:private
参数:
- graphics: ChatComponent.ChatGraphicsAccess
- screenHeight: int
- ticks: int
- displayMode: ChatComponent.DisplayMode
说明:
TODO
public void clearMessages(boolean history) @ L234
- 方法名:clearMessages
- 源码定位:L234
- 返回类型:void
- 修饰符:public
参数:
- history: boolean
说明:
TODO
public void addClientSystemMessage(Component message) @ L245
- 方法名:addClientSystemMessage
- 源码定位:L245
- 返回类型:void
- 修饰符:public
参数:
- message: Component
说明:
TODO
public void addServerSystemMessage(Component message) @ L249
- 方法名:addServerSystemMessage
- 源码定位:L249
- 返回类型:void
- 修饰符:public
参数:
- message: Component
说明:
TODO
public void addPlayerMessage(Component message, MessageSignature signature, GuiMessageTag tag) @ L253
- 方法名:addPlayerMessage
- 源码定位:L253
- 返回类型:void
- 修饰符:public
参数:
- message: Component
- signature: MessageSignature
- tag: GuiMessageTag
说明:
TODO
private void addMessage(Component contents, MessageSignature signature, GuiMessageSource source, GuiMessageTag tag) @ L257
- 方法名:addMessage
- 源码定位:L257
- 返回类型:void
- 修饰符:private
参数:
- contents: Component
- signature: MessageSignature
- source: GuiMessageSource
- tag: GuiMessageTag
说明:
TODO
private void logChatMessage(GuiMessage message) @ L266
- 方法名:logChatMessage
- 源码定位:L266
- 返回类型:void
- 修饰符:private
参数:
- message: GuiMessage
说明:
TODO
private void addMessageToDisplayQueue(GuiMessage message) @ L276
- 方法名:addMessageToDisplayQueue
- 源码定位:L276
- 返回类型:void
- 修饰符:private
参数:
- message: GuiMessage
说明:
TODO
private void addMessageToQueue(GuiMessage message) @ L297
- 方法名:addMessageToQueue
- 源码定位:L297
- 返回类型:void
- 修饰符:private
参数:
- message: GuiMessage
说明:
TODO
private void processMessageDeletionQueue() @ L305
- 方法名:processMessageDeletionQueue
- 源码定位:L305
- 返回类型:void
- 修饰符:private
参数:
- 无
说明:
TODO
public void deleteMessage(MessageSignature signature) @ L310
- 方法名:deleteMessage
- 源码定位:L310
- 返回类型:void
- 修饰符:public
参数:
- signature: MessageSignature
说明:
TODO
private ChatComponent.DelayedMessageDeletion deleteMessageOrDelay(MessageSignature signature) @ L317
- 方法名:deleteMessageOrDelay
- 源码定位:L317
- 返回类型:ChatComponent.DelayedMessageDeletion
- 修饰符:private
参数:
- signature: MessageSignature
说明:
TODO
private static GuiMessage createDeletedMarker(GuiMessage message) @ L338
- 方法名:createDeletedMarker
- 源码定位:L338
- 返回类型:GuiMessage
- 修饰符:private static
参数:
- message: GuiMessage
说明:
TODO
public void rescaleChat() @ L342
- 方法名:rescaleChat
- 源码定位:L342
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
private void refreshTrimmedMessages() @ L347
- 方法名:refreshTrimmedMessages
- 源码定位:L347
- 返回类型:void
- 修饰符:private
参数:
- 无
说明:
TODO
public ArrayListDeque<String> getRecentChat() @ L357
- 方法名:getRecentChat
- 源码定位:L357
- 返回类型:ArrayListDeque
- 修饰符:public
参数:
- 无
说明:
TODO
public void addRecentChat(String message) @ L361
- 方法名:addRecentChat
- 源码定位:L361
- 返回类型:void
- 修饰符:public
参数:
- message: String
说明:
TODO
public void resetChatScroll() @ L375
- 方法名:resetChatScroll
- 源码定位:L375
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public void scrollChat(int dir) @ L380
- 方法名:scrollChat
- 源码定位:L380
- 返回类型:void
- 修饰符:public
参数:
- dir: int
说明:
TODO
public boolean isChatFocused() @ L393
- 方法名:isChatFocused
- 源码定位:L393
- 返回类型:boolean
- 修饰符:public
参数:
- 无
说明:
TODO
private int getWidth() @ L397
- 方法名:getWidth
- 源码定位:L397
- 返回类型:int
- 修饰符:private
参数:
- 无
说明:
TODO
private int getHeight() @ L401
- 方法名:getHeight
- 源码定位:L401
- 返回类型:int
- 修饰符:private
参数:
- 无
说明:
TODO
private double getScale() @ L405
- 方法名:getScale
- 源码定位:L405
- 返回类型:double
- 修饰符:private
参数:
- 无
说明:
TODO
public static int getWidth(double pct) @ L409
- 方法名:getWidth
- 源码定位:L409
- 返回类型:int
- 修饰符:public static
参数:
- pct: double
说明:
TODO
public static int getHeight(double pct) @ L415
- 方法名:getHeight
- 源码定位:L415
- 返回类型:int
- 修饰符:public static
参数:
- pct: double
说明:
TODO
public static double defaultUnfocusedPct() @ L421
- 方法名:defaultUnfocusedPct
- 源码定位:L421
- 返回类型:double
- 修饰符:public static
参数:
- 无
说明:
TODO
public int getLinesPerPage() @ L427
- 方法名:getLinesPerPage
- 源码定位:L427
- 返回类型:int
- 修饰符:public
参数:
- 无
说明:
TODO
private int getLineHeight() @ L431
- 方法名:getLineHeight
- 源码定位:L431
- 返回类型:int
- 修饰符:private
参数:
- 无
说明:
TODO
public void saveAsDraft(String text) @ L435
- 方法名:saveAsDraft
- 源码定位:L435
- 返回类型:void
- 修饰符:public
参数:
- text: String
说明:
TODO
public void discardDraft() @ L440
- 方法名:discardDraft
- 源码定位:L440
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public <T extends ChatScreen> T createScreen(ChatComponent.ChatMethod chatMethod, ChatScreen.ChatConstructor<T> chat) @ L444
- 方法名:createScreen
- 源码定位:L444
- 返回类型:
T - 修饰符:public
参数:
- chatMethod: ChatComponent.ChatMethod
- chat: ChatScreen.ChatConstructor
说明:
TODO
public void openScreen(ChatComponent.ChatMethod chatMethod, ChatScreen.ChatConstructor<?> chat) @ L450
- 方法名:openScreen
- 源码定位:L450
- 返回类型:void
- 修饰符:public
参数:
- chatMethod: ChatComponent.ChatMethod
- chat: ChatScreen.ChatConstructor<?>
说明:
TODO
public void preserveCurrentChatScreen() @ L454
- 方法名:preserveCurrentChatScreen
- 源码定位:L454
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public ChatScreen restoreChatScreen() @ L460
- 方法名:restoreChatScreen
- 源码定位:L460
- 返回类型:ChatScreen
- 修饰符:public
参数:
- 无
说明:
TODO
public ChatComponent.State storeState() @ L466
- 方法名:storeState
- 源码定位:L466
- 返回类型:ChatComponent.State
- 修饰符:public
参数:
- 无
说明:
TODO
public void restoreState(ChatComponent.State state) @ L470
- 方法名:restoreState
- 源码定位:L470
- 返回类型:void
- 修饰符:public
参数:
- state: ChatComponent.State
说明:
TODO
代码
@OnlyIn(Dist.CLIENT)
public class ChatComponent {
private static final Logger LOGGER = LogUtils.getLogger();
private static final int MAX_CHAT_HISTORY = 100;
private static final int MESSAGE_INDENT = 4;
private static final int BOTTOM_MARGIN = 40;
private static final int TOOLTIP_MAX_WIDTH = 210;
private static final int TIME_BEFORE_MESSAGE_DELETION = 60;
private static final Component DELETED_CHAT_MESSAGE = Component.translatable("chat.deleted_marker").withStyle(ChatFormatting.GRAY, ChatFormatting.ITALIC);
public static final int MESSAGE_BOTTOM_TO_MESSAGE_TOP = 8;
public static final Identifier QUEUE_EXPAND_ID = Identifier.withDefaultNamespace("internal/expand_chat_queue");
private static final Style QUEUE_EXPAND_TEXT_STYLE = Style.EMPTY
.withClickEvent(new ClickEvent.Custom(QUEUE_EXPAND_ID, Optional.empty()))
.withHoverEvent(new HoverEvent.ShowText(Component.translatable("chat.queue.tooltip")));
public static final Identifier GO_TO_RESTRICTIONS_SCREEN = Identifier.withDefaultNamespace("internal/go_to_restrictions_screen");
private static final Component RESTRICTED_CHAT_MESSAGE = Component.translatable("chat_screen.restricted")
.withStyle(
Style.EMPTY.withColor(ChatFormatting.RED).withUnderlined(true).withClickEvent(new ClickEvent.Custom(GO_TO_RESTRICTIONS_SCREEN, Optional.empty()))
);
private static final Component RESTRICTED_CHAT_MESSAGE_WITH_HOVER = ComponentUtils.mergeStyles(
RESTRICTED_CHAT_MESSAGE, Style.EMPTY.withHoverEvent(new HoverEvent.ShowText(Component.translatable("chat_screen.restricted")))
);
private final Minecraft minecraft;
private final ArrayListDeque<String> recentChat = new ArrayListDeque<>(100);
private final List<GuiMessage> allMessages = Lists.newArrayList();
private final List<GuiMessage.Line> trimmedMessages = Lists.newArrayList();
private int chatScrollbarPos;
private boolean newMessageSinceScroll;
private ChatComponent.@Nullable Draft latestDraft;
private @Nullable ChatScreen preservedScreen;
private final List<ChatComponent.DelayedMessageDeletion> messageDeletionQueue = new ArrayList<>();
private Predicate<GuiMessage> visibleMessageFilter = var0 -> true;
public ChatComponent(Minecraft minecraft) {
this.minecraft = minecraft;
this.recentChat.addAll(minecraft.commandHistory().history());
}
public void tick() {
if (!this.messageDeletionQueue.isEmpty()) {
this.processMessageDeletionQueue();
}
}
public void setVisibleMessageFilter(Predicate<GuiMessage> visibleMessageFilter) {
this.visibleMessageFilter = visibleMessageFilter;
this.refreshTrimmedMessages();
}
private int forEachLine(ChatComponent.AlphaCalculator alphaCalculator, ChatComponent.LineConsumer lineConsumer) {
int perPage = this.getLinesPerPage();
int count = 0;
for (int i = Math.min(this.trimmedMessages.size() - this.chatScrollbarPos, perPage) - 1; i >= 0; i--) {
int messageIndex = i + this.chatScrollbarPos;
GuiMessage.Line message = this.trimmedMessages.get(messageIndex);
float alpha = alphaCalculator.calculate(message);
if (alpha > 1.0E-5F) {
count++;
lineConsumer.accept(message, i, alpha);
}
}
return count;
}
public void extractRenderState(
GuiGraphicsExtractor graphics, Font font, int ticks, int mouseX, int mouseY, ChatComponent.DisplayMode displayMode, boolean changeCursorOnInsertions
) {
graphics.pose().pushMatrix();
this.extractRenderState(
(ChatComponent.ChatGraphicsAccess)(displayMode.foreground
? new ChatComponent.DrawingFocusedGraphicsAccess(graphics, font, mouseX, mouseY, changeCursorOnInsertions)
: new ChatComponent.DrawingBackgroundGraphicsAccess(graphics)),
graphics.guiHeight(),
ticks,
displayMode
);
graphics.pose().popMatrix();
}
public void captureClickableText(ActiveTextCollector activeTextCollector, int screenHeight, int ticks, ChatComponent.DisplayMode displayMode) {
this.extractRenderState(new ChatComponent.ClickableTextOnlyGraphicsAccess(activeTextCollector), screenHeight, ticks, displayMode);
}
private void extractRenderState(ChatComponent.ChatGraphicsAccess graphics, int screenHeight, int ticks, ChatComponent.DisplayMode displayMode) {
boolean isForeground = displayMode.foreground;
boolean isRestricted = displayMode.showRestrictedPrompt;
int total = this.trimmedMessages.size();
if (total > 0 || isRestricted) {
ProfilerFiller profiler = Profiler.get();
profiler.push("chat");
float scale = (float)this.getScale();
int maxWidth = Mth.ceil(this.getWidth() / scale);
final int chatBottom = Mth.floor((screenHeight - 40) / scale);
final float textOpacity = this.minecraft.options.chatOpacity().get().floatValue() * 0.9F + 0.1F;
float backgroundOpacity = this.minecraft.options.textBackgroundOpacity().get().floatValue();
final int messageHeight = 9;
int messageBottomToMessageTop = 8;
double chatLineSpacing = this.minecraft.options.chatLineSpacing().get();
final int entryHeight = (int)(messageHeight * (chatLineSpacing + 1.0));
final int entryBottomToMessageY = (int)Math.round(8.0 * (chatLineSpacing + 1.0) - 4.0 * chatLineSpacing);
long queueSize = this.minecraft.getChatListener().queueSize();
ChatComponent.AlphaCalculator alphaCalculator = isForeground
? ChatComponent.AlphaCalculator.FULLY_VISIBLE
: ChatComponent.AlphaCalculator.timeBased(ticks);
graphics.updatePose(pose -> {
pose.scale(scale, scale);
pose.translate(4.0F, 0.0F);
});
int count = this.forEachLine(alphaCalculator, (var5x, lineIndex, alphax) -> {
int entryBottom = chatBottom - lineIndex * entryHeight;
int entryTop = entryBottom - entryHeight;
graphics.fill(-4, entryTop, maxWidth + 4 + 4, entryBottom, ARGB.black(alphax * backgroundOpacity));
});
int lineAboveMessagesY = chatBottom - (count + 1) * entryHeight;
if (queueSize > 0L) {
graphics.fill(-2, chatBottom, maxWidth + 4, chatBottom + messageHeight, ARGB.black(backgroundOpacity));
}
if (isRestricted) {
graphics.fill(-2, lineAboveMessagesY, maxWidth + 4 + 4, lineAboveMessagesY + entryHeight, ARGB.black(backgroundOpacity));
}
this.forEachLine(alphaCalculator, new ChatComponent.LineConsumer() {
boolean hoveredOverCurrentMessage;
{
Objects.requireNonNull(ChatComponent.this);
}
@Override
public void accept(GuiMessage.Line line, int lineIndex, float alpha) {
int entryBottom = chatBottom - lineIndex * entryHeight;
int entryTop = entryBottom - entryHeight;
int textTop = entryBottom - entryBottomToMessageY;
boolean hoveredOverCurrentLine = graphics.handleMessage(textTop, alpha * textOpacity, line.content());
this.hoveredOverCurrentMessage |= hoveredOverCurrentLine;
boolean forceIconRendering;
if (line.endOfEntry()) {
forceIconRendering = this.hoveredOverCurrentMessage;
this.hoveredOverCurrentMessage = false;
} else {
forceIconRendering = false;
}
GuiMessageTag tag = line.tag();
if (tag != null) {
graphics.handleTag(-4, entryTop, -2, entryBottom, alpha * textOpacity, tag);
if (tag.icon() != null) {
int iconLeft = line.getTagIconLeft(ChatComponent.this.minecraft.font);
int textBottom = textTop + messageHeight;
graphics.handleTagIcon(iconLeft, textBottom, forceIconRendering, tag, tag.icon());
}
}
}
});
if (queueSize > 0L) {
int queueLineBottom = chatBottom + messageHeight;
Component queueMessage = Component.translatable("chat.queue", queueSize).setStyle(QUEUE_EXPAND_TEXT_STYLE);
graphics.handleMessage(queueLineBottom - 8, 0.5F * textOpacity, queueMessage.getVisualOrderText());
}
if (isRestricted) {
int restrictedMessageWidth = this.minecraft.font.width(RESTRICTED_CHAT_MESSAGE);
FormattedCharSequence restrictedMessage = restrictedMessageWidth > maxWidth
? ComponentRenderUtils.clipText(RESTRICTED_CHAT_MESSAGE_WITH_HOVER, this.minecraft.font, maxWidth)
: RESTRICTED_CHAT_MESSAGE.getVisualOrderText();
graphics.handleMessage(lineAboveMessagesY + entryHeight - entryBottomToMessageY - 1, textOpacity, restrictedMessage);
}
if (total > 0 && isForeground) {
int chatHeight = count * entryHeight;
int virtualHeight = total * entryHeight;
int y = this.chatScrollbarPos * chatHeight / total - chatBottom;
int height = chatHeight * chatHeight / virtualHeight;
if (virtualHeight != chatHeight) {
int alpha = y > 0 ? 170 : 96;
int color = this.newMessageSinceScroll ? 13382451 : 3355562;
int scrollBarStartX = maxWidth + 4;
graphics.fill(scrollBarStartX, -y, scrollBarStartX + 2, -y - height, ARGB.color(alpha, color));
graphics.fill(scrollBarStartX + 2, -y, scrollBarStartX + 1, -y - height, ARGB.color(alpha, 13421772));
}
}
profiler.pop();
}
}
public void clearMessages(boolean history) {
this.minecraft.getChatListener().flushQueue();
this.messageDeletionQueue.clear();
this.trimmedMessages.clear();
this.allMessages.clear();
if (history) {
this.recentChat.clear();
this.recentChat.addAll(this.minecraft.commandHistory().history());
}
}
public void addClientSystemMessage(Component message) {
this.addMessage(message, null, GuiMessageSource.SYSTEM_CLIENT, GuiMessageTag.systemSinglePlayer());
}
public void addServerSystemMessage(Component message) {
this.addMessage(message, null, GuiMessageSource.SYSTEM_SERVER, GuiMessageTag.systemSinglePlayer());
}
public void addPlayerMessage(Component message, @Nullable MessageSignature signature, @Nullable GuiMessageTag tag) {
this.addMessage(message, signature, GuiMessageSource.PLAYER, tag);
}
private void addMessage(Component contents, @Nullable MessageSignature signature, GuiMessageSource source, @Nullable GuiMessageTag tag) {
GuiMessage message = new GuiMessage(this.minecraft.gui.getGuiTicks(), contents, signature, source, tag);
if (this.visibleMessageFilter.test(message)) {
this.logChatMessage(message);
this.addMessageToDisplayQueue(message);
this.addMessageToQueue(message);
}
}
private void logChatMessage(GuiMessage message) {
String messageString = message.content().getString().replaceAll("\r", "\\\\r").replaceAll("\n", "\\\\n");
String logTag = Optionull.map(message.tag(), GuiMessageTag::logTag);
if (logTag != null) {
LOGGER.info("[{}] [CHAT] {}", logTag, messageString);
} else {
LOGGER.info("[CHAT] {}", messageString);
}
}
private void addMessageToDisplayQueue(GuiMessage message) {
int maxWidth = Mth.floor(this.getWidth() / this.getScale());
List<FormattedCharSequence> lines = message.splitLines(this.minecraft.font, maxWidth);
boolean chatting = this.isChatFocused();
for (int i = 0; i < lines.size(); i++) {
FormattedCharSequence line = lines.get(i);
if (chatting && this.chatScrollbarPos > 0) {
this.newMessageSinceScroll = true;
this.scrollChat(1);
}
boolean endOfEntry = i == lines.size() - 1;
this.trimmedMessages.addFirst(new GuiMessage.Line(message, line, endOfEntry));
}
while (this.trimmedMessages.size() > 100) {
this.trimmedMessages.removeLast();
}
}
private void addMessageToQueue(GuiMessage message) {
this.allMessages.addFirst(message);
while (this.allMessages.size() > 100) {
this.allMessages.removeLast();
}
}
private void processMessageDeletionQueue() {
int time = this.minecraft.gui.getGuiTicks();
this.messageDeletionQueue.removeIf(entry -> time >= entry.deletableAfter() ? this.deleteMessageOrDelay(entry.signature()) == null : false);
}
public void deleteMessage(MessageSignature signature) {
ChatComponent.DelayedMessageDeletion delayedMessage = this.deleteMessageOrDelay(signature);
if (delayedMessage != null) {
this.messageDeletionQueue.add(delayedMessage);
}
}
private ChatComponent.@Nullable DelayedMessageDeletion deleteMessageOrDelay(MessageSignature signature) {
int time = this.minecraft.gui.getGuiTicks();
ListIterator<GuiMessage> iterator = this.allMessages.listIterator();
while (iterator.hasNext()) {
GuiMessage message = iterator.next();
if (signature.equals(message.signature())) {
int deletableAfter = message.addedTime() + 60;
if (time >= deletableAfter) {
iterator.set(createDeletedMarker(message));
this.refreshTrimmedMessages();
return null;
}
return new ChatComponent.DelayedMessageDeletion(signature, deletableAfter);
}
}
return null;
}
private static GuiMessage createDeletedMarker(GuiMessage message) {
return new GuiMessage(message.addedTime(), DELETED_CHAT_MESSAGE, null, GuiMessageSource.SYSTEM_SERVER, GuiMessageTag.system());
}
public void rescaleChat() {
this.resetChatScroll();
this.refreshTrimmedMessages();
}
private void refreshTrimmedMessages() {
this.trimmedMessages.clear();
for (GuiMessage message : Lists.reverse(this.allMessages)) {
if (this.visibleMessageFilter.test(message)) {
this.addMessageToDisplayQueue(message);
}
}
}
public ArrayListDeque<String> getRecentChat() {
return this.recentChat;
}
public void addRecentChat(String message) {
if (!message.equals(this.recentChat.peekLast())) {
if (this.recentChat.size() >= 100) {
this.recentChat.removeFirst();
}
this.recentChat.addLast(message);
}
if (message.startsWith("/")) {
this.minecraft.commandHistory().addCommand(message);
}
}
public void resetChatScroll() {
this.chatScrollbarPos = 0;
this.newMessageSinceScroll = false;
}
public void scrollChat(int dir) {
this.chatScrollbarPos += dir;
int max = this.trimmedMessages.size();
if (this.chatScrollbarPos > max - this.getLinesPerPage()) {
this.chatScrollbarPos = max - this.getLinesPerPage();
}
if (this.chatScrollbarPos <= 0) {
this.chatScrollbarPos = 0;
this.newMessageSinceScroll = false;
}
}
public boolean isChatFocused() {
return this.minecraft.screen instanceof ChatScreen;
}
private int getWidth() {
return getWidth(this.minecraft.options.chatWidth().get());
}
private int getHeight() {
return getHeight(this.isChatFocused() ? this.minecraft.options.chatHeightFocused().get() : this.minecraft.options.chatHeightUnfocused().get());
}
private double getScale() {
return this.minecraft.options.chatScale().get();
}
public static int getWidth(double pct) {
int max = 320;
int min = 40;
return Mth.floor(pct * 280.0 + 40.0);
}
public static int getHeight(double pct) {
int max = 180;
int min = 20;
return Mth.floor(pct * 160.0 + 20.0);
}
public static double defaultUnfocusedPct() {
int max = 180;
int min = 20;
return 70.0 / (getHeight(1.0) - 20);
}
public int getLinesPerPage() {
return this.getHeight() / this.getLineHeight();
}
private int getLineHeight() {
return (int)(9.0 * (this.minecraft.options.chatLineSpacing().get() + 1.0));
}
public void saveAsDraft(String text) {
boolean isCommand = text.startsWith("/");
this.latestDraft = new ChatComponent.Draft(text, isCommand ? ChatComponent.ChatMethod.COMMAND : ChatComponent.ChatMethod.MESSAGE);
}
public void discardDraft() {
this.latestDraft = null;
}
public <T extends ChatScreen> T createScreen(ChatComponent.ChatMethod chatMethod, ChatScreen.ChatConstructor<T> chat) {
return this.latestDraft != null && chatMethod.isDraftRestorable(this.latestDraft)
? chat.create(this.latestDraft.text(), true)
: chat.create(chatMethod.prefix(), false);
}
public void openScreen(ChatComponent.ChatMethod chatMethod, ChatScreen.ChatConstructor<?> chat) {
this.minecraft.setScreen(this.createScreen(chatMethod, chat));
}
public void preserveCurrentChatScreen() {
if (this.minecraft.screen instanceof ChatScreen chatScreen) {
this.preservedScreen = chatScreen;
}
}
public @Nullable ChatScreen restoreChatScreen() {
ChatScreen restoredScreen = this.preservedScreen;
this.preservedScreen = null;
return restoredScreen;
}
public ChatComponent.State storeState() {
return new ChatComponent.State(List.copyOf(this.allMessages), List.copyOf(this.recentChat), List.copyOf(this.messageDeletionQueue));
}
public void restoreState(ChatComponent.State state) {
this.recentChat.clear();
this.recentChat.addAll(state.history);
this.messageDeletionQueue.clear();
this.messageDeletionQueue.addAll(state.delayedMessageDeletions);
this.allMessages.clear();
this.allMessages.addAll(state.messages);
this.refreshTrimmedMessages();
}
@FunctionalInterface
@OnlyIn(Dist.CLIENT)
private interface AlphaCalculator {
ChatComponent.AlphaCalculator FULLY_VISIBLE = var0 -> 1.0F;
static ChatComponent.AlphaCalculator timeBased(int currentTickTime) {
return message -> {
int tickDelta = currentTickTime - message.addedTime();
double t = tickDelta / 200.0;
t = 1.0 - t;
t *= 10.0;
t = Mth.clamp(t, 0.0, 1.0);
t *= t;
return (float)t;
};
}
float calculate(GuiMessage.Line message);
}
@OnlyIn(Dist.CLIENT)
public interface ChatGraphicsAccess {
void updatePose(final Consumer<Matrix3x2f> updater);
void fill(int x0, int y0, int x1, int y1, int color);
boolean handleMessage(int textTop, float opacity, FormattedCharSequence message);
void handleTag(int x0, int y0, int x1, int y1, float opacity, GuiMessageTag tag);
void handleTagIcon(int left, int bottom, boolean forceVisible, GuiMessageTag tag, GuiMessageTag.Icon icon);
}
@OnlyIn(Dist.CLIENT)
public static enum ChatMethod {
MESSAGE("") {
@Override
public boolean isDraftRestorable(ChatComponent.Draft draft) {
return true;
}
},
COMMAND("/") {
@Override
public boolean isDraftRestorable(ChatComponent.Draft draft) {
return this == draft.chatMethod;
}
};
private final String prefix;
private ChatMethod(String prefix) {
this.prefix = prefix;
}
public String prefix() {
return this.prefix;
}
public abstract boolean isDraftRestorable(ChatComponent.Draft draft);
}
@OnlyIn(Dist.CLIENT)
private static class ClickableTextOnlyGraphicsAccess implements ChatComponent.ChatGraphicsAccess {
private final ActiveTextCollector output;
public ClickableTextOnlyGraphicsAccess(ActiveTextCollector output) {
this.output = output;
}
@Override
public void updatePose(Consumer<Matrix3x2f> updater) {
ActiveTextCollector.Parameters defaultParameters = this.output.defaultParameters();
Matrix3x2f newPose = new Matrix3x2f(defaultParameters.pose());
updater.accept(newPose);
this.output.defaultParameters(defaultParameters.withPose(newPose));
}
@Override
public void fill(int x0, int y0, int x1, int y1, int color) {
}
@Override
public boolean handleMessage(int textTop, float opacity, FormattedCharSequence message) {
this.output.accept(TextAlignment.LEFT, 0, textTop, message);
return false;
}
@Override
public void handleTag(int x0, int y0, int x1, int y1, float opacity, GuiMessageTag tag) {
}
@Override
public void handleTagIcon(int left, int bottom, boolean forceVisible, GuiMessageTag tag, GuiMessageTag.Icon icon) {
}
}
@OnlyIn(Dist.CLIENT)
private record DelayedMessageDeletion(MessageSignature signature, int deletableAfter) {
}
@OnlyIn(Dist.CLIENT)
public static enum DisplayMode {
BACKGROUND(false, false),
FOREGROUND(true, false),
FOREGROUND_RESTRICTED(true, true);
public final boolean foreground;
public final boolean showRestrictedPrompt;
private DisplayMode(boolean foreground, boolean showRestrictedPrompt) {
this.foreground = foreground;
this.showRestrictedPrompt = showRestrictedPrompt;
}
}
@OnlyIn(Dist.CLIENT)
public record Draft(String text, ChatComponent.ChatMethod chatMethod) {
}
@OnlyIn(Dist.CLIENT)
private static class DrawingBackgroundGraphicsAccess implements ChatComponent.ChatGraphicsAccess {
private final GuiGraphicsExtractor graphics;
private final ActiveTextCollector textRenderer;
private ActiveTextCollector.Parameters parameters;
public DrawingBackgroundGraphicsAccess(GuiGraphicsExtractor graphics) {
this.graphics = graphics;
this.textRenderer = graphics.textRenderer(GuiGraphicsExtractor.HoveredTextEffects.NONE, null);
this.parameters = this.textRenderer.defaultParameters();
}
@Override
public void updatePose(Consumer<Matrix3x2f> updater) {
updater.accept(this.graphics.pose());
this.parameters = this.parameters.withPose(new Matrix3x2f(this.graphics.pose()));
}
@Override
public void fill(int x0, int y0, int x1, int y1, int color) {
this.graphics.fill(x0, y0, x1, y1, color);
}
@Override
public boolean handleMessage(int textTop, float opacity, FormattedCharSequence message) {
this.textRenderer.accept(TextAlignment.LEFT, 0, textTop, this.parameters.withOpacity(opacity), message);
return false;
}
@Override
public void handleTag(int x0, int y0, int x1, int y1, float opacity, GuiMessageTag tag) {
int indicatorColor = ARGB.color(opacity, tag.indicatorColor());
this.graphics.fill(x0, y0, x1, y1, indicatorColor);
}
@Override
public void handleTagIcon(int left, int bottom, boolean forceVisible, GuiMessageTag tag, GuiMessageTag.Icon icon) {
}
}
@OnlyIn(Dist.CLIENT)
private static class DrawingFocusedGraphicsAccess implements ChatComponent.ChatGraphicsAccess, Consumer<Style> {
private final GuiGraphicsExtractor graphics;
private final Font font;
private final ActiveTextCollector textRenderer;
private ActiveTextCollector.Parameters parameters;
private final int globalMouseX;
private final int globalMouseY;
private final Vector2f localMousePos = new Vector2f();
private @Nullable Style hoveredStyle;
private final boolean changeCursorOnInsertions;
public DrawingFocusedGraphicsAccess(GuiGraphicsExtractor graphics, Font font, int mouseX, int mouseY, boolean changeCursorOnInsertions) {
this.graphics = graphics;
this.font = font;
this.textRenderer = graphics.textRenderer(GuiGraphicsExtractor.HoveredTextEffects.TOOLTIP_AND_CURSOR, this);
this.globalMouseX = mouseX;
this.globalMouseY = mouseY;
this.changeCursorOnInsertions = changeCursorOnInsertions;
this.parameters = this.textRenderer.defaultParameters();
this.updateLocalMousePos();
}
private void updateLocalMousePos() {
this.graphics.pose().invert(new Matrix3x2f()).transformPosition(this.globalMouseX, this.globalMouseY, this.localMousePos);
}
@Override
public void updatePose(Consumer<Matrix3x2f> updater) {
updater.accept(this.graphics.pose());
this.parameters = this.parameters.withPose(new Matrix3x2f(this.graphics.pose()));
this.updateLocalMousePos();
}
@Override
public void fill(int x0, int y0, int x1, int y1, int color) {
this.graphics.fill(x0, y0, x1, y1, color);
}
public void accept(Style style) {
this.hoveredStyle = style;
}
@Override
public boolean handleMessage(int textTop, float opacity, FormattedCharSequence message) {
this.hoveredStyle = null;
this.textRenderer.accept(TextAlignment.LEFT, 0, textTop, this.parameters.withOpacity(opacity), message);
if (this.changeCursorOnInsertions && this.hoveredStyle != null && this.hoveredStyle.getInsertion() != null) {
this.graphics.requestCursor(CursorTypes.POINTING_HAND);
}
return this.hoveredStyle != null;
}
private boolean isMouseOver(int left, int top, int right, int bottom) {
return ActiveTextCollector.isPointInRectangle(this.localMousePos.x, this.localMousePos.y, left, top, right, bottom);
}
@Override
public void handleTag(int x0, int y0, int x1, int y1, float opacity, GuiMessageTag tag) {
int indicatorColor = ARGB.color(opacity, tag.indicatorColor());
this.graphics.fill(x0, y0, x1, y1, indicatorColor);
if (this.isMouseOver(x0, y0, x1, y1)) {
this.showTooltip(tag);
}
}
@Override
public void handleTagIcon(int left, int bottom, boolean forceVisible, GuiMessageTag tag, GuiMessageTag.Icon icon) {
int top = bottom - icon.height - 1;
int right = left + icon.width;
boolean isMouseOver = this.isMouseOver(left, top, right, bottom);
if (isMouseOver) {
this.showTooltip(tag);
}
if (forceVisible || isMouseOver) {
icon.extractRenderState(this.graphics, left, top);
}
}
private void showTooltip(GuiMessageTag tag) {
if (tag.text() != null) {
this.graphics.setTooltipForNextFrame(this.font, this.font.split(tag.text(), 210), this.globalMouseX, this.globalMouseY);
}
}
}
@FunctionalInterface
@OnlyIn(Dist.CLIENT)
private interface LineConsumer {
void accept(GuiMessage.Line line, int lineIndex, float alpha);
}
@OnlyIn(Dist.CLIENT)
public static class State {
private final List<GuiMessage> messages;
private final List<String> history;
private final List<ChatComponent.DelayedMessageDeletion> delayedMessageDeletions;
public State(List<GuiMessage> messages, List<String> history, List<ChatComponent.DelayedMessageDeletion> delayedMessageDeletions) {
this.messages = messages;
this.history = history;
this.delayedMessageDeletions = delayedMessageDeletions;
}
}
}引用的其他类
-
- 引用位置:
方法调用 - 关联成员:
Optionull.map()
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
参数/方法调用 - 关联成员:
ActiveTextCollector.isPointInRectangle()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
ComponentRenderUtils.clipText()
- 引用位置:
-
- 引用位置:
参数/字段/返回值
- 引用位置:
-
- 引用位置:
参数/字段/方法调用/构造调用/返回值 - 关联成员:
GuiMessage(), GuiMessage.Line(), Line()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数/方法调用 - 关联成员:
GuiMessageTag.system(), GuiMessageTag.systemSinglePlayer()
- 引用位置:
-
- 引用位置:
方法调用/构造调用 - 关联成员:
ClickEvent.Custom(), Custom()
- 引用位置:
-
- 引用位置:
参数/字段/方法调用 - 关联成员:
Component.translatable()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
ComponentUtils.mergeStyles()
- 引用位置:
-
- 引用位置:
方法调用/构造调用 - 关联成员:
HoverEvent.ShowText(), ShowText()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
字段
- 引用位置:
-
- 引用位置:
字段/方法调用 - 关联成员:
Identifier.withDefaultNamespace()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
ARGB.black(), ARGB.color()
- 引用位置:
-
- 引用位置:
字段/返回值
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Mth.ceil(), Mth.clamp(), Mth.floor()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Profiler.get()
- 引用位置: