Bugfix compatibility
This commit is contained in:
@@ -9,6 +9,9 @@ public final class LobbyConfig {
|
||||
public float lobbyPitch = 0.0f;
|
||||
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. */
|
||||
public int portalCheckIntervalTicks = 5;
|
||||
/** Cooldown setelah portal terpicu. 60 tick = 3 detik. */
|
||||
|
||||
@@ -3,6 +3,7 @@ package id.dartokloning.lobbysystems;
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
@@ -79,6 +80,8 @@ public final class LobbySystemsMod implements ModInitializer {
|
||||
"Configured dimensions: " + DIMENSION_GAMEMODES.all().size()
|
||||
);
|
||||
|
||||
logDimensionInventoryCompatibility();
|
||||
|
||||
boolean gameRulesLoaded = DIMENSION_GAMERULES.load();
|
||||
LobbyLog.state(
|
||||
gameRulesLoaded ? "DIMENSION GAMERULES LOADED" : "DIMENSION GAMERULES LOAD FAILED",
|
||||
@@ -145,7 +148,9 @@ public final class LobbySystemsMod implements ModInitializer {
|
||||
}
|
||||
});
|
||||
|
||||
DIMENSION_GAMEMODES.tick(server);
|
||||
if (CONFIG.get().manageDimensionGamemode) {
|
||||
DIMENSION_GAMEMODES.tick(server);
|
||||
}
|
||||
|
||||
ResourceKey<Level> lobby = lobbyKey();
|
||||
for (ServerPlayer player : server.getPlayerList().getPlayers()) {
|
||||
@@ -229,6 +234,7 @@ public final class LobbySystemsMod implements ModInitializer {
|
||||
.then(Commands.literal("list")
|
||||
.executes(ctx -> listDimensionGameModes(ctx.getSource())))
|
||||
.then(Commands.literal("set")
|
||||
.requires(source -> CONFIG.get().manageDimensionGamemode)
|
||||
.then(Commands.argument("dimension", IdentifierArgument.id())
|
||||
.suggests((ctx, builder) -> SharedSuggestionProvider.suggestResource(
|
||||
ctx.getSource().getServer().levelKeys().stream().map(ResourceKey::identifier), builder))
|
||||
@@ -241,18 +247,13 @@ public final class LobbySystemsMod implements ModInitializer {
|
||||
IdentifierArgument.getId(ctx, "dimension").toString(),
|
||||
StringArgumentType.getString(ctx, "mode"))))))
|
||||
.then(Commands.literal("remove")
|
||||
.requires(source -> CONFIG.get().manageDimensionGamemode)
|
||||
.then(Commands.argument("dimension", IdentifierArgument.id())
|
||||
.suggests((ctx, builder) -> SharedSuggestionProvider.suggestResource(
|
||||
ctx.getSource().getServer().levelKeys().stream().map(ResourceKey::identifier), builder))
|
||||
.executes(ctx -> removeDimensionGameMode(
|
||||
ctx.getSource(),
|
||||
IdentifierArgument.getId(ctx, "dimension").toString()))))
|
||||
.then(Commands.argument("dimension", IdentifierArgument.id())
|
||||
.suggests((ctx, builder) -> SharedSuggestionProvider.suggestResource(
|
||||
ctx.getSource().getServer().levelKeys().stream().map(ResourceKey::identifier), builder))
|
||||
.executes(ctx -> showDimensionGameMode(
|
||||
ctx.getSource(),
|
||||
IdentifierArgument.getId(ctx, "dimension").toString()))))
|
||||
IdentifierArgument.getId(ctx, "dimension").toString())))))
|
||||
.then(Commands.literal("portal")
|
||||
.then(Commands.literal("create")
|
||||
.then(Commands.argument("name", StringArgumentType.word())
|
||||
@@ -357,9 +358,13 @@ public final class LobbySystemsMod implements ModInitializer {
|
||||
LobbyLog.state("RELOAD FAILED", "Reason: dimension-gamemodes.json gagal dibaca");
|
||||
return 0;
|
||||
}
|
||||
for (String dimension : DIMENSION_GAMEMODES.all().keySet()) {
|
||||
DIMENSION_GAMEMODES.applyToDimension(server, dimension);
|
||||
if (CONFIG.get().manageDimensionGamemode) {
|
||||
for (String dimension : DIMENSION_GAMEMODES.all().keySet()) {
|
||||
DIMENSION_GAMEMODES.applyToDimension(server, dimension);
|
||||
}
|
||||
}
|
||||
logDimensionInventoryCompatibility();
|
||||
refreshCommandTrees(server);
|
||||
|
||||
boolean gameRulesOk = DIMENSION_GAMERULES.load();
|
||||
if (!gameRulesOk) {
|
||||
@@ -380,7 +385,8 @@ public final class LobbySystemsMod implements ModInitializer {
|
||||
"Lobby: " + CONFIG.get().lobbyDimension,
|
||||
"Minimum play: " + CONFIG.get().minimumPlaySeconds + "s",
|
||||
"Portals: " + PORTALS.size(),
|
||||
"Dimension gamemodes: " + DIMENSION_GAMEMODES.all().size(),
|
||||
"Dimension gamemodes: " + DIMENSION_GAMEMODES.all().size()
|
||||
+ " (management " + (CONFIG.get().manageDimensionGamemode ? "enabled" : "disabled") + ")",
|
||||
"Dimension gamerules: " + DIMENSION_GAMERULES.all().size() + " dimensions / " + gameRuleSummary.applied() + " rules applied",
|
||||
"Player positions lobby exclusion: active"
|
||||
);
|
||||
@@ -570,34 +576,29 @@ public final class LobbySystemsMod implements ModInitializer {
|
||||
return rule.serialize(level.getGameRules().get(rule));
|
||||
}
|
||||
|
||||
private static int showDimensionGameMode(CommandSourceStack source, String dimensionId) {
|
||||
String mode = DIMENSION_GAMEMODES.get(dimensionId);
|
||||
if (mode == null) {
|
||||
sendCommandMessage(source, Component.literal(
|
||||
"§6Lobby Systems Gamemode\n§7Dimension: §f" + dimensionId
|
||||
+ "\n§7Configured: §e<none>"
|
||||
+ "\n§8Player akan mempertahankan gamemode sebelumnya sampai mapping dibuat."));
|
||||
return 1;
|
||||
}
|
||||
sendCommandMessage(source, Component.literal(
|
||||
"§6Lobby Systems Gamemode\n§7Dimension: §f" + dimensionId + "\n§7Gamemode: §a" + mode));
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int listDimensionGameModes(CommandSourceStack source) {
|
||||
Map<String, String> all = DIMENSION_GAMEMODES.all();
|
||||
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(
|
||||
"§eBelum ada gamemode dimension yang dikonfigurasi.\n§7Gunakan §f/ls gamemode set <dimension> <mode>"));
|
||||
"§eBelum ada gamemode dimension yang dikonfigurasi." + hint));
|
||||
return 1;
|
||||
}
|
||||
sendCommandMessage(source, Component.literal("§6§lLobby Systems Dimension Gamemodes §r§7(" + all.size() + ")"));
|
||||
sendCommandMessage(source, Component.literal(
|
||||
"§6§lLobby Systems Dimension Gamemodes §r§7(" + all.size() + ")"
|
||||
+ (CONFIG.get().manageDimensionGamemode ? " §8[managed]" : " §8[viewer-only]")));
|
||||
all.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(entry ->
|
||||
sendCommandMessage(source, Component.literal("§8• §f" + entry.getKey() + " §7= §a" + entry.getValue())));
|
||||
return all.size();
|
||||
}
|
||||
|
||||
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);
|
||||
if (level == null) {
|
||||
source.sendFailure(Component.literal("§cDimension '" + dimensionId + "' tidak ditemukan atau tidak ter-load."));
|
||||
@@ -627,6 +628,10 @@ public final class LobbySystemsMod implements ModInitializer {
|
||||
}
|
||||
|
||||
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)) {
|
||||
source.sendFailure(Component.literal("§cTidak ada mapping gamemode untuk dimension '" + dimensionId + "'."));
|
||||
return 0;
|
||||
@@ -638,6 +643,39 @@ public final class LobbySystemsMod implements ModInitializer {
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static void logDimensionInventoryCompatibility() {
|
||||
if (!FabricLoader.getInstance().isModLoaded("dimensional-inventories")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (CONFIG.get().manageDimensionGamemode) {
|
||||
LobbyLog.state(
|
||||
"COMPATIBILITY WARNING",
|
||||
"Dimensional Inventories: detected",
|
||||
"manageDimensionGamemode: true",
|
||||
"Both mods can apply player gamemode on dimension/pool changes.",
|
||||
"Keep matching gamemodes in Lobby Systems and Dimensional Inventories 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) {
|
||||
for (ServerPlayer player : server.getPlayerList().getPlayers()) {
|
||||
try {
|
||||
server.getCommands().sendCommands(player);
|
||||
} catch (RuntimeException e) {
|
||||
LOGGER.warn("Failed to refresh command tree for {} after config reload.", player.getGameProfile().name(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private record GameRuleEntry(String name, String value) {}
|
||||
|
||||
private static int createPortal(ServerPlayer player, MinecraftServer server, String rawName, String rawTarget) {
|
||||
|
||||
@@ -9,6 +9,9 @@ import java.lang.reflect.Modifier;
|
||||
/**
|
||||
* Soft integration dengan WorldEdit. Reflection sengaja dipakai agar Lobby Systems
|
||||
* tetap dapat dijalankan tanpa WorldEdit; portal yang sudah tersimpan tetap bekerja.
|
||||
*
|
||||
* Mendukung WorldEdit Fabric 7.4.x (FabricAdapter.get().fromNativePlayer(...))
|
||||
* sekaligus fallback API lama agar bridge tidak rapuh saat server memakai build berbeda.
|
||||
*/
|
||||
public final class WorldEditSelectionBridge {
|
||||
private WorldEditSelectionBridge() {}
|
||||
@@ -23,13 +26,10 @@ public final class WorldEditSelectionBridge {
|
||||
}
|
||||
|
||||
Class<?> adapterClass = Class.forName("com.sk89q.worldedit.fabric.FabricAdapter");
|
||||
Object actor;
|
||||
try {
|
||||
actor = invokeCompatibleStatic(adapterClass, "adaptPlayer", player);
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
actor = invokeCompatibleStatic(adapterClass, "adapt", player);
|
||||
Object actor = adaptPlayer(adapterClass, player);
|
||||
if (actor == null) {
|
||||
throw new IllegalStateException("FabricAdapter tidak dapat mengadaptasi player.");
|
||||
}
|
||||
if (actor == null) throw new IllegalStateException("FabricAdapter tidak dapat mengadaptasi player.");
|
||||
|
||||
Class<?> worldEditClass = Class.forName("com.sk89q.worldedit.WorldEdit");
|
||||
Object worldEdit = worldEditClass.getMethod("getInstance").invoke(null);
|
||||
@@ -53,6 +53,30 @@ public final class WorldEditSelectionBridge {
|
||||
);
|
||||
}
|
||||
|
||||
private static Object adaptPlayer(Class<?> adapterClass, ServerPlayer player) throws Exception {
|
||||
// WorldEdit 7.4.x Fabric API: FabricAdapter.get().fromNativePlayer(ServerPlayer)
|
||||
try {
|
||||
Object adapter = adapterClass.getMethod("get").invoke(null);
|
||||
try {
|
||||
return invokeCompatible(adapter, "fromNativePlayer", player);
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
// Some CoreMcAdapter builds may expose a differently named instance bridge.
|
||||
try {
|
||||
return invokeCompatible(adapter, "adaptPlayer", player);
|
||||
} catch (NoSuchMethodException ignoredAgain) {
|
||||
return invokeCompatible(adapter, "adapt", player);
|
||||
}
|
||||
}
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
// Backward compatibility for older WorldEdit Fabric adapters.
|
||||
try {
|
||||
return invokeCompatibleStatic(adapterClass, "adaptPlayer", player);
|
||||
} catch (NoSuchMethodException ignoredAgain) {
|
||||
return invokeCompatibleStatic(adapterClass, "adapt", player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int intValue(Object object, String method) throws Exception {
|
||||
return ((Number) object.getClass().getMethod(method).invoke(object)).intValue();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user