Added Quests and Real Settings (yay)

This commit is contained in:
2026-07-11 10:46:47 +02:00
parent d3fc829dee
commit 652fe728e1
7 changed files with 392 additions and 77 deletions
@@ -18,6 +18,9 @@ public class Config {
public int fpsY = 1;
public String lastModule = "FPS";
public int keyX = 1;
public int keyY = 1;
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static final Path PATH = FabricLoader.getInstance()
.getConfigDir()
@@ -0,0 +1,130 @@
package de.fullrisk.citrusDev.UI;
import io.wispforest.owo.ui.component.LabelComponent;
import io.wispforest.owo.ui.component.UIComponents;
import io.wispforest.owo.ui.container.FlowLayout;
import io.wispforest.owo.ui.container.UIContainers;
import io.wispforest.owo.ui.core.*;
import io.wispforest.owo.ui.hud.Hud;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.Identifier;
import de.fullrisk.citrusDev.Config;
public class Module_KeyStrokes {
private static FlowLayout keyContainer;
private static FlowLayout topRow;
private static FlowLayout bottomRow;
private static FlowLayout wBox, aBox, sBox, dBox;
private static LabelComponent wLabel, aLabel, sLabel, dLabel;
static boolean toggle = true;
private static boolean shown = false;
public static boolean isEnabled() {
return toggle;
}
public static void setEnabled(boolean value) {
toggle = value;
}
private static final Config CONFIG = Config.get();
private static final Surface GLASS_PANEL = Surface.blur(5f, 15f)
.and(Surface.flat(0x40FFFFFF));
private static final int KEY_SIZE = 16;
private static final int PRESSED_COLOR = 0xFF64de4b;
private static final int IDLE_COLOR = 0x40FFFFFF;
public static void setPosition(int x, int y) {
if (keyContainer != null) {
keyContainer.positioning(Positioning.relative(x, y));
}
CONFIG.keyX = x;
CONFIG.keyY = y;
CONFIG.save();
}
public static void register() {
Hud.add(Identifier.fromNamespaceAndPath("citrus-dev", "keystrokes_display"), () -> {
if (keyContainer == null) {
wLabel = UIComponents.label(Component.literal("W"));
aLabel = UIComponents.label(Component.literal("A"));
sLabel = UIComponents.label(Component.literal("S"));
dLabel = UIComponents.label(Component.literal("D"));
wBox = makeKeyBox(wLabel);
aBox = makeKeyBox(aLabel);
sBox = makeKeyBox(sLabel);
dBox = makeKeyBox(dLabel);
topRow = UIContainers.horizontalFlow(Sizing.content(), Sizing.content());
topRow.gap(2);
topRow.horizontalAlignment(HorizontalAlignment.CENTER);
topRow.child(UIContainers.horizontalFlow(Sizing.fixed(KEY_SIZE), Sizing.fixed(KEY_SIZE))); // spacer
topRow.child(wBox);
topRow.child(UIContainers.horizontalFlow(Sizing.fixed(KEY_SIZE), Sizing.fixed(KEY_SIZE))); // spacer
bottomRow = UIContainers.horizontalFlow(Sizing.content(), Sizing.content());
bottomRow.gap(2);
bottomRow.horizontalAlignment(HorizontalAlignment.CENTER);
bottomRow.child(aBox);
bottomRow.child(sBox);
bottomRow.child(dBox);
keyContainer = UIContainers.verticalFlow(Sizing.content(), Sizing.content());
keyContainer.gap(2);
keyContainer.verticalAlignment(VerticalAlignment.CENTER);
keyContainer.horizontalAlignment(HorizontalAlignment.CENTER);
keyContainer.padding(Insets.of(0));
keyContainer.positioning(Positioning.relative(CONFIG.keyX, CONFIG.keyY));
}
return keyContainer;
});
}
private static FlowLayout makeKeyBox(LabelComponent label) {
FlowLayout box = UIContainers.verticalFlow(Sizing.fixed(KEY_SIZE), Sizing.fixed(KEY_SIZE));
box.horizontalAlignment(HorizontalAlignment.CENTER);
box.verticalAlignment(VerticalAlignment.CENTER);
box.surface(Surface.flat(IDLE_COLOR));
box.child(label);
return box;
}
public static void tick() {
if (keyContainer == null) return;
if (toggle && !shown) {
keyContainer.clearChildren(); // <-- safety net against duplicate adds
keyContainer.surface(GLASS_PANEL);
keyContainer.padding(Insets.of(Config.get().fpsP));
keyContainer.child(topRow);
keyContainer.child(bottomRow);
shown = true;
} else if (!toggle && shown) {
keyContainer.clearChildren();
keyContainer.surface(Surface.flat(0));
keyContainer.padding(Insets.of(0));
shown = false;
}
if (!toggle) return;
Minecraft client = Minecraft.getInstance();
KeyMapping up = client.options.keyUp;
KeyMapping left = client.options.keyLeft;
KeyMapping down = client.options.keyDown;
KeyMapping right = client.options.keyRight;
wBox.surface(Surface.flat(up.isDown() ? PRESSED_COLOR : IDLE_COLOR));
aBox.surface(Surface.flat(left.isDown() ? PRESSED_COLOR : IDLE_COLOR));
sBox.surface(Surface.flat(down.isDown() ? PRESSED_COLOR : IDLE_COLOR));
dBox.surface(Surface.flat(right.isDown() ? PRESSED_COLOR : IDLE_COLOR));
}
}
@@ -56,6 +56,7 @@ public class MyScreen extends BaseOwoScreen<FlowLayout> {
private FlowLayout content;
private final String initialModule;
public MyScreen() {
this(null);
}
@@ -130,8 +131,8 @@ public class MyScreen extends BaseOwoScreen<FlowLayout> {
rootComponent.child(panel);
if ("FPS".equals(initialModule)) {
openModuleSettings("FPS", fpsModuleSettings());
if (initialModule != null) {
openModuleByKey(initialModule);
} else {
buildGeneralPanel(content);
}
@@ -249,72 +250,51 @@ public class MyScreen extends BaseOwoScreen<FlowLayout> {
}
private void buildGeneralPanel(FlowLayout content) {
FlowLayout iconButton = UIContainers.horizontalFlow(Sizing.content(), Sizing.content());
iconButton.gap(8);
iconButton.verticalAlignment(VerticalAlignment.TOP);
iconButton.horizontalAlignment(HorizontalAlignment.CENTER);
iconButton.padding(Insets.of(6));
iconButton.horizontalSizing(Sizing.fixed(0));
iconButton.verticalSizing(Sizing.fixed(0));
iconButton.surface(toggle ? GLASS_PANEL : DISABLED);
iconButton.child(UIComponents.texture(
FlowLayout fpsRow = ModuleRow.build(
GLASS_PANEL, DISABLED, FLAT,
Identifier.fromNamespaceAndPath("citrus-dev", "textures/icons/block_culling_file.png"),
0, 0, 18, 12, 18, 12
)).horizontalAlignment(HorizontalAlignment.LEFT)
.verticalAlignment(VerticalAlignment.CENTER);
FlowLayout textStack = UIContainers.verticalFlow(Sizing.content(), Sizing.content());
textStack.gap(2);
textStack.horizontalAlignment(HorizontalAlignment.LEFT);
textStack.verticalAlignment(VerticalAlignment.CENTER);
var fpsLabel = UIComponents.label(
Component.literal("FPS")
.withStyle(style -> style.withFont(new FontDescription.Resource(MC_FIVE)))
).color(Color.ofRgb(toggle ? 0xffffff : 0x797b86));
textStack.child(fpsLabel);
textStack.child(UIComponents.label(
Component.literal("Displays your FPS"))
.color(Color.ofRgb(0xa3a3ac))
.maxWidth(130)
);
iconButton.child(textStack);
iconButton.child(UIComponents.spacer());
FlowLayout settingsButton = SettingsControls.makeSmallButton(
FLAT,
18, 12,
MC_FIVE,
"FPS",
"Displays your FPS",
new ModuleRow.ToggleState() {
public boolean get() { return toggle; }
public void set(boolean value) { toggle = value; }
},
Identifier.fromNamespaceAndPath("citrus-dev", "textures/icons/settings.png"),
() -> {
Config.get().lastModule = "FPS";
Config.get().save();
openModuleSettings("FPS", fpsModuleSettings());
}
},
"Module Enabled", "FPS counter is now active",
"Module Disabled", "FPS counter is now inactive"
);
iconButton.child(settingsButton);
iconButton.mouseEnter().subscribe(() -> iconButton.surface(toggle ? GLASS_PANEL : DISABLED));
iconButton.mouseLeave().subscribe(() -> iconButton.surface(toggle ? GLASS_PANEL : DISABLED));
iconButton.mouseDown().subscribe((click, doubled) -> {
toggle = !toggle;
fpsLabel.color(Color.ofRgb(toggle ? 0xffffff : 0x797b86));
iconButton.surface(toggle ? GLASS_PANEL : DISABLED);
CitrusToast.show("Module Enabled", "FPS counter is now active");
Minecraft.getInstance().getSoundManager().play(
SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK.value(), 2.0F, 2)
FlowLayout keyStrokesRow = ModuleRow.build(
GLASS_PANEL, DISABLED, FLAT,
Identifier.fromNamespaceAndPath("citrus-dev", "textures/icons/block_culling_file.png"),
18, 12,
MC_FIVE,
"Keystrokes",
"Current Key Presses",
new ModuleRow.ToggleState() {
public boolean get() { return Module_KeyStrokes.isEnabled(); }
public void set(boolean value) { Module_KeyStrokes.setEnabled(value); }
},
Identifier.fromNamespaceAndPath("citrus-dev", "textures/icons/settings.png"),
() -> {
Config.get().lastModule = "Key";
Config.get().save();
openModuleSettings("Key", keyStrokesSettings());
},
"Module Enabled", "Keystrokes is now active",
"Module Disabled", "KeyStrokes is now inactive"
);
return true;
});
content.child(keyStrokesRow);
content.child(fpsRow);
iconButton.horizontalSizing().animate(150, Easing.CUBIC, Sizing.fixed(200)).forwards();
iconButton.verticalSizing().animate(150, Easing.CUBIC, Sizing.fixed(35)).forwards();
content.child(iconButton);
}
@@ -366,6 +346,14 @@ public class MyScreen extends BaseOwoScreen<FlowLayout> {
content.child(scrollArea);
}
private void openModuleByKey(String key) {
switch (key) {
case "FPS" -> openModuleSettings("FPS", fpsModuleSettings());
case "Key" -> openModuleSettings("Keystrokes", keyStrokesSettings());
default -> buildGeneralPanel(content);
}
}
private FlowLayout makeSettingRow(SettingRow setting) {
FlowLayout row = UIContainers.horizontalFlow(Sizing.fixed(CONTENT_WIDTH - 8), Sizing.fixed(16));
row.verticalAlignment(VerticalAlignment.CENTER);
@@ -398,12 +386,48 @@ public class MyScreen extends BaseOwoScreen<FlowLayout> {
value -> Module_FPS.fpsContainer.gap((int) value)
);
int currentIndex = positionIndex(Config.get().fpsX, Config.get().fpsY);
return List.of(
new SettingRow("Position", SettingsControls.makeCyclingButton(GLASS_PANEL, positionStates)),
new SettingRow("Position", SettingsControls.makeCyclingButton(GLASS_PANEL, positionStates, currentIndex)),
new SettingRow("Size", sizeSlider)
);
}
private List<SettingRow> keyStrokesSettings() {
List<SettingsControls.ButtonState> positionStates = List.of(
new SettingsControls.ButtonState("L-TOP", () -> Module_KeyStrokes.setPosition(1, 1)),
new SettingsControls.ButtonState("R-TOP", () -> Module_KeyStrokes.setPosition(99, 1)),
new SettingsControls.ButtonState("R-BOTTOM", () -> Module_KeyStrokes.setPosition(99, 99)),
new SettingsControls.ButtonState("L-BOTTOM", () -> Module_KeyStrokes.setPosition(1, 99))
);
FlowLayout sizeSlider = SettingsControls.makeSlider(
FLAT,
80,
0.0, 20.0,
4.0,
value -> (int) value + "px",
value -> {} // fixed: was Module_FPS.fpsContainer.gap(...)
);
int currentIndex = positionIndex(Config.get().keyX, Config.get().keyY);
return List.of(
new SettingRow("Position", SettingsControls.makeCyclingButton(GLASS_PANEL, positionStates, currentIndex)),
new SettingRow("Size", sizeSlider)
);
}
private int positionIndex(int x, int y) {
boolean right = x > 50;
boolean bottom = y > 50;
if (!right && !bottom) return 0; // L-TOP
if (right && !bottom) return 1; // R-TOP
if (right && bottom) return 2; // R-BOTTOM
return 3; // L-BOTTOM
}
@Override
public boolean isPauseScreen() {
return false;
@@ -1,5 +1,6 @@
package de.fullrisk.citrusDev.UI;
import io.wispforest.owo.ui.component.LabelComponent;
import io.wispforest.owo.ui.component.UIComponents;
import io.wispforest.owo.ui.container.FlowLayout;
import io.wispforest.owo.ui.container.UIContainers;
@@ -7,12 +8,15 @@ import io.wispforest.owo.ui.core.*;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.FontDescription;
import de.fullrisk.citrusDev.client.PlaytimeTracker;
import de.fullrisk.citrusDev.UIHelper.CitrusToast;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class QuestsPanel {
private static final int ACCENT = 0xbaff86;
private static final int ACCENT = 0x64de4b;
private record QuestData(String title, String description, int requiredPlaytime) {
boolean isUnlocked() {
@@ -20,7 +24,50 @@ public class QuestsPanel {
}
}
public static void build(FlowLayout content, int contentWidth, int contentHeight) {
public static class Handle {
private final LabelComponent playtimeLabel;
private final LabelComponent percentLabel;
private final FlowLayout barFill;
private final int barWidth;
private final List<QuestData> quests;
private final Set<String> notifiedTitles = new HashSet<>();
private Handle(LabelComponent playtimeLabel, LabelComponent percentLabel, FlowLayout barFill, int barWidth, List<QuestData> quests) {
this.playtimeLabel = playtimeLabel;
this.percentLabel = percentLabel;
this.barFill = barFill;
this.barWidth = barWidth;
this.quests = quests;
// seed with whatever's already unlocked on open, so we don't spam
// toasts for quests the player unlocked before opening this screen
for (QuestData quest : quests) {
if (quest.isUnlocked()) {
notifiedTitles.add(quest.title());
}
}
}
public void refresh() {
int playtime = PlaytimeTracker.getCurrentPlaytimeSeconds();
int maxPlaytime = 360;
int progress = Math.min(playtime * 100 / maxPlaytime, 100);
playtimeLabel.text(Component.literal(formatPlaytime(playtime)));
percentLabel.text(Component.literal(progress + "%"));
int fillWidth = Math.max(barWidth * progress / 100, progress > 0 ? 2 : 0);
barFill.horizontalSizing(Sizing.fixed(fillWidth));
for (QuestData quest : quests) {
if (quest.isUnlocked() && notifiedTitles.add(quest.title())) {
CitrusToast.show("Quest Unlocked", quest.title());
}
}
}
}
public static Handle build(FlowLayout content, int contentWidth, int contentHeight) {
List<QuestData> quests = quests();
int playtime = PlaytimeTracker.getCurrentPlaytimeSeconds();
int maxPlaytime = 360;
@@ -28,7 +75,6 @@ public class QuestsPanel {
int barWidth = contentWidth - 8;
long unlockedCount = quests.stream().filter(QuestData::isUnlocked).count();
// --- status row: playtime + percentage ---
FlowLayout statusBar = UIContainers.horizontalFlow(Sizing.fixed(barWidth), Sizing.fixed(20));
statusBar.gap(4);
statusBar.padding(Insets.of(4));
@@ -36,15 +82,17 @@ public class QuestsPanel {
statusBar.horizontalAlignment(HorizontalAlignment.LEFT);
statusBar.surface(MyScreen.GLASS_PANEL);
statusBar.child(UIComponents.label(Component.literal("Playtime: " + formatPlaytime(playtime)))
.color(Color.ofRgb(0xFFFFFF)));
LabelComponent playtimeLabel = UIComponents.label(Component.literal(formatPlaytime(playtime)));
playtimeLabel.color(Color.ofRgb(0xFFFFFF));
statusBar.child(playtimeLabel);
statusBar.child(UIComponents.spacer());
statusBar.child(UIComponents.label(Component.literal(progress + "%"))
.color(Color.ofRgb(ACCENT)));
LabelComponent percentLabel = UIComponents.label(Component.literal(progress + "%"));
percentLabel.color(Color.ofRgb(ACCENT));
statusBar.child(percentLabel);
content.child(statusBar);
// --- progress bar ---
FlowLayout barBg = UIContainers.horizontalFlow(Sizing.fixed(barWidth), Sizing.fixed(6));
barBg.surface(Surface.flat(0x30FFFFFF).and(Surface.outline(0x30FFFFFF)));
barBg.horizontalAlignment(HorizontalAlignment.LEFT);
@@ -58,7 +106,6 @@ public class QuestsPanel {
content.child(barBg);
// --- unlocked count summary ---
FlowLayout summaryRow = UIContainers.horizontalFlow(Sizing.fixed(barWidth), Sizing.content());
summaryRow.padding(Insets.of(3, 0, 2, 2));
@@ -69,7 +116,6 @@ public class QuestsPanel {
content.child(summaryRow);
// --- quest list (scrollable) ---
FlowLayout questList = UIContainers.verticalFlow(Sizing.fixed(barWidth), Sizing.content());
questList.gap(3);
questList.padding(Insets.of(2, 0, 2, 2));
@@ -78,7 +124,7 @@ public class QuestsPanel {
questList.child(buildQuestEntry(quest, contentWidth));
}
int usedHeight = 20 + 6 + 18 + 6; // statusBar + barBg + summaryRow + gaps
int usedHeight = 20 + 6 + 18 + 6;
int scrollHeight = contentHeight - usedHeight;
var scrollArea = UIContainers.verticalScroll(
@@ -87,6 +133,8 @@ public class QuestsPanel {
questList
);
content.child(scrollArea);
return new Handle(playtimeLabel, percentLabel, barFill, barWidth, quests);
}
private static String formatPlaytime(int seconds) {
@@ -130,7 +178,7 @@ public class QuestsPanel {
: Surface.flat(0x40FFFFFF));
iconBox.horizontalAlignment(HorizontalAlignment.CENTER);
iconBox.verticalAlignment(VerticalAlignment.CENTER);
iconBox.child(UIComponents.label(Component.literal(unlocked ? "" : ""))
iconBox.child(UIComponents.label(Component.literal(""))
.color(Color.ofRgb(0x1c1c1c)));
row.child(iconBox);
@@ -0,0 +1,102 @@
package de.fullrisk.citrusDev.UIHelper;
import io.wispforest.owo.ui.component.UIComponents;
import io.wispforest.owo.ui.container.FlowLayout;
import io.wispforest.owo.ui.container.UIContainers;
import io.wispforest.owo.ui.core.*;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.FontDescription;
import net.minecraft.resources.Identifier;
import net.minecraft.sounds.SoundEvents;
public class ModuleRow {
/** Bridge to whatever boolean field actually holds the module's on/off state. */
public interface ToggleState {
boolean get();
void set(boolean value);
}
public static FlowLayout build(
Surface enabledSurface,
Surface disabledSurface,
Surface flatSurface,
Identifier icon,
int iconWidth,
int iconHeight,
Identifier titleFont,
String title,
String description,
ToggleState state,
Identifier settingsIcon,
Runnable onSettingsClick,
String enabledToastTitle,
String enabledToastMessage,
String disabledToastTitle,
String disabledToastMessage
) {
FlowLayout row = UIContainers.horizontalFlow(Sizing.content(), Sizing.content());
row.gap(8);
row.verticalAlignment(VerticalAlignment.TOP);
row.horizontalAlignment(HorizontalAlignment.CENTER);
row.padding(Insets.of(6));
row.horizontalSizing(Sizing.fixed(0));
row.verticalSizing(Sizing.fixed(0));
row.surface(state.get() ? enabledSurface : disabledSurface);
row.child(UIComponents.texture(icon, 0, 0, iconWidth, iconHeight, iconWidth, iconHeight))
.horizontalAlignment(HorizontalAlignment.LEFT)
.verticalAlignment(VerticalAlignment.CENTER);
FlowLayout textStack = UIContainers.verticalFlow(Sizing.content(), Sizing.content());
textStack.gap(2);
textStack.horizontalAlignment(HorizontalAlignment.LEFT);
textStack.verticalAlignment(VerticalAlignment.CENTER);
var titleLabel = UIComponents.label(
Component.literal(title)
.withStyle(style -> style.withFont(new FontDescription.Resource(titleFont)))
);
titleLabel.color(Color.ofRgb(state.get() ? 0xffffff : 0x797b86));
textStack.child(titleLabel);
textStack.child(UIComponents.label(Component.literal(description))
.color(Color.ofRgb(0xa3a3ac))
.maxWidth(130));
row.child(textStack);
row.child(UIComponents.spacer());
FlowLayout settingsButton = SettingsControls.makeSmallButton(flatSurface, settingsIcon, onSettingsClick);
row.child(settingsButton);
row.mouseEnter().subscribe(() -> row.surface(state.get() ? enabledSurface : disabledSurface));
row.mouseLeave().subscribe(() -> row.surface(state.get() ? enabledSurface : disabledSurface));
row.mouseDown().subscribe((click, doubled) -> {
boolean newState = !state.get();
state.set(newState);
titleLabel.color(Color.ofRgb(newState ? 0xffffff : 0x797b86));
row.surface(newState ? enabledSurface : disabledSurface);
if (newState) {
CitrusToast.show(enabledToastTitle, enabledToastMessage);
} else {
CitrusToast.show(disabledToastTitle, disabledToastMessage);
}
Minecraft.getInstance().getSoundManager().play(
SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK.value(), 2.0F, 2)
);
return true;
});
row.horizontalSizing().animate(150, Easing.CUBIC, Sizing.fixed(200)).forwards();
row.verticalSizing().animate(150, Easing.CUBIC, Sizing.fixed(35)).forwards();
return row;
}
}
@@ -73,15 +73,15 @@ public class SettingsControls {
return button;
}
public static FlowLayout makeCyclingButton(Surface baseSurface, List<ButtonState> states) {
int[] currentIndex = {0};
public static FlowLayout makeCyclingButton(Surface baseSurface, List<ButtonState> states, int initialIndex) {
int[] currentIndex = { initialIndex };
FlowLayout button = UIContainers.verticalFlow(Sizing.fixed(50), Sizing.fixed(16));
button.verticalAlignment(VerticalAlignment.CENTER);
button.horizontalAlignment(HorizontalAlignment.CENTER);
button.surface(baseSurface);
var label = UIComponents.label(Component.literal(states.get(0).label()))
var label = UIComponents.label(Component.literal(states.get(initialIndex).label()))
.color(Color.ofRgb(0xFFFFFF));
button.child(label);
@@ -104,6 +104,11 @@ public class SettingsControls {
return button;
}
// keep the old call sites compiling; defaults to index 0
public static FlowLayout makeCyclingButton(Surface baseSurface, List<ButtonState> states) {
return makeCyclingButton(baseSurface, states, 0);
}
public static FlowLayout makeSlider(Surface baseSurface, int width, double min, double max, double initial,
DoubleFunction<String> labelFormatter, DoubleConsumer onChange) {
int labelWidth = 34;
@@ -3,6 +3,7 @@ package de.fullrisk.citrusDev.client;
import de.fullrisk.citrusDev.Config;
import de.fullrisk.citrusDev.UI.Module_FPS;
import de.fullrisk.citrusDev.UI.Module_KeyStrokes;
import de.fullrisk.citrusDev.UI.MyScreen;
import de.fullrisk.citrusDev.UI.OverviewScreen;
import io.wispforest.owo.ui.hud.Hud;
@@ -21,6 +22,7 @@ public class CitrusDevClient implements ClientModInitializer {
@Override
public void onInitializeClient() {
Module_FPS.register();
Module_KeyStrokes.register();
KeyMapping.Category category = KeyMapping.Category.register(
Identifier.fromNamespaceAndPath("citrus-dev", "general"));
@@ -41,7 +43,8 @@ public class CitrusDevClient implements ClientModInitializer {
PlaytimeTracker.tick();
}
Module_FPS.tick(); // update every tick, unconditionally
Module_FPS.tick();
Module_KeyStrokes.tick();
while (openScreenKey.consumeClick()) {
client.setScreen(new MyScreen(null)); // always general tab
}