CommandSuggestions.java
net.minecraft.client.gui.components.CommandSuggestions
信息
- 全限定名:net.minecraft.client.gui.components.CommandSuggestions
- 类型:public class
- 包:net.minecraft.client.gui.components
- 源码路径:src/main/java/net/minecraft/client/gui/components/CommandSuggestions.java
- 起始行号:L57
- 职责:
TODO
字段/常量
-
WHITESPACE_PATTERN- 类型:
Pattern - 修饰符:
private static final - 源码定位:
L58 - 说明:
TODO
- 类型:
-
UNPARSED_STYLE- 类型:
Style - 修饰符:
private static final - 源码定位:
L59 - 说明:
TODO
- 类型:
-
LITERAL_STYLE- 类型:
Style - 修饰符:
private static final - 源码定位:
L60 - 说明:
TODO
- 类型:
-
USAGE_FORMAT- 类型:
Style - 修饰符:
public static final - 源码定位:
L61 - 说明:
TODO
- 类型:
-
ARGUMENT_STYLES- 类型:
List<Style> - 修饰符:
private static final - 源码定位:
L62 - 说明:
TODO
- 类型:
-
LINE_HEIGHT- 类型:
int - 修饰符:
public static final - 源码定位:
L67 - 说明:
TODO
- 类型:
-
USAGE_OFFSET_FROM_BOTTOM- 类型:
int - 修饰符:
public static final - 源码定位:
L68 - 说明:
TODO
- 类型:
-
COMMANDS_NOT_ALLOWED_TEXT- 类型:
Component - 修饰符:
private static final - 源码定位:
L69 - 说明:
TODO
- 类型:
-
MESSAGES_NOT_ALLOWED_TEXT- 类型:
Component - 修饰符:
private static final - 源码定位:
L70 - 说明:
TODO
- 类型:
-
minecraft- 类型:
Minecraft - 修饰符:
private final - 源码定位:
L71 - 说明:
TODO
- 类型:
-
screen- 类型:
Screen - 修饰符:
private final - 源码定位:
L72 - 说明:
TODO
- 类型:
-
input- 类型:
EditBox - 修饰符:
private final - 源码定位:
L73 - 说明:
TODO
- 类型:
-
font- 类型:
Font - 修饰符:
private final - 源码定位:
L74 - 说明:
TODO
- 类型:
-
commandsOnly- 类型:
boolean - 修饰符:
private final - 源码定位:
L75 - 说明:
TODO
- 类型:
-
onlyShowIfCursorPastError- 类型:
boolean - 修饰符:
private final - 源码定位:
L76 - 说明:
TODO
- 类型:
-
lineStartOffset- 类型:
int - 修饰符:
private final - 源码定位:
L77 - 说明:
TODO
- 类型:
-
suggestionLineLimit- 类型:
int - 修饰符:
private final - 源码定位:
L78 - 说明:
TODO
- 类型:
-
anchorToBottom- 类型:
boolean - 修饰符:
private final - 源码定位:
L79 - 说明:
TODO
- 类型:
-
fillColor- 类型:
int - 修饰符:
private final - 源码定位:
L80 - 说明:
TODO
- 类型:
-
commandUsage- 类型:
List<FormattedCharSequence> - 修饰符:
private final - 源码定位:
L81 - 说明:
TODO
- 类型:
-
commandUsagePosition- 类型:
int - 修饰符:
private - 源码定位:
L82 - 说明:
TODO
- 类型:
-
commandUsageWidth- 类型:
int - 修饰符:
private - 源码定位:
L83 - 说明:
TODO
- 类型:
-
currentParse- 类型:
ParseResults<ClientSuggestionProvider> - 修饰符:
private - 源码定位:
L84 - 说明:
TODO
- 类型:
-
pendingSuggestions- 类型:
CompletableFuture<Suggestions> - 修饰符:
private - 源码定位:
L85 - 说明:
TODO
- 类型:
-
suggestions- 类型:
CommandSuggestions.SuggestionsList - 修饰符:
private - 源码定位:
L86 - 说明:
TODO
- 类型:
-
currentParseIsCommand- 类型:
boolean - 修饰符:
private - 源码定位:
L87 - 说明:
TODO
- 类型:
-
currentParseIsMessage- 类型:
boolean - 修饰符:
private - 源码定位:
L88 - 说明:
TODO
- 类型:
-
allowSuggestions- 类型:
boolean - 修饰符:
private - 源码定位:
L89 - 说明:
TODO
- 类型:
-
keepSuggestions- 类型:
boolean - 修饰符:
private - 源码定位:
L90 - 说明:
TODO
- 类型:
-
allowHiding- 类型:
boolean - 修饰符:
private - 源码定位:
L91 - 说明:
TODO
- 类型:
-
messagesAllowed- 类型:
boolean - 修饰符:
private - 源码定位:
L92 - 说明:
TODO
- 类型:
-
commandsAllowed- 类型:
boolean - 修饰符:
private - 源码定位:
L93 - 说明:
TODO
- 类型:
内部类/嵌套类型
-
net.minecraft.client.gui.components.CommandSuggestions.Visitor- 类型:
class - 修饰符:
package-private - 源码定位:
L272 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.components.CommandSuggestions.SuggestionsList- 类型:
class - 修饰符:
public - 源码定位:
L482 - 说明:
TODO
- 类型:
构造器
public CommandSuggestions(Minecraft minecraft, Screen screen, EditBox input, Font font, boolean commandsOnly, boolean onlyShowIfCursorPastError, int lineStartOffset, int suggestionLineLimit, boolean anchorToBottom, int fillColor) @ L95
- 构造器名:CommandSuggestions
- 源码定位:L95
- 修饰符:public
参数:
- minecraft: Minecraft
- screen: Screen
- input: EditBox
- font: Font
- commandsOnly: boolean
- onlyShowIfCursorPastError: boolean
- lineStartOffset: int
- suggestionLineLimit: int
- anchorToBottom: boolean
- fillColor: int
说明:
TODO
方法
下面的方法块按源码顺序生成。
public void setAllowSuggestions(boolean allowSuggestions) @ L120
- 方法名:setAllowSuggestions
- 源码定位:L120
- 返回类型:void
- 修饰符:public
参数:
- allowSuggestions: boolean
说明:
TODO
public void setAllowHiding(boolean allowHiding) @ L127
- 方法名:setAllowHiding
- 源码定位:L127
- 返回类型:void
- 修饰符:public
参数:
- allowHiding: boolean
说明:
TODO
public void setRestrictions(boolean messagesAllowed, boolean commandsAllowed) @ L131
- 方法名:setRestrictions
- 源码定位:L131
- 返回类型:void
- 修饰符:public
参数:
- messagesAllowed: boolean
- commandsAllowed: boolean
说明:
TODO
public boolean keyPressed(KeyEvent event) @ L136
- 方法名:keyPressed
- 源码定位:L136
- 返回类型:boolean
- 修饰符:public
参数:
- event: KeyEvent
说明:
TODO
public boolean mouseScrolled(double scroll) @ L148
- 方法名:mouseScrolled
- 源码定位:L148
- 返回类型:boolean
- 修饰符:public
参数:
- scroll: double
说明:
TODO
public boolean mouseClicked(MouseButtonEvent event) @ L152
- 方法名:mouseClicked
- 源码定位:L152
- 返回类型:boolean
- 修饰符:public
参数:
- event: MouseButtonEvent
说明:
TODO
public void showSuggestions(boolean immediateNarration) @ L156
- 方法名:showSuggestions
- 源码定位:L156
- 返回类型:void
- 修饰符:public
参数:
- immediateNarration: boolean
说明:
TODO
public boolean isVisible() @ L175
- 方法名:isVisible
- 源码定位:L175
- 返回类型:boolean
- 修饰符:public
参数:
- 无
说明:
TODO
public Component getUsageNarration() @ L179
- 方法名:getUsageNarration
- 源码定位:L179
- 返回类型:Component
- 修饰符:public
参数:
- 无
说明:
TODO
public void hide() @ L191
- 方法名:hide
- 源码定位:L191
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
private List<Suggestion> sortSuggestions(Suggestions suggestions) @ L195
- 方法名:sortSuggestions
- 源码定位:L195
- 返回类型:List
- 修饰符:private
参数:
- suggestions: Suggestions
说明:
TODO
public void updateCommandInfo() @ L214
- 方法名:updateCommandInfo
- 源码定位:L214
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
private static boolean hasMessageArguments(ParseResults<ClientSuggestionProvider> parseResults) @ L270
- 方法名:hasMessageArguments
- 源码定位:L270
- 返回类型:boolean
- 修饰符:private static
参数:
- parseResults: ParseResults
说明:
TODO
private static int getLastWordIndex(String text) @ L290
- 方法名:getLastWordIndex
- 源码定位:L290
- 返回类型:int
- 修饰符:private static
参数:
- text: String
说明:
TODO
private static FormattedCharSequence getExceptionMessage(CommandSyntaxException e) @ L305
- 方法名:getExceptionMessage
- 源码定位:L305
- 返回类型:FormattedCharSequence
- 修饰符:private static
参数:
- e: CommandSyntaxException
说明:
TODO
private void updateUsageInfo(ParseResults<ClientSuggestionProvider> currentParse, Suggestions suggestions) @ L313
- 方法名:updateUsageInfo
- 源码定位:L313
- 返回类型:void
- 修饰符:private
参数:
- currentParse: ParseResults
- suggestions: Suggestions
说明:
TODO
private List<FormattedCharSequence> fillNodeUsage(SuggestionContext<ClientSuggestionProvider> suggestionContext, Style usageFormat) @ L374
- 方法名:fillNodeUsage
- 源码定位:L374
- 返回类型:List
- 修饰符:private
参数:
- suggestionContext: SuggestionContext
- usageFormat: Style
说明:
TODO
private void recomputeUsageBoxWidth() @ L391
- 方法名:recomputeUsageBoxWidth
- 源码定位:L391
- 返回类型:void
- 修饰符:private
参数:
- 无
说明:
TODO
private FormattedCharSequence formatChat(String text, int offset) @ L401
- 方法名:formatChat
- 源码定位:L401
- 返回类型:FormattedCharSequence
- 修饰符:private
参数:
- text: String
- offset: int
说明:
TODO
private static String calculateSuggestionSuffix(String contents, String suggestion) @ L405
- 方法名:calculateSuggestionSuffix
- 源码定位:L405
- 返回类型:String
- 修饰符:private static
参数:
- contents: String
- suggestion: String
说明:
TODO
private static FormattedCharSequence formatText(ParseResults<ClientSuggestionProvider> currentParse, String text, int offset) @ L409
- 方法名:formatText
- 源码定位:L409
- 返回类型:FormattedCharSequence
- 修饰符:private static
参数:
- currentParse: ParseResults
- text: String
- offset: int
说明:
TODO
public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY) @ L447
- 方法名:extractRenderState
- 源码定位:L447
- 返回类型:void
- 修饰符:public
参数:
- graphics: GuiGraphicsExtractor
- mouseX: int
- mouseY: int
说明:
TODO
public boolean extractSuggestions(GuiGraphicsExtractor graphics, int mouseX, int mouseY) @ L453
- 方法名:extractSuggestions
- 源码定位:L453
- 返回类型:boolean
- 修饰符:public
参数:
- graphics: GuiGraphicsExtractor
- mouseX: int
- mouseY: int
说明:
TODO
public void extractUsage(GuiGraphicsExtractor graphics) @ L462
- 方法名:extractUsage
- 源码定位:L462
- 返回类型:void
- 修饰符:public
参数:
- graphics: GuiGraphicsExtractor
说明:
TODO
public Component getNarrationMessage() @ L473
- 方法名:getNarrationMessage
- 源码定位:L473
- 返回类型:Component
- 修饰符:public
参数:
- 无
说明:
TODO
public boolean hasAllowedInput() @ L477
- 方法名:hasAllowedInput
- 源码定位:L477
- 返回类型:boolean
- 修饰符:public
参数:
- 无
说明:
TODO
代码
@OnlyIn(Dist.CLIENT)
public class CommandSuggestions {
private static final Pattern WHITESPACE_PATTERN = Pattern.compile("(\\s+)");
private static final Style UNPARSED_STYLE = Style.EMPTY.withColor(ChatFormatting.RED);
private static final Style LITERAL_STYLE = Style.EMPTY.withColor(ChatFormatting.GRAY);
public static final Style USAGE_FORMAT = Style.EMPTY.withColor(ChatFormatting.GRAY);
private static final List<Style> ARGUMENT_STYLES = Stream.of(
ChatFormatting.AQUA, ChatFormatting.YELLOW, ChatFormatting.GREEN, ChatFormatting.LIGHT_PURPLE, ChatFormatting.GOLD
)
.map(Style.EMPTY::withColor)
.collect(ImmutableList.toImmutableList());
public static final int LINE_HEIGHT = 12;
public static final int USAGE_OFFSET_FROM_BOTTOM = 27;
private static final Component COMMANDS_NOT_ALLOWED_TEXT = Component.translatable("chat_screen.commands_not_allowed").withStyle(ChatFormatting.RED);
private static final Component MESSAGES_NOT_ALLOWED_TEXT = Component.translatable("chat_screen.messages_not_allowed").withStyle(ChatFormatting.RED);
private final Minecraft minecraft;
private final Screen screen;
private final EditBox input;
private final Font font;
private final boolean commandsOnly;
private final boolean onlyShowIfCursorPastError;
private final int lineStartOffset;
private final int suggestionLineLimit;
private final boolean anchorToBottom;
private final int fillColor;
private final List<FormattedCharSequence> commandUsage = Lists.newArrayList();
private int commandUsagePosition;
private int commandUsageWidth;
private @Nullable ParseResults<ClientSuggestionProvider> currentParse;
private @Nullable CompletableFuture<Suggestions> pendingSuggestions;
private CommandSuggestions.@Nullable SuggestionsList suggestions;
private boolean currentParseIsCommand;
private boolean currentParseIsMessage;
private boolean allowSuggestions;
private boolean keepSuggestions;
private boolean allowHiding = true;
private boolean messagesAllowed = true;
private boolean commandsAllowed = true;
public CommandSuggestions(
Minecraft minecraft,
Screen screen,
EditBox input,
Font font,
boolean commandsOnly,
boolean onlyShowIfCursorPastError,
int lineStartOffset,
int suggestionLineLimit,
boolean anchorToBottom,
int fillColor
) {
this.minecraft = minecraft;
this.screen = screen;
this.input = input;
this.font = font;
this.commandsOnly = commandsOnly;
this.onlyShowIfCursorPastError = onlyShowIfCursorPastError;
this.lineStartOffset = lineStartOffset;
this.suggestionLineLimit = suggestionLineLimit;
this.anchorToBottom = anchorToBottom;
this.fillColor = fillColor;
input.addFormatter(this::formatChat);
}
public void setAllowSuggestions(boolean allowSuggestions) {
this.allowSuggestions = allowSuggestions;
if (!allowSuggestions) {
this.suggestions = null;
}
}
public void setAllowHiding(boolean allowHiding) {
this.allowHiding = allowHiding;
}
public void setRestrictions(boolean messagesAllowed, boolean commandsAllowed) {
this.messagesAllowed = messagesAllowed;
this.commandsAllowed = commandsAllowed;
}
public boolean keyPressed(KeyEvent event) {
boolean isVisible = this.suggestions != null;
if (isVisible && this.suggestions.keyPressed(event)) {
return true;
} else if (this.screen.getFocused() != this.input || !event.isCycleFocus() || this.allowHiding && !isVisible) {
return false;
} else {
this.showSuggestions(true);
return true;
}
}
public boolean mouseScrolled(double scroll) {
return this.suggestions != null && this.suggestions.mouseScrolled(Mth.clamp(scroll, -1.0, 1.0));
}
public boolean mouseClicked(MouseButtonEvent event) {
return this.suggestions != null && this.suggestions.mouseClicked((int)event.x(), (int)event.y());
}
public void showSuggestions(boolean immediateNarration) {
if (this.pendingSuggestions != null && this.pendingSuggestions.isDone()) {
Suggestions suggestions = this.pendingSuggestions.join();
if (!suggestions.isEmpty()) {
int maxSuggestionWidth = 0;
for (Suggestion suggestion : suggestions.getList()) {
maxSuggestionWidth = Math.max(maxSuggestionWidth, this.font.width(suggestion.getText()));
}
int x = Mth.clamp(
this.input.getScreenX(suggestions.getRange().getStart()), 0, this.input.getScreenX(0) + this.input.getInnerWidth() - maxSuggestionWidth
);
int y = this.anchorToBottom ? this.screen.height - 12 : 72;
this.suggestions = new CommandSuggestions.SuggestionsList(x, y, maxSuggestionWidth, this.sortSuggestions(suggestions), immediateNarration);
}
}
}
public boolean isVisible() {
return this.suggestions != null;
}
public Component getUsageNarration() {
if (this.suggestions != null && this.suggestions.tabCycles) {
return this.allowHiding
? Component.translatable("narration.suggestion.usage.cycle.hidable")
: Component.translatable("narration.suggestion.usage.cycle.fixed");
} else {
return this.allowHiding
? Component.translatable("narration.suggestion.usage.fill.hidable")
: Component.translatable("narration.suggestion.usage.fill.fixed");
}
}
public void hide() {
this.suggestions = null;
}
private List<Suggestion> sortSuggestions(Suggestions suggestions) {
String partialCommand = this.input.getValue().substring(0, this.input.getCursorPosition());
int lastWordIndex = getLastWordIndex(partialCommand);
String lastWord = partialCommand.substring(lastWordIndex).toLowerCase(Locale.ROOT);
List<Suggestion> suggestionList = Lists.newArrayList();
List<Suggestion> partial = Lists.newArrayList();
for (Suggestion suggestion : suggestions.getList()) {
if (!suggestion.getText().startsWith(lastWord) && !suggestion.getText().startsWith("minecraft:" + lastWord)) {
partial.add(suggestion);
} else {
suggestionList.add(suggestion);
}
}
suggestionList.addAll(partial);
return suggestionList;
}
public void updateCommandInfo() {
String command = this.input.getValue();
if (this.currentParse != null && !this.currentParse.getReader().getString().equals(command)) {
this.currentParse = null;
this.currentParseIsCommand = false;
this.currentParseIsMessage = false;
}
if (!this.keepSuggestions) {
this.input.setSuggestion(null);
this.suggestions = null;
}
this.commandUsage.clear();
StringReader reader = new StringReader(command);
boolean startsWithSlash = reader.canRead() && reader.peek() == '/';
if (startsWithSlash) {
reader.skip();
}
boolean isCommand = this.commandsOnly || startsWithSlash;
int cursorPosition = this.input.getCursorPosition();
if (isCommand) {
CommandDispatcher<ClientSuggestionProvider> commands = this.minecraft.player.connection.getCommands();
if (this.currentParse == null) {
this.currentParse = commands.parse(reader, this.minecraft.player.connection.getSuggestionsProvider());
this.currentParseIsCommand = true;
this.currentParseIsMessage = hasMessageArguments(this.currentParse);
}
int parseStart = this.onlyShowIfCursorPastError ? reader.getCursor() : 1;
if (cursorPosition >= parseStart && (this.suggestions == null || !this.keepSuggestions)) {
this.pendingSuggestions = commands.getCompletionSuggestions(this.currentParse, cursorPosition);
this.pendingSuggestions.thenAccept(suggestionResult -> {
if (this.pendingSuggestions.isDone()) {
this.updateUsageInfo(this.currentParse, suggestionResult);
}
});
}
} else if (!command.isBlank()) {
this.currentParseIsMessage = true;
String partialCommand = command.substring(0, cursorPosition);
int lastWord = getLastWordIndex(partialCommand);
Collection<String> nonCommandSuggestions = this.minecraft.player.connection.getSuggestionsProvider().getCustomTabSuggestions();
this.pendingSuggestions = SharedSuggestionProvider.suggest(nonCommandSuggestions, new SuggestionsBuilder(partialCommand, lastWord));
if (this.currentParseIsMessage && !this.messagesAllowed) {
this.commandUsage.add(MESSAGES_NOT_ALLOWED_TEXT.getVisualOrderText());
}
this.recomputeUsageBoxWidth();
this.commandUsagePosition = 0;
} else {
this.pendingSuggestions = null;
}
}
private static boolean hasMessageArguments(ParseResults<ClientSuggestionProvider> parseResults) {
@OnlyIn(Dist.CLIENT)
class Visitor implements ArgumentVisitor.Output<ClientSuggestionProvider> {
boolean foundMessageArgument;
@Override
public <T> void accept(
CommandContextBuilder<ClientSuggestionProvider> context,
ArgumentCommandNode<ClientSuggestionProvider, T> argument,
@Nullable ParsedArgument<ClientSuggestionProvider, T> value
) {
this.foundMessageArgument = this.foundMessageArgument | (value != null && value.getResult() instanceof MessageArgument.Message);
}
}
Visitor visitor = new Visitor();
ArgumentVisitor.visitArguments(parseResults, visitor, false);
return visitor.foundMessageArgument;
}
private static int getLastWordIndex(String text) {
if (Strings.isNullOrEmpty(text)) {
return 0;
} else {
int result = 0;
Matcher matcher = WHITESPACE_PATTERN.matcher(text);
while (matcher.find()) {
result = matcher.end();
}
return result;
}
}
private static FormattedCharSequence getExceptionMessage(CommandSyntaxException e) {
Component message = ComponentUtils.fromMessage(e.getRawMessage());
String context = e.getContext();
return context == null
? message.getVisualOrderText()
: Component.translatable("command.context.parse_error", message, e.getCursor(), context).getVisualOrderText();
}
private void updateUsageInfo(ParseResults<ClientSuggestionProvider> currentParse, Suggestions suggestions) {
boolean trailingCharacters = false;
if (this.input.getCursorPosition() == this.input.getValue().length()) {
if (suggestions.isEmpty() && !currentParse.getExceptions().isEmpty()) {
int literals = 0;
for (Entry<CommandNode<ClientSuggestionProvider>, CommandSyntaxException> entry : currentParse.getExceptions().entrySet()) {
CommandSyntaxException exception = entry.getValue();
if (exception.getType() == CommandSyntaxException.BUILT_IN_EXCEPTIONS.literalIncorrect()) {
literals++;
} else {
this.commandUsage.add(getExceptionMessage(exception));
}
}
if (literals > 0) {
this.commandUsage
.add(
getExceptionMessage(
CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().createWithContext(currentParse.getReader())
)
);
}
} else if (currentParse.getReader().canRead()) {
trailingCharacters = true;
}
}
SuggestionContext<ClientSuggestionProvider> suggestionContextAtCursor = currentParse.getContext().findSuggestionContext(this.input.getCursorPosition());
if (this.commandUsage.isEmpty()) {
List<FormattedCharSequence> usageEntries = this.fillNodeUsage(suggestionContextAtCursor, USAGE_FORMAT);
if (usageEntries.isEmpty() && trailingCharacters) {
this.commandUsage.add(getExceptionMessage(Commands.getParseException(currentParse)));
}
this.commandUsage.addAll(usageEntries);
}
if (this.currentParseIsCommand && !this.commandsAllowed) {
this.commandUsage.add(COMMANDS_NOT_ALLOWED_TEXT.getVisualOrderText());
}
if (this.currentParseIsMessage && !this.messagesAllowed) {
this.commandUsage.add(MESSAGES_NOT_ALLOWED_TEXT.getVisualOrderText());
}
this.recomputeUsageBoxWidth();
if (!this.commandUsage.isEmpty()) {
this.commandUsagePosition = Mth.clamp(
this.input.getScreenX(suggestionContextAtCursor.startPos), 0, this.input.getScreenX(0) + this.input.getInnerWidth() - this.commandUsageWidth
);
} else {
this.commandUsagePosition = 0;
}
this.suggestions = null;
if (this.allowSuggestions && this.minecraft.options.autoSuggestions().get()) {
this.showSuggestions(false);
}
}
private List<FormattedCharSequence> fillNodeUsage(SuggestionContext<ClientSuggestionProvider> suggestionContext, Style usageFormat) {
Map<CommandNode<ClientSuggestionProvider>, String> usage = this.minecraft
.player
.connection
.getCommands()
.getSmartUsage(suggestionContext.parent, this.minecraft.player.connection.getSuggestionsProvider());
List<FormattedCharSequence> lines = new ArrayList<>();
for (Entry<CommandNode<ClientSuggestionProvider>, String> entry : usage.entrySet()) {
if (!(entry.getKey() instanceof LiteralCommandNode)) {
lines.add(FormattedCharSequence.forward(entry.getValue(), usageFormat));
}
}
return lines;
}
private void recomputeUsageBoxWidth() {
int longest = 0;
for (FormattedCharSequence entry : this.commandUsage) {
longest = Math.max(longest, this.font.width(entry));
}
this.commandUsageWidth = longest;
}
private @Nullable FormattedCharSequence formatChat(String text, int offset) {
return this.currentParse != null ? formatText(this.currentParse, text, offset) : null;
}
private static @Nullable String calculateSuggestionSuffix(String contents, String suggestion) {
return suggestion.startsWith(contents) ? suggestion.substring(contents.length()) : null;
}
private static FormattedCharSequence formatText(ParseResults<ClientSuggestionProvider> currentParse, String text, int offset) {
List<FormattedCharSequence> parts = Lists.newArrayList();
int unformattedStart = 0;
int nextColor = -1;
CommandContextBuilder<ClientSuggestionProvider> context = currentParse.getContext().getLastChild();
for (ParsedArgument<ClientSuggestionProvider, ?> argument : context.getArguments().values()) {
if (++nextColor >= ARGUMENT_STYLES.size()) {
nextColor = 0;
}
int start = Math.max(argument.getRange().getStart() - offset, 0);
if (start >= text.length()) {
break;
}
int end = Math.min(argument.getRange().getEnd() - offset, text.length());
if (end > 0) {
parts.add(FormattedCharSequence.forward(text.substring(unformattedStart, start), LITERAL_STYLE));
parts.add(FormattedCharSequence.forward(text.substring(start, end), ARGUMENT_STYLES.get(nextColor)));
unformattedStart = end;
}
}
if (currentParse.getReader().canRead()) {
int startx = Math.max(currentParse.getReader().getCursor() - offset, 0);
if (startx < text.length()) {
int end = Math.min(startx + currentParse.getReader().getRemainingLength(), text.length());
parts.add(FormattedCharSequence.forward(text.substring(unformattedStart, startx), LITERAL_STYLE));
parts.add(FormattedCharSequence.forward(text.substring(startx, end), UNPARSED_STYLE));
unformattedStart = end;
}
}
parts.add(FormattedCharSequence.forward(text.substring(unformattedStart), LITERAL_STYLE));
return FormattedCharSequence.composite(parts);
}
public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY) {
if (!this.extractSuggestions(graphics, mouseX, mouseY)) {
this.extractUsage(graphics);
}
}
public boolean extractSuggestions(GuiGraphicsExtractor graphics, int mouseX, int mouseY) {
if (this.suggestions != null) {
this.suggestions.extractRenderState(graphics, mouseX, mouseY);
return true;
} else {
return false;
}
}
public void extractUsage(GuiGraphicsExtractor graphics) {
int y = 0;
for (FormattedCharSequence line : this.commandUsage) {
int lineY = this.anchorToBottom ? this.screen.height - 27 - 12 * y : 72 + 12 * y;
graphics.fill(this.commandUsagePosition - 1, lineY, this.commandUsagePosition + this.commandUsageWidth + 1, lineY + 12, this.fillColor);
graphics.text(this.font, line, this.commandUsagePosition, lineY + 2, -1);
y++;
}
}
public Component getNarrationMessage() {
return (Component)(this.suggestions != null ? CommonComponents.NEW_LINE.copy().append(this.suggestions.getNarrationMessage()) : CommonComponents.EMPTY);
}
public boolean hasAllowedInput() {
return this.currentParseIsMessage && !this.messagesAllowed ? false : !this.currentParseIsCommand || this.commandsAllowed;
}
@OnlyIn(Dist.CLIENT)
public class SuggestionsList {
private final Rect2i rect;
private final String originalContents;
private final List<Suggestion> suggestionList;
private int offset;
private int current;
private Vec2 lastMouse;
private boolean tabCycles;
private int lastNarratedEntry;
private SuggestionsList(int x, int y, int width, List<Suggestion> suggestionList, boolean immediateNarration) {
Objects.requireNonNull(CommandSuggestions.this);
super();
this.lastMouse = Vec2.ZERO;
int listX = x - (CommandSuggestions.this.input.isBordered() ? 0 : 1);
int listY = CommandSuggestions.this.anchorToBottom
? y - 3 - Math.min(suggestionList.size(), CommandSuggestions.this.suggestionLineLimit) * 12
: y - (CommandSuggestions.this.input.isBordered() ? 1 : 0);
this.rect = new Rect2i(listX, listY, width + 1, Math.min(suggestionList.size(), CommandSuggestions.this.suggestionLineLimit) * 12);
this.originalContents = CommandSuggestions.this.input.getValue();
this.lastNarratedEntry = immediateNarration ? -1 : 0;
this.suggestionList = suggestionList;
this.select(0);
}
public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY) {
int limit = Math.min(this.suggestionList.size(), CommandSuggestions.this.suggestionLineLimit);
int unselectedColor = -5592406;
boolean hasPrevious = this.offset > 0;
boolean hasNext = this.suggestionList.size() > this.offset + limit;
boolean limited = hasPrevious || hasNext;
boolean mouseMoved = this.lastMouse.x != mouseX || this.lastMouse.y != mouseY;
if (mouseMoved) {
this.lastMouse = new Vec2(mouseX, mouseY);
}
if (limited) {
graphics.fill(
this.rect.getX(), this.rect.getY() - 1, this.rect.getX() + this.rect.getWidth(), this.rect.getY(), CommandSuggestions.this.fillColor
);
graphics.fill(
this.rect.getX(),
this.rect.getY() + this.rect.getHeight(),
this.rect.getX() + this.rect.getWidth(),
this.rect.getY() + this.rect.getHeight() + 1,
CommandSuggestions.this.fillColor
);
if (hasPrevious) {
for (int x = 0; x < this.rect.getWidth(); x++) {
if (x % 2 == 0) {
graphics.fill(this.rect.getX() + x, this.rect.getY() - 1, this.rect.getX() + x + 1, this.rect.getY(), -1);
}
}
}
if (hasNext) {
for (int xx = 0; xx < this.rect.getWidth(); xx++) {
if (xx % 2 == 0) {
graphics.fill(
this.rect.getX() + xx,
this.rect.getY() + this.rect.getHeight(),
this.rect.getX() + xx + 1,
this.rect.getY() + this.rect.getHeight() + 1,
-1
);
}
}
}
}
boolean hovered = false;
for (int i = 0; i < limit; i++) {
Suggestion suggestion = this.suggestionList.get(i + this.offset);
graphics.fill(
this.rect.getX(),
this.rect.getY() + 12 * i,
this.rect.getX() + this.rect.getWidth(),
this.rect.getY() + 12 * i + 12,
CommandSuggestions.this.fillColor
);
if (mouseX > this.rect.getX()
&& mouseX < this.rect.getX() + this.rect.getWidth()
&& mouseY > this.rect.getY() + 12 * i
&& mouseY < this.rect.getY() + 12 * i + 12) {
if (mouseMoved) {
this.select(i + this.offset);
}
hovered = true;
}
graphics.text(
CommandSuggestions.this.font,
suggestion.getText(),
this.rect.getX() + 1,
this.rect.getY() + 2 + 12 * i,
i + this.offset == this.current ? -256 : -5592406
);
}
if (hovered) {
Message tooltip = this.suggestionList.get(this.current).getTooltip();
if (tooltip != null) {
graphics.setTooltipForNextFrame(CommandSuggestions.this.font, ComponentUtils.fromMessage(tooltip), mouseX, mouseY);
}
}
if (this.rect.contains(mouseX, mouseY)) {
graphics.requestCursor(CursorTypes.POINTING_HAND);
}
}
public boolean mouseClicked(int x, int y) {
if (!this.rect.contains(x, y)) {
return false;
} else {
int line = (y - this.rect.getY()) / 12 + this.offset;
if (line >= 0 && line < this.suggestionList.size()) {
this.select(line);
this.useSuggestion();
}
return true;
}
}
public boolean mouseScrolled(double scroll) {
int mouseX = (int)CommandSuggestions.this.minecraft.mouseHandler.getScaledXPos(CommandSuggestions.this.minecraft.getWindow());
int mouseY = (int)CommandSuggestions.this.minecraft.mouseHandler.getScaledYPos(CommandSuggestions.this.minecraft.getWindow());
if (this.rect.contains(mouseX, mouseY)) {
this.offset = Mth.clamp((int)(this.offset - scroll), 0, Math.max(this.suggestionList.size() - CommandSuggestions.this.suggestionLineLimit, 0));
return true;
} else {
return false;
}
}
public boolean keyPressed(KeyEvent event) {
if (event.isUp()) {
this.cycle(-1);
this.tabCycles = false;
return true;
} else if (event.isDown()) {
this.cycle(1);
this.tabCycles = false;
return true;
} else if (event.isCycleFocus()) {
if (this.tabCycles) {
this.cycle(event.hasShiftDown() ? -1 : 1);
}
this.useSuggestion();
return true;
} else if (event.isEscape()) {
CommandSuggestions.this.hide();
CommandSuggestions.this.input.setSuggestion(null);
return true;
} else {
return false;
}
}
public void cycle(int direction) {
this.select(this.current + direction);
int first = this.offset;
int last = this.offset + CommandSuggestions.this.suggestionLineLimit - 1;
if (this.current < first) {
this.offset = Mth.clamp(this.current, 0, Math.max(this.suggestionList.size() - CommandSuggestions.this.suggestionLineLimit, 0));
} else if (this.current > last) {
this.offset = Mth.clamp(
this.current + CommandSuggestions.this.lineStartOffset - CommandSuggestions.this.suggestionLineLimit,
0,
Math.max(this.suggestionList.size() - CommandSuggestions.this.suggestionLineLimit, 0)
);
}
}
public void select(int index) {
this.current = index;
if (this.current < 0) {
this.current = this.current + this.suggestionList.size();
}
if (this.current >= this.suggestionList.size()) {
this.current = this.current - this.suggestionList.size();
}
Suggestion suggestion = this.suggestionList.get(this.current);
CommandSuggestions.this.input
.setSuggestion(CommandSuggestions.calculateSuggestionSuffix(CommandSuggestions.this.input.getValue(), suggestion.apply(this.originalContents)));
if (this.lastNarratedEntry != this.current) {
CommandSuggestions.this.minecraft.getNarrator().saySystemNow(this.getNarrationMessage());
}
}
public void useSuggestion() {
Suggestion suggestion = this.suggestionList.get(this.current);
CommandSuggestions.this.keepSuggestions = true;
CommandSuggestions.this.input.setValue(suggestion.apply(this.originalContents));
int end = suggestion.getRange().getStart() + suggestion.getText().length();
CommandSuggestions.this.input.setCursorPosition(end);
CommandSuggestions.this.input.setHighlightPos(end);
this.select(this.current);
CommandSuggestions.this.keepSuggestions = false;
this.tabCycles = true;
}
private Component getNarrationMessage() {
this.lastNarratedEntry = this.current;
Suggestion suggestion = this.suggestionList.get(this.current);
Message tooltip = suggestion.getTooltip();
return tooltip != null
? Component.translatable(
"narration.suggestion.tooltip", this.current + 1, this.suggestionList.size(), suggestion.getText(), Component.translationArg(tooltip)
)
: Component.translatable("narration.suggestion", this.current + 1, this.suggestionList.size(), suggestion.getText());
}
}
}引用的其他类
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
Rect2i()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
ArgumentVisitor.visitArguments()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Commands.getParseException()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
SharedSuggestionProvider.suggest()
- 引用位置:
-
- 引用位置:
字段/方法调用/返回值 - 关联成员:
Component.translatable(), Component.translationArg()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
ComponentUtils.fromMessage()
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
字段/方法调用/返回值 - 关联成员:
FormattedCharSequence.composite(), FormattedCharSequence.forward()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Mth.clamp()
- 引用位置:
-
- 引用位置:
字段/方法调用 - 关联成员:
Pattern.compile()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
Vec2()
- 引用位置: