Remove manageDimensionGamemode option

This commit is contained in:
Darto KLoning
2026-09-07 09:12:11 +07:00
parent 964af6c856
commit c1747e2c27
5 changed files with 37 additions and 65 deletions
+8 -9
View File
@@ -1,10 +1,10 @@
# Lobby Systems v1.5.6 — Fabric 26.2 # Lobby Systems v1.5.7 — Fabric 26.2
Server-side lobby routing untuk Minecraft 26.2/Fabric. v1.5.6 mengubah proses login agar Lobby menjadi initial dimension player sebelum world awal dikirim ke client, sehingga tidak ada lagi teleport join yang ditunda atau "persinggahan" di dimension terakhir. Server-side lobby routing untuk Minecraft 26.2/Fabric. v1.5.7 mempertahankan initial Lobby placement sebelum world awal dikirim ke client dan menjadikan Lobby Systems sebagai pengelola gamemode per-dimension yang selalu aktif.
**v1.5.6 login placement fix:** player data tetap dibaca untuk menyimpan posisi gameplay terakhir, tetapi sebelum `PlayerList` mengirim initial world state, Lobby Systems mengganti initial level, posisi, yaw/pitch, dan gamemode ke konfigurasi Lobby. Mekanisme scheduled join teleport dari versi sebelumnya telah dihapus. `compile.bat` / `compile.sh` tetap mendeteksi JAR versi yang sama dan menawarkan Compile ulang atau Git-only. **v1.5.6 login placement fix (dipertahankan):** player data tetap dibaca untuk menyimpan posisi gameplay terakhir, tetapi sebelum `PlayerList` mengirim initial world state, Lobby Systems mengganti initial level, posisi, dan yaw/pitch ke konfigurasi Lobby. Gamemode disinkronkan segera setelah JOIN dan dikoreksi singkat pada +1, +5, dan +20 tick.
**v1.5.0 feature release:** Portal Visual System menambahkan permukaan swirl ungu memakai block state vanilla `minecraft:nether_portal`, dengan axis X/Z yang ditentukan otomatis dari WorldEdit selection. Frame boleh memakai block apa saja. `manageDimensionGamemode` tetap default `true`, compatibility warning Dimensional Inventories tetap aktif, dan bridge WorldEdit 7.4.x tetap dipakai. **v1.5.7 behavior update:** Lobby Systems sekarang selalu menjadi source of truth untuk gamemode per-dimension. Opsi `manageDimensionGamemode` dihapus; config lama akan dimigrasikan otomatis dengan membuang field tersebut. Command `list`, `set`, dan `remove` selalu tersedia. Compatibility warning Dimensional Inventories tetap aktif.
### Reload feedback ### Reload feedback
@@ -90,7 +90,7 @@ State penting Lobby Systems memakai separator agar mudah terlihat di server cons
============================================ ============================================
``` ```
## Struktur konfigurasi v1.5.6 ## Struktur konfigurasi v1.5.7
```text ```text
config/ config/
@@ -115,7 +115,6 @@ Contoh:
"lobbyYaw": 0.0, "lobbyYaw": 0.0,
"lobbyPitch": 0.0, "lobbyPitch": 0.0,
"minimumPlaySeconds": 300, "minimumPlaySeconds": 300,
"manageDimensionGamemode": true,
"portalCheckIntervalTicks": 5, "portalCheckIntervalTicks": 5,
"portalCooldownTicks": 60, "portalCooldownTicks": 60,
"inLobbyMessage": "§eKamu sudah berada di lobby.", "inLobbyMessage": "§eKamu sudah berada di lobby.",
@@ -164,7 +163,7 @@ Trigger portal tetap berupa region Lobby Systems. Mulai v1.5.0, portal baru yang
### `config/lobby/dimension-gamemodes.json` ### `config/lobby/dimension-gamemodes.json`
Minecraft menyimpan gamemode pada player, bukan pada dimension. Lobby Systems menyimpan mapping dimension → gamemode di file ini. Jika `manageDimensionGamemode=true` (default), mapping diterapkan ketika player memasuki dimension. Jika `false`, Lobby Systems tidak mengubah gamemode player dan command gamemode menjadi viewer-only. Minecraft menyimpan gamemode pada player, bukan pada dimension. Lobby Systems menyimpan mapping dimension → gamemode di file ini dan selalu menerapkannya pada join serta perpindahan dimension. Sejak v1.5.7, Lobby Systems adalah source of truth gamemode per-dimension dan tidak memiliki mode viewer-only.
Contoh: Contoh:
@@ -178,7 +177,7 @@ Contoh:
Gamemode yang didukung: `survival`, `creative`, `adventure`, dan `spectator`. Gamemode yang didukung: `survival`, `creative`, `adventure`, dan `spectator`.
Jika mod **Dimensional Inventories** (`dimensional-inventories`) terpasang dan `manageDimensionGamemode=true`, Lobby Systems akan menampilkan warning di console karena kedua mod dapat mengubah gamemode player saat perpindahan dimension/pool. Agar transisi konsisten, samakan gamemode dimension/pool pada kedua mod. Jika Anda ingin Dimensional Inventories menjadi pengelola utama gamemode, set `manageDimensionGamemode=false`. Jika mod **Dimensional Inventories** (`dimensional-inventories`) terpasang, Lobby Systems menampilkan warning di console karena kedua mod dapat memiliki aturan gamemode pada transisi dimension/pool. Lobby Systems tetap authoritative dan akan menerapkan `dimension-gamemodes.json`; untuk hasil paling konsisten, samakan konfigurasi gamemode pool Dimensional Inventories atau nonaktifkan pengelolaan gamemode pada mod tersebut bila tersedia.
## Migrasi dari v1.1.x ## Migrasi dari v1.1.x
@@ -287,7 +286,7 @@ Gunakan mapping gamemode agar player otomatis mendapat gamemode yang sesuai saat
/ls gamemode set minecraft:overworld survival /ls gamemode set minecraft:overworld survival
``` ```
`/ls gamemode list` menampilkan semua mapping. Saat `manageDimensionGamemode=true`, subcommand `set` dan `remove` tersedia dan autocomplete dimension hanya muncul setelah kedua subcommand tersebut. Saat `manageDimensionGamemode=false`, command tree hanya menampilkan `/ls gamemode list`. Mapping tetap disimpan di `config/lobby/dimension-gamemodes.json` dan ikut direload oleh `/ls reload`. Command gamemode selalu tersedia: `/ls gamemode list`, `/ls gamemode set <dimension> <mode>`, dan `/ls gamemode remove <dimension>`. Mapping disimpan di `config/lobby/dimension-gamemodes.json`, diterapkan langsung ke player pada dimension terkait, dan ikut direload oleh `/ls reload`.
### `/ls reload` ### `/ls reload`
+1 -1
View File
@@ -5,6 +5,6 @@ minecraft_version=26.2
loader_version=0.19.3 loader_version=0.19.3
loom_version=1.17-SNAPSHOT loom_version=1.17-SNAPSHOT
fabric_api_version=0.156.0+26.2 fabric_api_version=0.156.0+26.2
mod_version=1.5.6 mod_version=1.5.7
maven_group=id.dartokloning maven_group=id.dartokloning
archives_base_name=lobby-systems archives_base_name=lobby-systems
@@ -2,6 +2,8 @@ package id.dartokloning.lobbysystems;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.Reader; import java.io.Reader;
import java.io.Writer; import java.io.Writer;
@@ -24,10 +26,16 @@ public final class ConfigManager {
} }
try (Reader reader = Files.newBufferedReader(PATH)) { try (Reader reader = Files.newBufferedReader(PATH)) {
LobbyConfig loaded = GSON.fromJson(reader, LobbyConfig.class); JsonObject root = JsonParser.parseReader(reader).getAsJsonObject();
boolean hadDeprecatedGamemodeFlag = root.has("manageDimensionGamemode");
LobbyConfig loaded = GSON.fromJson(root, LobbyConfig.class);
if (loaded == null) throw new IllegalArgumentException("Config JSON kosong atau tidak valid."); if (loaded == null) throw new IllegalArgumentException("Config JSON kosong atau tidak valid.");
validate(loaded); validate(loaded);
config = loaded; config = loaded;
if (hadDeprecatedGamemodeFlag) {
LobbySystemsMod.LOGGER.info("Removing deprecated config option manageDimensionGamemode; Lobby Systems now always manages dimension gamemodes.");
save();
}
return true; return true;
} catch (Exception e) { } catch (Exception e) {
LobbySystemsMod.LOGGER.error("Failed to load {}. Keeping previous config.", PATH, e); LobbySystemsMod.LOGGER.error("Failed to load {}. Keeping previous config.", PATH, e);
@@ -9,8 +9,6 @@ public final class LobbyConfig {
public float lobbyPitch = 0.0f; public float lobbyPitch = 0.0f;
public int minimumPlaySeconds = 300; public int minimumPlaySeconds = 300;
/** Jika true, Lobby Systems menjadi source of truth gamemode per dimension. */
public boolean manageDimensionGamemode = true;
/** Seberapa sering region portal diperiksa. 5 tick = 4 kali/detik. */ /** Seberapa sering region portal diperiksa. 5 tick = 4 kali/detik. */
public int portalCheckIntervalTicks = 5; public int portalCheckIntervalTicks = 5;
@@ -137,10 +137,8 @@ public final class LobbySystemsMod implements ModInitializer {
// sebelum paket login/world awal dikirim. Di titik JOIN ini kita hanya // sebelum paket login/world awal dikirim. Di titik JOIN ini kita hanya
// sinkronkan state runtime dan memberi enforcement singkat sebagai proteksi // sinkronkan state runtime dan memberi enforcement singkat sebagai proteksi
// terhadap mod lain yang mengubah gamemode tepat setelah login. // terhadap mod lain yang mengubah gamemode tepat setelah login.
if (CONFIG.get().manageDimensionGamemode) {
DIMENSION_GAMEMODES.applyForPlayer(player, true); DIMENSION_GAMEMODES.applyForPlayer(player, true);
DIMENSION_GAMEMODES.beginJoinEnforcement(player.getUUID()); DIMENSION_GAMEMODES.beginJoinEnforcement(player.getUUID());
}
SESSIONS.onJoin(player.getUUID(), lobbyKey()); SESSIONS.onJoin(player.getUUID(), lobbyKey());
LobbyLog.state( LobbyLog.state(
@@ -170,9 +168,7 @@ public final class LobbySystemsMod implements ModInitializer {
ServerTickEvents.END_SERVER_TICK.register(server -> { ServerTickEvents.END_SERVER_TICK.register(server -> {
TELEPORTS.tick(); TELEPORTS.tick();
if (CONFIG.get().manageDimensionGamemode) {
DIMENSION_GAMEMODES.tick(server); DIMENSION_GAMEMODES.tick(server);
}
ResourceKey<Level> lobby = lobbyKey(); ResourceKey<Level> lobby = lobbyKey();
for (ServerPlayer player : server.getPlayerList().getPlayers()) { for (ServerPlayer player : server.getPlayerList().getPlayers()) {
@@ -257,7 +253,6 @@ public final class LobbySystemsMod implements ModInitializer {
.then(Commands.literal("list") .then(Commands.literal("list")
.executes(ctx -> listDimensionGameModes(ctx.getSource()))) .executes(ctx -> listDimensionGameModes(ctx.getSource())))
.then(Commands.literal("set") .then(Commands.literal("set")
.requires(source -> CONFIG.get().manageDimensionGamemode)
.then(Commands.argument("dimension", IdentifierArgument.id()) .then(Commands.argument("dimension", IdentifierArgument.id())
.suggests((ctx, builder) -> SharedSuggestionProvider.suggestResource( .suggests((ctx, builder) -> SharedSuggestionProvider.suggestResource(
ctx.getSource().getServer().levelKeys().stream().map(ResourceKey::identifier), builder)) ctx.getSource().getServer().levelKeys().stream().map(ResourceKey::identifier), builder))
@@ -270,7 +265,6 @@ public final class LobbySystemsMod implements ModInitializer {
IdentifierArgument.getId(ctx, "dimension").toString(), IdentifierArgument.getId(ctx, "dimension").toString(),
StringArgumentType.getString(ctx, "mode")))))) StringArgumentType.getString(ctx, "mode"))))))
.then(Commands.literal("remove") .then(Commands.literal("remove")
.requires(source -> CONFIG.get().manageDimensionGamemode)
.then(Commands.argument("dimension", IdentifierArgument.id()) .then(Commands.argument("dimension", IdentifierArgument.id())
.suggests((ctx, builder) -> SharedSuggestionProvider.suggestResource( .suggests((ctx, builder) -> SharedSuggestionProvider.suggestResource(
ctx.getSource().getServer().levelKeys().stream().map(ResourceKey::identifier), builder)) ctx.getSource().getServer().levelKeys().stream().map(ResourceKey::identifier), builder))
@@ -382,11 +376,9 @@ public final class LobbySystemsMod implements ModInitializer {
LobbyLog.state("RELOAD FAILED", "Reason: dimension-gamemodes.json gagal dibaca"); LobbyLog.state("RELOAD FAILED", "Reason: dimension-gamemodes.json gagal dibaca");
return 0; return 0;
} }
if (CONFIG.get().manageDimensionGamemode) {
for (String dimension : DIMENSION_GAMEMODES.all().keySet()) { for (String dimension : DIMENSION_GAMEMODES.all().keySet()) {
DIMENSION_GAMEMODES.applyToDimension(server, dimension); DIMENSION_GAMEMODES.applyToDimension(server, dimension);
} }
}
logDimensionInventoryCompatibility(); logDimensionInventoryCompatibility();
refreshCommandTrees(server); refreshCommandTrees(server);
@@ -410,8 +402,7 @@ public final class LobbySystemsMod implements ModInitializer {
"Minimum play: " + CONFIG.get().minimumPlaySeconds + "s", "Minimum play: " + CONFIG.get().minimumPlaySeconds + "s",
"Portals: " + PORTALS.size(), "Portals: " + PORTALS.size(),
"Portal visual blocks restored: " + repairedPortalVisuals, "Portal visual blocks restored: " + repairedPortalVisuals,
"Dimension gamemodes: " + DIMENSION_GAMEMODES.all().size() "Dimension gamemodes: " + DIMENSION_GAMEMODES.all().size() + " (authoritative)",
+ " (management " + (CONFIG.get().manageDimensionGamemode ? "enabled" : "disabled") + ")",
"Dimension gamerules: " + DIMENSION_GAMERULES.all().size() + " dimensions / " + gameRuleSummary.applied() + " rules applied", "Dimension gamerules: " + DIMENSION_GAMERULES.all().size() + " dimensions / " + gameRuleSummary.applied() + " rules applied",
"Player positions lobby exclusion: active" "Player positions lobby exclusion: active"
); );
@@ -604,26 +595,19 @@ public final class LobbySystemsMod implements ModInitializer {
private static int listDimensionGameModes(CommandSourceStack source) { private static int listDimensionGameModes(CommandSourceStack source) {
Map<String, String> all = DIMENSION_GAMEMODES.all(); Map<String, String> all = DIMENSION_GAMEMODES.all();
if (all.isEmpty()) { if (all.isEmpty()) {
String hint = CONFIG.get().manageDimensionGamemode
? "\n§7Gunakan §f/ls gamemode set <dimension> <mode>"
: "\n§7Management gamemode sedang §cdisabled§7; mode viewer-only aktif.";
sendCommandMessage(source, Component.literal( sendCommandMessage(source, Component.literal(
"§eBelum ada gamemode dimension yang dikonfigurasi." + hint)); "§eBelum ada gamemode dimension yang dikonfigurasi."
+ "\n§7Gunakan §f/ls gamemode set <dimension> <mode>"));
return 1; return 1;
} }
sendCommandMessage(source, Component.literal( sendCommandMessage(source, Component.literal(
"§6§lLobby Systems Dimension Gamemodes §r§7(" + all.size() + ")" "§6§lLobby Systems Dimension Gamemodes §r§7(" + all.size() + ") §8[authoritative]"));
+ (CONFIG.get().manageDimensionGamemode ? " §8[managed]" : " §8[viewer-only]")));
all.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(entry -> all.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(entry ->
sendCommandMessage(source, Component.literal("§8• §f" + entry.getKey() + " §7= §a" + entry.getValue()))); sendCommandMessage(source, Component.literal("§8• §f" + entry.getKey() + " §7= §a" + entry.getValue())));
return all.size(); return all.size();
} }
private static int setDimensionGameMode(CommandSourceStack source, MinecraftServer server, String dimensionId, String rawMode) { private static int setDimensionGameMode(CommandSourceStack source, MinecraftServer server, String dimensionId, String rawMode) {
if (!CONFIG.get().manageDimensionGamemode) {
source.sendFailure(Component.literal("§cDimension gamemode management sedang disabled di config.json."));
return 0;
}
ServerLevel level = findLevel(server, dimensionId); ServerLevel level = findLevel(server, dimensionId);
if (level == null) { if (level == null) {
source.sendFailure(Component.literal("§cDimension '" + dimensionId + "' tidak ditemukan atau tidak ter-load.")); source.sendFailure(Component.literal("§cDimension '" + dimensionId + "' tidak ditemukan atau tidak ter-load."));
@@ -653,10 +637,6 @@ public final class LobbySystemsMod implements ModInitializer {
} }
private static int removeDimensionGameMode(CommandSourceStack source, String dimensionId) { private static int removeDimensionGameMode(CommandSourceStack source, String dimensionId) {
if (!CONFIG.get().manageDimensionGamemode) {
source.sendFailure(Component.literal("§cDimension gamemode management sedang disabled di config.json."));
return 0;
}
if (!DIMENSION_GAMEMODES.remove(dimensionId)) { if (!DIMENSION_GAMEMODES.remove(dimensionId)) {
source.sendFailure(Component.literal("§cTidak ada mapping gamemode untuk dimension '" + dimensionId + "'.")); source.sendFailure(Component.literal("§cTidak ada mapping gamemode untuk dimension '" + dimensionId + "'."));
return 0; return 0;
@@ -673,22 +653,13 @@ public final class LobbySystemsMod implements ModInitializer {
return; return;
} }
if (CONFIG.get().manageDimensionGamemode) {
LobbyLog.state( LobbyLog.state(
"COMPATIBILITY WARNING", "COMPATIBILITY WARNING",
"Dimensional Inventories: detected", "Dimensional Inventories: detected",
"manageDimensionGamemode: true", "Lobby Systems dimension gamemode management: authoritative / always enabled",
"Both mods can apply player gamemode on dimension/pool changes.", "Lobby Systems will enforce dimension-gamemodes.json on join and dimension changes.",
"Keep matching gamemodes in Lobby Systems and Dimensional Inventories to avoid conflicting transitions." "Keep Dimensional Inventories pool gamemodes aligned (or disable its gamemode handling) to avoid conflicting transitions."
); );
} else {
LobbyLog.state(
"DIMENSION GAMEMODE COMPATIBILITY",
"Dimensional Inventories: detected",
"manageDimensionGamemode: false",
"Lobby Systems gamemode commands are viewer-only; Dimensional Inventories may manage player gamemode."
);
}
} }
private static void refreshCommandTrees(MinecraftServer server) { private static void refreshCommandTrees(MinecraftServer server) {
@@ -926,9 +897,7 @@ public final class LobbySystemsMod implements ModInitializer {
boolean ok = TELEPORTS.teleport(player, target, x, y, z, yaw, pitch); boolean ok = TELEPORTS.teleport(player, target, x, y, z, yaw, pitch);
if (!ok) return 0; if (!ok) return 0;
if (CONFIG.get().manageDimensionGamemode) {
DIMENSION_GAMEMODES.applyForPlayer(player, true); DIMENSION_GAMEMODES.applyForPlayer(player, true);
}
if (sendMessage) { if (sendMessage) {
player.sendSystemMessage(Component.literal(returning player.sendSystemMessage(Component.literal(returning
@@ -988,9 +957,7 @@ public final class LobbySystemsMod implements ModInitializer {
"Position: [" + String.format("%.2f", c.lobbyX) + ", " "Position: [" + String.format("%.2f", c.lobbyX) + ", "
+ String.format("%.2f", c.lobbyY) + ", " + String.format("%.2f", c.lobbyY) + ", "
+ String.format("%.2f", c.lobbyZ) + "]", + String.format("%.2f", c.lobbyZ) + "]",
"Gamemode: " + (c.manageDimensionGamemode "Gamemode: " + String.valueOf(DIMENSION_GAMEMODES.get(c.lobbyDimension))
? String.valueOf(DIMENSION_GAMEMODES.get(c.lobbyDimension))
: "unmanaged")
); );
} }
@@ -1032,7 +999,7 @@ public final class LobbySystemsMod implements ModInitializer {
LobbyConfig c = CONFIG.get(); LobbyConfig c = CONFIG.get();
boolean ok = TELEPORTS.teleport(player, target, c.lobbyX, c.lobbyY, c.lobbyZ, c.lobbyYaw, c.lobbyPitch); boolean ok = TELEPORTS.teleport(player, target, c.lobbyX, c.lobbyY, c.lobbyZ, c.lobbyYaw, c.lobbyPitch);
if (ok && CONFIG.get().manageDimensionGamemode) { if (ok) {
DIMENSION_GAMEMODES.applyForPlayer(player, true); DIMENSION_GAMEMODES.applyForPlayer(player, true);
} }
if (ok && sendMessage) player.sendSystemMessage(Component.literal(c.returnedMessage)); if (ok && sendMessage) player.sendSystemMessage(Component.literal(c.returnedMessage));