Skip to content

Commit

Permalink
Introduce "GotoScreenTab" concept
Browse files Browse the repository at this point in the history
The `Tab` implementation provides a method to produce a list of `TargetListEntries`.

Currently, the only implementation is `PlayerTab`, which provides a list of `PlayerListEntries` & a "perspective" button.
  • Loading branch information
MattSturgeon committed Jan 4, 2024
1 parent 7db712a commit aef98cb
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 42 deletions.
2 changes: 2 additions & 0 deletions common/src/main/java/net/xolt/freecam/config/ModConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import me.shedaniel.autoconfig.serializer.JanksonConfigSerializer;
import me.shedaniel.clothconfig2.gui.entries.SelectionListEntry;
import net.minecraft.client.gui.screens.Screen;
import net.xolt.freecam.gui.go.tabs.GotoScreenTab;
import net.xolt.freecam.variant.api.BuildVariant;
import org.jetbrains.annotations.NotNull;

Expand Down Expand Up @@ -125,6 +126,7 @@ public static class NotificationConfig {
@ConfigEntry.Gui.Excluded
public Hidden hidden = new Hidden();
public static class Hidden {
public GotoScreenTab currentTab = GotoScreenTab.PLAYER;
public Perspective gotoPlayerPerspective = Perspective.THIRD_PERSON;
}

Expand Down
25 changes: 10 additions & 15 deletions common/src/main/java/net/xolt/freecam/gui/go/GotoScreen.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.CycleButton;
import net.minecraft.client.gui.components.Tooltip;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.layouts.FrameLayout;
Expand All @@ -16,6 +15,7 @@
import net.xolt.freecam.Freecam;
import net.xolt.freecam.config.ModConfig;
import net.xolt.freecam.gui.textures.ScaledTexture;
import net.xolt.freecam.gui.go.tabs.GotoScreenTab;
import org.jetbrains.annotations.Nullable;

import java.util.Objects;
Expand All @@ -35,7 +35,6 @@ public class GotoScreen extends Screen {
private TargetsPane targets;
private Button buttonBack;
private Button buttonJump;
private CycleButton<ModConfig.Perspective> buttonPerspective;
private boolean initialized;

public GotoScreen() {
Expand All @@ -47,27 +46,17 @@ protected void init() {
super.init();

if (!initialized) {
targets = new TargetsPane(LIST_TOP, width, height);
targets = new TargetsPane(LIST_TOP, width, height, ModConfig.get().hidden.currentTab);

buttonJump = Button.builder(Component.translatable("gui.freecam.goto.button.go"), button -> targets.gotoTarget())
.tooltip(Tooltip.create(Component.translatable("gui.freecam.goto.button.go.@Tooltip")))
.width(48)
.build();

buttonPerspective = CycleButton
.builder((ModConfig.Perspective value) -> Component.translatable(value.getKey()))
.withValues(ModConfig.Perspective.values())
.withInitialValue(ModConfig.get().hidden.gotoPlayerPerspective)
.withTooltip(value -> Tooltip.create(Component.translatable("gui.freecam.goto.button.perspective.@Tooltip")))
.displayOnlyValue()
.create(0, 0, 80, 20, null, (button, value) -> {
ModConfig.get().hidden.gotoPlayerPerspective = value;
ModConfig.save();
});

buttonBack = Button.builder(CommonComponents.GUI_BACK, button -> onClose()).width(48).build();
}

targets.setTab(ModConfig.get().hidden.currentTab);
targets.setSize(width, getListHeight());

int innerWidth = GUI_WIDTH - 10;
Expand All @@ -82,7 +71,7 @@ protected void init() {
.paddingHorizontal(2);

layout.addChild(buttonBack);
layout.addChild(buttonPerspective);
ModConfig.get().hidden.currentTab.extraButtons().forEach(layout::addChild);
layout.addChild(buttonJump);

positioner.arrangeElements();
Expand Down Expand Up @@ -139,6 +128,12 @@ public boolean isPauseScreen() {
return false;
}

public void setTab(GotoScreenTab tab) {
ModConfig.get().hidden.currentTab = tab;
ModConfig.save();
init();
}

// GUI height
private int getGuiHeight() {
return Math.max(MIN_GUI_HEIGHT, height - (GUI_TOP * 2));
Expand Down
40 changes: 13 additions & 27 deletions common/src/main/java/net/xolt/freecam/gui/go/TargetsPane.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
import net.minecraft.resources.ResourceLocation;
import net.xolt.freecam.Freecam;
import net.xolt.freecam.gui.textures.ScaledTexture;
import net.xolt.freecam.util.FreeCamera;
import net.xolt.freecam.variant.api.BuildVariant;
import net.xolt.freecam.gui.go.tabs.GotoScreenTab;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;

import java.util.*;
import java.util.stream.Collectors;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;

import static net.xolt.freecam.Freecam.MC;

Expand All @@ -39,11 +40,13 @@ public class TargetsPane extends AbstractContainerWidget implements Tickable {
private final TargetListWidget list;
private final List<AbstractWidget> children;

private GotoScreenTab currentTab;
private String currentSearch;

public TargetsPane(int top, int width, int height) {
public TargetsPane(int top, int width, int height, GotoScreenTab tab) {
super(0, top, width, height, Component.empty());

this.currentTab = tab;
this.list = new TargetListWidget(top + LIST_Y_OFFSET, width, height - LIST_Y_OFFSET - 1, LIST_ITEM_HEIGHT);
this.searchBox = new EditBox(MC.font, list.getRowWidth() - SEARCH_X_OFFSET - 1, SEARCH_HEIGHT, SEARCH_TEXT);
this.searchBox.setPosition(renderX() + SEARCH_X_OFFSET, getY() + SEARCH_Y_OFFSET);
Expand Down Expand Up @@ -80,7 +83,7 @@ protected void updateWidgetNarration(NarrationElementOutput narrationElementOutp

@Override
public void tick() {
list.replaceEntries(calculatePlayerEntries().stream()
list.replaceEntries(currentTab.provideEntriesFor(list).stream()
.filter(entry -> currentSearch == null
|| currentSearch.isEmpty()
|| entry.matchesSearch(currentSearch))
Expand Down Expand Up @@ -161,27 +164,6 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
return false;
}

private List<TargetListEntry> calculatePlayerEntries() {
// Store the existing entries in a UUID map for easy lookup
Map<UUID, PlayerListEntry> currentEntries = list.children()
.parallelStream()
.filter(PlayerListEntry.class::isInstance)
.map(PlayerListEntry.class::cast)
.collect(Collectors.toUnmodifiableMap(PlayerListEntry::getUUID, entry -> entry));

// Map the in-range players into PlayerListEntries
// Use existing entries if possible
return MC.level.players()
.parallelStream()
.filter(player -> !(player instanceof FreeCamera))
.filter(player -> BuildVariant.getInstance().cheatsPermitted() || Objects.equals(MC.player, player)) // TODO check if player is visible
.map(player -> Objects.requireNonNullElseGet(
currentEntries.get(player.getUUID()),
() -> new PlayerListEntry(list, player)))
.map(TargetListEntry.class::cast)
.toList();
}

private int renderWidth() {
return list.getRowWidth() + 2;
}
Expand All @@ -190,6 +172,10 @@ private int renderX() {
return (width - renderWidth()) / 2;
}

public void setTab(GotoScreenTab tab) {
this.currentTab = tab;
}

/**
* @return whether a text entry widget is in focus.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package net.xolt.freecam.gui.go.tabs;

import net.minecraft.client.gui.components.AbstractButton;
import net.xolt.freecam.gui.go.TargetListEntry;
import net.xolt.freecam.gui.go.TargetListWidget;

import java.util.List;

public enum GotoScreenTab implements Tab {
PLAYER(new PlayerTab());

private final Tab implementation;

GotoScreenTab(Tab tab) {
this.implementation = tab;
}

@Override
public List<TargetListEntry> provideEntriesFor(TargetListWidget widget) {
return implementation.provideEntriesFor(widget);
}

@Override
public List<AbstractButton> extraButtons() {
return implementation.extraButtons();
}
}
67 changes: 67 additions & 0 deletions common/src/main/java/net/xolt/freecam/gui/go/tabs/PlayerTab.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package net.xolt.freecam.gui.go.tabs;

import com.google.common.base.Suppliers;
import net.minecraft.client.gui.components.AbstractButton;
import net.minecraft.client.gui.components.CycleButton;
import net.minecraft.client.gui.components.Tooltip;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.network.chat.Component;
import net.xolt.freecam.config.ModConfig;
import net.xolt.freecam.gui.go.PlayerListEntry;
import net.xolt.freecam.gui.go.TargetListEntry;
import net.xolt.freecam.gui.go.TargetListWidget;
import net.xolt.freecam.util.FreeCamera;
import net.xolt.freecam.variant.api.BuildVariant;

import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import static net.xolt.freecam.Freecam.MC;

class PlayerTab implements Tab {

private final Supplier<CycleButton<ModConfig.Perspective>> perspectiveButton = Suppliers.memoize(() -> CycleButton
.builder((ModConfig.Perspective value) -> Component.translatable(value.getKey()))
.withValues(ModConfig.Perspective.values())
.withInitialValue(ModConfig.get().hidden.gotoPlayerPerspective)
.withTooltip(value -> Tooltip.create(Component.translatable("gui.freecam.goto.button.perspective.@Tooltip")))
.displayOnlyValue()
.create(0, 0, 80, 20, Component.empty(), (button, value) -> {
ModConfig.get().hidden.gotoPlayerPerspective = value;
ModConfig.save();
}));

@Override
public List<TargetListEntry> provideEntriesFor(TargetListWidget widget) {
// Store the existing entries in a UUID map for easy lookup
Map<UUID, PlayerListEntry> currentEntries = widget.children()
.parallelStream()
.filter(PlayerListEntry.class::isInstance)
.map(PlayerListEntry.class::cast)
.collect(Collectors.toUnmodifiableMap(PlayerListEntry::getUUID, Function.identity()));

// Map the in-range players into PlayerListEntries
// Use existing entries if possible
return MC.level.players()
.parallelStream()
.filter(player -> !(player instanceof FreeCamera))
.filter(this::permitted)
.map(player -> Objects.requireNonNullElseGet(
currentEntries.get(player.getUUID()),
() -> new PlayerListEntry(widget, player)))
.map(TargetListEntry.class::cast)
.toList();
}

@Override
public List<AbstractButton> extraButtons() {
return Collections.singletonList(perspectiveButton.get());
}

private boolean permitted(AbstractClientPlayer player) {
// TODO check if player is visible
return BuildVariant.getInstance().cheatsPermitted() || Objects.equals(MC.player, player);
}
}
14 changes: 14 additions & 0 deletions common/src/main/java/net/xolt/freecam/gui/go/tabs/Tab.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package net.xolt.freecam.gui.go.tabs;

import net.minecraft.client.gui.components.AbstractButton;
import net.xolt.freecam.gui.go.TargetListEntry;
import net.xolt.freecam.gui.go.TargetListWidget;

import java.util.List;

interface Tab {

List<TargetListEntry> provideEntriesFor(TargetListWidget widget);

List<AbstractButton> extraButtons();
}

0 comments on commit aef98cb

Please sign in to comment.