This commit is contained in:
Darto KLoning
2026-10-04 00:04:25 +07:00
parent f2dc75d6c8
commit daa48f819e
5 changed files with 1 additions and 255 deletions
-15
View File
@@ -257,18 +257,3 @@ Local/cracked identity tidak mempunyai Mojang profile public key. Dengan `enforc
## License
All Rights Reserved. Source dan asset Lobby Systems tidak boleh didistribusikan atau digunakan ulang di luar izin pemilik project.
## v1.10.0 - Configuration GUI
Operator-only `/ls config` opens a vanilla 6-row chest menu named **Lobby Systems Configuration**. No client-side mod is required for the menu itself.
The first GUI release focuses on settings that can be changed safely with inventory clicks:
- **Lobby**: minimum play time, portal check interval, portal cooldown.
- **Authentication**: enabled, premium auto-login, premium username protection, require-login-every-join, authentication timeout, max attempts, minimum password length, PBKDF2 iterations.
- **Server Rules**: enabled, rules version, rules timeout.
- **Dimensions**, **Starter Kits**, and **Portals** are represented in the root menu and direct administrators to their existing `/ls` management commands. This deliberately avoids turning structured lists and world-specific records into unsafe one-click edits.
Controls: left click increases numeric values, right click decreases them; boolean entries toggle on click. Changes are saved immediately. Auth/Rules changes are also applied to the current runtime state, so a separate `/ls reload` is not required for GUI edits. Manual JSON edits still use `/ls reload`.
The configuration GUI edits configuration only. `player.json` and `starterkit/recipients.json` remain persistent runtime databases and are not exposed as raw editable GUI data.
+1 -1
View File
@@ -5,6 +5,6 @@ minecraft_version=26.2
loader_version=0.19.3
loom_version=1.17-SNAPSHOT
fabric_api_version=0.156.0+26.2
mod_version=1.10.1
mod_version=1.9.0
maven_group=id.dartokloning
archives_base_name=lobby-systems
@@ -76,17 +76,6 @@ public final class AuthManager {
}
public AuthConfig config() { return config; }
public RulesConfig rules() { return rules; }
public void saveConfiguration() {
try {
Files.createDirectories(ConfigPaths.AUTH_DIRECTORY);
saveConfig();
saveRules();
} catch (Exception e) {
LobbySystemsMod.LOGGER.error("Failed to save Lobby Systems Auth configuration", e);
}
}
/** Re-applies the freshly loaded auth configuration to players already online. */
public void applyReload(MinecraftServer server) {
@@ -1,225 +0,0 @@
package id.dartokloning.lobbysystems;
import net.minecraft.ChatFormatting;
import net.minecraft.core.component.DataComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.ChestMenu;
import net.minecraft.world.inventory.ContainerInput;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.SimpleMenuProvider;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
/** Server-side vanilla chest GUI for Lobby Systems administration. */
public final class ConfigGui {
private static final int SIZE = 54;
private final ConfigManager configManager;
private final AuthManager authManager;
public ConfigGui(ConfigManager configManager, AuthManager authManager) {
this.configManager = configManager;
this.authManager = authManager;
}
public void open(ServerPlayer player) { open(player, Page.ROOT); }
private void open(ServerPlayer player, Page page) {
Component title = Component.literal(switch (page) {
case ROOT -> "Lobby Systems Configuration";
case AUTH -> "Authentication Configuration";
case RULES -> "Server Rules Configuration";
case LOBBY -> "Lobby Configuration";
});
player.openMenu(new SimpleMenuProvider(
(id, inventory, ignored) -> new GuiMenu(id, inventory, player, page), title));
}
private final class GuiMenu extends ChestMenu {
private final ServerPlayer viewer;
private final Page page;
private final SimpleContainer gui;
GuiMenu(int id, Inventory inventory, ServerPlayer viewer, Page page) {
this(id, inventory, viewer, page, new SimpleContainer(SIZE));
}
private GuiMenu(int id, Inventory inventory, ServerPlayer viewer, Page page, SimpleContainer gui) {
super(MenuType.GENERIC_9x6, id, inventory, gui, 6);
this.viewer = viewer;
this.page = page;
this.gui = gui;
render();
}
@Override
public void clicked(int slotIndex, int buttonNum, ContainerInput input, Player player) {
if (slotIndex < 0 || slotIndex >= SIZE) return;
if (input != ContainerInput.PICKUP && input != ContainerInput.QUICK_MOVE) return;
handle(slotIndex, buttonNum);
}
@Override
public ItemStack quickMoveStack(Player player, int slotIndex) { return ItemStack.EMPTY; }
@Override
public boolean stillValid(Player player) { return true; }
private void handle(int slot, int button) {
boolean right = button == 1;
switch (page) {
case ROOT -> {
if (slot == 20) open(viewer, Page.LOBBY);
else if (slot == 22) open(viewer, Page.AUTH);
else if (slot == 24) open(viewer, Page.RULES);
else if (slot == 38) viewer.sendSystemMessage(Component.literal("Dimension settings are managed by /ls gamemode and /ls gamerule.").withStyle(ChatFormatting.YELLOW));
else if (slot == 40) viewer.sendSystemMessage(Component.literal("Starter Kits are managed by /ls starterkit commands.").withStyle(ChatFormatting.YELLOW));
else if (slot == 42) viewer.sendSystemMessage(Component.literal("Portals are managed by /ls portal commands.").withStyle(ChatFormatting.YELLOW));
else if (slot == 49) viewer.closeContainer();
}
case AUTH -> handleAuth(slot, right);
case RULES -> handleRules(slot, right);
case LOBBY -> handleLobby(slot, right);
}
}
private void handleAuth(int slot, boolean right) {
AuthConfig c = authManager.config();
boolean changed = true;
switch (slot) {
case 10 -> c.enabled = !c.enabled;
case 12 -> c.premiumAutoLogin = !c.premiumAutoLogin;
case 14 -> c.protectPremiumUsernames = !c.protectPremiumUsernames;
case 16 -> c.requireLoginEveryJoin = !c.requireLoginEveryJoin;
case 28 -> c.authenticationTimeoutSeconds = adjust(c.authenticationTimeoutSeconds, right ? -30 : 30, 30, 3600);
case 30 -> c.maxLoginAttempts = adjust(c.maxLoginAttempts, right ? -1 : 1, 1, 20);
case 32 -> c.minimumPasswordLength = adjust(c.minimumPasswordLength, right ? -1 : 1, 4, 128);
case 34 -> c.pbkdf2Iterations = adjust(c.pbkdf2Iterations, right ? -10000 : 10000, 50000, 2000000);
case 45 -> { open(viewer, Page.ROOT); return; }
case 49 -> { viewer.closeContainer(); return; }
default -> changed = false;
}
if (changed) {
authManager.saveConfiguration();
authManager.applyReload(viewer.level().getServer());
render();
}
}
private void handleRules(int slot, boolean right) {
RulesConfig c = authManager.rules();
boolean changed = true;
switch (slot) {
case 11 -> c.enabled = !c.enabled;
case 13 -> c.version = adjust(c.version, right ? -1 : 1, 1, Integer.MAX_VALUE);
case 15 -> c.timeoutSeconds = adjust(c.timeoutSeconds, right ? -15 : 15, 15, 3600);
case 45 -> { open(viewer, Page.ROOT); return; }
case 49 -> { viewer.closeContainer(); return; }
default -> changed = false;
}
if (changed) {
authManager.saveConfiguration();
authManager.applyReload(viewer.level().getServer());
render();
}
}
private void handleLobby(int slot, boolean right) {
LobbyConfig c = configManager.get();
boolean changed = true;
switch (slot) {
case 20 -> c.minimumPlaySeconds = adjust(c.minimumPlaySeconds, right ? -30 : 30, 0, 86400);
case 22 -> c.portalCheckIntervalTicks = adjust(c.portalCheckIntervalTicks, right ? -1 : 1, 1, 200);
case 24 -> c.portalCooldownTicks = adjust(c.portalCooldownTicks, right ? -10 : 10, 1, 1200);
case 45 -> { open(viewer, Page.ROOT); return; }
case 49 -> { viewer.closeContainer(); return; }
default -> changed = false;
}
if (changed) { configManager.save(); render(); }
}
private void render() {
gui.clearContent();
switch (page) {
case ROOT -> renderRoot();
case AUTH -> renderAuth();
case RULES -> renderRules();
case LOBBY -> renderLobby();
}
broadcastFullState();
}
private void renderRoot() {
set(20, Items.COMPASS, "Lobby", ChatFormatting.AQUA);
set(22, Items.IRON_DOOR, "Authentication", ChatFormatting.GREEN);
set(24, Items.WRITABLE_BOOK, "Server Rules", ChatFormatting.YELLOW);
set(38, Items.GRASS_BLOCK, "Dimensions", ChatFormatting.GREEN);
set(40, Items.CHEST, "Starter Kits", ChatFormatting.GOLD);
set(42, Items.ENDER_PEARL, "Portals", ChatFormatting.LIGHT_PURPLE);
set(49, Items.BARRIER, "Close", ChatFormatting.RED);
}
private void renderAuth() {
AuthConfig c = authManager.config();
toggle(10, Items.LEVER, "Auth Enabled", c.enabled);
toggle(12, Items.GOLD_INGOT, "Premium Auto Login", c.premiumAutoLogin);
toggle(14, Items.SHIELD, "Protect Premium Usernames", c.protectPremiumUsernames);
toggle(16, Items.NAME_TAG, "Require Login Every Join", c.requireLoginEveryJoin);
number(28, Items.CLOCK, "Authentication Timeout", c.authenticationTimeoutSeconds, "seconds", 30);
number(30, Items.REDSTONE, "Maximum Login Attempts", c.maxLoginAttempts, "attempts", 1);
number(32, Items.PAPER, "Minimum Password Length", c.minimumPasswordLength, "characters", 1);
number(34, Items.REPEATER, "PBKDF2 Iterations", c.pbkdf2Iterations, "iterations", 10000);
navigation();
}
private void renderRules() {
RulesConfig c = authManager.rules();
toggle(11, Items.LEVER, "Rules Enabled", c.enabled);
number(13, Items.BOOK, "Rules Version", c.version, "", 1);
number(15, Items.CLOCK, "Rules Timeout", c.timeoutSeconds, "seconds", 15);
set(31, Items.WRITABLE_BOOK, "Rule text: edit auth/rules.json", ChatFormatting.GRAY);
navigation();
}
private void renderLobby() {
LobbyConfig c = configManager.get();
set(13, Items.COMPASS, "Lobby Dimension: " + c.lobbyDimension, ChatFormatting.AQUA);
number(20, Items.CLOCK, "Minimum Play Time", c.minimumPlaySeconds, "seconds", 30);
number(22, Items.ENDER_EYE, "Portal Check Interval", c.portalCheckIntervalTicks, "ticks", 1);
number(24, Items.RECOVERY_COMPASS, "Portal Cooldown", c.portalCooldownTicks, "ticks", 10);
navigation();
}
private void navigation() {
set(45, Items.ARROW, "Back", ChatFormatting.YELLOW);
set(49, Items.BARRIER, "Close", ChatFormatting.RED);
}
private void toggle(int slot, Item item, String label, boolean value) {
set(slot, item, label + ": " + (value ? "ON" : "OFF"), value ? ChatFormatting.GREEN : ChatFormatting.RED);
}
private void number(int slot, Item item, String label, int value, String unit, int step) {
String suffix = unit.isBlank() ? "" : " " + unit;
set(slot, item, label + ": " + value + suffix + " (L +" + step + " / R -" + step + ")", ChatFormatting.YELLOW);
}
private void set(int slot, Item item, String name, ChatFormatting color) {
ItemStack stack = new ItemStack(item);
stack.set(DataComponents.CUSTOM_NAME, Component.literal(name).withStyle(color));
gui.setItem(slot, stack);
}
}
private static int adjust(int value, int delta, int min, int max) {
long n = (long) value + delta;
return (int) Math.max(min, Math.min(max, n));
}
private enum Page { ROOT, AUTH, RULES, LOBBY }
}
@@ -48,7 +48,6 @@ public final class LobbySystemsMod implements ModInitializer {
private static final DimensionGameRuleManager DIMENSION_GAMERULES = new DimensionGameRuleManager();
private static final StarterKitManager STARTER_KITS = new StarterKitManager();
private static final AuthManager AUTH = new AuthManager();
private static final ConfigGui CONFIG_GUI = new ConfigGui(CONFIG, AUTH);
private static int saveTicker;
private static final java.util.Set<String> LOCAL_LOGIN_NAMES = java.util.concurrent.ConcurrentHashMap.newKeySet();
@@ -272,8 +271,6 @@ public final class LobbySystemsMod implements ModInitializer {
dispatcher.register(Commands.literal("ls")
.requires(Commands.hasPermission(Commands.LEVEL_ADMINS))
.then(Commands.literal("config")
.executes(ctx -> { CONFIG_GUI.open(ctx.getSource().getPlayerOrException()); return 1; }))
.then(Commands.literal("reload")
.executes(ctx -> reloadAll(ctx.getSource().getServer(), ctx.getSource())))
.then(Commands.literal("tp")