Skip to content

Commit 86aec70

Browse files
Switch Bukkit config handling to ConfigLib (#229)
1 parent 94f8c27 commit 86aec70

4 files changed

Lines changed: 331 additions & 55 deletions

File tree

bukkit/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ plugins {
55
dependencies {
66
implementation("net.pistonmaster:PistonUtils:1.4.0")
77
implementation("org.bstats:bstats-bukkit:3.1.0")
8+
implementation("de.exlll:configlib-yaml:4.6.3")
89

910
compileOnly("net.dmulloy2:ProtocolLib:5.4.0")
1011
compileOnly("org.spigotmc:spigot-api:1.18.1-R0.1-SNAPSHOT")

bukkit/src/main/java/net/pistonmaster/pistonqueue/bukkit/PistonQueueBukkit.java

Lines changed: 151 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,32 @@
1919
*/
2020
package net.pistonmaster.pistonqueue.bukkit;
2121

22+
import de.exlll.configlib.NameFormatters;
23+
import de.exlll.configlib.YamlConfigurations;
2224
import lombok.Getter;
2325
import net.md_5.bungee.api.ChatColor;
26+
import net.pistonmaster.pistonqueue.bukkit.config.BukkitConfig;
2427
import net.pistonmaster.pistonutils.update.GitHubUpdateChecker;
2528
import net.pistonmaster.pistonutils.update.SemanticVersion;
2629
import org.bukkit.World;
30+
import org.bukkit.configuration.file.YamlConfiguration;
2731
import org.bukkit.plugin.java.JavaPlugin;
2832

33+
import java.io.File;
2934
import java.io.IOException;
30-
import java.util.logging.Logger;
35+
import java.nio.file.Files;
36+
import java.nio.file.Path;
37+
import java.util.HashSet;
38+
import java.util.Set;
39+
import java.util.function.Consumer;
40+
import java.util.function.IntConsumer;
3141
import java.util.logging.Level;
42+
import java.util.logging.Logger;
3243

3344
@Getter
3445
public final class PistonQueueBukkit extends JavaPlugin {
46+
private final Set<String> warnedLegacyPaths = new HashSet<>();
47+
private BukkitConfig pluginConfig;
3548
private boolean forceLocation;
3649

3750
private String forcedWorldName;
@@ -72,36 +85,13 @@ public void onEnable() {
7285
log.info(ChatColor.BLUE + "PistonQueue V" + getDescription().getVersion());
7386

7487
log.info(ChatColor.BLUE + "Loading config");
75-
saveDefaultConfig();
76-
77-
forceLocation = getConfig().getBoolean("forceLocation");
78-
forcedWorldName = getConfig().getString("forcedWorldName");
79-
forcedX = getConfig().getInt("forcedX");
80-
forcedY = getConfig().getInt("forcedY");
81-
forcedZ = getConfig().getInt("forcedZ");
82-
hidePlayers = getConfig().getBoolean("hidePlayers");
83-
restrictMovement = getConfig().getBoolean("restrictMovement");
84-
forceGamemode = getConfig().getBoolean("forceGamemode");
85-
disableChat = getConfig().getBoolean("disableChat");
86-
disableCmd = getConfig().getBoolean("disableCmd");
87-
forcedGamemode = getConfig().getString("forcedGamemode");
88-
team = getConfig().getBoolean("team");
89-
teamName = getConfig().getString("teamName");
90-
91-
preventExperience = getConfig().getBoolean("preventExperience");
92-
preventDamage = getConfig().getBoolean("preventDamage");
93-
preventHunger = getConfig().getBoolean("preventHunger");
94-
95-
disableDebug = getConfig().getBoolean("disableDebug");
96-
97-
noChunkPackets = getConfig().getBoolean("noChunkPackets");
98-
noTimePackets = getConfig().getBoolean("noTimePackets");
99-
noHealthPackets = getConfig().getBoolean("noHealthPackets");
100-
noAdvancementPackets = getConfig().getBoolean("noAdvancementPackets");
101-
noExperiencePackets = getConfig().getBoolean("noExperiencePackets");
102-
showHeadPacket = getConfig().getBoolean("showHeadPacket");
103-
104-
playXP = getConfig().getBoolean("playXP");
88+
try {
89+
pluginConfig = loadConfig();
90+
} catch (IOException e) {
91+
throw new IllegalStateException("Failed to load config", e);
92+
}
93+
94+
applyConfig(pluginConfig);
10595

10696
log.info(ChatColor.BLUE + "Preparing server");
10797
if (hidePlayers) {
@@ -149,4 +139,134 @@ public void onEnable() {
149139
public void onDisable() {
150140
this.getServer().getMessenger().unregisterOutgoingPluginChannel(this);
151141
}
142+
143+
private BukkitConfig loadConfig() throws IOException {
144+
Path dataFolder = getDataFolder().toPath();
145+
if (Files.notExists(dataFolder)) {
146+
Files.createDirectories(dataFolder);
147+
}
148+
149+
Path configFile = dataFolder.resolve("config.yml");
150+
BukkitConfig config = YamlConfigurations.update(
151+
configFile,
152+
BukkitConfig.class,
153+
builder -> builder.setNameFormatter(NameFormatters.IDENTITY)
154+
);
155+
156+
if (applyLegacyOverrides(configFile.toFile(), config)) {
157+
YamlConfigurations.save(configFile, BukkitConfig.class, config);
158+
}
159+
160+
return config;
161+
}
162+
163+
private void applyConfig(BukkitConfig config) {
164+
forceLocation = config.location.enabled;
165+
forcedWorldName = config.location.world;
166+
forcedX = config.location.coordinates.x;
167+
forcedY = config.location.coordinates.y;
168+
forcedZ = config.location.coordinates.z;
169+
170+
hidePlayers = config.visibility.hidePlayers;
171+
restrictMovement = config.visibility.restrictMovement;
172+
forceGamemode = config.visibility.forceGamemode.enabled;
173+
forcedGamemode = config.visibility.forceGamemode.mode;
174+
team = config.visibility.team.enabled;
175+
teamName = config.visibility.team.name;
176+
177+
disableChat = config.communication.disableChat;
178+
disableCmd = config.communication.disableCommands;
179+
180+
playXP = config.audio.playXpSound;
181+
182+
preventExperience = config.protections.preventExperience;
183+
preventDamage = config.protections.preventDamage;
184+
preventHunger = config.protections.preventHunger;
185+
186+
disableDebug = config.protocolLib.disableDebug;
187+
noChunkPackets = config.protocolLib.suppressPackets.chunk;
188+
noTimePackets = config.protocolLib.suppressPackets.time;
189+
noHealthPackets = config.protocolLib.suppressPackets.health;
190+
noAdvancementPackets = config.protocolLib.suppressPackets.advancement;
191+
noExperiencePackets = config.protocolLib.suppressPackets.experience;
192+
showHeadPacket = config.protocolLib.showFullHead;
193+
}
194+
195+
private boolean applyLegacyOverrides(File file, BukkitConfig config) {
196+
if (file == null || !file.exists()) {
197+
return false;
198+
}
199+
200+
YamlConfiguration legacy = YamlConfiguration.loadConfiguration(file);
201+
boolean updated = false;
202+
203+
updated |= copyBoolean(legacy, "forceLocation", "location.enabled", value -> config.location.enabled = value);
204+
updated |= copyString(legacy, "forcedWorldName", "location.world", value -> config.location.world = value);
205+
updated |= copyInt(legacy, "forcedX", "location.coordinates.x", value -> config.location.coordinates.x = value);
206+
updated |= copyInt(legacy, "forcedY", "location.coordinates.y", value -> config.location.coordinates.y = value);
207+
updated |= copyInt(legacy, "forcedZ", "location.coordinates.z", value -> config.location.coordinates.z = value);
208+
209+
updated |= copyBoolean(legacy, "hidePlayers", "visibility.hidePlayers", value -> config.visibility.hidePlayers = value);
210+
updated |= copyBoolean(legacy, "restrictMovement", "visibility.restrictMovement", value -> config.visibility.restrictMovement = value);
211+
updated |= copyBoolean(legacy, "forceGamemode", "visibility.forceGamemode.enabled", value -> config.visibility.forceGamemode.enabled = value);
212+
updated |= copyString(legacy, "forcedGamemode", "visibility.forceGamemode.mode", value -> config.visibility.forceGamemode.mode = value);
213+
updated |= copyBoolean(legacy, "team", "visibility.team.enabled", value -> config.visibility.team.enabled = value);
214+
updated |= copyString(legacy, "teamName", "visibility.team.name", value -> config.visibility.team.name = value);
215+
216+
updated |= copyBoolean(legacy, "disableChat", "communication.disableChat", value -> config.communication.disableChat = value);
217+
updated |= copyBoolean(legacy, "disableCmd", "communication.disableCommands", value -> config.communication.disableCommands = value);
218+
219+
updated |= copyBoolean(legacy, "playXP", "audio.playXpSound", value -> config.audio.playXpSound = value);
220+
221+
updated |= copyBoolean(legacy, "preventExperience", "protections.preventExperience", value -> config.protections.preventExperience = value);
222+
updated |= copyBoolean(legacy, "preventDamage", "protections.preventDamage", value -> config.protections.preventDamage = value);
223+
updated |= copyBoolean(legacy, "preventHunger", "protections.preventHunger", value -> config.protections.preventHunger = value);
224+
225+
updated |= copyBoolean(legacy, "disableDebug", "protocolLib.disableDebug", value -> config.protocolLib.disableDebug = value);
226+
updated |= copyBoolean(legacy, "noChunkPackets", "protocolLib.suppressPackets.chunk", value -> config.protocolLib.suppressPackets.chunk = value);
227+
updated |= copyBoolean(legacy, "noTimePackets", "protocolLib.suppressPackets.time", value -> config.protocolLib.suppressPackets.time = value);
228+
updated |= copyBoolean(legacy, "noHealthPackets", "protocolLib.suppressPackets.health", value -> config.protocolLib.suppressPackets.health = value);
229+
updated |= copyBoolean(legacy, "noAdvancementPackets", "protocolLib.suppressPackets.advancement", value -> config.protocolLib.suppressPackets.advancement = value);
230+
updated |= copyBoolean(legacy, "noExperiencePackets", "protocolLib.suppressPackets.experience", value -> config.protocolLib.suppressPackets.experience = value);
231+
updated |= copyBoolean(legacy, "showHeadPacket", "protocolLib.showFullHead", value -> config.protocolLib.showFullHead = value);
232+
233+
return updated;
234+
}
235+
236+
private boolean copyBoolean(YamlConfiguration legacy, String legacyPath, String newPath, Consumer<Boolean> setter) {
237+
if (!legacy.contains(legacyPath)) {
238+
return false;
239+
}
240+
241+
setter.accept(legacy.getBoolean(legacyPath));
242+
logLegacyUsage(newPath, legacyPath);
243+
return true;
244+
}
245+
246+
private boolean copyInt(YamlConfiguration legacy, String legacyPath, String newPath, IntConsumer setter) {
247+
if (!legacy.contains(legacyPath)) {
248+
return false;
249+
}
250+
251+
setter.accept(legacy.getInt(legacyPath));
252+
logLegacyUsage(newPath, legacyPath);
253+
return true;
254+
}
255+
256+
private boolean copyString(YamlConfiguration legacy, String legacyPath, String newPath, Consumer<String> setter) {
257+
if (!legacy.contains(legacyPath)) {
258+
return false;
259+
}
260+
261+
setter.accept(legacy.getString(legacyPath));
262+
logLegacyUsage(newPath, legacyPath);
263+
return true;
264+
}
265+
266+
private void logLegacyUsage(String newPath, String legacyPath) {
267+
if (warnedLegacyPaths.add(legacyPath)) {
268+
getLogger()
269+
.warning(String.format("Configuration option '%s' has moved to '%s'. Please update your config.", legacyPath, newPath));
270+
}
271+
}
152272
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package net.pistonmaster.pistonqueue.bukkit.config;
2+
3+
import de.exlll.configlib.Comment;
4+
import de.exlll.configlib.Configuration;
5+
6+
@Configuration
7+
public final class BukkitConfig {
8+
@Comment("Force the user to remain in a certain position.")
9+
public LocationSection location = new LocationSection();
10+
11+
@Comment(
12+
"Visibility controls. Hiding players also disables join/leave messages."
13+
)
14+
public VisibilitySection visibility = new VisibilitySection();
15+
16+
@Comment("Options that prevent communication while waiting in queue.")
17+
public CommunicationSection communication = new CommunicationSection();
18+
19+
@Comment("Audio feedback played when the proxy sends plugin messages.")
20+
public AudioSection audio = new AudioSection();
21+
22+
@Comment("General player protection toggles applied while in queue.")
23+
public ProtectionsSection protections = new ProtectionsSection();
24+
25+
@Comment({ "ProtocolLib specific options", "Only applied when ProtocolLib is present" })
26+
public ProtocolLibSection protocolLib = new ProtocolLibSection();
27+
28+
@Configuration
29+
public static final class LocationSection {
30+
@Comment("Force the user to remain in a certain position.")
31+
public boolean enabled = true;
32+
33+
@Comment("Forced world")
34+
public String world = "world_the_end";
35+
36+
@Comment("Forced coordinates")
37+
public CoordinatesSection coordinates = new CoordinatesSection();
38+
}
39+
40+
@Configuration
41+
public static final class CoordinatesSection {
42+
@Comment("Forced x coordinate")
43+
public int x = 500;
44+
45+
@Comment("Forced y coordinate")
46+
public int y = 256;
47+
48+
@Comment("Forced z coordinate")
49+
public int z = 500;
50+
}
51+
52+
@Configuration
53+
public static final class VisibilitySection {
54+
@Comment(
55+
"Hide players from each other so that it looks like every user is alone in the world."
56+
)
57+
public boolean hidePlayers = true;
58+
59+
@Comment("Prevent players from moving.")
60+
public boolean restrictMovement = true;
61+
62+
@Comment("Force players to remain in a gamemode.")
63+
public ForceGamemodeSection forceGamemode = new ForceGamemodeSection();
64+
65+
@Comment("Show a player's own name to themselves in spectator menu.")
66+
public TeamSection team = new TeamSection();
67+
}
68+
69+
@Configuration
70+
public static final class ForceGamemodeSection {
71+
@Comment("Force players to remain in a gamemode.")
72+
public boolean enabled = true;
73+
74+
@Comment("The gamemode to force players to remain in.")
75+
public String mode = "spectator";
76+
}
77+
78+
@Configuration
79+
public static final class TeamSection {
80+
@Comment("Show a player's own name to themselves in spectator menu.")
81+
public boolean enabled = false;
82+
83+
@Comment("The team name the user sees. (Valid placeholders: %player_name%, %random%)")
84+
public String name = "%player_name%";
85+
}
86+
87+
@Configuration
88+
public static final class CommunicationSection {
89+
@Comment("Don't allow players to chat.")
90+
public boolean disableChat = true;
91+
92+
@Comment("Don't allow commands.")
93+
public boolean disableCommands = true;
94+
}
95+
96+
@Configuration
97+
public static final class AudioSection {
98+
@Comment("Plays an XP sound when the proxy sends a plugin message.")
99+
public boolean playXpSound = true;
100+
}
101+
102+
@Configuration
103+
public static final class ProtectionsSection {
104+
@Comment("Prevents players from gaining experience.")
105+
public boolean preventExperience = true;
106+
107+
@Comment("Prevents players from getting damage.")
108+
public boolean preventDamage = true;
109+
110+
@Comment("Prevents players from gaining hunger.")
111+
public boolean preventHunger = true;
112+
}
113+
114+
@Configuration
115+
public static final class ProtocolLibSection {
116+
@Comment("Doesn't show the client's position on F3.")
117+
public boolean disableDebug = true;
118+
119+
@Comment("Packets that should be suppressed when ProtocolLib is installed.")
120+
public SuppressPacketsSection suppressPackets = new SuppressPacketsSection();
121+
122+
@Comment(
123+
"Does not send entity metadata anymore, causing that the entire player head is shown while in spectator."
124+
)
125+
public boolean showFullHead = true;
126+
}
127+
128+
@Configuration
129+
public static final class SuppressPacketsSection {
130+
@Comment("Do not send chunk data packets.")
131+
public boolean chunk = true;
132+
133+
@Comment("Do not send time packets.")
134+
public boolean time = true;
135+
136+
@Comment("Do not send health packets.")
137+
public boolean health = true;
138+
139+
@Comment("Do not send advancement packets.")
140+
public boolean advancement = true;
141+
142+
@Comment("Do not send experience packets.")
143+
public boolean experience = true;
144+
}
145+
}

0 commit comments

Comments
 (0)