Fork of Poseidon providing Bukkit #1060 to older Beta versions (b1.0-b1.7.3)
1package com.legacyminecraft.poseidon;
2
3import org.bukkit.util.config.Configuration;
4
5import java.io.File;
6import java.util.Arrays;
7import java.util.UUID;
8import java.util.regex.Pattern;
9
10public class PoseidonConfig extends Configuration {
11 private static PoseidonConfig singleton;
12 private final int configVersion = 5;
13 private Integer[] treeBlacklistIDs;
14
15 public Integer[] getTreeBlacklistIDs() {
16 return treeBlacklistIDs;
17 }
18
19 private PoseidonConfig() {
20 super(new File("poseidon.yml"));
21 this.reload();
22 }
23
24 public void reload() {
25 this.load();
26 this.write();
27 this.validation();
28 this.save();
29 }
30
31 public void resetConfig() {
32 // Delete all the config options
33 for (String key : this.getKeys()) {
34 this.removeProperty(key);
35 }
36 // Reload the config
37 this.write();
38 }
39
40 private void validation() {
41 //Confirm settings.uuid-fetcher.method.value is either POST or GET
42 if (!this.getConfigString("settings.uuid-fetcher.method.value").equalsIgnoreCase("POST") && !this.getConfigString("settings.uuid-fetcher.method.value").equalsIgnoreCase("GET")) {
43 System.out.println("[Poseidon] Config: settings.uuid-fetcher.method.value is not POST or GET. Changing to POST.");
44 this.setProperty("settings.uuid-fetcher.method.value", "POST");
45 }
46 }
47
48 private void write() {
49 if (this.getString("config-version") == null || Integer.valueOf(this.getString("config-version")) < configVersion) {
50 System.out.println("[Poseidon] Converting from config version " + (this.getString("config-version") == null ? "0" : this.getString("config-version")) + " to " + configVersion);
51 convertToNewConfig();
52 this.setProperty("config-version", configVersion);
53 }
54 //Main
55 generateConfigOption("config-version", configVersion);
56 //Setting
57// generateConfigOption("settings.allow-graceful-uuids", true);
58 generateConfigOption("settings.delete-duplicate-uuids", false);
59 generateConfigOption("settings.save-playerdata-by-uuid", true);
60 // Log management and rotation
61 generateConfigOption("settings.per-day-log-file.info", "This setting causes the server to create a new log file each day. This is useful for log rotation and log file management.");
62 generateConfigOption("settings.per-day-log-file.enabled", false);
63 generateConfigOption("settings.per-day-log-file.latest-log.info", "This setting causes the server to create a latest.log similar to modern Minecraft servers. This can be useful for certain control panels and log file management.");
64 generateConfigOption("settings.per-day-log-file.latest-log.enabled", true);
65
66 //generateConfigOption("settings.fetch-uuids-from", "https://api.mojang.com/profiles/minecraft");
67
68 // UUID Fetcher Settings
69 generateConfigOption("settings.uuid-fetcher.post.info", "This setting allows you to change the URL that the server fetches UUIDs from. This is useful if you have a custom UUID server or a proxy server that fetches UUIDs.");
70 generateConfigOption("settings.uuid-fetcher.post.value", "https://api.minecraftservices.com/minecraft/profile/lookup/bulk/byname");
71
72 generateConfigOption("settings.uuid-fetcher.get.info", "This setting allows you to change the URL that the server fetches UUIDs from. This is useful if you have a custom UUID server or a proxy server that fetches UUIDs.");
73 generateConfigOption("settings.uuid-fetcher.get.value", "https://api.minecraftservices.com/minecraft/profile/lookup/name/{username}");
74 generateConfigOption("settings.uuid-fetcher.get.enforce-case-sensitivity.enabled", true);
75 generateConfigOption("settings.uuid-fetcher.get.enforce-case-sensitivity.info", "The Mojang API is case-insensitive by default meaning usernames with different casing will return the same UUID. This setting checks the case of the username to prevent this issue. If the name is invalid, the player will be kicked.");
76
77
78 generateConfigOption("settings.uuid-fetcher.method.value", "POST");
79 generateConfigOption("settings.uuid-fetcher.method.info", "This setting allows for POST or GET method for fetching UUIDs. This is useful if you have a custom UUID server, Mojang API is down, or a proxy server that fetches UUIDs.");
80
81 generateConfigOption("settings.uuid-fetcher.allow-graceful-uuids.value", true);
82 generateConfigOption("settings.uuid-fetcher.allow-graceful-uuids.info", "This setting means offline UUIDs are generated for players who don't have a Mojang UUID. This is useful for cracked or semi-cracked servers.");
83
84 generateConfigOption("settings.remove-join-leave-debug", true);
85 generateConfigOption("settings.enable-tpc-nodelay", false);
86
87 //generateConfigOption("settings.use-get-for-uuids.enabled", true);
88 //generateConfigOption("settings.use-get-for-uuids.info", "This setting causes the server to use the GET method for Username to UUID conversion. This is useful incase the POST method goes offline.");
89
90 //generateConfigOption("settings.use-get-for-uuids.case-sensitive.enabled", true);
91 //generateConfigOption("settings.use-get-for-uuids.case-sensitive.info", "This setting will verify sensitivity of the username as the GET method is case-insensitive.");
92
93 generateConfigOption("settings.faster-packets.enabled", true);
94 generateConfigOption("settings.faster-packets.info", "This setting increases the speed of packets, a fix from newer Minecraft versions.");
95
96 generateConfigOption("settings.fix-drowning-push-down.enabled", true);
97 generateConfigOption("settings.fix-drowning-push-down.info", "This setting fixes taking drowning damage pushing you down.");
98
99 generateConfigOption("settings.player-knockback-fix.enabled", true);
100 generateConfigOption("settings.player-knockback-fix.info", "This setting fixes reduced knockback for certain players on the server.");
101
102 //Watchdog
103 //generateConfigOption("settings.enable-watchdog", true);
104 generateConfigOption("settings.watchdog.info", "Watchdog is a automatic hang detection system which can print stacktraces and kill the server automatically after a predefined interval.");
105 generateConfigOption("settings.watchdog.enable", true);
106 generateConfigOption("settings.watchdog.timeout.value", 120);
107 generateConfigOption("settings.watchdog.timeout.info", "The number of seconds to kill the server process after no ticks occurring.");
108 generateConfigOption("settings.watchdog.debug-timeout.enabled", false);
109 generateConfigOption("settings.watchdog.debug-timeout.value", 30);
110 generateConfigOption("settings.watchdog.debug-timeout.info", "debug-timeout can be used to print a stack trace at a lower interval then the main timeout allowing admins to locate blocking tasks that cause hangs over a certain duration. Only enable this if you have experienced temporary hangs/server freezes.");
111
112 //Packet Events
113 generateConfigOption("settings.packet-events.enabled", false);
114 generateConfigOption("settings.packet-events.info", "This setting causes the server to fire a Bukkit event for each packet received and sent to a player once they have finished the initial login process. This only needs to be enabled if you have a plugin that uses this specific feature.");
115// generateConfigOption("settings.bukkit-event.disabled-plugin-unregister.value", true);
116// generateConfigOption("settings.bukkit-event.disabled-plugin-unregister.info", "This setting will automatically unregister listeners from disabled plugins. This is useful if you have a plugin that can get disabled at runtime and you want to prevent errors to the disabled plugin.");
117 generateConfigOption("settings.packet-spam-detection.enabled", true);
118 generateConfigOption("settings.packet-spam-detection.info", "This setting causes the server to detect and kick malicious players who send too many packets in a short period of time. This is useful to prevent players from sending too many packets to the server to cause lag.");
119 generateConfigOption("settings.packet-spam-detection.threshold", 10000);
120
121 //Statistics
122 generateConfigOption("settings.statistics.key", UUID.randomUUID().toString());
123 generateConfigOption("settings.statistics.enabled", true);
124
125 //World Settings
126 generateConfigOption("world-settings.optimized-explosions", false);
127 generateConfigOption("world-settings.send-explosion-velocity", true);
128 generateConfigOption("world-settings.randomize-spawn", true);
129 generateConfigOption("world-settings.teleport-to-highest-safe-block", true);
130 generateConfigOption("world-settings.use-modern-fence-bounding-boxes", false);
131 //TODO: Actually implement the tree growth functionality stuff
132 generateConfigOption("world.settings.block-tree-growth.enabled", true);
133 generateConfigOption("world.settings.block-tree-growth.list", "54,63,68");
134 generateConfigOption("world.settings.block-tree-growth.info", "This setting allows for server owners to easily block trees growing from automatically destroying certain blocks. The list must be a string with numerical item ids separated by commas.");
135 generateConfigOption("world.settings.block-pistons-pushing-furnaces.info", "This workaround prevents pistons from pushing furnaces which prevents a malicious server crash.");
136 generateConfigOption("world.settings.block-pistons-pushing-furnaces.enabled", true);
137 generateConfigOption("world.settings.pistons.transmutation-fix.enabled", true);
138 generateConfigOption("world.settings.pistons.transmutation-fix.info", "This setting fixes block transmutation exploits.");
139 generateConfigOption("world.settings.pistons.sand-gravel-duping-fix.enabled", true);
140 generateConfigOption("world.settings.pistons.sand-gravel-duping-fix.info", "This setting fixes sand/gravel duplication exploits.");
141 generateConfigOption("world.settings.pistons.other-fixes.enabled", true);
142 generateConfigOption("world.settings.pistons.other-fixes.info", "This setting fixes various other piston exploits like creating illegal pistons, breaking bedrock and duplicating redstone torches.");
143 generateConfigOption("world.settings.skeleton-shooting-sound-fix.info", "This setting fixes the sound of skeletons and players shooting not playing on clients.");
144 generateConfigOption("world.settings.skeleton-shooting-sound-fix.enabled", true);
145 generateConfigOption("world.settings.speed-hack-check.enable", true);
146 generateConfigOption("world.settings.speed-hack-check.teleport", true);
147 generateConfigOption("world.settings.speed-hack-check.distance", 100.0D);
148 generateConfigOption("world.settings.speed-hack-check.info", "This setting allows you to configure the automatic speedhack detection.");
149 //Mob Spawner Area Limit (8 chunks)
150 generateConfigOption("world.settings.mob-spawner-area-limit.enable", true);
151 generateConfigOption("world.settings.mob-spawner-area-limit.limit", 150);
152 generateConfigOption("world.settings.mob-spawner-area-limit.chunk-radius", 8);
153 generateConfigOption("world.settings.mob-spawner-area-limit.info", "This setting controls the maximum number of entities of a mob spawner type that can exist within the defined chunk radius around a mob spawner. If the number of entities exceeds this limit, the spawner will stop spawning additional entities of that type. This is useful to stop the extreme lag that can be caused by mob spawners.");
154
155
156 //generateConfigOption("world-settings.eject-from-vehicle-on-teleport.enabled", true);
157 //generateConfigOption("world-settings.eject-from-vehicle-on-teleport.info", "Eject the player from a boat or minecart before teleporting them preventing cross world coordinate exploits.");
158
159 //Release2Beta Settings
160 generateConfigOption("settings.release2beta.enable-ip-pass-through", false);
161 generateConfigOption("settings.release2beta.proxy-ip", "127.0.0.1");
162
163 //BungeeCord
164 generateConfigOption("settings.bungeecord.bungee-mode.enable", false);
165 generateConfigOption("settings.bungeecord.bungee-mode.kick-message", "You must connect through BungeeCord to join this server!");
166 generateConfigOption("settings.bungeecord.bungee-mode.info", "Only allows connections via BungeeCord to join. Includes optional custom kick message for players not using BungeeCord.");
167
168 //Modded Jar Support
169 generateConfigOption("settings.support.modloader.enable", false);
170 generateConfigOption("settings.support.modloader.info", "EXPERIMENTAL support for ModloaderMP.");
171
172 //Offline Username Check
173 generateConfigOption("settings.check-username-validity.enabled", true);
174 generateConfigOption("settings.check-username-validity.info", "If enabled, verifies the validity of a usernames of cracked players.");
175 generateConfigOption("settings.check-username-validity.regex", "[a-zA-Z0-9_?]*");
176 generateConfigOption("settings.check-username-validity.max-length", 16);
177 generateConfigOption("settings.check-username-validity.min-length", 3);
178 generateConfigOption("emergency.debug.regenerate-corrupt-chunks.enable", false);
179 generateConfigOption("emergency.debug.regenerate-corrupt-chunks.info", "This setting allows you to automatically regenerate corrupt chunks. This is useful after a ungraceful shutdown while a file is being written to or out of memory exception.");
180
181 generateConfigOption("settings.update-checker.enabled", true);
182 generateConfigOption("settings.update-checker.info", "This setting allows you to disable the update checker. This is useful if you have a custom build of Poseidon or don't want to be notified of updates.");
183 generateConfigOption("settings.update-checker.notify-staff.enabled", true);
184 generateConfigOption("settings.update-checker.notify-staff.info", "This setting notifies operators and players with the permission poseidon.update when a new version of Poseidon is available on join.");
185
186 //Messages
187 generateConfigOption("message.kick.banned", "You are banned from this server!");
188 generateConfigOption("message.kick.ip-banned", "Your IP address is banned from this server!");
189 generateConfigOption("message.kick.not-whitelisted", "You are not white-listed on this server!");
190 generateConfigOption("message.kick.full", "The server is full!");
191 generateConfigOption("message.kick.shutdown", "\u00A7cServer is shutting down, please rejoin later.");
192 generateConfigOption("message.kick.already-online", "\u00A7cA player with your username or uuid is already online, try reconnecting in a minute.");
193 generateConfigOption("message.player.join", "\u00A7e%player% joined the game.");
194 generateConfigOption("message.player.leave", "\u00A7e%player% left the game.");
195 generateConfigOption("message.update.available", "\u00A7dA newer version of Poseidon is available: %newversion%");
196
197 //Optional Poseidon Commands
198 generateConfigOption("command.info", "This section allows you to enable or disable optional Poseidon commands. This is useful if you have a plugin that conflicts with a Poseidon command.");
199 generateConfigOption("command.tps.info", "Enables the /tps command to show the server's TPS for various intervals.");
200 generateConfigOption("command.tps.enabled", true);
201
202 //UberBukkit
203 generateConfigOption("fix.optimize-sponges.enabled", true);
204 generateConfigOption("fix.optimize-sponges.info", "Optimizes sponges by removing unnecessary block updates. This can also prevent some block duplication methods.");
205
206 //Tree Leave Destroy Blacklist
207 if (Boolean.valueOf(String.valueOf(getConfigOption("world.settings.block-tree-growth.enabled", true)))) {
208 if (String.valueOf(this.getConfigOption("world.settings.block-tree-growth.list", "")).trim().isEmpty()) {
209 //Empty Blacklist
210 } else {
211 String[] rawBlacklist = String.valueOf(this.getConfigOption("world.settings.block-tree-growth.list", "")).trim().split(",");
212 int blackListCount = 0;
213 for (String stringID : rawBlacklist) {
214 if (Pattern.compile("-?[0-9]+").matcher(stringID).matches()) {
215 blackListCount = blackListCount + 1;
216 } else {
217 System.out.println("The ID " + stringID + " for leaf decay blocker has been detected as invalid, and won't be used.");
218 }
219 }
220 //Loop a second time to get correct array length. I know this is horrible code, but it works and only runs on server startup.
221 treeBlacklistIDs = new Integer[blackListCount];
222 int i = 0;
223 for (String stringID : rawBlacklist) {
224 if (Pattern.compile("-?[0-9]+").matcher(stringID).matches()) {
225 treeBlacklistIDs[i] = Integer.valueOf(stringID);
226 i = i + 1;
227 }
228 }
229 System.out.println("Leaf blocks can't replace the following block IDs: " + Arrays.toString(treeBlacklistIDs));
230 }
231 } else {
232 treeBlacklistIDs = new Integer[0];
233 }
234 }
235
236
237 private void generateConfigOption(String key, Object defaultValue) {
238 if (this.getProperty(key) == null) {
239 this.setProperty(key, defaultValue);
240 }
241 final Object value = this.getProperty(key);
242 this.removeProperty(key);
243 this.setProperty(key, value);
244 }
245
246 //Getters Start
247 public Object getConfigOption(String key) {
248 return this.getProperty(key);
249 }
250
251 public Object getConfigOption(String key, Object defaultValue) {
252 Object value = getConfigOption(key);
253 if (value == null) {
254 value = defaultValue;
255 }
256 return value;
257
258 }
259
260 public String getConfigString(String key) {
261 return String.valueOf(getConfigOption(key));
262 }
263
264 public Integer getConfigInteger(String key) {
265 return Integer.valueOf(getConfigString(key));
266 }
267
268 public Long getConfigLong(String key) {
269 return Long.valueOf(getConfigString(key));
270 }
271
272 public Double getConfigDouble(String key) {
273 return Double.valueOf(getConfigString(key));
274 }
275
276 public Boolean getConfigBoolean(String key) {
277 return Boolean.valueOf(getConfigString(key));
278 }
279
280 public Boolean getConfigBoolean(String key, Boolean defaultValue) {
281 Boolean value = getConfigBoolean(key);
282 if (value == null) {
283 System.out.println("[Poseidon] Config: " + key + " does not exist. Using default value: " + defaultValue);
284 System.out.println("[Poseidon] Config: This is likely the result of an error. Please report this to the developer.");
285 value = defaultValue;
286 }
287 return value;
288 }
289
290 //Getters End
291
292 private void convertToNewConfig() {
293 // 1- 2/3 Conversion
294 convertToNewAddress("settings.statistics.enabled", "settings.enable-statistics");
295 convertToNewAddress("settings.allow-graceful-uuids", "allowGracefulUUID");
296 convertToNewAddress("settings.save-playerdata-by-uuid", "savePlayerdataByUUID");
297 convertToNewAddress("settings.watchdog.enable", "settings.enable-watchdog");
298 // 3-4 Conversion
299
300 // Don't automatically enable the latest log file for servers that have the per-day-logfile setting enabled as this is a change in behavior
301 if (this.getString("settings.per-day-logfile") != null && this.getConfigBoolean("settings.per-day-logfile")) {
302 this.setProperty("settings.per-day-log-file.latest-log.enabled", false);
303 }
304 convertToNewAddress("settings.per-day-log-file.enabled", "settings.per-day-logfile");
305
306 // 4-5 Conversion
307 convertToNewAddress("settings.uuid-fetcher.post.value", "settings.fetch-uuids-from");
308 if (this.getString("settings.uuid-fetcher.post.value", "https://api.minecraftservices.com/minecraft/profile/lookup/bulk/byname").equals("https://api.mojang.com/profiles/minecraft")) {
309 System.out.println("[Poseidon] Config: settings.fetch-uuids-from is set to the default value (" + this.getString("settings.uuid-fetcher.post.value") + "). Changing to the new default value (https://api.minecraftservices.com/minecraft/profile/lookup/bulk/byname)");
310 this.setProperty("settings.uuid-fetcher.post.value", "https://api.minecraftservices.com/minecraft/profile/lookup/bulk/byname");
311 }
312
313 boolean usePost = !this.getConfigBoolean("settings.use-get-for-uuids.enabled", false); // Is the server currently using POST?
314 if (usePost) {
315 this.setProperty("settings.uuid-fetcher.method.value", "POST");
316 } else {
317 this.setProperty("settings.uuid-fetcher.method.value", "GET");
318 }
319
320 removeDeprecatedConfig("settings.use-get-for-uuids.enabled", "settings.use-get-for-uuids.info");
321
322 convertToNewAddress("settings.uuid-fetcher.allow-graceful-uuids.value", "settings.allow-graceful-uuids");
323 convertToNewAddress("settings.uuid-fetcher.get.enforce-case-sensitivity.enabled", "settings.use-get-for-uuids.case-sensitive.enabled");
324 removeDeprecatedConfig("settings.use-get-for-uuids.case-sensitive.info");
325
326
327 }
328
329 //Allow any number of string arguments to be passed to this method
330 private boolean removeDeprecatedConfig(String... keys) {
331 boolean removed = false;
332 for (String key : keys) {
333 if (this.getString(key) != null) {
334 System.out.println("[Poseidon] Config: " + key + " is deprecated. Removing.");
335 this.removeProperty(key);
336 removed = true;
337 }
338 }
339 return removed;
340 }
341
342 private boolean convertToNewAddress(String newKey, String oldKey) {
343 if (this.getString(newKey) != null) {
344 return false;
345 }
346 if (this.getString(oldKey) == null) {
347 System.out.println("[Poseidon] Config: " + oldKey + " does not exist. Skipping conversion.");
348 return false;
349 }
350 System.out.println("[Poseidon] Converting Config: " + oldKey + " to " + newKey);
351 Object value = this.getProperty(oldKey);
352 this.setProperty(newKey, value);
353 this.removeProperty(oldKey);
354 return true;
355
356 }
357
358
359 public synchronized static PoseidonConfig getInstance() {
360 if (PoseidonConfig.singleton == null) {
361 PoseidonConfig.singleton = new PoseidonConfig();
362 }
363 return PoseidonConfig.singleton;
364 }
365
366}