388 lines
16 KiB
Java
388 lines
16 KiB
Java
package com.mojang.realmsclient.gui.screens;
|
|
|
|
import com.google.common.collect.Lists;
|
|
import com.mojang.datafixers.util.Either;
|
|
import com.mojang.logging.LogUtils;
|
|
import com.mojang.realmsclient.client.RealmsClient;
|
|
import com.mojang.realmsclient.dto.WorldTemplate;
|
|
import com.mojang.realmsclient.dto.WorldTemplatePaginatedList;
|
|
import com.mojang.realmsclient.dto.RealmsServer.WorldType;
|
|
import com.mojang.realmsclient.exception.RealmsServiceException;
|
|
import com.mojang.realmsclient.util.RealmsTextureManager;
|
|
import com.mojang.realmsclient.util.TextRenderingUtils;
|
|
import com.mojang.realmsclient.util.TextRenderingUtils.Line;
|
|
import com.mojang.realmsclient.util.TextRenderingUtils.LineSegment;
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import java.util.function.Consumer;
|
|
import java.util.stream.Collectors;
|
|
import net.fabricmc.api.EnvType;
|
|
import net.fabricmc.api.Environment;
|
|
import net.minecraft.Util;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.client.gui.GuiGraphics;
|
|
import net.minecraft.client.gui.components.AbstractWidget;
|
|
import net.minecraft.client.gui.components.Button;
|
|
import net.minecraft.client.gui.components.ImageButton;
|
|
import net.minecraft.client.gui.components.ObjectSelectionList;
|
|
import net.minecraft.client.gui.components.Tooltip;
|
|
import net.minecraft.client.gui.components.WidgetSprites;
|
|
import net.minecraft.client.gui.layouts.HeaderAndFooterLayout;
|
|
import net.minecraft.client.gui.layouts.LinearLayout;
|
|
import net.minecraft.client.gui.screens.ConfirmLinkScreen;
|
|
import net.minecraft.client.renderer.RenderType;
|
|
import net.minecraft.client.resources.language.I18n;
|
|
import net.minecraft.network.chat.CommonComponents;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.realms.RealmsScreen;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import net.minecraft.util.CommonLinks;
|
|
import org.jetbrains.annotations.Nullable;
|
|
import org.slf4j.Logger;
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public class RealmsSelectWorldTemplateScreen extends RealmsScreen {
|
|
static final Logger LOGGER = LogUtils.getLogger();
|
|
static final ResourceLocation SLOT_FRAME_SPRITE = ResourceLocation.withDefaultNamespace("widget/slot_frame");
|
|
private static final Component SELECT_BUTTON_NAME = Component.translatable("mco.template.button.select");
|
|
private static final Component TRAILER_BUTTON_NAME = Component.translatable("mco.template.button.trailer");
|
|
private static final Component PUBLISHER_BUTTON_NAME = Component.translatable("mco.template.button.publisher");
|
|
private static final int BUTTON_WIDTH = 100;
|
|
private static final int BUTTON_SPACING = 10;
|
|
private final HeaderAndFooterLayout layout = new HeaderAndFooterLayout(this);
|
|
final Consumer<WorldTemplate> callback;
|
|
RealmsSelectWorldTemplateScreen.WorldTemplateList worldTemplateList;
|
|
private final WorldType worldType;
|
|
private Button selectButton;
|
|
private Button trailerButton;
|
|
private Button publisherButton;
|
|
@Nullable
|
|
WorldTemplate selectedTemplate = null;
|
|
@Nullable
|
|
String currentLink;
|
|
@Nullable
|
|
private Component[] warning;
|
|
@Nullable
|
|
List<Line> noTemplatesMessage;
|
|
|
|
public RealmsSelectWorldTemplateScreen(Component title, Consumer<WorldTemplate> callback, WorldType worldType) {
|
|
this(title, callback, worldType, null);
|
|
}
|
|
|
|
public RealmsSelectWorldTemplateScreen(
|
|
Component title, Consumer<WorldTemplate> callback, WorldType worldType, @Nullable WorldTemplatePaginatedList worldTemplatePaginatedList
|
|
) {
|
|
super(title);
|
|
this.callback = callback;
|
|
this.worldType = worldType;
|
|
if (worldTemplatePaginatedList == null) {
|
|
this.worldTemplateList = new RealmsSelectWorldTemplateScreen.WorldTemplateList();
|
|
this.fetchTemplatesAsync(new WorldTemplatePaginatedList(10));
|
|
} else {
|
|
this.worldTemplateList = new RealmsSelectWorldTemplateScreen.WorldTemplateList(Lists.<WorldTemplate>newArrayList(worldTemplatePaginatedList.templates));
|
|
this.fetchTemplatesAsync(worldTemplatePaginatedList);
|
|
}
|
|
}
|
|
|
|
public void setWarning(Component... warning) {
|
|
this.warning = warning;
|
|
}
|
|
|
|
@Override
|
|
public void init() {
|
|
this.layout.addTitleHeader(this.title, this.font);
|
|
this.worldTemplateList = this.layout.addToContents(new RealmsSelectWorldTemplateScreen.WorldTemplateList(this.worldTemplateList.getTemplates()));
|
|
LinearLayout linearLayout = this.layout.addToFooter(LinearLayout.horizontal().spacing(10));
|
|
linearLayout.defaultCellSetting().alignHorizontallyCenter();
|
|
this.trailerButton = linearLayout.addChild(Button.builder(TRAILER_BUTTON_NAME, button -> this.onTrailer()).width(100).build());
|
|
this.selectButton = linearLayout.addChild(Button.builder(SELECT_BUTTON_NAME, button -> this.selectTemplate()).width(100).build());
|
|
linearLayout.addChild(Button.builder(CommonComponents.GUI_CANCEL, button -> this.onClose()).width(100).build());
|
|
this.publisherButton = linearLayout.addChild(Button.builder(PUBLISHER_BUTTON_NAME, button -> this.onPublish()).width(100).build());
|
|
this.updateButtonStates();
|
|
this.layout.visitWidgets(guiEventListener -> {
|
|
AbstractWidget var10000 = this.addRenderableWidget(guiEventListener);
|
|
});
|
|
this.repositionElements();
|
|
}
|
|
|
|
@Override
|
|
protected void repositionElements() {
|
|
this.worldTemplateList.setSize(this.width, this.height - this.layout.getFooterHeight() - this.getHeaderHeight());
|
|
this.layout.arrangeElements();
|
|
}
|
|
|
|
@Override
|
|
public Component getNarrationMessage() {
|
|
List<Component> list = Lists.<Component>newArrayListWithCapacity(2);
|
|
list.add(this.title);
|
|
if (this.warning != null) {
|
|
list.addAll(Arrays.asList(this.warning));
|
|
}
|
|
|
|
return CommonComponents.joinLines(list);
|
|
}
|
|
|
|
void updateButtonStates() {
|
|
this.publisherButton.visible = this.selectedTemplate != null && !this.selectedTemplate.link.isEmpty();
|
|
this.trailerButton.visible = this.selectedTemplate != null && !this.selectedTemplate.trailer.isEmpty();
|
|
this.selectButton.active = this.selectedTemplate != null;
|
|
}
|
|
|
|
@Override
|
|
public void onClose() {
|
|
this.callback.accept(null);
|
|
}
|
|
|
|
private void selectTemplate() {
|
|
if (this.selectedTemplate != null) {
|
|
this.callback.accept(this.selectedTemplate);
|
|
}
|
|
}
|
|
|
|
private void onTrailer() {
|
|
if (this.selectedTemplate != null && !this.selectedTemplate.trailer.isBlank()) {
|
|
ConfirmLinkScreen.confirmLinkNow(this, this.selectedTemplate.trailer);
|
|
}
|
|
}
|
|
|
|
private void onPublish() {
|
|
if (this.selectedTemplate != null && !this.selectedTemplate.link.isBlank()) {
|
|
ConfirmLinkScreen.confirmLinkNow(this, this.selectedTemplate.link);
|
|
}
|
|
}
|
|
|
|
private void fetchTemplatesAsync(WorldTemplatePaginatedList output) {
|
|
(new Thread("realms-template-fetcher") {
|
|
public void run() {
|
|
WorldTemplatePaginatedList worldTemplatePaginatedList = output;
|
|
RealmsClient realmsClient = RealmsClient.getOrCreate();
|
|
|
|
while (worldTemplatePaginatedList != null) {
|
|
Either<WorldTemplatePaginatedList, Exception> either = RealmsSelectWorldTemplateScreen.this.fetchTemplates(worldTemplatePaginatedList, realmsClient);
|
|
worldTemplatePaginatedList = (WorldTemplatePaginatedList)RealmsSelectWorldTemplateScreen.this.minecraft.submit(() -> {
|
|
if (either.right().isPresent()) {
|
|
RealmsSelectWorldTemplateScreen.LOGGER.error("Couldn't fetch templates", (Throwable)either.right().get());
|
|
if (RealmsSelectWorldTemplateScreen.this.worldTemplateList.isEmpty()) {
|
|
RealmsSelectWorldTemplateScreen.this.noTemplatesMessage = TextRenderingUtils.decompose(I18n.get("mco.template.select.failure"));
|
|
}
|
|
|
|
return null;
|
|
} else {
|
|
WorldTemplatePaginatedList worldTemplatePaginatedListx = (WorldTemplatePaginatedList)either.left().get();
|
|
|
|
for (WorldTemplate worldTemplate : worldTemplatePaginatedListx.templates) {
|
|
RealmsSelectWorldTemplateScreen.this.worldTemplateList.addEntry(worldTemplate);
|
|
}
|
|
|
|
if (worldTemplatePaginatedListx.templates.isEmpty()) {
|
|
if (RealmsSelectWorldTemplateScreen.this.worldTemplateList.isEmpty()) {
|
|
String string = I18n.get("mco.template.select.none", "%link");
|
|
LineSegment lineSegment = LineSegment.link(I18n.get("mco.template.select.none.linkTitle"), CommonLinks.REALMS_CONTENT_CREATION.toString());
|
|
RealmsSelectWorldTemplateScreen.this.noTemplatesMessage = TextRenderingUtils.decompose(string, lineSegment);
|
|
}
|
|
|
|
return null;
|
|
} else {
|
|
return worldTemplatePaginatedListx;
|
|
}
|
|
}
|
|
}).join();
|
|
}
|
|
}
|
|
}).start();
|
|
}
|
|
|
|
Either<WorldTemplatePaginatedList, Exception> fetchTemplates(WorldTemplatePaginatedList templates, RealmsClient realmsClient) {
|
|
try {
|
|
return Either.left(realmsClient.fetchWorldTemplates(templates.page + 1, templates.size, this.worldType));
|
|
} catch (RealmsServiceException var4) {
|
|
return Either.right(var4);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
|
|
super.render(guiGraphics, mouseX, mouseY, partialTick);
|
|
this.currentLink = null;
|
|
if (this.noTemplatesMessage != null) {
|
|
this.renderMultilineMessage(guiGraphics, mouseX, mouseY, this.noTemplatesMessage);
|
|
}
|
|
|
|
if (this.warning != null) {
|
|
for (int i = 0; i < this.warning.length; i++) {
|
|
Component component = this.warning[i];
|
|
guiGraphics.drawCenteredString(this.font, component, this.width / 2, row(-1 + i), -6250336);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void renderMultilineMessage(GuiGraphics guiGraphics, int x, int y, List<Line> lines) {
|
|
for (int i = 0; i < lines.size(); i++) {
|
|
Line line = (Line)lines.get(i);
|
|
int j = row(4 + i);
|
|
int k = line.segments.stream().mapToInt(lineSegmentx -> this.font.width(lineSegmentx.renderedText())).sum();
|
|
int l = this.width / 2 - k / 2;
|
|
|
|
for (LineSegment lineSegment : line.segments) {
|
|
int m = lineSegment.isLink() ? 3368635 : -1;
|
|
int n = guiGraphics.drawString(this.font, lineSegment.renderedText(), l, j, m);
|
|
if (lineSegment.isLink() && x > l && x < n && y > j - 3 && y < j + 8) {
|
|
this.setTooltipForNextRenderPass(Component.literal(lineSegment.getLinkUrl()));
|
|
this.currentLink = lineSegment.getLinkUrl();
|
|
}
|
|
|
|
l = n;
|
|
}
|
|
}
|
|
}
|
|
|
|
int getHeaderHeight() {
|
|
return this.warning != null ? row(1) : 33;
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
class Entry extends ObjectSelectionList.Entry<RealmsSelectWorldTemplateScreen.Entry> {
|
|
private static final WidgetSprites WEBSITE_LINK_SPRITES = new WidgetSprites(
|
|
ResourceLocation.withDefaultNamespace("icon/link"), ResourceLocation.withDefaultNamespace("icon/link_highlighted")
|
|
);
|
|
private static final WidgetSprites TRAILER_LINK_SPRITES = new WidgetSprites(
|
|
ResourceLocation.withDefaultNamespace("icon/video_link"), ResourceLocation.withDefaultNamespace("icon/video_link_highlighted")
|
|
);
|
|
private static final Component PUBLISHER_LINK_TOOLTIP = Component.translatable("mco.template.info.tooltip");
|
|
private static final Component TRAILER_LINK_TOOLTIP = Component.translatable("mco.template.trailer.tooltip");
|
|
public final WorldTemplate template;
|
|
private long lastClickTime;
|
|
@Nullable
|
|
private ImageButton websiteButton;
|
|
@Nullable
|
|
private ImageButton trailerButton;
|
|
|
|
public Entry(final WorldTemplate template) {
|
|
this.template = template;
|
|
if (!template.link.isBlank()) {
|
|
this.websiteButton = new ImageButton(
|
|
15, 15, WEBSITE_LINK_SPRITES, ConfirmLinkScreen.confirmLink(RealmsSelectWorldTemplateScreen.this, template.link), PUBLISHER_LINK_TOOLTIP
|
|
);
|
|
this.websiteButton.setTooltip(Tooltip.create(PUBLISHER_LINK_TOOLTIP));
|
|
}
|
|
|
|
if (!template.trailer.isBlank()) {
|
|
this.trailerButton = new ImageButton(
|
|
15, 15, TRAILER_LINK_SPRITES, ConfirmLinkScreen.confirmLink(RealmsSelectWorldTemplateScreen.this, template.trailer), TRAILER_LINK_TOOLTIP
|
|
);
|
|
this.trailerButton.setTooltip(Tooltip.create(TRAILER_LINK_TOOLTIP));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
|
RealmsSelectWorldTemplateScreen.this.selectedTemplate = this.template;
|
|
RealmsSelectWorldTemplateScreen.this.updateButtonStates();
|
|
if (Util.getMillis() - this.lastClickTime < 250L && this.isFocused()) {
|
|
RealmsSelectWorldTemplateScreen.this.callback.accept(this.template);
|
|
}
|
|
|
|
this.lastClickTime = Util.getMillis();
|
|
if (this.websiteButton != null) {
|
|
this.websiteButton.mouseClicked(mouseX, mouseY, button);
|
|
}
|
|
|
|
if (this.trailerButton != null) {
|
|
this.trailerButton.mouseClicked(mouseX, mouseY, button);
|
|
}
|
|
|
|
return super.mouseClicked(mouseX, mouseY, button);
|
|
}
|
|
|
|
@Override
|
|
public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) {
|
|
guiGraphics.blit(
|
|
RenderType::guiTextured, RealmsTextureManager.worldTemplate(this.template.id, this.template.image), left + 1, top + 1 + 1, 0.0F, 0.0F, 38, 38, 38, 38
|
|
);
|
|
guiGraphics.blitSprite(RenderType::guiTextured, RealmsSelectWorldTemplateScreen.SLOT_FRAME_SPRITE, left, top + 1, 40, 40);
|
|
int i = 5;
|
|
int j = RealmsSelectWorldTemplateScreen.this.font.width(this.template.version);
|
|
if (this.websiteButton != null) {
|
|
this.websiteButton.setPosition(left + width - j - this.websiteButton.getWidth() - 10, top);
|
|
this.websiteButton.render(guiGraphics, mouseX, mouseY, partialTick);
|
|
}
|
|
|
|
if (this.trailerButton != null) {
|
|
this.trailerButton.setPosition(left + width - j - this.trailerButton.getWidth() * 2 - 15, top);
|
|
this.trailerButton.render(guiGraphics, mouseX, mouseY, partialTick);
|
|
}
|
|
|
|
int k = left + 45 + 20;
|
|
int l = top + 5;
|
|
guiGraphics.drawString(RealmsSelectWorldTemplateScreen.this.font, this.template.name, k, l, -1);
|
|
guiGraphics.drawString(RealmsSelectWorldTemplateScreen.this.font, this.template.version, left + width - j - 5, l, 7105644);
|
|
guiGraphics.drawString(RealmsSelectWorldTemplateScreen.this.font, this.template.author, k, l + 9 + 5, -6250336);
|
|
if (!this.template.recommendedPlayers.isBlank()) {
|
|
guiGraphics.drawString(RealmsSelectWorldTemplateScreen.this.font, this.template.recommendedPlayers, k, top + height - 9 / 2 - 5, 5000268);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public Component getNarration() {
|
|
Component component = CommonComponents.joinLines(
|
|
Component.literal(this.template.name),
|
|
Component.translatable("mco.template.select.narrate.authors", this.template.author),
|
|
Component.literal(this.template.recommendedPlayers),
|
|
Component.translatable("mco.template.select.narrate.version", this.template.version)
|
|
);
|
|
return Component.translatable("narrator.select", component);
|
|
}
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
class WorldTemplateList extends ObjectSelectionList<RealmsSelectWorldTemplateScreen.Entry> {
|
|
public WorldTemplateList() {
|
|
this(Collections.emptyList());
|
|
}
|
|
|
|
public WorldTemplateList(final Iterable<WorldTemplate> templates) {
|
|
super(
|
|
Minecraft.getInstance(),
|
|
RealmsSelectWorldTemplateScreen.this.width,
|
|
RealmsSelectWorldTemplateScreen.this.height - 33 - RealmsSelectWorldTemplateScreen.this.getHeaderHeight(),
|
|
RealmsSelectWorldTemplateScreen.this.getHeaderHeight(),
|
|
46
|
|
);
|
|
templates.forEach(this::addEntry);
|
|
}
|
|
|
|
public void addEntry(WorldTemplate template) {
|
|
this.addEntry(RealmsSelectWorldTemplateScreen.this.new Entry(template));
|
|
}
|
|
|
|
@Override
|
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
|
if (RealmsSelectWorldTemplateScreen.this.currentLink != null) {
|
|
ConfirmLinkScreen.confirmLinkNow(RealmsSelectWorldTemplateScreen.this, RealmsSelectWorldTemplateScreen.this.currentLink);
|
|
return true;
|
|
} else {
|
|
return super.mouseClicked(mouseX, mouseY, button);
|
|
}
|
|
}
|
|
|
|
public void setSelected(@Nullable RealmsSelectWorldTemplateScreen.Entry entry) {
|
|
super.setSelected(entry);
|
|
RealmsSelectWorldTemplateScreen.this.selectedTemplate = entry == null ? null : entry.template;
|
|
RealmsSelectWorldTemplateScreen.this.updateButtonStates();
|
|
}
|
|
|
|
@Override
|
|
public int getRowWidth() {
|
|
return 300;
|
|
}
|
|
|
|
public boolean isEmpty() {
|
|
return this.getItemCount() == 0;
|
|
}
|
|
|
|
public List<WorldTemplate> getTemplates() {
|
|
return (List<WorldTemplate>)this.children().stream().map(entry -> entry.template).collect(Collectors.toList());
|
|
}
|
|
}
|
|
}
|