diff --git a/build.gradle.kts b/build.gradle.kts index 7057eb2..524d76d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -44,6 +44,11 @@ subprojects { archiveClassifier.set("") archiveFileName.set("${rootProject.name}-${project.name}-${rootProject.version}.jar") + relocate("org.jspecify", "${project.group}.shaded.jspecify") + relocate("org.bouncycastle", "${project.group}.shaded.bouncycastle") + relocate("io.nats", "${project.group}.shaded.nats") + relocate("com.google", "${project.group}.shaded.google") + finalizedBy("publishShadowPublicationToMavenLocal") } diff --git a/common/build.gradle.kts b/common/build.gradle.kts new file mode 100644 index 0000000..4c96ace --- /dev/null +++ b/common/build.gradle.kts @@ -0,0 +1,8 @@ +group = "fun.ogtimes.skywars" +version = "1.0.0" + +dependencies { + api("com.google.code.gson:gson:2.13.2") + api("com.google.guava:guava:33.5.0-jre") + api("io.nats:jnats:2.22.0") +} \ No newline at end of file diff --git a/common/src/main/java/fun/ogtimes/skywars/common/SkyWarsCommon.java b/common/src/main/java/fun/ogtimes/skywars/common/SkyWarsCommon.java new file mode 100644 index 0000000..319532b --- /dev/null +++ b/common/src/main/java/fun/ogtimes/skywars/common/SkyWarsCommon.java @@ -0,0 +1,39 @@ +package fun.ogtimes.skywars.common; + +import fun.ogtimes.skywars.common.keepalive.KeepAliveService; +import fun.ogtimes.skywars.common.nats.NatsHandler; +import io.nats.client.Connection; +import io.nats.client.Nats; +import io.nats.client.Options; + +import java.io.IOException; +import java.time.Duration; + +public class SkyWarsCommon { + private final NatsHandler natsHandler; + private final KeepAliveService keepAliveService; + + public SkyWarsCommon(Options natsOptions) throws IOException, InterruptedException { + Connection connection = Nats.connect(natsOptions); + this.natsHandler = new NatsHandler(connection); + this.keepAliveService = new KeepAliveService(this.natsHandler, Duration.ofSeconds(5), Duration.ofSeconds(15)); + } + + public SkyWarsCommon(Connection connection) { + this.natsHandler = new NatsHandler(connection); + this.keepAliveService = new KeepAliveService(this.natsHandler, Duration.ofSeconds(5), Duration.ofSeconds(15)); + } + + public NatsHandler nats() { + return natsHandler; + } + + public KeepAliveService keepAlive() { + return keepAliveService; + } + + public void destroy() { + if (keepAliveService != null) keepAliveService.stop(); + if (natsHandler != null) natsHandler.close(); + } +} diff --git a/common/src/main/java/fun/ogtimes/skywars/common/instance/InstanceProperties.java b/common/src/main/java/fun/ogtimes/skywars/common/instance/InstanceProperties.java new file mode 100644 index 0000000..ee1a149 --- /dev/null +++ b/common/src/main/java/fun/ogtimes/skywars/common/instance/InstanceProperties.java @@ -0,0 +1,12 @@ +package fun.ogtimes.skywars.common.instance; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class InstanceProperties { + private String id; + private String address; + private int port; +} \ No newline at end of file diff --git a/common/src/main/java/fun/ogtimes/skywars/common/keepalive/KeepAliveListener.java b/common/src/main/java/fun/ogtimes/skywars/common/keepalive/KeepAliveListener.java new file mode 100644 index 0000000..cdfb43a --- /dev/null +++ b/common/src/main/java/fun/ogtimes/skywars/common/keepalive/KeepAliveListener.java @@ -0,0 +1,9 @@ +package fun.ogtimes.skywars.common.keepalive; + +import fun.ogtimes.skywars.common.instance.InstanceProperties; + +public interface KeepAliveListener { + void onInstanceAlive(InstanceProperties properties); + void onInstanceOffline(InstanceProperties properties); +} + diff --git a/common/src/main/java/fun/ogtimes/skywars/common/keepalive/KeepAliveService.java b/common/src/main/java/fun/ogtimes/skywars/common/keepalive/KeepAliveService.java new file mode 100644 index 0000000..97e3ff1 --- /dev/null +++ b/common/src/main/java/fun/ogtimes/skywars/common/keepalive/KeepAliveService.java @@ -0,0 +1,153 @@ +package fun.ogtimes.skywars.common.keepalive; + +import fun.ogtimes.skywars.common.instance.InstanceProperties; +import fun.ogtimes.skywars.common.nats.NatsHandler; +import fun.ogtimes.skywars.common.nats.annotation.IncomingPacketHandler; +import fun.ogtimes.skywars.common.nats.packet.PacketListener; +import fun.ogtimes.skywars.common.nats.packet.impl.KeepAlivePacket; + +import java.time.Duration; +import java.time.Instant; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class KeepAliveService { + private static final Logger LOGGER = Logger.getLogger(KeepAliveService.class.getName()); + + private final NatsHandler nats; + private final ScheduledExecutorService scheduler; + private final Map lastSeen = new ConcurrentHashMap<>(); + private final CopyOnWriteArraySet listeners = new CopyOnWriteArraySet<>(); + private final Duration interval; + private final Duration timeout; + private final AtomicBoolean running = new AtomicBoolean(false); + private ScheduledFuture future; + private final PacketListener packetListener; + + public KeepAliveService(NatsHandler natsHandler, Duration interval, Duration timeout) { + this.nats = natsHandler; + this.interval = interval; + this.timeout = timeout; + this.scheduler = Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "skywars-keepalive")); + + this.packetListener = new PacketListener() { + @IncomingPacketHandler + public void onKeepAlive(KeepAlivePacket packet) { + if (packet != null && packet.properties() != null) { + lastSeen.put(packet.properties().getId(), Instant.now()); + listeners.forEach(l -> l.onInstanceAlive(packet.properties())); + } + } + }; + } + + public void start(InstanceProperties properties) { + if (running.compareAndSet(false, true)) { + try { + nats.registerListener(packetListener); + try { + nats.subscribe(); + LOGGER.info("KeepAliveService: subscribed to NATS channels"); + } catch (Exception ex) { + LOGGER.log(Level.WARNING, "KeepAliveService: failed to subscribe to NATS channels", ex); + } + } catch (Exception ex) { + LOGGER.log(Level.SEVERE, "Failed to register keepalive listener", ex); + } + + LOGGER.info("KeepAliveService: starting scheduler (interval=" + interval.toMillis() + "ms, timeout=" + timeout.toMillis() + "ms)"); + future = scheduler.scheduleAtFixedRate(() -> { + try { + nats.sendPacket(new KeepAlivePacket(properties)); + LOGGER.fine("KeepAliveService: sent keepalive for " + properties.getId()); + lastSeen.put(properties.getId(), Instant.now()); + + Instant cutoff = Instant.now().minus(timeout); + for (Map.Entry e : lastSeen.entrySet()) { + if (e.getValue().isBefore(cutoff)) { + listeners.forEach(l -> l.onInstanceOffline(new InstanceProperties(e.getKey(), "", 0))); + lastSeen.remove(e.getKey()); + } + } + } catch (Exception ex) { + LOGGER.log(Level.SEVERE, "KeepAlive send failed", ex); + } + }, 0, interval.toMillis(), TimeUnit.MILLISECONDS); + } + } + + public void stop() { + if (running.compareAndSet(true, false)) { + if (future != null) future.cancel(true); + scheduler.shutdownNow(); + + try { + nats.unregisterListener(packetListener); + LOGGER.info("KeepAliveService: unregistered packet listener from NATS"); + } catch (Exception ex) { + LOGGER.log(Level.WARNING, "KeepAliveService: failed to unregister packet listener", ex); + } + + lastSeen.clear(); + listeners.clear(); + + LOGGER.info("KeepAliveService: stopped"); + } + } + + public void sendNow(InstanceProperties properties) { + nats.sendPacket(new KeepAlivePacket(properties)); + lastSeen.put(properties.getId(), Instant.now()); + } + + public void registerListener(KeepAliveListener listener) { + listeners.add(listener); + } + + public void unregisterListener(KeepAliveListener listener) { + listeners.remove(listener); + } + + public boolean isAlive(String instanceId) { + Instant i = lastSeen.get(instanceId); + return i != null && i.isAfter(Instant.now().minus(timeout)); + } + + public Set getAliveInstances() { + return lastSeen.keySet(); + } + + /** + * Start only listening for incoming KeepAlivePacket without sending periodic keepalives. + * Useful for proxies that only need to observe instance keepalives. + */ + public void startListening() { + try { + nats.registerListener(packetListener); + try { + nats.subscribe(); + LOGGER.info("KeepAliveService: subscribed to NATS channels (listen-only)"); + } catch (Exception ex) { + LOGGER.log(Level.WARNING, "KeepAliveService: failed to subscribe to NATS channels (listen-only)", ex); + } + } catch (Exception ex) { + LOGGER.log(Level.SEVERE, "Failed to register keepalive listener (listen-only)", ex); + } + } + + /** + * Stop listening for keepalive packets without affecting the send scheduler. + */ + public void stopListening() { + try { + nats.unregisterListener(packetListener); + LOGGER.info("KeepAliveService: unregistered keepalive listener (listen-only)"); + } catch (Exception ex) { + LOGGER.log(Level.WARNING, "KeepAliveService: failed to unregister keepalive listener (listen-only)", ex); + } + } +} diff --git a/common/src/main/java/fun/ogtimes/skywars/common/nats/NatsHandler.java b/common/src/main/java/fun/ogtimes/skywars/common/nats/NatsHandler.java new file mode 100644 index 0000000..0b0989b --- /dev/null +++ b/common/src/main/java/fun/ogtimes/skywars/common/nats/NatsHandler.java @@ -0,0 +1,190 @@ +package fun.ogtimes.skywars.common.nats; + +import com.google.common.collect.Multimap; +import com.google.common.collect.MultimapBuilder; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import fun.ogtimes.skywars.common.nats.annotation.IncomingPacketHandler; +import fun.ogtimes.skywars.common.nats.packet.Packet; +import fun.ogtimes.skywars.common.nats.packet.PacketListener; +import io.nats.client.Connection; +import io.nats.client.Dispatcher; +import io.nats.client.Message; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; + +import java.io.Closeable; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +public class NatsHandler implements Closeable { + private static final Logger LOGGER = Logger.getLogger(NatsHandler.class.getName()); + + private final Connection connection; + + private final Gson gson = new GsonBuilder().create(); + + private final Multimap listeners = + MultimapBuilder.hashKeys().arrayListValues().build(); + + private final Set channels = ConcurrentHashMap.newKeySet(); + private final Multimap channelToListener = + MultimapBuilder.hashKeys().arrayListValues().build(); + + private final Set subscribedChannels = ConcurrentHashMap.newKeySet(); + + private volatile Dispatcher dispatcher; + + public synchronized void subscribe() { + if (channels.isEmpty()) { + throw new IllegalStateException("No channels to subscribe to. Register listeners first."); + } + if (dispatcher != null) return; + try { + dispatcher = connection.createDispatcher(this::handleMessage); + for (String channel : channels) { + dispatcher.subscribe(channel); + subscribedChannels.add(channel); + } + LOGGER.info("Subscribed to channels: " + channels); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Subscription failed", e); + } + } + + public void registerListener(PacketListener listener) { + Set packetHandlerMethods = + Arrays.stream(listener.getClass().getDeclaredMethods()) + .filter(m -> m.isAnnotationPresent(IncomingPacketHandler.class)) + .filter(m -> m.getParameterCount() == 1) + .collect(Collectors.toSet()); + + if (packetHandlerMethods.isEmpty()) { + LOGGER.warning("No valid @IncomingPacketHandler in " + listener.getClass().getName()); + return; + } + + for (Method method : packetHandlerMethods) { + Class parameterType = method.getParameterTypes()[0]; + String channel = "skywars@" + parameterType.getName(); + channels.add(channel); + + synchronized (this) { + listeners.put(listener, method); + channelToListener.put(channel, listener); + } + + if (dispatcher != null && !subscribedChannels.contains(channel)) { + try { + dispatcher.subscribe(channel); + subscribedChannels.add(channel); + LOGGER.info("Dynamically subscribed to channel: " + channel); + } catch (Exception e) { + LOGGER.log(Level.WARNING, "Failed to dynamically subscribe to channel " + channel, e); + } + } + + try { + method.setAccessible(true); + } catch (Exception ignored) { } + } + + LOGGER.info("Registered listener: " + listener.getClass().getName()); + } + + public void unregisterListener(PacketListener listener) { + Set methods; + synchronized (this) { + methods = new HashSet<>(listeners.get(listener)); + } + + for (Method method : methods) { + Class parameterType = method.getParameterTypes()[0]; + String channel = "skywars@" + parameterType.getName(); + + synchronized (this) { + listeners.remove(listener, method); + channelToListener.remove(channel, listener); + Collection remaining = channelToListener.get(channel); + if (remaining.isEmpty()) { + channels.remove(channel); + try { + if (dispatcher != null && subscribedChannels.contains(channel)) { + dispatcher.unsubscribe(channel); + subscribedChannels.remove(channel); + } + } catch (Exception e) { + LOGGER.log(Level.WARNING, "Failed to unsubscribe channel " + channel, e); + } + } + } + } + + LOGGER.info("Unregistered listener: " + listener.getClass().getName()); + } + + public void sendPacket(Packet packet) { + String channel = "skywars@" + packet.getClass().getName(); + try { + connection.publish(channel, gson.toJson(packet).getBytes(StandardCharsets.UTF_8)); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Failed to send packet to channel: " + channel, e); + } + } + + private void handleMessage(Message message) { + String channel = message.getSubject(); + String data = new String(message.getData(), StandardCharsets.UTF_8); + + Collection listenerObjs; + synchronized (this) { + listenerObjs = new ArrayList<>(channelToListener.get(channel)); + } + + for (Object listenerObj : listenerObjs) { + Collection methods; + synchronized (this) { + methods = new ArrayList<>(listeners.get(listenerObj)); + } + + for (Method method : methods) { + if (!method.isAnnotationPresent(IncomingPacketHandler.class)) continue; + + Class paramType = method.getParameterTypes()[0]; + String expectedChannel = "skywars@" + paramType.getName(); + if (!expectedChannel.equals(channel)) continue; + + try { + Object packet = gson.fromJson(data, paramType); + method.invoke(listenerObj, packet); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, + "Failed to invoke handler " + method.getName() + " on " + + listenerObj.getClass().getName(), e); + } + } + } + } + + @Override + @SneakyThrows + public synchronized void close() { + if (dispatcher != null) { + for (String ch : new ArrayList<>(subscribedChannels)) { + try { + dispatcher.unsubscribe(ch); + } catch (Exception ignored) { + } + } + subscribedChannels.clear(); + } + connection.close(); + LOGGER.info("NATS connection closed."); + } +} \ No newline at end of file diff --git a/common/src/main/java/fun/ogtimes/skywars/common/nats/annotation/IncomingPacketHandler.java b/common/src/main/java/fun/ogtimes/skywars/common/nats/annotation/IncomingPacketHandler.java new file mode 100644 index 0000000..cea6879 --- /dev/null +++ b/common/src/main/java/fun/ogtimes/skywars/common/nats/annotation/IncomingPacketHandler.java @@ -0,0 +1,10 @@ +package fun.ogtimes.skywars.common.nats.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface IncomingPacketHandler { } diff --git a/common/src/main/java/fun/ogtimes/skywars/common/nats/packet/Packet.java b/common/src/main/java/fun/ogtimes/skywars/common/nats/packet/Packet.java new file mode 100644 index 0000000..fe489ab --- /dev/null +++ b/common/src/main/java/fun/ogtimes/skywars/common/nats/packet/Packet.java @@ -0,0 +1,4 @@ +package fun.ogtimes.skywars.common.nats.packet; + +public interface Packet { +} diff --git a/common/src/main/java/fun/ogtimes/skywars/common/nats/packet/PacketListener.java b/common/src/main/java/fun/ogtimes/skywars/common/nats/packet/PacketListener.java new file mode 100644 index 0000000..1864a9c --- /dev/null +++ b/common/src/main/java/fun/ogtimes/skywars/common/nats/packet/PacketListener.java @@ -0,0 +1,4 @@ +package fun.ogtimes.skywars.common.nats.packet; + +public interface PacketListener { +} diff --git a/common/src/main/java/fun/ogtimes/skywars/common/nats/packet/impl/InstanceStartPacket.java b/common/src/main/java/fun/ogtimes/skywars/common/nats/packet/impl/InstanceStartPacket.java new file mode 100644 index 0000000..dee278d --- /dev/null +++ b/common/src/main/java/fun/ogtimes/skywars/common/nats/packet/impl/InstanceStartPacket.java @@ -0,0 +1,6 @@ +package fun.ogtimes.skywars.common.nats.packet.impl; + +import fun.ogtimes.skywars.common.instance.InstanceProperties; +import fun.ogtimes.skywars.common.nats.packet.Packet; + +public record InstanceStartPacket(InstanceProperties properties) implements Packet { } \ No newline at end of file diff --git a/common/src/main/java/fun/ogtimes/skywars/common/nats/packet/impl/InstanceStopPacket.java b/common/src/main/java/fun/ogtimes/skywars/common/nats/packet/impl/InstanceStopPacket.java new file mode 100644 index 0000000..2d3271b --- /dev/null +++ b/common/src/main/java/fun/ogtimes/skywars/common/nats/packet/impl/InstanceStopPacket.java @@ -0,0 +1,6 @@ +package fun.ogtimes.skywars.common.nats.packet.impl; + +import fun.ogtimes.skywars.common.instance.InstanceProperties; +import fun.ogtimes.skywars.common.nats.packet.Packet; + +public record InstanceStopPacket(InstanceProperties properties) implements Packet { } \ No newline at end of file diff --git a/common/src/main/java/fun/ogtimes/skywars/common/nats/packet/impl/KeepAlivePacket.java b/common/src/main/java/fun/ogtimes/skywars/common/nats/packet/impl/KeepAlivePacket.java new file mode 100644 index 0000000..18760ae --- /dev/null +++ b/common/src/main/java/fun/ogtimes/skywars/common/nats/packet/impl/KeepAlivePacket.java @@ -0,0 +1,6 @@ +package fun.ogtimes.skywars.common.nats.packet.impl; + +import fun.ogtimes.skywars.common.instance.InstanceProperties; +import fun.ogtimes.skywars.common.nats.packet.Packet; + +public record KeepAlivePacket(InstanceProperties properties) implements Packet { } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index b18a9b6..647651a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,5 +3,6 @@ rootProject.name = "SkyWars" include( "spigot", "bungee", - "velocity" + "velocity", + "common" ) \ No newline at end of file diff --git a/spigot/build.gradle.kts b/spigot/build.gradle.kts index 5e007a9..61dcb77 100644 --- a/spigot/build.gradle.kts +++ b/spigot/build.gradle.kts @@ -11,17 +11,19 @@ repositories { } dependencies { + implementation(project(":common")) implementation("org.jetbrains:annotations:26.0.2-1") implementation("net.kyori:adventure-api:4.26.1") implementation("net.kyori:adventure-platform-bukkit:4.4.1") + implementation("com.zaxxer:HikariCP:7.0.2") compileOnly("me.clip:placeholderapi:2.11.7") compileOnly("org.spigotmc:spigot-api:1.8.8-R0.1-SNAPSHOT") - compileOnly("com.zaxxer:HikariCP:7.0.2") compileOnly("com.github.MilkBowl:VaultAPI:1.7.1") compileOnly("me.filoghost.holographicdisplays:holographicdisplays-api:3.0.5") } tasks.shadowJar { + minimize() relocate("net.kyori", "fun.ogtimes.skywars.libs.kyori") } \ No newline at end of file diff --git a/spigot/src/main/java/fun/ogtimes/skywars/spigot/SkyWars.java b/spigot/src/main/java/fun/ogtimes/skywars/spigot/SkyWars.java index 64cdc07..4815b75 100644 --- a/spigot/src/main/java/fun/ogtimes/skywars/spigot/SkyWars.java +++ b/spigot/src/main/java/fun/ogtimes/skywars/spigot/SkyWars.java @@ -12,6 +12,7 @@ import fun.ogtimes.skywars.spigot.database.DatabaseHandler; import fun.ogtimes.skywars.spigot.events.EventsManager; import fun.ogtimes.skywars.spigot.events.enums.ArenaLeaveCause; +import fun.ogtimes.skywars.spigot.instance.InstanceModeHandler; import fun.ogtimes.skywars.spigot.kit.KitManager; import fun.ogtimes.skywars.spigot.listener.*; import fun.ogtimes.skywars.spigot.listener.skywars.ArenaListener; @@ -57,11 +58,11 @@ public class SkyWars extends JavaPlugin implements Listener { @Getter private static SkyWars plugin; - public static final HashMap skyPlayersUUID; - public static final HashMap skyPlayers; + public static final HashMap skyPlayersUUID = new HashMap<>(); + public static final HashMap skyPlayers = new HashMap<>(); @Getter public static Location spawn; - public static final List hologram; + public static final List hologram = new ArrayList<>(); public static final String arenas = "games"; public static final String kits = "kits"; @@ -77,20 +78,13 @@ public class SkyWars extends JavaPlugin implements Listener { public static boolean login; public static boolean firstJoin; public static String prefix = "[SkyWars] "; - public static long seconds; + public static long seconds = 0L; public static VariableManager variableManager; private static ResourceBundle messageBundle; private static ResourceBundle customBundle; private static DatabaseHandler databaseHandler; - - static { - skyPlayersUUID = new HashMap<>(); - skyPlayers = new HashMap<>(); - hologram = new ArrayList<>(); - prefix = "[SkyWars] "; - seconds = 0L; - } + private static InstanceModeHandler instanceHandler; private Metrics metrics; private BukkitAudiences adventure; @@ -270,6 +264,12 @@ public static String getRandomLobby() { } public static boolean getMysql() { + try { + if (ConfigManager.database != null && ConfigManager.database.isSet("type")) { + return ConfigManager.database.getString("type", "SQLite").equalsIgnoreCase("MySQL"); + } + } catch (Exception ignored) { + } return ConfigManager.main.getString("data.type").equalsIgnoreCase("MySQL"); } @@ -350,6 +350,7 @@ public void onEnable() { ConfigManager.abilitiesConfig(); ConfigManager.shopConfig(); ConfigManager.signsConfig(); + ConfigManager.databaseConfig(); variableManager = new VariableManager(); variableManager.registerVariableReplacer(new VariablesDefault()); @@ -458,6 +459,13 @@ public void onEnable() { this, "skywars:sign-update", new BungeeRecieveListener() ); ServerManager.initServers(); + } else { + try { + instanceHandler = new InstanceModeHandler(this); + instanceHandler.start(); + } catch (Exception e) { + log("Failed to start InstanceModeHandler: " + e.getMessage()); + } } if (isProxyMode()) { @@ -571,6 +579,10 @@ public void onDisable() { console(prefix + "&cDisabling all data"); DatabaseHandler.getDS().close(); } + + if (instanceHandler != null) { + instanceHandler.stop(); + } } public void reloadSigns() { diff --git a/spigot/src/main/java/fun/ogtimes/skywars/spigot/arena/Arena.java b/spigot/src/main/java/fun/ogtimes/skywars/spigot/arena/Arena.java index b4eab87..3a3b1d4 100644 --- a/spigot/src/main/java/fun/ogtimes/skywars/spigot/arena/Arena.java +++ b/spigot/src/main/java/fun/ogtimes/skywars/spigot/arena/Arena.java @@ -168,15 +168,15 @@ public Arena(String name) { this.startTicks(); } - public Arena(String var1, boolean var2) { - super(var1, var1, 0, true, ArenaState.WAITING); - this.disabled = var2; - this.createConfig(var1); + public Arena(String name, boolean disabled) { + super(name, name, 0, true, ArenaState.WAITING); + this.disabled = disabled; + this.createConfig(name); if (this.getWorld() == null) { this.loadFirstWorld(); } - ArenaManager.games.put(var1, this); + ArenaManager.games.put(name, this); this.playSignUpdate(SkySignUpdateCause.ALL); } diff --git a/spigot/src/main/java/fun/ogtimes/skywars/spigot/arena/ArenaState.java b/spigot/src/main/java/fun/ogtimes/skywars/spigot/arena/ArenaState.java index 45e7e74..191bbe2 100644 --- a/spigot/src/main/java/fun/ogtimes/skywars/spigot/arena/ArenaState.java +++ b/spigot/src/main/java/fun/ogtimes/skywars/spigot/arena/ArenaState.java @@ -1,8 +1,8 @@ package fun.ogtimes.skywars.spigot.arena; public enum ArenaState { - WAITING, - STARTING, - INGAME, - ENDING + WAITING, + STARTING, + INGAME, + ENDING } diff --git a/spigot/src/main/java/fun/ogtimes/skywars/spigot/config/ConfigManager.java b/spigot/src/main/java/fun/ogtimes/skywars/spigot/config/ConfigManager.java index b6e7e9a..6549b0c 100644 --- a/spigot/src/main/java/fun/ogtimes/skywars/spigot/config/ConfigManager.java +++ b/spigot/src/main/java/fun/ogtimes/skywars/spigot/config/ConfigManager.java @@ -5,453 +5,483 @@ import com.google.common.collect.Lists; import java.io.File; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; public class ConfigManager { - public static SkyConfiguration main; - public static SkyConfiguration score; - public static SkyConfiguration abilities; - public static SkyConfiguration shop; - public static SkyConfiguration signs; + public static SkyConfiguration main; + public static SkyConfiguration score; + public static SkyConfiguration abilities; + public static SkyConfiguration shop; + public static SkyConfiguration signs; + public static SkyConfiguration database; - public static void mainConfig() { - File var0 = new File(SkyWars.getPlugin().getDataFolder(), "config.yml"); - main = new SkyConfiguration(var0); - main.setHeader("-------------------------------- #", "", "SKYWARS", "By CookLoco and the OGTimes Development Team", "Battle with players in the sky", "", "-------------------------------- #"); - main.addDefault("check_updates", true, "Check if exists a new update (RECOMMENDED YOU LEAVE TRUE)"); - main.addDefault("debug", false, "Debug mode", "enable if you have some crash/error and create an issue at our GitHub repository."); - main.addDefault("debug-database", false, "Debug database (MySQL)", "enable if you have some crash/error and create an issue at our GitHub repository."); - main.addDefault("locale", "en", "Available languages:", " en: English (Default)", " es: Spanish", " nl: Dutch"); - main.addDefault("kitmenu_rows", 3, "Rows/Lines from the Kit Menu (WAITING GAME)"); - main.addDefault("kit_permission", false, "If is true, players with the permission (skywars.kit.KitName) can buy this kit"); - main.addDefault("maxtime", 1200, "Maximum time for every arena/game"); - main.addDefault("spawn", "", "Lobby coords [MultiArena/Lobby]", "type /sw lobbyspawn to set the Lobby Spawn"); - ArrayList var1 = new ArrayList(); - var1.add("Lobby"); - main.addDefault("lobbies_servers", var1, "Lobby server list for random tp (BUNGEECORD SERVERS)"); - main.addDefault("max_items_types_chest", 15, "max slots used per generated chest (IN GAME)"); - main.addDefault("economy.mode", - "Custom", - "Economy types:", - " Custom: included per default in SkyWars (RECOMMENDED)", - " Vault: hook with Vault and other plugin like Essentials or iConomy"); - main.addDefault("economy.craftconomy3_currency", "Dollar", "Currency set when you has been configured CraftConomy3 (Default: Dollar)"); - main.addDefault("reward.death", 1, "reward that receive every survivor when a player die"); - main.addDefault("reward.kill", 2, "reward for kill some player"); - main.addDefault("reward.win", 10, "reward for winner"); - main.addDefault("reward.wincmd.enabled", false, "Enable or disable winner commands (EXECUTED BY CONSOLE)"); - ArrayList var2 = new ArrayList(); - var2.add("20/money give %winner% 20"); - var2.add("100/say %winner% won a game!"); - main.addDefault("reward.wincmd.list", var2, "Commands list (VARIABLES: %winner% , %map%)", "\tFORMAT: 'CHANCE/CMD'", "\tExample: 90/give %winner% minecraft:diamond_block 1", "\tCHANCE: 0-100"); - main.addDefault("item.kits", "1 PAPER", "Items in waiting Lobby, for message and translation go to the item section in messages files", "Format: SLOT ITEM_NAME", "SLOT From 1 to 9 (hotbar)", "If you want to edit Shop item in Lobby go to shop.yml"); - main.addDefault("item.settings", "2 DIAMOND"); - main.addDefault("item.vote", "3 EMPTY_MAP"); - main.addDefault("item.exit", "9 BED"); - main.addDefault("menu.kits", null, "Kit Selector menu options"); - main.addDefault("menu.kits.unavailable.enabled", false, "Enable or disable if should replace unavailable kit icon for some item (Default: false)"); - main.addDefault("menu.kits.unavailable.item", "STAINED_GLASS_PANE:14", "ITEM_NAME:DATA"); - main.addDefault("mode.plugin", "MultiArena", "Plugin Modes:", " BungeeMode: Only one game per server (better performance)", " MultiArena: Unlimited games per server (underperforming with many games)", " Lobby: Only Lobby System for Bungee Servers (before SkyWarsLobby)"); - main.addDefault("mode.bungee-autostart", true, "Auto Start when a game ends (BungeeMode)"); - main.addDefault("mode.bungeerandom", true, "Select a random map from configured arenas"); - main.addDefault("mode.bungeemapset", "default", "Select the same map all the time (BUNGEERANDOM MUST BE FALSE)"); - main.addDefault("server", "", "BungeeMode setting for Sign System (MySQL REQUIRED)", "enabled by default if the server is in BungeeMode, You will need a Lobby server", "with SkyWars in Lobby mode for the Sign System (MySQL REQUIRED IN BOTH SERVERS)"); - main.addDefault("server.bungeeid", "SkyWars-1", "bungee name that correspond to this server (Only for Arena server)"); - main.addDefault("data.type", "SQLite", "Types:", " SQLite: Local File (Default)", " MySQL: MySQL Server required"); - main.addDefault("data.mysql.server", "localhost", "MySQL server address/ip"); - main.addDefault("data.mysql.db", "SkyWars", "database name"); - main.addDefault("data.mysql.user", "root", "MySQL User"); - main.addDefault("data.mysql.port", 3306, "MySQL Port"); - main.addDefault("data.mysql.password", "password", "MySQL password"); - main.addDefault("data.mysql.tablename.data", "SkyWars_Data", "Table name of player data"); - main.addDefault("data.mysql.tablename.economy", "SkyWars_Economy", "Table name of custom economy data"); - main.addDefault("data.mysql.tablename.servers", "SkyWars_Servers", "Table name of servers info"); - main.addDefault("options.weather", false, "enable or disable weather in arena worlds"); - main.addDefault("options.creaturespawn", false, "enable or disable mobs spawn in arena worlds"); - main.addDefault("options.saveInventory", true, "save inventory when player join to the game and restored when leave"); - main.addDefault("options.forceLobbySpawn", true, "force teleport to spawn when a player join"); - main.addDefault("options.orderedSpawnPoints", true, "sequencial spawn points in arena"); - main.addDefault("options.disablePvP-Outside-The-Arena", false, "disable pvp in Lobby world"); - main.addDefault("options.disableDamage-Outside-The-Arena", false, "disable all damage in Lobby"); - main.addDefault("options.leaveMessage", false, "enable or disable leave message when player leave from the server"); - main.addDefault("options.joinMessage", false, "enable or disable join message when player join to the server"); - main.addDefault("options.disableLeaveItem", false, "disable leave item (bed)"); - main.addDefault("options.disablePerWorldTab", false, "disable separated Tab per world (RECOMMEND YOU LEAVE FALSE FOR 1.8 & 1.9 SERVERS)"); - main.addDefault("options.disablePerWorldChat", false, "disable separated chat per world"); - main.addDefault("options.disableSpectatorMode-Death", false, "disable spectator mode when player die"); - main.addDefault("options.removeAllCageOnStart", true, "true: remove all cage, false: remove cage's floor"); - main.addDefault("options.perWorldTabBypass", false, "Enable or disable perWorldTab for players with the permisison: skywars.tab.bypass"); - main.addDefault("options.combatLogTime", 3, "The time in seconds that CombatLog will act after a player takes damage from another", "Default: 3"); - ArrayList var3 = new ArrayList(); - var3.add("help"); - var3.add("spawn"); - var3.add("home"); - main.addDefault("block.commands.mode", "blacklist", "Available modes:", " blacklist: block all commands in the list", " whitelist: only allow commands in the list"); - main.addDefault("block.commands.ingame", var3, "Commands blocked for players in game (in arena)"); - main.options().copyDefaults(true); - main.getEConfig().setNewLinePerKey(true); - main.save(); - } + public static void mainConfig() { + File var0 = new File(SkyWars.getPlugin().getDataFolder(), "config.yml"); + main = new SkyConfiguration(var0); + main.setHeader("-------------------------------- #", "", "SKYWARS", "By CookLoco and the OGTimes Development Team", "Battle with players in the sky", "", "-------------------------------- #"); + main.addDefault("check_updates", true, "Check if exists a new update (RECOMMENDED YOU LEAVE TRUE)"); + main.addDefault("debug", false, "Debug mode", "enable if you have some crash/error and create an issue at our GitHub repository."); + main.addDefault("debug-database", false, "Debug database (MySQL)", "enable if you have some crash/error and create an issue at our GitHub repository."); + main.addDefault("locale", "en", "Available languages:", " en: English (Default)", " es: Spanish", " nl: Dutch"); + main.addDefault("kitmenu_rows", 3, "Rows/Lines from the Kit Menu (WAITING GAME)"); + main.addDefault("kit_permission", false, "If is true, players with the permission (skywars.kit.KitName) can buy this kit"); + main.addDefault("maxtime", 1200, "Maximum time for every arena/game"); + main.addDefault("spawn", "", "Lobby coords [MultiArena/Lobby]", "type /sw lobbyspawn to set the Lobby Spawn"); + ArrayList var1 = new ArrayList(); + var1.add("Lobby"); + main.addDefault("lobbies_servers", var1, "Lobby server list for random tp (BUNGEECORD SERVERS)"); + main.addDefault("max_items_types_chest", 15, "max slots used per generated chest (IN GAME)"); + main.addDefault("economy.mode", + "Custom", + "Economy types:", + " Custom: included per default in SkyWars (RECOMMENDED)", + " Vault: hook with Vault and other plugin like Essentials or iConomy"); + main.addDefault("economy.craftconomy3_currency", "Dollar", "Currency set when you has been configured CraftConomy3 (Default: Dollar)"); + main.addDefault("reward.death", 1, "reward that receive every survivor when a player die"); + main.addDefault("reward.kill", 2, "reward for kill some player"); + main.addDefault("reward.win", 10, "reward for winner"); + main.addDefault("reward.wincmd.enabled", false, "Enable or disable winner commands (EXECUTED BY CONSOLE)"); + ArrayList var2 = new ArrayList(); + var2.add("20/money give %winner% 20"); + var2.add("100/say %winner% won a game!"); + main.addDefault("reward.wincmd.list", var2, "Commands list (VARIABLES: %winner% , %map%)", "\tFORMAT: 'CHANCE/CMD'", "\tExample: 90/give %winner% minecraft:diamond_block 1", "\tCHANCE: 0-100"); + main.addDefault("item.kits", "1 PAPER", "Items in waiting Lobby, for message and translation go to the item section in messages files", "Format: SLOT ITEM_NAME", "SLOT From 1 to 9 (hotbar)", "If you want to edit Shop item in Lobby go to shop.yml"); + main.addDefault("item.settings", "2 DIAMOND"); + main.addDefault("item.vote", "3 EMPTY_MAP"); + main.addDefault("item.exit", "9 BED"); + main.addDefault("menu.kits", null, "Kit Selector menu options"); + main.addDefault("menu.kits.unavailable.enabled", false, "Enable or disable if should replace unavailable kit icon for some item (Default: false)"); + main.addDefault("menu.kits.unavailable.item", "STAINED_GLASS_PANE:14", "ITEM_NAME:DATA"); + main.addDefault("mode.plugin", "MultiArena", "Plugin Modes:", " BungeeMode: Only one game per server (better performance)", " MultiArena: Unlimited games per server (underperforming with many games)", " Lobby: Only Lobby System for Bungee Servers (before SkyWarsLobby)"); + main.addDefault("mode.bungee-autostart", true, "Auto Start when a game ends (BungeeMode)"); + main.addDefault("mode.bungeerandom", true, "Select a random map from configured arenas"); + main.addDefault("mode.bungeemapset", "default", "Select the same map all the time (BUNGEERANDOM MUST BE FALSE)"); + main.addDefault("server", "", "BungeeMode setting for Sign System (MySQL REQUIRED)", "enabled by default if the server is in BungeeMode, You will need a Lobby server", "with SkyWars in Lobby mode for the Sign System (MySQL REQUIRED IN BOTH SERVERS)"); + main.addDefault("data.type", "SQLite", "Types:", " SQLite: Local File (Default)", " MySQL: MySQL Server required"); + main.addDefault("data.mysql.server", "localhost", "MySQL server address/ip"); + main.addDefault("data.mysql.db", "SkyWars", "database name"); + main.addDefault("data.mysql.user", "root", "MySQL User"); + main.addDefault("data.mysql.port", 3306, "MySQL Port"); + main.addDefault("data.mysql.password", "password", "MySQL password"); + main.addDefault("data.mysql.tablename.data", "SkyWars_Data", "Table name of player data"); + main.addDefault("data.mysql.tablename.economy", "SkyWars_Economy", "Table name of custom economy data"); + main.addDefault("data.mysql.tablename.servers", "SkyWars_Servers", "Table name of servers info"); + main.addDefault("options.weather", false, "enable or disable weather in arena worlds"); + main.addDefault("options.creaturespawn", false, "enable or disable mobs spawn in arena worlds"); + main.addDefault("options.saveInventory", true, "save inventory when player join to the game and restored when leave"); + main.addDefault("options.forceLobbySpawn", true, "force teleport to spawn when a player join"); + main.addDefault("options.orderedSpawnPoints", true, "sequencial spawn points in arena"); + main.addDefault("options.disablePvP-Outside-The-Arena", false, "disable pvp in Lobby world"); + main.addDefault("options.disableDamage-Outside-The-Arena", false, "disable all damage in Lobby"); + main.addDefault("options.leaveMessage", false, "enable or disable leave message when player leave from the server"); + main.addDefault("options.joinMessage", false, "enable or disable join message when player join to the server"); + main.addDefault("options.disableLeaveItem", false, "disable leave item (bed)"); + main.addDefault("options.disablePerWorldTab", false, "disable separated Tab per world (RECOMMEND YOU LEAVE FALSE FOR 1.8 & 1.9 SERVERS)"); + main.addDefault("options.disablePerWorldChat", false, "disable separated chat per world"); + main.addDefault("options.disableSpectatorMode-Death", false, "disable spectator mode when player die"); + main.addDefault("options.removeAllCageOnStart", true, "true: remove all cage, false: remove cage's floor"); + main.addDefault("options.perWorldTabBypass", false, "Enable or disable perWorldTab for players with the permisison: skywars.tab.bypass"); + main.addDefault("options.combatLogTime", 3, "The time in seconds that CombatLog will act after a player takes damage from another", "Default: 3"); + ArrayList var3 = new ArrayList(); + var3.add("help"); + var3.add("spawn"); + var3.add("home"); + main.addDefault("block.commands.mode", "blacklist", "Available modes:", " blacklist: block all commands in the list", " whitelist: only allow commands in the list"); + main.addDefault("block.commands.ingame", var3, "Commands blocked for players in game (in arena)"); + main.options().copyDefaults(true); + main.getEConfig().setNewLinePerKey(true); + main.save(); + } - public static void scoreboardConfig() { - File var0 = new File(SkyWars.getPlugin().getDataFolder(), "scoreboard.yml"); - score = new SkyConfiguration(var0); - score.setHeader("VARIABLES:", " - Player name: " + "%PLAYER%, %USERNAME%".toLowerCase(), " - Player Coins: " + "%COINS%, %POINTS%".toLowerCase(), " - Player Deaths: " + "%SW-DEATHS%, %SW-D%, %STATS-DEATHS%".toLowerCase(), " - Player Kills: " + "%SW-KILLS%, %SW-K%, %STATS-KILLS%".toLowerCase(), " - Player Wins: " + "%SW-WINS%, %SW-W%, %STATS-WINS%".toLowerCase(), " - Games Played: " + "%SW-PLAYED%, %SW-P%, %STATS-PLAYED%".toLowerCase(), " - Arrow Shot: " + "%SW-ARROW-SHOT%, %SW-AS%, %STATS-ARROW-SHOT%".toLowerCase(), " - Arrow Hit: " + "%SW-ARROW-HIT%, %SW-AH%, %STATS-ARROW-HIT%".toLowerCase(), " - Blocks Broken: " + "%SW-BLOCKS-BROKEN%, %SW-BB%, %STATS-BLOCKS-BROKEN%".toLowerCase(), " - Block Placed: " + "%SW-BLOCKS-PLACED%, %SW-BP%, %STATS-BLOCKS-PLACED%".toLowerCase(), " - Distance Walked: " + "%SW-DISTANCE-WALKED%, %SW-DW%, %STATS-DISTANCE-WALKED%".toLowerCase(), " - Time Played: " + "%SW-TIME-PLAYED%, %SW-TP%, %STATS-TIME-PLAYED%".toLowerCase(), " - Kill/Death Ratio: " + "%SW-KILLS-DEATHS%, %SW-KDR%".toLowerCase(), " - Selected Glass: " + "%GLASS%".toLowerCase(), "SCOREBOARD VARIABLES:", " - Empty line: %empty%", "GAME SCOREBOARD VARIABLES:", " - Arena Name: " + "%ARENA-NAME%, %A-NAME%".toLowerCase(), " - Arena Max Players: " + "%ARENA-MAX-PLAYERS%, %A-MAX-P%".toLowerCase(), " - Players in Arena: " + "%ARENA-INGAME-PLAYERS%, %A-INGAME-P%".toLowerCase(), " - Current event title: " + "%ARENA-EVENT-TITLE% %A-EVENT-TITLE%".toLowerCase(), " - Current event time: " + "%ARENA-EVENT-TIME% %A-EVENT-TIME%".toLowerCase(), " - Current kill streak: " + "%SW-KILL-STREAK% %SW-KS%".toLowerCase(), "SCOREBOARD CONDITIONALS:", " Check if the arena has events enabled", " Check if the arena is in game"); - score.addDefault("lobby.enabled", true, "Enable or disable Lobby Scoreboard"); - ArrayList var1 = new ArrayList(); - var1.add("test1"); - var1.add("test2"); - score.addDefault("lobby.disabledWorlds", var1, "Lobby Scoreboard blacklist (Disabled worlds)"); - score.addDefault("lobby.title", "&e&lSkyWars", "Lobby Scoreboard title"); - ArrayList var2 = new ArrayList(); - var2.add("&5Coins:"); - var2.add("&a%coins%"); - var2.add("%empty%"); - var2.add("&6Server Name"); - score.addDefault("lobby.lines", var2, "Lobby Scoreboard lines (Max: 16)"); - score.addDefault("game.title", "&e&lSkyWars", "Game Scoreboard title"); - ArrayList var3 = new ArrayList(); - var3.add("&5%a-event-title% in:"); - var3.add("&a%a-event-time%"); - var3.add("%empty%"); - var3.add("&5Map:"); - var3.add("&a%a-name%"); - var3.add("%empty%"); - var3.add("&5Players:"); - var3.add("&a%a-ingame-p%/%a-max-p%"); - var3.add("%empty%"); - var3.add("&6Server Name"); - score.addDefault("game.lines", var3, "Game Scoreboard lines (Max: 16)"); - ArrayList var4 = new ArrayList(); - score.addDefault("hologram.locations", var4, "Holographics Coords"); - ArrayList var5 = new ArrayList(); - var5.add("&a%PLAYER%'s &7&k&l||&3&lSkyWars&7&k&l||I&astatistics"); - var5.add("&aWins&7: &6%sw-w%"); - var5.add("&aKills&7: &6%sw-k%"); - var5.add("&aDeaths&7: &6%sw-d%"); - var5.add("&aGames played&7: &6%sw-p%"); - var5.add("&aArrows shot&7: &6%sw-as%"); - var5.add("&aArrows hit&7: &6%sw-ah%"); - var5.add("&aBlocks broken&7: &6%sw-bb%"); - var5.add("&aBlocks placed&7: &6%sw-bp%"); - var5.add("&aDistance walked&7: &6%sw-dw%"); - var5.add("&aTime played&7: &6%sw-tp%"); - score.addDefault("hologram.lines", var5, "Holographics Lines"); - score.options().copyDefaults(true); - score.getEConfig().setNewLinePerKey(true); - score.save(); - } + public static void scoreboardConfig() { + File var0 = new File(SkyWars.getPlugin().getDataFolder(), "scoreboard.yml"); + score = new SkyConfiguration(var0); + score.setHeader("VARIABLES:", " - Player name: " + "%PLAYER%, %USERNAME%".toLowerCase(), " - Player Coins: " + "%COINS%, %POINTS%".toLowerCase(), " - Player Deaths: " + "%SW-DEATHS%, %SW-D%, %STATS-DEATHS%".toLowerCase(), " - Player Kills: " + "%SW-KILLS%, %SW-K%, %STATS-KILLS%".toLowerCase(), " - Player Wins: " + "%SW-WINS%, %SW-W%, %STATS-WINS%".toLowerCase(), " - Games Played: " + "%SW-PLAYED%, %SW-P%, %STATS-PLAYED%".toLowerCase(), " - Arrow Shot: " + "%SW-ARROW-SHOT%, %SW-AS%, %STATS-ARROW-SHOT%".toLowerCase(), " - Arrow Hit: " + "%SW-ARROW-HIT%, %SW-AH%, %STATS-ARROW-HIT%".toLowerCase(), " - Blocks Broken: " + "%SW-BLOCKS-BROKEN%, %SW-BB%, %STATS-BLOCKS-BROKEN%".toLowerCase(), " - Block Placed: " + "%SW-BLOCKS-PLACED%, %SW-BP%, %STATS-BLOCKS-PLACED%".toLowerCase(), " - Distance Walked: " + "%SW-DISTANCE-WALKED%, %SW-DW%, %STATS-DISTANCE-WALKED%".toLowerCase(), " - Time Played: " + "%SW-TIME-PLAYED%, %SW-TP%, %STATS-TIME-PLAYED%".toLowerCase(), " - Kill/Death Ratio: " + "%SW-KILLS-DEATHS%, %SW-KDR%".toLowerCase(), " - Selected Glass: " + "%GLASS%".toLowerCase(), "SCOREBOARD VARIABLES:", " - Empty line: %empty%", "GAME SCOREBOARD VARIABLES:", " - Arena Name: " + "%ARENA-NAME%, %A-NAME%".toLowerCase(), " - Arena Max Players: " + "%ARENA-MAX-PLAYERS%, %A-MAX-P%".toLowerCase(), " - Players in Arena: " + "%ARENA-INGAME-PLAYERS%, %A-INGAME-P%".toLowerCase(), " - Current event title: " + "%ARENA-EVENT-TITLE% %A-EVENT-TITLE%".toLowerCase(), " - Current event time: " + "%ARENA-EVENT-TIME% %A-EVENT-TIME%".toLowerCase(), " - Current kill streak: " + "%SW-KILL-STREAK% %SW-KS%".toLowerCase(), "SCOREBOARD CONDITIONALS:", " Check if the arena has events enabled", " Check if the arena is in game"); + score.addDefault("lobby.enabled", true, "Enable or disable Lobby Scoreboard"); + ArrayList var1 = new ArrayList(); + var1.add("test1"); + var1.add("test2"); + score.addDefault("lobby.disabledWorlds", var1, "Lobby Scoreboard blacklist (Disabled worlds)"); + score.addDefault("lobby.title", "&e&lSkyWars", "Lobby Scoreboard title"); + ArrayList var2 = new ArrayList(); + var2.add("&5Coins:"); + var2.add("&a%coins%"); + var2.add("%empty%"); + var2.add("&6Server Name"); + score.addDefault("lobby.lines", var2, "Lobby Scoreboard lines (Max: 16)"); + score.addDefault("game.title", "&e&lSkyWars", "Game Scoreboard title"); + ArrayList var3 = new ArrayList(); + var3.add("&5%a-event-title% in:"); + var3.add("&a%a-event-time%"); + var3.add("%empty%"); + var3.add("&5Map:"); + var3.add("&a%a-name%"); + var3.add("%empty%"); + var3.add("&5Players:"); + var3.add("&a%a-ingame-p%/%a-max-p%"); + var3.add("%empty%"); + var3.add("&6Server Name"); + score.addDefault("game.lines", var3, "Game Scoreboard lines (Max: 16)"); + ArrayList var4 = new ArrayList(); + score.addDefault("hologram.locations", var4, "Holographics Coords"); + ArrayList var5 = new ArrayList(); + var5.add("&a%PLAYER%'s &7&k&l||&3&lSkyWars&7&k&l||I&astatistics"); + var5.add("&aWins&7: &6%sw-w%"); + var5.add("&aKills&7: &6%sw-k%"); + var5.add("&aDeaths&7: &6%sw-d%"); + var5.add("&aGames played&7: &6%sw-p%"); + var5.add("&aArrows shot&7: &6%sw-as%"); + var5.add("&aArrows hit&7: &6%sw-ah%"); + var5.add("&aBlocks broken&7: &6%sw-bb%"); + var5.add("&aBlocks placed&7: &6%sw-bp%"); + var5.add("&aDistance walked&7: &6%sw-dw%"); + var5.add("&aTime played&7: &6%sw-tp%"); + score.addDefault("hologram.lines", var5, "Holographics Lines"); + score.options().copyDefaults(true); + score.getEConfig().setNewLinePerKey(true); + score.save(); + } - public static void abilitiesConfig() { - File var0 = new File(SkyWars.getPlugin().getDataFolder(), "abilities.yml"); - abilities = new SkyConfiguration(var0); - ArrayList var2 = new ArrayList(); - abilities.addDefault("enabled", true, "enable or disable abilities on the server"); - abilities.addDefault("configVersion", 2, "Don't edit this value"); - abilities.addDefault("menu.lore.price", "&6Price: %price% points"); - abilities.addDefault("menu.lore.disabled", "&8&lDISABLED"); - abilities.addDefault("menu.lore.clickto.enable", "&6Click to enable", "Click ability icon to enable"); - abilities.addDefault("menu.lore.clickto.disable", "&6Click to disable", "Click ability icon to disable"); - abilities.addDefault("menu.lore.status.purchase", "&6Click to purchase this ability upgrade!", "Level item lore status"); - abilities.addDefault("menu.lore.status.afford", "&cYou cannot afford this ability!"); - abilities.addDefault("menu.lore.status.purchased", "&cAlready purchased!"); - abilities.addDefault("menu.lore.status.unavailable", "&cYou cannot purchase this item yet!"); - abilities.addDefault("menu.lore.status.disabled", "&6Click the icon to the left to enable"); - abilities.addDefault("menu.item.status.purchase", "95:4,1", "item displayed in menu ID:DATA,AMOUNT"); - abilities.addDefault("menu.item.status.afford", "95:14,1", "item displayed in menu ID:DATA,AMOUNT"); - abilities.addDefault("menu.item.status.purchased", "95:5,1", "item displayed in menu ID:DATA,AMOUNT"); - abilities.addDefault("menu.item.status.unavailable", "95:14,1", "item displayed in menu ID:DATA,AMOUNT"); - abilities.addDefault("menu.item.status.disabled", "95:8,1", "item displayed in menu ID:DATA,AMOUNT"); - abilities.addDefault("menu.item.level", "level %number%", "Item/Ability level"); - var2.add("%level-desc%"); - var2.add(""); - var2.add("%price-format%"); - var2.add(""); - var2.add("%status-format%"); - abilities.addDefault("menu.lore.levels.enabled", var2, "Level enabled item format"); - ArrayList var3 = new ArrayList(); - var3.add("%level-desc%"); - var3.add(""); - var3.add("%disabled%"); - var3.add("%status-format%"); - abilities.addDefault("menu.lore.levels.disabled", var3, "Level disabled item format"); - String var1 = "triple_arrow"; - ArrayList var4 = new ArrayList(); - var4.add("&7Shoot 3 arrows at the same time"); - addAbilitieSection(abilities, var4, var1, "&aTriple arrow shot", "262,3"); - ArrayList var5 = new ArrayList(); - var5.add("&7Have a %chance%% chance of shooting 3 arrows"); - var5.add("&7at the same time"); - addAbilitieLevelSection(abilities, var5, var1, "1", 50, 4, false, 3); - addAbilitieLevelSection(abilities, var5, var1, "2", 100, 6, false, 3); - addAbilitieLevelSection(abilities, var5, var1, "3", 200, 8, false, 3); - addAbilitieLevelSection(abilities, var5, var1, "4", 1000, 10, false, 3); - addAbilitieLevelSection(abilities, var5, var1, "5", 2000, 12, false, 3); - addAbilitieLevelSection(abilities, var5, var1, "6", 5000, 14, false, 3); - addAbilitieLevelSection(abilities, var5, var1, "7", 10000, 16, false, 3); - addAbilitieLevelSection(abilities, var5, var1, "8", 20000, 18, false, 3); - var1 = "adrenaline_boost"; - ArrayList var6 = new ArrayList(); - var6.add("&7When you get hurt have the chance to get a speed boost"); - addAbilitieSection(abilities, var6, var1, "&aAdrenaline boost", "373,1"); - ArrayList var7 = new ArrayList(); - var7.add("&7Have a %chance%% chance of getting a speed"); - var7.add("&7boost when you get hurt"); - addAbilitieLevelSection(abilities, var7, var1, "1", 50, 4, false, 0); - addAbilitieLevelSection(abilities, var7, var1, "2", 100, 6, false, 0); - addAbilitieLevelSection(abilities, var7, var1, "3", 200, 8, false, 0); - addAbilitieLevelSection(abilities, var7, var1, "4", 1000, 10, false, 0); - addAbilitieLevelSection(abilities, var7, var1, "5", 2000, 12, false, 0); - addAbilitieLevelSection(abilities, var7, var1, "6", 5000, 14, false, 0); - addAbilitieLevelSection(abilities, var7, var1, "7", 10000, 16, false, 0); - addAbilitieLevelSection(abilities, var7, var1, "8", 20000, 18, false, 0); - var1 = "feather_weight"; - ArrayList var8 = new ArrayList(); - var8.add("&7Take less fall damage"); - addAbilitieSection(abilities, var8, var1, "&aFeather weight", "288,1"); - ArrayList var9 = new ArrayList(); - var9.add("&7Take %value%% less fall damage %chance%%"); - var9.add("&7of the time"); - addAbilitieLevelSection(abilities, var9, var1, "1", 50, 4, true, 50); - addAbilitieLevelSection(abilities, var9, var1, "2", 100, 8, true, 50); - addAbilitieLevelSection(abilities, var9, var1, "3", 200, 12, true, 50); - addAbilitieLevelSection(abilities, var9, var1, "4", 1000, 16, true, 50); - addAbilitieLevelSection(abilities, var9, var1, "5", 2000, 20, true, 50); - addAbilitieLevelSection(abilities, var9, var1, "6", 5000, 24, true, 50); - addAbilitieLevelSection(abilities, var9, var1, "7", 10000, 28, true, 50); - addAbilitieLevelSection(abilities, var9, var1, "8", 20000, 32, true, 50); - var1 = "aggressive_mode"; - ArrayList var10 = new ArrayList(); - var10.add("&7Do more damage when you have less"); - var10.add("&7than 5 hearts"); - addAbilitieSection(abilities, var10, var1, "&aAggressive mode", "267,1"); - ArrayList var11 = new ArrayList(); - var11.add("&7When you have less than 5 hearts you"); - var11.add("&7inflict %value%% more damage %chance%% of the time"); - addAbilitieLevelSection(abilities, var11, var1, "1", 50, 2, true, 50); - addAbilitieLevelSection(abilities, var11, var1, "2", 100, 4, true, 50); - addAbilitieLevelSection(abilities, var11, var1, "3", 200, 6, true, 50); - addAbilitieLevelSection(abilities, var11, var1, "4", 1000, 8, true, 50); - addAbilitieLevelSection(abilities, var11, var1, "5", 2000, 10, true, 50); - addAbilitieLevelSection(abilities, var11, var1, "6", 5000, 12, true, 50); - addAbilitieLevelSection(abilities, var11, var1, "7", 10000, 14, true, 50); - addAbilitieLevelSection(abilities, var11, var1, "8", 20000, 16, true, 50); - var1 = "arrow_tank"; - ArrayList var12 = new ArrayList(); - var12.add("&7Take less damage from arrows"); - addAbilitieSection(abilities, var12, var1, "&aArrow tank skin", "307,1"); - ArrayList var13 = new ArrayList(); - var13.add("&7Have a %chance%% chance of taking %value%%"); - var13.add("&7less projectile damage"); - addAbilitieLevelSection(abilities, var13, var1, "1", 50, 4, true, 50); - addAbilitieLevelSection(abilities, var13, var1, "2", 100, 6, true, 50); - addAbilitieLevelSection(abilities, var13, var1, "3", 200, 8, true, 50); - addAbilitieLevelSection(abilities, var13, var1, "4", 1000, 10, true, 50); - addAbilitieLevelSection(abilities, var13, var1, "5", 2000, 12, true, 50); - addAbilitieLevelSection(abilities, var13, var1, "6", 5000, 14, true, 50); - addAbilitieLevelSection(abilities, var13, var1, "7", 10000, 16, true, 50); - addAbilitieLevelSection(abilities, var13, var1, "8", 20000, 18, true, 50); - var1 = "mining_luck"; - ArrayList var14 = new ArrayList(); - var14.add("&7Mining skill is increased so you can get"); - var14.add("&7more from each ore"); - addAbilitieSection(abilities, var14, var1, "&aMining luck", "278,1"); - ArrayList var15 = new ArrayList(); - var15.add("&7Have a %chance%% chance of getting %value% of an"); - var15.add("&7resource wjem you mine and ore"); - addAbilitieLevelSection(abilities, var15, var1, "1", 25, 4, true, 2); - addAbilitieLevelSection(abilities, var15, var1, "2", 50, 8, true, 2); - addAbilitieLevelSection(abilities, var15, var1, "3", 100, 12, true, 2); - addAbilitieLevelSection(abilities, var15, var1, "4", 500, 16, true, 2); - addAbilitieLevelSection(abilities, var15, var1, "5", 1000, 20, true, 2); - addAbilitieLevelSection(abilities, var15, var1, "6", 2500, 24, true, 2); - addAbilitieLevelSection(abilities, var15, var1, "7", 5000, 28, true, 2); - addAbilitieLevelSection(abilities, var15, var1, "8", 10000, 32, true, 2); - var1 = "woodchopping_luck"; - ArrayList var16 = new ArrayList(); - var16.add("&7Woodchopping skill is increased so you can get"); - var16.add("&7more from logs from a single piece"); - addAbilitieSection(abilities, var16, var1, "&aWoodchopping luck", "279,1"); - ArrayList var17 = new ArrayList(); - var17.add("&7Have a %chance%% chance of getting %value% logs"); - addAbilitieLevelSection(abilities, var17, var1, "1", 25, 4, true, 2); - addAbilitieLevelSection(abilities, var17, var1, "2", 50, 8, true, 2); - addAbilitieLevelSection(abilities, var17, var1, "3", 100, 12, true, 2); - addAbilitieLevelSection(abilities, var17, var1, "4", 500, 16, true, 2); - addAbilitieLevelSection(abilities, var17, var1, "5", 1000, 20, true, 2); - addAbilitieLevelSection(abilities, var17, var1, "6", 2500, 24, true, 2); - addAbilitieLevelSection(abilities, var17, var1, "7", 5000, 28, true, 2); - addAbilitieLevelSection(abilities, var17, var1, "8", 10000, 32, true, 2); - var1 = "pirate"; - ArrayList var18 = new ArrayList(); - var18.add("&7Find hidden treasures in dirt"); - addAbilitieSection(abilities, var18, var1, "&aPirate", "3,1"); - ArrayList var19 = new ArrayList(); - var19.add("1 1 apple"); - var19.add("2 12 arrow"); - var19.add("2 2 egg"); - var19.add("1 1 stone_sword"); - var19.add("2 6 wood"); - var19.add("2 6 cobblestone"); - var19.add("3 6 snow_ball"); - var19.add("1 1 leather_boots"); - abilities.addDefault("abilities." + var1 + ".treasures", var19, "Possible treasure items", "Format: MIN-AMOUNT MAX-AMOUNT ITEM:DATA"); - ArrayList var20 = new ArrayList(); - var20.add("&7Find treasure in %chance%% of dirt"); - addAbilitieLevelSection(abilities, var20, var1, "1", 25, 4, false, 0); - addAbilitieLevelSection(abilities, var20, var1, "2", 50, 6, false, 0); - addAbilitieLevelSection(abilities, var20, var1, "3", 100, 8, false, 0); - addAbilitieLevelSection(abilities, var20, var1, "4", 500, 10, false, 0); - addAbilitieLevelSection(abilities, var20, var1, "5", 1000, 12, false, 0); - addAbilitieLevelSection(abilities, var20, var1, "6", 2500, 14, false, 0); - addAbilitieLevelSection(abilities, var20, var1, "7", 5000, 16, false, 0); - addAbilitieLevelSection(abilities, var20, var1, "8", 10000, 18, false, 0); - var1 = "fire_resistance"; - ArrayList var21 = new ArrayList(); - var21.add("&7Take less fire damage"); - addAbilitieSection(abilities, var21, var1, "&aFire resistance", "259,1"); - ArrayList var22 = new ArrayList(); - var22.add("&7Take %value%% less fire and lava damage"); - var22.add("&7%chance%% of the time"); - addAbilitieLevelSection(abilities, var22, var1, "1", 50, 4, true, 50); - addAbilitieLevelSection(abilities, var22, var1, "2", 100, 8, true, 50); - addAbilitieLevelSection(abilities, var22, var1, "3", 200, 12, true, 50); - addAbilitieLevelSection(abilities, var22, var1, "4", 1000, 16, true, 50); - addAbilitieLevelSection(abilities, var22, var1, "5", 2000, 20, true, 50); - addAbilitieLevelSection(abilities, var22, var1, "6", 5000, 24, true, 50); - addAbilitieLevelSection(abilities, var22, var1, "7", 10000, 28, true, 50); - addAbilitieLevelSection(abilities, var22, var1, "8", 20000, 32, true, 50); - abilities.options().copyDefaults(true); - abilities.getEConfig().setNewLinePerKey(false); - abilities.save(); - } + public static void abilitiesConfig() { + File var0 = new File(SkyWars.getPlugin().getDataFolder(), "abilities.yml"); + abilities = new SkyConfiguration(var0); + ArrayList var2 = new ArrayList(); + abilities.addDefault("enabled", true, "enable or disable abilities on the server"); + abilities.addDefault("configVersion", 2, "Don't edit this value"); + abilities.addDefault("menu.lore.price", "&6Price: %price% points"); + abilities.addDefault("menu.lore.disabled", "&8&lDISABLED"); + abilities.addDefault("menu.lore.clickto.enable", "&6Click to enable", "Click ability icon to enable"); + abilities.addDefault("menu.lore.clickto.disable", "&6Click to disable", "Click ability icon to disable"); + abilities.addDefault("menu.lore.status.purchase", "&6Click to purchase this ability upgrade!", "Level item lore status"); + abilities.addDefault("menu.lore.status.afford", "&cYou cannot afford this ability!"); + abilities.addDefault("menu.lore.status.purchased", "&cAlready purchased!"); + abilities.addDefault("menu.lore.status.unavailable", "&cYou cannot purchase this item yet!"); + abilities.addDefault("menu.lore.status.disabled", "&6Click the icon to the left to enable"); + abilities.addDefault("menu.item.status.purchase", "95:4,1", "item displayed in menu ID:DATA,AMOUNT"); + abilities.addDefault("menu.item.status.afford", "95:14,1", "item displayed in menu ID:DATA,AMOUNT"); + abilities.addDefault("menu.item.status.purchased", "95:5,1", "item displayed in menu ID:DATA,AMOUNT"); + abilities.addDefault("menu.item.status.unavailable", "95:14,1", "item displayed in menu ID:DATA,AMOUNT"); + abilities.addDefault("menu.item.status.disabled", "95:8,1", "item displayed in menu ID:DATA,AMOUNT"); + abilities.addDefault("menu.item.level", "level %number%", "Item/Ability level"); + var2.add("%level-desc%"); + var2.add(""); + var2.add("%price-format%"); + var2.add(""); + var2.add("%status-format%"); + abilities.addDefault("menu.lore.levels.enabled", var2, "Level enabled item format"); + ArrayList var3 = new ArrayList(); + var3.add("%level-desc%"); + var3.add(""); + var3.add("%disabled%"); + var3.add("%status-format%"); + abilities.addDefault("menu.lore.levels.disabled", var3, "Level disabled item format"); + String var1 = "triple_arrow"; + ArrayList var4 = new ArrayList(); + var4.add("&7Shoot 3 arrows at the same time"); + addAbilitieSection(abilities, var4, var1, "&aTriple arrow shot", "262,3"); + ArrayList var5 = new ArrayList(); + var5.add("&7Have a %chance%% chance of shooting 3 arrows"); + var5.add("&7at the same time"); + addAbilitieLevelSection(abilities, var5, var1, "1", 50, 4, false, 3); + addAbilitieLevelSection(abilities, var5, var1, "2", 100, 6, false, 3); + addAbilitieLevelSection(abilities, var5, var1, "3", 200, 8, false, 3); + addAbilitieLevelSection(abilities, var5, var1, "4", 1000, 10, false, 3); + addAbilitieLevelSection(abilities, var5, var1, "5", 2000, 12, false, 3); + addAbilitieLevelSection(abilities, var5, var1, "6", 5000, 14, false, 3); + addAbilitieLevelSection(abilities, var5, var1, "7", 10000, 16, false, 3); + addAbilitieLevelSection(abilities, var5, var1, "8", 20000, 18, false, 3); + var1 = "adrenaline_boost"; + ArrayList var6 = new ArrayList(); + var6.add("&7When you get hurt have the chance to get a speed boost"); + addAbilitieSection(abilities, var6, var1, "&aAdrenaline boost", "373,1"); + ArrayList var7 = new ArrayList(); + var7.add("&7Have a %chance%% chance of getting a speed"); + var7.add("&7boost when you get hurt"); + addAbilitieLevelSection(abilities, var7, var1, "1", 50, 4, false, 0); + addAbilitieLevelSection(abilities, var7, var1, "2", 100, 6, false, 0); + addAbilitieLevelSection(abilities, var7, var1, "3", 200, 8, false, 0); + addAbilitieLevelSection(abilities, var7, var1, "4", 1000, 10, false, 0); + addAbilitieLevelSection(abilities, var7, var1, "5", 2000, 12, false, 0); + addAbilitieLevelSection(abilities, var7, var1, "6", 5000, 14, false, 0); + addAbilitieLevelSection(abilities, var7, var1, "7", 10000, 16, false, 0); + addAbilitieLevelSection(abilities, var7, var1, "8", 20000, 18, false, 0); + var1 = "feather_weight"; + ArrayList var8 = new ArrayList(); + var8.add("&7Take less fall damage"); + addAbilitieSection(abilities, var8, var1, "&aFeather weight", "288,1"); + ArrayList var9 = new ArrayList(); + var9.add("&7Take %value%% less fall damage %chance%%"); + var9.add("&7of the time"); + addAbilitieLevelSection(abilities, var9, var1, "1", 50, 4, true, 50); + addAbilitieLevelSection(abilities, var9, var1, "2", 100, 8, true, 50); + addAbilitieLevelSection(abilities, var9, var1, "3", 200, 12, true, 50); + addAbilitieLevelSection(abilities, var9, var1, "4", 1000, 16, true, 50); + addAbilitieLevelSection(abilities, var9, var1, "5", 2000, 20, true, 50); + addAbilitieLevelSection(abilities, var9, var1, "6", 5000, 24, true, 50); + addAbilitieLevelSection(abilities, var9, var1, "7", 10000, 28, true, 50); + addAbilitieLevelSection(abilities, var9, var1, "8", 20000, 32, true, 50); + var1 = "aggressive_mode"; + ArrayList var10 = new ArrayList(); + var10.add("&7Do more damage when you have less"); + var10.add("&7than 5 hearts"); + addAbilitieSection(abilities, var10, var1, "&aAggressive mode", "267,1"); + ArrayList var11 = new ArrayList(); + var11.add("&7When you have less than 5 hearts you"); + var11.add("&7inflict %value%% more damage %chance%% of the time"); + addAbilitieLevelSection(abilities, var11, var1, "1", 50, 2, true, 50); + addAbilitieLevelSection(abilities, var11, var1, "2", 100, 4, true, 50); + addAbilitieLevelSection(abilities, var11, var1, "3", 200, 6, true, 50); + addAbilitieLevelSection(abilities, var11, var1, "4", 1000, 8, true, 50); + addAbilitieLevelSection(abilities, var11, var1, "5", 2000, 10, true, 50); + addAbilitieLevelSection(abilities, var11, var1, "6", 5000, 12, true, 50); + addAbilitieLevelSection(abilities, var11, var1, "7", 10000, 14, true, 50); + addAbilitieLevelSection(abilities, var11, var1, "8", 20000, 16, true, 50); + var1 = "arrow_tank"; + ArrayList var12 = new ArrayList(); + var12.add("&7Take less damage from arrows"); + addAbilitieSection(abilities, var12, var1, "&aArrow tank skin", "307,1"); + ArrayList var13 = new ArrayList(); + var13.add("&7Have a %chance%% chance of taking %value%%"); + var13.add("&7less projectile damage"); + addAbilitieLevelSection(abilities, var13, var1, "1", 50, 4, true, 50); + addAbilitieLevelSection(abilities, var13, var1, "2", 100, 6, true, 50); + addAbilitieLevelSection(abilities, var13, var1, "3", 200, 8, true, 50); + addAbilitieLevelSection(abilities, var13, var1, "4", 1000, 10, true, 50); + addAbilitieLevelSection(abilities, var13, var1, "5", 2000, 12, true, 50); + addAbilitieLevelSection(abilities, var13, var1, "6", 5000, 14, true, 50); + addAbilitieLevelSection(abilities, var13, var1, "7", 10000, 16, true, 50); + addAbilitieLevelSection(abilities, var13, var1, "8", 20000, 18, true, 50); + var1 = "mining_luck"; + ArrayList var14 = new ArrayList(); + var14.add("&7Mining skill is increased so you can get"); + var14.add("&7more from each ore"); + addAbilitieSection(abilities, var14, var1, "&aMining luck", "278,1"); + ArrayList var15 = new ArrayList(); + var15.add("&7Have a %chance%% chance of getting %value% of an"); + var15.add("&7resource wjem you mine and ore"); + addAbilitieLevelSection(abilities, var15, var1, "1", 25, 4, true, 2); + addAbilitieLevelSection(abilities, var15, var1, "2", 50, 8, true, 2); + addAbilitieLevelSection(abilities, var15, var1, "3", 100, 12, true, 2); + addAbilitieLevelSection(abilities, var15, var1, "4", 500, 16, true, 2); + addAbilitieLevelSection(abilities, var15, var1, "5", 1000, 20, true, 2); + addAbilitieLevelSection(abilities, var15, var1, "6", 2500, 24, true, 2); + addAbilitieLevelSection(abilities, var15, var1, "7", 5000, 28, true, 2); + addAbilitieLevelSection(abilities, var15, var1, "8", 10000, 32, true, 2); + var1 = "woodchopping_luck"; + ArrayList var16 = new ArrayList(); + var16.add("&7Woodchopping skill is increased so you can get"); + var16.add("&7more from logs from a single piece"); + addAbilitieSection(abilities, var16, var1, "&aWoodchopping luck", "279,1"); + ArrayList var17 = new ArrayList(); + var17.add("&7Have a %chance%% chance of getting %value% logs"); + addAbilitieLevelSection(abilities, var17, var1, "1", 25, 4, true, 2); + addAbilitieLevelSection(abilities, var17, var1, "2", 50, 8, true, 2); + addAbilitieLevelSection(abilities, var17, var1, "3", 100, 12, true, 2); + addAbilitieLevelSection(abilities, var17, var1, "4", 500, 16, true, 2); + addAbilitieLevelSection(abilities, var17, var1, "5", 1000, 20, true, 2); + addAbilitieLevelSection(abilities, var17, var1, "6", 2500, 24, true, 2); + addAbilitieLevelSection(abilities, var17, var1, "7", 5000, 28, true, 2); + addAbilitieLevelSection(abilities, var17, var1, "8", 10000, 32, true, 2); + var1 = "pirate"; + ArrayList var18 = new ArrayList(); + var18.add("&7Find hidden treasures in dirt"); + addAbilitieSection(abilities, var18, var1, "&aPirate", "3,1"); + ArrayList var19 = new ArrayList(); + var19.add("1 1 apple"); + var19.add("2 12 arrow"); + var19.add("2 2 egg"); + var19.add("1 1 stone_sword"); + var19.add("2 6 wood"); + var19.add("2 6 cobblestone"); + var19.add("3 6 snow_ball"); + var19.add("1 1 leather_boots"); + abilities.addDefault("abilities." + var1 + ".treasures", var19, "Possible treasure items", "Format: MIN-AMOUNT MAX-AMOUNT ITEM:DATA"); + ArrayList var20 = new ArrayList(); + var20.add("&7Find treasure in %chance%% of dirt"); + addAbilitieLevelSection(abilities, var20, var1, "1", 25, 4, false, 0); + addAbilitieLevelSection(abilities, var20, var1, "2", 50, 6, false, 0); + addAbilitieLevelSection(abilities, var20, var1, "3", 100, 8, false, 0); + addAbilitieLevelSection(abilities, var20, var1, "4", 500, 10, false, 0); + addAbilitieLevelSection(abilities, var20, var1, "5", 1000, 12, false, 0); + addAbilitieLevelSection(abilities, var20, var1, "6", 2500, 14, false, 0); + addAbilitieLevelSection(abilities, var20, var1, "7", 5000, 16, false, 0); + addAbilitieLevelSection(abilities, var20, var1, "8", 10000, 18, false, 0); + var1 = "fire_resistance"; + ArrayList var21 = new ArrayList(); + var21.add("&7Take less fire damage"); + addAbilitieSection(abilities, var21, var1, "&aFire resistance", "259,1"); + ArrayList var22 = new ArrayList(); + var22.add("&7Take %value%% less fire and lava damage"); + var22.add("&7%chance%% of the time"); + addAbilitieLevelSection(abilities, var22, var1, "1", 50, 4, true, 50); + addAbilitieLevelSection(abilities, var22, var1, "2", 100, 8, true, 50); + addAbilitieLevelSection(abilities, var22, var1, "3", 200, 12, true, 50); + addAbilitieLevelSection(abilities, var22, var1, "4", 1000, 16, true, 50); + addAbilitieLevelSection(abilities, var22, var1, "5", 2000, 20, true, 50); + addAbilitieLevelSection(abilities, var22, var1, "6", 5000, 24, true, 50); + addAbilitieLevelSection(abilities, var22, var1, "7", 10000, 28, true, 50); + addAbilitieLevelSection(abilities, var22, var1, "8", 20000, 32, true, 50); + abilities.options().copyDefaults(true); + abilities.getEConfig().setNewLinePerKey(false); + abilities.save(); + } - private static void addAbilitieSection(SkyConfiguration var0, List var1, String var2, String var3, String var4) { - var0.addDefault("abilities." + var2 + ".enabled", true, "enable or disable this ability"); - var0.addDefault("abilities." + var2 + ".name", var3, "ability title/name"); - var0.addDefault("abilities." + var2 + ".desc", var1, "ability description item"); - var0.addDefault("abilities." + var2 + ".item", var4, "item displayed in menu ID:DATA,AMOUNT"); - } + private static void addAbilitieSection(SkyConfiguration var0, List var1, String var2, String var3, String var4) { + var0.addDefault("abilities." + var2 + ".enabled", true, "enable or disable this ability"); + var0.addDefault("abilities." + var2 + ".name", var3, "ability title/name"); + var0.addDefault("abilities." + var2 + ".desc", var1, "ability description item"); + var0.addDefault("abilities." + var2 + ".item", var4, "item displayed in menu ID:DATA,AMOUNT"); + } - private static void addAbilitieLevelSection(SkyConfiguration var0, List var1, String var2, String var3, int var4, int var5, boolean var6, int var7) { - var0.addDefault("abilities." + var2 + ".levels_desc", var1, "levels description displayed in menu"); - var0.addDefault("abilities." + var2 + ".level." + var3 + ".price", var4, "level price"); - var0.addDefault("abilities." + var2 + ".level." + var3 + ".chance", var5, "level chance"); - if (var6) { - var0.addDefault("abilities." + var2 + ".level." + var3 + ".value", var7, "level value"); - } + private static void addAbilitieLevelSection(SkyConfiguration var0, List var1, String var2, String var3, int var4, int var5, boolean var6, int var7) { + var0.addDefault("abilities." + var2 + ".levels_desc", var1, "levels description displayed in menu"); + var0.addDefault("abilities." + var2 + ".level." + var3 + ".price", var4, "level price"); + var0.addDefault("abilities." + var2 + ".level." + var3 + ".chance", var5, "level chance"); + if (var6) { + var0.addDefault("abilities." + var2 + ".level." + var3 + ".value", var7, "level value"); + } - } + } - public static void shopConfig() { - File var0 = new File(SkyWars.getPlugin().getDataFolder(), "shop.yml"); - shop = new SkyConfiguration(var0); - if (!shop.isSet("config_version") || shop.getInt("config_version") != 1 && shop.getInt("config_version") != 2) { - shop.setHeader("---------------------------------------------------------------- #", "", "IMPORTANT: ALL MENU NAMES (SUB MENUS AND MAIN MENU) HAVE TO BE DIFFERENT", "", "---------------------------------------------------------------- #"); - ArrayList var1 = new ArrayList(); - shop.addDefault("config_version", 2, "Don't edit this value"); - shop.addDefault("shopingame", true); - shop.addDefault("item.enabled", false, "false (Shop menu and Item disabled), true (Shop menu and Item enabled)"); - shop.addDefault("item.inventorySlot", 1, "Slot where the item will be placed (Recommended: 0-8)"); - shop.addDefault("item.item", 340, "ID:Data or NAME:Data (If Data equals to 0 is not necessary to write it)"); - shop.addDefault("item.name", "&e&lShop", "Item name"); - var1.add("&7Click me to open the shop"); - var1.add("&7to buy lots of cool stuff for SkyWars"); - shop.addDefault("item.lore", var1, "lore: Item lore or description"); - shop.addDefault("shop_size", 6, "All Shop menu size (rows) (MAX VALUE: 6)"); - shop.addDefault("main.main_name", "&fSkyWars Shop", "main_name: Main Menu Title"); - shop.addDefault("main.items.51.item", 340, "item: ID:Data or NAME:Data"); - shop.addDefault("main.items.51.name", "&9Close menu", "name: Item Name"); - ArrayList var2 = new ArrayList(); - var2.add("&7Close the shopping"); - var2.add("&7menu."); - shop.addDefault("main.items.51.lore", var2, "Item lore or description"); - shop.addDefault("main.items.51.action", "CLOSE", "action:", "\tCLOSE: Close menu", "\tNONE: Does nothing"); - shop.addDefault("all.49.item", 395, "ID:Data or NAME:Data"); - shop.addDefault("all.49.name", "&6Total points: &a%coins%", "name: Item Name"); - ArrayList var3 = new ArrayList(); - var3.add("&5Earn point from"); - var3.add("&5playing games"); - shop.addDefault("all.49.lore", var3, "Item lore or description"); - shop.addDefault("all.49.action", "CLOSE", "action:", "\tCLOSE: Close menu", "\tNONE: Does nothing"); - shop.addDefault("allsubmenus.50.item", 340, "ID:Data or NAME:Data"); - shop.addDefault("allsubmenus.50.name", "&9Back", "Item name"); - ArrayList var4 = new ArrayList(); - var4.add("&7Go back to the shopping menu"); - shop.addDefault("allsubmenus.50.lore", var4, "Item lore or description"); - shop.addDefault("allsubmenus.50.action", "MAIN", "action:", "\tCLOSE: Close menu", "\tNONE: Does nothing", "\tMAIN: Back to the main menu"); - byte var5 = 22; - shop.addDefault("submenus." + var5 + ".sub_name", "&fSkyWars Kits", "Sub menu title"); - shop.addDefault("submenus." + var5 + ".item", 265, "ID:Data or NAME:Data"); - shop.addDefault("submenus." + var5 + ".name", "&eSkyWars Kits", "Item name"); - ArrayList var6 = new ArrayList(); - var6.add("&7Purchase SkyWars kits"); - shop.addDefault("submenus." + var5 + ".lore", var6, "Item lore or description"); - shop.addDefault("submenus." + var5 + ".content.11.item", "KIT,Fisherman", "Item variable: KIT,KitName (Get item, name, description and price from the kit)"); - shop.addDefault("submenus." + var5 + ".content.12.item", "KIT,Lumberjack"); - shop.addDefault("submenus." + var5 + ".content.13.item", "KIT,Spiderman"); - shop.addDefault("submenus." + var5 + ".content.14.item", "KIT,Blacksmith"); - shop.addDefault("submenus." + var5 + ".content.15.item", "KIT,Digger"); - shop.addDefault("submenus." + var5 + ".content.16.item", "KIT,Redstone_master"); - shop.addDefault("submenus." + var5 + ".content.17.item", "KIT,Farmer"); - shop.addDefault("submenus." + var5 + ".content.20.item", "KIT,Chicken"); - shop.addDefault("submenus." + var5 + ".content.21.item", "KIT,Joker"); - shop.addDefault("submenus." + var5 + ".content.22.item", "KIT,Scout"); - shop.addDefault("submenus." + var5 + ".content.23.item", "KIT,Pyromaniac"); - shop.addDefault("submenus." + var5 + ".content.24.item", "KIT,Archer"); - shop.addDefault("submenus." + var5 + ".content.25.item", "KIT,Enchanter"); - shop.addDefault("submenus." + var5 + ".content.26.item", "KIT,Enderman"); - shop.addDefault("submenus." + var5 + ".content.30.item", "KIT,Iron_golem"); - shop.addDefault("submenus." + var5 + ".content.31.item", "KIT,Healer"); - shop.addDefault("submenus." + var5 + ".content.32.item", "KIT,Bomber"); - shop.addDefault("submenus." + var5 + ".content.33.item", "KIT,Swordsman"); - shop.addDefault("submenu.abilities.enabled", true, "Enable or disable Abilities in shop menu"); - shop.addDefault("submenu.abilities.name", "&fSkyWars Abilities - Page %number%", "Abilities submenu name"); - shop.addDefault("submenu.abilities.slot", 24, "Abilities main menu item slot"); - shop.addDefault("submenu.abilities.item.name", "&eSkyWars Abilities", "Abilities item name"); - shop.addDefault("submenu.abilities.item.item", 301, "Abilities item"); - ArrayList var7 = new ArrayList(); - var7.add("&7Purchase SkyWars abilities"); - shop.addDefault("submenu.abilities.item.lore", var7, "Abilities item description"); - shop.addDefault("submenu.abilities.next.item", 338, "Abilities next page item"); - shop.addDefault("submenu.abilities.next.name", "&6Next page", "Abilities next page item name"); - shop.addDefault("submenu.abilities.next.slot", 54, "Abilities next page item slot"); - shop.addDefault("submenu.abilities.previous.item", 338, "Abilities previous page item"); - shop.addDefault("submenu.abilities.previous.name", "&6Previous page", "Abilities previous page item name"); - shop.addDefault("submenu.abilities.previous.slot", 46, "Abilities previous page item slot"); - shop.options().copyDefaults(true); - shop.getEConfig().setNewLinePerKey(true); - shop.save(); - } - } + public static void shopConfig() { + File var0 = new File(SkyWars.getPlugin().getDataFolder(), "shop.yml"); + shop = new SkyConfiguration(var0); + if (!shop.isSet("config_version") || shop.getInt("config_version") != 1 && shop.getInt("config_version") != 2) { + shop.setHeader("---------------------------------------------------------------- #", "", "IMPORTANT: ALL MENU NAMES (SUB MENUS AND MAIN MENU) HAVE TO BE DIFFERENT", "", "---------------------------------------------------------------- #"); + ArrayList var1 = new ArrayList(); + shop.addDefault("config_version", 2, "Don't edit this value"); + shop.addDefault("shopingame", true); + shop.addDefault("item.enabled", false, "false (Shop menu and Item disabled), true (Shop menu and Item enabled)"); + shop.addDefault("item.inventorySlot", 1, "Slot where the item will be placed (Recommended: 0-8)"); + shop.addDefault("item.item", 340, "ID:Data or NAME:Data (If Data equals to 0 is not necessary to write it)"); + shop.addDefault("item.name", "&e&lShop", "Item name"); + var1.add("&7Click me to open the shop"); + var1.add("&7to buy lots of cool stuff for SkyWars"); + shop.addDefault("item.lore", var1, "lore: Item lore or description"); + shop.addDefault("shop_size", 6, "All Shop menu size (rows) (MAX VALUE: 6)"); + shop.addDefault("main.main_name", "&fSkyWars Shop", "main_name: Main Menu Title"); + shop.addDefault("main.items.51.item", 340, "item: ID:Data or NAME:Data"); + shop.addDefault("main.items.51.name", "&9Close menu", "name: Item Name"); + ArrayList var2 = new ArrayList(); + var2.add("&7Close the shopping"); + var2.add("&7menu."); + shop.addDefault("main.items.51.lore", var2, "Item lore or description"); + shop.addDefault("main.items.51.action", "CLOSE", "action:", "\tCLOSE: Close menu", "\tNONE: Does nothing"); + shop.addDefault("all.49.item", 395, "ID:Data or NAME:Data"); + shop.addDefault("all.49.name", "&6Total points: &a%coins%", "name: Item Name"); + ArrayList var3 = new ArrayList(); + var3.add("&5Earn point from"); + var3.add("&5playing games"); + shop.addDefault("all.49.lore", var3, "Item lore or description"); + shop.addDefault("all.49.action", "CLOSE", "action:", "\tCLOSE: Close menu", "\tNONE: Does nothing"); + shop.addDefault("allsubmenus.50.item", 340, "ID:Data or NAME:Data"); + shop.addDefault("allsubmenus.50.name", "&9Back", "Item name"); + ArrayList var4 = new ArrayList(); + var4.add("&7Go back to the shopping menu"); + shop.addDefault("allsubmenus.50.lore", var4, "Item lore or description"); + shop.addDefault("allsubmenus.50.action", "MAIN", "action:", "\tCLOSE: Close menu", "\tNONE: Does nothing", "\tMAIN: Back to the main menu"); + byte var5 = 22; + shop.addDefault("submenus." + var5 + ".sub_name", "&fSkyWars Kits", "Sub menu title"); + shop.addDefault("submenus." + var5 + ".item", 265, "ID:Data or NAME:Data"); + shop.addDefault("submenus." + var5 + ".name", "&eSkyWars Kits", "Item name"); + ArrayList var6 = new ArrayList(); + var6.add("&7Purchase SkyWars kits"); + shop.addDefault("submenus." + var5 + ".lore", var6, "Item lore or description"); + shop.addDefault("submenus." + var5 + ".content.11.item", "KIT,Fisherman", "Item variable: KIT,KitName (Get item, name, description and price from the kit)"); + shop.addDefault("submenus." + var5 + ".content.12.item", "KIT,Lumberjack"); + shop.addDefault("submenus." + var5 + ".content.13.item", "KIT,Spiderman"); + shop.addDefault("submenus." + var5 + ".content.14.item", "KIT,Blacksmith"); + shop.addDefault("submenus." + var5 + ".content.15.item", "KIT,Digger"); + shop.addDefault("submenus." + var5 + ".content.16.item", "KIT,Redstone_master"); + shop.addDefault("submenus." + var5 + ".content.17.item", "KIT,Farmer"); + shop.addDefault("submenus." + var5 + ".content.20.item", "KIT,Chicken"); + shop.addDefault("submenus." + var5 + ".content.21.item", "KIT,Joker"); + shop.addDefault("submenus." + var5 + ".content.22.item", "KIT,Scout"); + shop.addDefault("submenus." + var5 + ".content.23.item", "KIT,Pyromaniac"); + shop.addDefault("submenus." + var5 + ".content.24.item", "KIT,Archer"); + shop.addDefault("submenus." + var5 + ".content.25.item", "KIT,Enchanter"); + shop.addDefault("submenus." + var5 + ".content.26.item", "KIT,Enderman"); + shop.addDefault("submenus." + var5 + ".content.30.item", "KIT,Iron_golem"); + shop.addDefault("submenus." + var5 + ".content.31.item", "KIT,Healer"); + shop.addDefault("submenus." + var5 + ".content.32.item", "KIT,Bomber"); + shop.addDefault("submenus." + var5 + ".content.33.item", "KIT,Swordsman"); + shop.addDefault("submenu.abilities.enabled", true, "Enable or disable Abilities in shop menu"); + shop.addDefault("submenu.abilities.name", "&fSkyWars Abilities - Page %number%", "Abilities submenu name"); + shop.addDefault("submenu.abilities.slot", 24, "Abilities main menu item slot"); + shop.addDefault("submenu.abilities.item.name", "&eSkyWars Abilities", "Abilities item name"); + shop.addDefault("submenu.abilities.item.item", 301, "Abilities item"); + ArrayList var7 = new ArrayList(); + var7.add("&7Purchase SkyWars abilities"); + shop.addDefault("submenu.abilities.item.lore", var7, "Abilities item description"); + shop.addDefault("submenu.abilities.next.item", 338, "Abilities next page item"); + shop.addDefault("submenu.abilities.next.name", "&6Next page", "Abilities next page item name"); + shop.addDefault("submenu.abilities.next.slot", 54, "Abilities next page item slot"); + shop.addDefault("submenu.abilities.previous.item", 338, "Abilities previous page item"); + shop.addDefault("submenu.abilities.previous.name", "&6Previous page", "Abilities previous page item name"); + shop.addDefault("submenu.abilities.previous.slot", 46, "Abilities previous page item slot"); + shop.options().copyDefaults(true); + shop.getEConfig().setNewLinePerKey(true); + shop.save(); + } + } - public static void signsConfig() { - File var0 = new File(SkyWars.getPlugin().getDataFolder(), "signs.yml"); - signs = new SkyConfiguration(var0); - signs.setHeader("SIGNS CONFIGURATION"); - signs.addDefault("rotation", false, "Enable or disable rotation system (disabled by default)", "If rotation is enabled the sign will select a random arena available, that means that your server can have 30 arenas and only 10 signs", "and all arenas can be played without have one sign per arena"); - signs.addDefault("rotationDelay", 60, "Delay in ticks (20 Ticks = 1 Second) when the sign will search another game after being in-game (Only if rotation is enable)"); - signs.addDefault("change_block", true, "Enable or disable the change of the block depending of the arena state"); - ArrayList var1 = Lists.newArrayList("&lSkyWars", "%state%", "&nMap: %map%", "&8%players%/%maxplayers%"); - signs.addDefault("format.game", var1); - ArrayList var2 = Lists.newArrayList("&l----------", "SEARCHING", "GAMES", "&l----------"); - signs.addDefault("format.searching", var2); - signs.addDefault("state", "", "The block that will be placed on the wall depending of the arena state (change_block must be enabled)", "Block Format: ITEM_NAME:DATA (If DATA is 0 you don't have to type it)"); - signs.addDefault("state.waiting", "STAINED_GLASS:5"); - signs.addDefault("state.starting", "STAINED_GLASS:4"); - signs.addDefault("state.full", "STAINED_GLASS:10"); - signs.addDefault("state.ingame", "STAINED_GLASS:14"); - signs.addDefault("state.searching", "STAINED_GLASS"); - signs.addDefault("signs", new ArrayList<>()); - signs.options().copyDefaults(true); - signs.getEConfig().setNewLinePerKey(true); + public static void signsConfig() { + File file = new File(SkyWars.getPlugin().getDataFolder(), "signs.yml"); + signs = new SkyConfiguration(file); + signs.setHeader("SIGNS CONFIGURATION"); + signs.addDefault("rotation", false, "Enable or disable rotation system (disabled by default)", "If rotation is enabled the sign will select a random arena available, that means that your server can have 30 arenas and only 10 signs", "and all arenas can be played without have one sign per arena"); + signs.addDefault("rotationDelay", 60, "Delay in ticks (20 Ticks = 1 Second) when the sign will search another game after being in-game (Only if rotation is enable)"); + signs.addDefault("change_block", true, "Enable or disable the change of the block depending of the arena state"); + ArrayList var1 = Lists.newArrayList("&lSkyWars", "%state%", "&nMap: %map%", "&8%players%/%maxplayers%"); + signs.addDefault("format.game", var1); + ArrayList var2 = Lists.newArrayList("&l----------", "SEARCHING", "GAMES", "&l----------"); + signs.addDefault("format.searching", var2); + signs.addDefault("state", "", "The block that will be placed on the wall depending of the arena state (change_block must be enabled)", "Block Format: ITEM_NAME:DATA (If DATA is 0 you don't have to type it)"); + signs.addDefault("state.waiting", "STAINED_GLASS:5"); + signs.addDefault("state.starting", "STAINED_GLASS:4"); + signs.addDefault("state.full", "STAINED_GLASS:10"); + signs.addDefault("state.ingame", "STAINED_GLASS:14"); + signs.addDefault("state.searching", "STAINED_GLASS"); + signs.addDefault("signs", new ArrayList<>()); + signs.options().copyDefaults(true); + signs.getEConfig().setNewLinePerKey(true); - for (String var4 : signs.getConfigurationSection("state").getKeys(false)) { - String var5 = signs.getString("state." + var4); - signs.set("state." + var4, Utils.readItem(var5).toString()); - } + for (String var4 : signs.getConfigurationSection("state").getKeys(false)) { + String var5 = signs.getString("state." + var4); + signs.set("state." + var4, Utils.readItem(var5).toString()); + } - signs.save(); - } + signs.save(); + } + + public static void databaseConfig() { + File file = new File(SkyWars.getPlugin().getDataFolder(), "database.yml"); + database = new SkyConfiguration(file); + database.setHeader("DATABASE CONFIGURATION"); + + database.addDefault("type", "SQLite", "Database engine: SQLite or MySQL"); + database.addDefault("sqlite.path", "plugins/SkyWars/Database.db", "SQLite database file path relative to server root"); + + database.addDefault("mysql.host", "localhost", "MySQL server host"); + database.addDefault("mysql.port", 3306, "MySQL server port"); + database.addDefault("mysql.database", "SkyWars", "MySQL database name"); + database.addDefault("mysql.user", "root", "MySQL user"); + database.addDefault("mysql.password", "CHANGEME", "MySQL password (DO NOT COMMIT REAL CREDENTIALS)"); + database.addDefault("mysql.useLog4Jdbc", false, "Use log4jdbc for debugging (optional)"); + database.addDefault("mysql.pool.maxPoolSize", 8, "HikariCP max pool size"); + database.addDefault("mysql.pool.minimumIdle", 1, "HikariCP minimum idle"); + database.addDefault("mysql.pool.maxLifetimeMs", 180000, "HikariCP max lifetime ms"); + + database.addDefault("tables.data", "SkyWars_Data", "Table name for player data"); + database.addDefault("tables.economy", "SkyWars_Economy", "Table name for economy data"); + database.addDefault("tables.servers", "SkyWars_Servers", "Table name for servers info"); + + database.addDefault("debug.debug-database", false, "Enable debug for database operations"); + + database.addDefault("nats.url", "nats://127.0.0.1:4222", "NATS server URL used for instance/proxy messaging"); + + database.options().copyDefaults(true); + database.getEConfig().setNewLinePerKey(true); + database.save(); + } } diff --git a/spigot/src/main/java/fun/ogtimes/skywars/spigot/config/SkyConfiguration.java b/spigot/src/main/java/fun/ogtimes/skywars/spigot/config/SkyConfiguration.java index dffe896..59093e2 100644 --- a/spigot/src/main/java/fun/ogtimes/skywars/spigot/config/SkyConfiguration.java +++ b/spigot/src/main/java/fun/ogtimes/skywars/spigot/config/SkyConfiguration.java @@ -9,19 +9,19 @@ import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; +@Getter public class SkyConfiguration extends YamlConfiguration implements IConfiguration { private final EConfiguration econfig = new EConfiguration(); - @Getter private File file; - public SkyConfiguration(File var1) { - this.file = var1; + public SkyConfiguration(File file) { + this.file = file; try { - this.load(var1); + this.load(file); } catch (FileNotFoundException ignored) { - } catch (InvalidConfigurationException | IOException var4) { - Bukkit.getLogger().log(Level.SEVERE, "Cannot load " + var1, var4); + } catch (InvalidConfigurationException | IOException ex) { + Bukkit.getLogger().log(Level.SEVERE, "Cannot load " + file, ex); } } @@ -30,116 +30,108 @@ public EConfiguration getEConfig() { return this.econfig; } - public void load(File var1) throws IOException, InvalidConfigurationException { - this.file = var1; - super.load(var1); + @Override + public void load(File file) throws IOException, InvalidConfigurationException { + this.file = file; + super.load(file); super.options().header(""); - BufferedReader var2 = null; - ArrayList var3 = new ArrayList(); - try { - var2 = new BufferedReader(new FileReader(var1)); - - String var4; - while((var4 = var2.readLine()) != null) { - var3.add(var4); - } - } finally { - if (var2 != null) { - var2.close(); + LinkedList lines = new LinkedList<>(); + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + while ((line = reader.readLine()) != null) { + lines.add(line); } + } + if (lines.isEmpty()) { + Bukkit.getLogger().log(Level.SEVERE, file.getName() + " doesn't have nothing to load"); + return; } - if (var3.isEmpty()) { - Bukkit.getLogger().log(Level.SEVERE, var1.getName() + " doesn't have nothing to load"); - } else { - boolean var13 = !this.econfig.trim((String)var3.getFirst()).isEmpty(); - LinkedHashMap var5 = new LinkedHashMap(); - - for(int var6 = 0; var6 < var3.size(); ++var6) { - String var7 = (String)var3.get(var6); - String var8 = this.econfig.trimPrefixSpaces(var7); - if (var8.startsWith("#") && (var6 > 0 || !var13)) { - String var9 = this.econfig.getPathToComment(var3, var6, var7); - if (var9 != null) { - Object var10 = var5.get(var9); - if (var10 == null) { - var10 = new ArrayList<>(); - } + boolean firstLineNotEmpty = !this.econfig.trim(lines.getFirst()).isEmpty(); + + Map> commentsMap = new LinkedHashMap<>(); - ((List)var10).add(var8.substring(var8.startsWith("# ") ? 2 : 1)); - var5.put(var9, var10); + for (int index = 0; index < lines.size(); ++index) { + String rawLine = lines.get(index); + String trimmed = this.econfig.trimPrefixSpaces(rawLine); + if (trimmed.startsWith("#") && (index > 0 || !firstLineNotEmpty)) { + String path = this.econfig.getPathToComment(lines, index, rawLine); + if (path != null) { + List list = commentsMap.get(path); + if (list == null) { + list = new ArrayList<>(); } + list.add(trimmed.substring(trimmed.startsWith("# ") ? 2 : 1)); + commentsMap.put(path, list); } } + } + if (!commentsMap.isEmpty()) { + this.econfig.getComments().putAll(commentsMap); } } public void save() { try { this.save(this.file); - } catch (IOException var2) { - var2.printStackTrace(); + } catch (IOException ex) { + Bukkit.getLogger().log(Level.SEVERE, "Cannot save " + this.file, ex); } } - public void save(File var1) throws IOException { - super.save(var1); - ArrayList var2 = new ArrayList(); - - try (BufferedReader var3 = new BufferedReader(new FileReader(var1))) { + @Override + public void save(File file) throws IOException { + super.save(file); + List lines = new ArrayList<>(); - String var4; - while ((var4 = var3.readLine()) != null) { - var2.add(var4); + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + while ((line = reader.readLine()) != null) { + lines.add(line); } } - try (BufferedWriter var20 = new BufferedWriter(new FileWriter(var1))) { - var20.write(""); + try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { + writer.write(""); - for (int var5 = 0; var5 < var2.size(); ++var5) { - String var6 = (String) var2.get(var5); - String var7 = null; - if (!var6.startsWith("#") && var6.contains(":")) { - var7 = this.econfig.getPathToKey(var2, var5, var6); + for (int i = 0; i < lines.size(); ++i) { + String currentLine = lines.get(i); + String path = null; + if (!currentLine.startsWith("#") && currentLine.contains(":")) { + path = this.econfig.getPathToKey(lines, i, currentLine); } - StringBuilder var9; - if (var7 != null && this.econfig.getComments().containsKey(var7)) { - int var8 = this.econfig.getPrefixSpaceCount(var6); - var9 = new StringBuilder(); - - for (int var10 = 0; var10 < var8; ++var10) { - var9.append(" "); - } - - List var22 = this.econfig.getComments().get(var7); - if (var22 != null) { - - for (Object object : var22) { - String var12 = (String) object; - var20.append(var9.toString()).append("# ").append(var12); - var20.newLine(); + StringBuilder builder; + if (path != null && this.econfig.getComments().containsKey(path)) { + int prefixSpaces = this.econfig.getPrefixSpaceCount(currentLine); + builder = new StringBuilder(); + builder.append(" ".repeat(Math.max(0, prefixSpaces))); + + List comments = this.econfig.getComments().get(path); + if (comments != null) { + for (String comment : comments) { + writer.append(builder.toString()).append("# ").append(comment); + writer.newLine(); } } } - boolean var21 = var6.startsWith("#"); - if (!var6.startsWith("-") && !var6.startsWith(" -") && !var6.startsWith(" -") && !var6.startsWith(" -")) { - var20.append(var6); + boolean isComment = currentLine.startsWith("#"); + if (!currentLine.startsWith("-") && !currentLine.startsWith(" -") && !currentLine.startsWith(" -") && !currentLine.startsWith(" -")) { + writer.append(currentLine); } else { - var20.append(" ").append(var6); + writer.append(" ").append(currentLine); } - var20.newLine(); - if (this.econfig.shouldAddNewLinePerKey() && var5 < var2.size() - 1 && !var21) { - var9 = new StringBuilder((String) var2.get(var5 + 1)); - if (var9 != null && !var9.toString().startsWith(" ") && !var9.toString().startsWith("'") && !var9.toString().startsWith("-")) { - var20.newLine(); + writer.newLine(); + if (this.econfig.shouldAddNewLinePerKey() && i < lines.size() - 1 && !isComment) { + String nextLine = lines.get(i + 1); + if (!nextLine.startsWith(" ") && !nextLine.startsWith("'") && !nextLine.startsWith("-")) { + writer.newLine(); } } } @@ -147,85 +139,75 @@ public void save(File var1) throws IOException { } - public void set(String var1, Object var2) { - if (var2 != null) { - if (!this.econfig.getComments(var1).isEmpty()) { - this.econfig.getComments().put(var1, this.econfig.getComments(var1)); + @Override + public void set(String key, Object value) { + if (value != null) { + List comments = this.econfig.getComments(key); + if (!comments.isEmpty()) { + this.econfig.getComments().put(key, comments); } else { - this.econfig.getComments().remove(var1); + this.econfig.getComments().remove(key); } } else { - this.econfig.getComments().remove(var1); + this.econfig.getComments().remove(key); } - super.set(var1, var2); + super.set(key, value); } - public void addDefault(String var1, Object var2, String... var3) { - if (var2 != null && var3 != null && var3.length > 0 && !this.econfig.getComments().containsKey(var1)) { - ArrayList var4 = new ArrayList(); - int var6 = var3.length; - - for(int var7 = 0; var7 < var6; ++var7) { - String var8 = var3[var7]; - var4.add(Objects.requireNonNullElse(var8, "")); + public void addDefault(String key, Object value, String... comments) { + if (value != null && comments != null && comments.length > 0 && !this.econfig.getComments().containsKey(key)) { + List list = new ArrayList<>(); + for (String c : comments) { + list.add(Objects.requireNonNullElse(c, "")); } - this.econfig.getComments().put(var1, var4); + this.econfig.getComments().put(key, list); } - super.addDefault(var1, var2); + super.addDefault(key, value); } - public void createSection(String var1, String... var2) { - if (var1 != null && var2 != null && var2.length > 0) { - ArrayList var3 = new ArrayList(); - int var5 = var2.length; - - for(int var6 = 0; var6 < var5; ++var6) { - String var7 = var2[var6]; - var3.add(Objects.requireNonNullElse(var7, "")); + public void createSection(String key, String... values) { + if (key != null && values != null && values.length > 0) { + List list = new ArrayList<>(); + for (String v : values) { + list.add(Objects.requireNonNullElse(v, "")); } - this.econfig.getComments().put(var1, var3); + this.econfig.getComments().put(key, list); } - super.createSection(var1); + super.createSection(key); } - public void setHeader(String... var1) { - StringBuilder var2 = new StringBuilder(); - int var4 = var1.length; - - for(int var5 = 0; var5 < var4; ++var5) { - String var6 = var1[var5]; - var2.append(var6).append("\n"); + public void setHeader(String... header) { + StringBuilder sb = new StringBuilder(); + for (String h : header) { + sb.append(h).append("\n"); } - super.options().header(var2.toString()); + super.options().header(sb.toString()); } - public void set(String var1, Object var2, String... var3) { - if (var2 != null) { - if (var3 != null) { - if (var3.length > 0) { - ArrayList var4 = new ArrayList(); - int var6 = var3.length; - - for(int var7 = 0; var7 < var6; ++var7) { - String var8 = var3[var7]; - var4.add(Objects.requireNonNullElse(var8, "")); + public void set(String key, Object value, String... comments) { + if (value != null) { + if (comments != null) { + if (comments.length > 0) { + List list = new ArrayList<>(); + for (String c : comments) { + list.add(Objects.requireNonNullElse(c, "")); } - this.econfig.getComments().put(var1, var4); + this.econfig.getComments().put(key, list); } else { - this.econfig.getComments().remove(var1); + this.econfig.getComments().remove(key); } } } else { - this.econfig.getComments().remove(var1); + this.econfig.getComments().remove(key); } - super.set(var1, var2); + super.set(key, value); } } diff --git a/spigot/src/main/java/fun/ogtimes/skywars/spigot/database/DataSource.java b/spigot/src/main/java/fun/ogtimes/skywars/spigot/database/DataSource.java index c96ff98..b2f4f3e 100644 --- a/spigot/src/main/java/fun/ogtimes/skywars/spigot/database/DataSource.java +++ b/spigot/src/main/java/fun/ogtimes/skywars/spigot/database/DataSource.java @@ -5,6 +5,7 @@ import fun.ogtimes.skywars.spigot.kit.Kit; import fun.ogtimes.skywars.spigot.kit.KitManager; import fun.ogtimes.skywars.spigot.player.SkyPlayer; +import fun.ogtimes.skywars.spigot.config.ConfigManager; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -15,9 +16,9 @@ import java.util.Map.Entry; public abstract class DataSource { - public final String TABLE_DATA = SkyWars.getPlugin().getConfig().getString("data.mysql.tablename.data"); - public final String TABLE_ECONOMY = SkyWars.getPlugin().getConfig().getString("data.mysql.tablename.economy"); - public final String TABLE_SERVER = SkyWars.getPlugin().getConfig().getString("data.mysql.tablename.servers"); + public final String TABLE_DATA = ConfigManager.database.getString("tables.data", "SkyWars_Data"); + public final String TABLE_ECONOMY = ConfigManager.database.getString("tables.economy", "SkyWars_Economy"); + public final String TABLE_SERVER = ConfigManager.database.getString("tables.servers", "SkyWars_Servers"); protected DataSource() { } diff --git a/spigot/src/main/java/fun/ogtimes/skywars/spigot/database/DatabaseHandler.java b/spigot/src/main/java/fun/ogtimes/skywars/spigot/database/DatabaseHandler.java index 95ba533..e0feb6e 100644 --- a/spigot/src/main/java/fun/ogtimes/skywars/spigot/database/DatabaseHandler.java +++ b/spigot/src/main/java/fun/ogtimes/skywars/spigot/database/DatabaseHandler.java @@ -3,6 +3,7 @@ import fun.ogtimes.skywars.spigot.SkyWars; import fun.ogtimes.skywars.spigot.database.types.MySQL; import fun.ogtimes.skywars.spigot.database.types.SQLite; +import fun.ogtimes.skywars.spigot.config.ConfigManager; import java.sql.SQLException; @@ -10,16 +11,24 @@ public class DatabaseHandler { private static DataSource manager; public DatabaseHandler() throws SQLException, ClassNotFoundException { - String var1 = SkyWars.getPlugin().getConfig().getString("data.type").toLowerCase(); + String type = "sqlite"; + try { + if (ConfigManager.database != null && ConfigManager.database.isSet("type")) { + type = ConfigManager.database.getString("type", "SQLite").toLowerCase(); + } else if (ConfigManager.main != null && ConfigManager.main.isSet("data.type")) { + type = ConfigManager.main.getString("data.type", "SQLite").toLowerCase(); + } + } catch (Exception ignored) { + } byte var2 = -1; - switch(var1.hashCode()) { + switch(type.hashCode()) { case -894935028: - if (var1.equals("sqlite")) { + if (type.equals("sqlite")) { var2 = 1; } break; case 104382626: - if (var1.equals("mysql")) { + if (type.equals("mysql")) { var2 = 0; } } diff --git a/spigot/src/main/java/fun/ogtimes/skywars/spigot/database/types/MySQL.java b/spigot/src/main/java/fun/ogtimes/skywars/spigot/database/types/MySQL.java index a6ce333..a195cb5 100644 --- a/spigot/src/main/java/fun/ogtimes/skywars/spigot/database/types/MySQL.java +++ b/spigot/src/main/java/fun/ogtimes/skywars/spigot/database/types/MySQL.java @@ -24,11 +24,11 @@ import java.util.Map.Entry; public class MySQL extends DataSource { - private final int port = SkyWars.getPlugin().getConfig().getInt("data.mysql.port"); - private final String host = SkyWars.getPlugin().getConfig().getString("data.mysql.server"); - private final String database = SkyWars.getPlugin().getConfig().getString("data.mysql.db"); - private final String username = SkyWars.getPlugin().getConfig().getString("data.mysql.user"); - private final String password = SkyWars.getPlugin().getConfig().getString("data.mysql.password"); + private final int port = ConfigManager.database.getInt("mysql.port", 3306); + private final String host = ConfigManager.database.getString("mysql.host", "localhost"); + private final String database = ConfigManager.database.getString("mysql.database", "SkyWars"); + private final String username = ConfigManager.database.getString("mysql.user", "root"); + private final String password = ConfigManager.database.getString("mysql.password", ""); private HikariDataSource ds; @SneakyThrows @@ -65,7 +65,8 @@ public MySQL() { private synchronized void setConnectionArguments() { this.ds = new HikariDataSource(); this.ds.setPoolName("SkyWars MySQL"); - if (ConfigManager.main.getBoolean("debug-database")) { + boolean debugDb = ConfigManager.database.getBoolean("debug.debug-database", ConfigManager.main.getBoolean("debug-database", false)); + if (debugDb) { this.ds.setJdbcUrl("jdbc:log4jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database); this.ds.setDriverClassName("net.sf.log4jdbc.sql.jdbcapi.DriverSpy"); } else { @@ -82,10 +83,13 @@ private synchronized void setConnectionArguments() { this.ds.addDataSourceProperty("useSSL", "false"); this.ds.setUsername(this.username); this.ds.setPassword(this.password); - this.ds.setMaxLifetime(180000L); + long maxLifetime = ConfigManager.database.getLong("mysql.pool.maxLifetimeMs", 180000L); + int minimumIdle = ConfigManager.database.getInt("mysql.pool.minimumIdle", 1); + int maxPool = ConfigManager.database.getInt("mysql.pool.maxPoolSize", SkyWars.isProxyMode() ? 4 : 8); + this.ds.setMaxLifetime(maxLifetime); this.ds.setIdleTimeout(60000L); - this.ds.setMinimumIdle(1); - this.ds.setMaximumPoolSize(SkyWars.isProxyMode() ? 4 : 8); + this.ds.setMinimumIdle(minimumIdle); + this.ds.setMaximumPoolSize(maxPool); SkyWars.log("Connection arguments loaded, Hikari ConnectionPool ready!"); } @@ -360,45 +364,45 @@ public void modifyCoins(SkyPlayer skyPlayer, double modifier) { } public void loadServer() { - PreparedStatement var1 = null; - ResultSet var2 = null; + PreparedStatement statement = null; + ResultSet result = null; try { - Connection var3 = this.getConnection(); - Throwable var4 = null; + Connection connection = this.getConnection(); + Throwable throwable = null; try { - var1 = var3.prepareStatement(String.format("SELECT * FROM %s WHERE bungeeid=?", this.TABLE_SERVER)); - var1.setString(1, SkyServer.getProxyId()); - var2 = var1.executeQuery(); - if (!var2.next()) { - var1.close(); - var1 = var3.prepareStatement(String.format("INSERT INTO %s (bungeeid) VALUES(?)", this.TABLE_SERVER)); - var1.setString(1, SkyServer.getProxyId()); - var1.executeUpdate(); + statement = connection.prepareStatement(String.format("SELECT * FROM %s WHERE bungeeid=?", this.TABLE_SERVER)); + statement.setString(1, SkyServer.getProxyId()); + result = statement.executeQuery(); + if (!result.next()) { + statement.close(); + statement = connection.prepareStatement(String.format("INSERT INTO %s (bungeeid) VALUES(?)", this.TABLE_SERVER)); + statement.setString(1, SkyServer.getProxyId()); + statement.executeUpdate(); } - } catch (Throwable var22) { - var4 = var22; - throw var22; + } catch (Throwable e) { + throwable = e; + throw e; } finally { - if (var3 != null) { - if (var4 != null) { + if (connection != null) { + if (throwable != null) { try { - var3.close(); - } catch (Throwable var21) { - var4.addSuppressed(var21); + connection.close(); + } catch (Throwable ex) { + throwable.addSuppressed(ex); } } else { - var3.close(); + connection.close(); } } } - } catch (SQLException var24) { - var24.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); } finally { - this.close(var2); - this.close(var1); + this.close(result); + this.close(statement); } } @@ -448,34 +452,34 @@ public void getServers() { } public void setServerData(Arena arena) { - PreparedStatement var2 = null; + PreparedStatement statement = null; try { - Connection var3 = this.getConnection(); + Connection connection = this.getConnection(); Throwable var4 = null; try { - var2 = var3.prepareStatement(String.format("UPDATE %s SET players=?, max_players=?, map=?, loading=?, state=? WHERE bungeeid=?", this.TABLE_SERVER)); - var2.setInt(1, arena.getAlivePlayers()); - var2.setInt(2, arena.getMaxPlayers()); - var2.setString(3, arena.getDisplayName()); - var2.setInt(4, arena.isLoading() ? 1 : 0); - var2.setString(5, arena.getState().toString()); - var2.setString(6, SkyServer.getProxyId()); - var2.executeUpdate(); + statement = connection.prepareStatement(String.format("UPDATE %s SET players=?, max_players=?, map=?, loading=?, state=? WHERE bungeeid=?", this.TABLE_SERVER)); + statement.setInt(1, arena.getAlivePlayers()); + statement.setInt(2, arena.getMaxPlayers()); + statement.setString(3, arena.getDisplayName()); + statement.setInt(4, arena.isLoading() ? 1 : 0); + statement.setString(5, arena.getState().toString()); + statement.setString(6, SkyServer.getProxyId()); + statement.executeUpdate(); } catch (Throwable var22) { var4 = var22; throw var22; } finally { - if (var3 != null) { + if (connection != null) { if (var4 != null) { try { - var3.close(); + connection.close(); } catch (Throwable var21) { var4.addSuppressed(var21); } } else { - var3.close(); + connection.close(); } } @@ -483,7 +487,7 @@ public void setServerData(Arena arena) { } catch (SQLException var24) { var24.printStackTrace(); } finally { - this.close(var2); + this.close(statement); } } diff --git a/spigot/src/main/java/fun/ogtimes/skywars/spigot/instance/InstanceModeHandler.java b/spigot/src/main/java/fun/ogtimes/skywars/spigot/instance/InstanceModeHandler.java new file mode 100644 index 0000000..d6c066f --- /dev/null +++ b/spigot/src/main/java/fun/ogtimes/skywars/spigot/instance/InstanceModeHandler.java @@ -0,0 +1,102 @@ +package fun.ogtimes.skywars.spigot.instance; + +import com.avaje.ebean.OrderBy; +import fun.ogtimes.skywars.spigot.SkyWars; +import fun.ogtimes.skywars.spigot.config.ConfigManager; +import fun.ogtimes.skywars.common.SkyWarsCommon; +import fun.ogtimes.skywars.common.instance.InstanceProperties; +import fun.ogtimes.skywars.common.nats.packet.impl.InstanceStartPacket; +import fun.ogtimes.skywars.common.nats.packet.impl.InstanceStopPacket; +import fun.ogtimes.skywars.common.nats.packet.impl.KeepAlivePacket; +import io.nats.client.Options; +import lombok.Getter; +import org.bukkit.Bukkit; + +import java.io.*; +import java.time.Duration; + +@Getter +public class InstanceModeHandler { + + public static InstanceModeHandler INSTANCE; + private final SkyWars plugin; + private SkyWarsCommon common; + private InstanceProperties properties; + + public InstanceModeHandler(SkyWars plugin) { + this.plugin = plugin; + INSTANCE = this; + + String address = Bukkit.getServer().getIp().isEmpty() ? "0.0.0.0" : Bukkit.getServer().getIp(); + int port = Bukkit.getServer().getPort(); + + String id; + String devFlag = System.getProperty("skywars.dev"); + if (devFlag != null && devFlag.equalsIgnoreCase("true")) { + id = "Staging"; + } else { + String sysId = System.getProperty("instance.id"); + if (sysId != null && !sysId.isEmpty()) { + id = sysId.replace("skywars-", ""); + } else { + throw new IllegalStateException("Instance ID not set! Please set the 'instance.id' system property."); + } + } + + this.properties = new InstanceProperties(id, address, port); + } + + public void start() { + if (!SkyWars.isMultiArenaMode()) return; + + String natsUrl = "nats://127.0.0.1:4222"; + try { + if (ConfigManager.database != null && ConfigManager.database.isSet("nats.url")) { + natsUrl = ConfigManager.database.getString("nats.url", natsUrl); + } else if (ConfigManager.main != null && ConfigManager.main.isSet("nats.url")) { + natsUrl = ConfigManager.main.getString("nats.url", natsUrl); + } + } catch (Exception ignored) { + } + + try { + Options opts = Options.builder().server(natsUrl).connectionTimeout(Duration.ofSeconds(5)).build(); + this.common = new SkyWarsCommon(opts); + } catch (Exception e) { + SkyWars.logError("Failed to initialize SkyWarsCommon NATS connection: " + e.getMessage()); + return; + } + + try { + this.common.nats().sendPacket(new InstanceStartPacket(this.properties)); + try { + this.common.nats().sendPacket(new KeepAlivePacket(this.properties)); + SkyWars.log("Sent initial KeepAlive for instance " + this.properties.getId()); + } catch (Exception ex) { + SkyWars.logError("Failed to send initial KeepAlive: " + ex.getMessage()); + } + + this.common.keepAlive().start(this.properties); + SkyWars.log("Instance announced to NATS with id " + this.properties.getId() + " (" + this.properties.getAddress() + ":" + this.properties.getPort() + ")"); + } catch (Exception e) { + SkyWars.logError("Failed to announce instance start: " + e.getMessage()); + } + } + + public void stop() { + if (this.common == null || this.properties == null) return; + + try { + this.common.nats().sendPacket(new InstanceStopPacket(this.properties)); + } catch (Exception e) { + SkyWars.logError("Failed to send InstanceStopPacket: " + e.getMessage()); + } + + try { + this.common.destroy(); + } catch (Exception e) { + SkyWars.logError("Failed to destroy SkyWarsCommon: " + e.getMessage()); + } + } + +} diff --git a/spigot/src/main/java/fun/ogtimes/skywars/spigot/listener/skywars/ArenaListener.java b/spigot/src/main/java/fun/ogtimes/skywars/spigot/listener/skywars/ArenaListener.java index 77c7e92..18b7803 100644 --- a/spigot/src/main/java/fun/ogtimes/skywars/spigot/listener/skywars/ArenaListener.java +++ b/spigot/src/main/java/fun/ogtimes/skywars/spigot/listener/skywars/ArenaListener.java @@ -258,77 +258,77 @@ public void onSkyPlayerArenaLeaveEvent(ArenaLeaveEvent var1) { } @EventHandler - public void onArenaTick(ArenaTickEvent var1) { - Arena var2 = var1.getArena(); - SkyServer.setValues(var2); - if (var2.getState() == ArenaState.INGAME) { - if (checkWinner(var2)) { + public void onArenaTick(ArenaTickEvent event) { + Arena state = event.getArena(); + SkyServer.setValues(state); + if (state.getState() == ArenaState.INGAME) { + if (checkWinner(state)) { return; } - if (!var2.isFallDamage()) { - if (var2.getStartCountdown() == -5) { - var2.setFallDamage(true); + if (!state.isFallDamage()) { + if (state.getStartCountdown() == -5) { + state.setFallDamage(true); } - var2.setStartCountdown(var2.getStartCountdown() - 1); + state.setStartCountdown(state.getStartCountdown() - 1); } - this.countEvents(var2); - this.countMaxTime(var2); + this.countEvents(state); + this.countMaxTime(state); } - if (var2.getState() == ArenaState.WAITING || var2.getState() == ArenaState.STARTING) { - int var3 = var2.getStartCountdown(); - if (this.checkEmpty(var2)) { + if (state.getState() == ArenaState.WAITING || state.getState() == ArenaState.STARTING) { + int countdown = state.getStartCountdown(); + if (this.checkEmpty(state)) { return; } - if (var3 == 0) { - if (var2.getPlayers().size() < var2.getMinPlayers() && !var2.isForceStart()) { - var2.setStartCountdown(var2.getStartFullCountdown()); - var2.broadcast(SkyWars.getMessage(Messages.GAME_START_NOREQUIREDPLAYERS)); + if (countdown == 0) { + if (state.getPlayers().size() < state.getMinPlayers() && !state.isForceStart()) { + state.setStartCountdown(state.getStartFullCountdown()); + state.broadcast(SkyWars.getMessage(Messages.GAME_START_NOREQUIREDPLAYERS)); return; } - if (var2.getState() == ArenaState.STARTING) { - var2.start(); + if (state.getState() == ArenaState.STARTING) { + state.start(); - for (SkyPlayer var5 : var2.getPlayers()) { - var5.getPlayer().setLevel(0); + for (SkyPlayer skyPlayer : state.getPlayers()) { + skyPlayer.getPlayer().setLevel(0); } return; } } - if (var2.getState() == ArenaState.WAITING) { - if (var2.getPlayers().size() < var2.getMinPlayers() && !var2.isForceStart()) { + if (state.getState() == ArenaState.WAITING) { + if (state.getPlayers().size() < state.getMinPlayers() && !state.isForceStart()) { return; } - if (var2.isForceStart()) { - var2.setStartCountdown(var2.getStartFullCountdown()); - var3 = var2.getStartCountdown(); - } else if (var2.getPlayers().size() >= var2.getMaxPlayers()) { - if (var3 > var2.getStartFullCountdown()) { - var2.setStartCountdown(var2.getStartFullCountdown()); - var3 = var2.getStartCountdown(); + if (state.isForceStart()) { + state.setStartCountdown(state.getStartFullCountdown()); + countdown = state.getStartCountdown(); + } else if (state.getPlayers().size() >= state.getMaxPlayers()) { + if (countdown > state.getStartFullCountdown()) { + state.setStartCountdown(state.getStartFullCountdown()); + countdown = state.getStartCountdown(); } - var2.broadcast(String.format(SkyWars.getMessage(Messages.GAME_START_NOWFULL), var3)); + state.broadcast(String.format(SkyWars.getMessage(Messages.GAME_START_NOWFULL), countdown)); } - if (var3 <= var2.getStartFullCountdown()) { - var2.setState(ArenaState.STARTING); + if (countdown <= state.getStartFullCountdown()) { + state.setState(ArenaState.STARTING); } } - this.countStart(var2); + this.countStart(state); } - if (var2.getState() == ArenaState.ENDING) { - this.countEnd(var2); + if (state.getState() == ArenaState.ENDING) { + this.countEnd(state); } } diff --git a/spigot/src/main/java/fun/ogtimes/skywars/spigot/server/Server.java b/spigot/src/main/java/fun/ogtimes/skywars/spigot/server/Server.java index 08eba0f..068a782 100644 --- a/spigot/src/main/java/fun/ogtimes/skywars/spigot/server/Server.java +++ b/spigot/src/main/java/fun/ogtimes/skywars/spigot/server/Server.java @@ -11,96 +11,115 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.logging.Level; + import org.bukkit.Bukkit; public class Server extends Game { - public Server(String var1) { - super(var1, "", 0, true, ArenaState.WAITING); - this.getData(false); - } - - public void getData(boolean var1) { - PreparedStatement var2 = null; - ResultSet var3 = null; - - try { - Connection var4 = DatabaseHandler.getDS().getConnection(); - Throwable var5 = null; - - try { - var2 = var4.prepareStatement(String.format("SELECT * FROM %s WHERE bungeeid=?", DatabaseHandler.getDS().TABLE_SERVER)); - var2.setString(1, this.name); - var2.execute(); - var3 = var2.getResultSet(); - if (var3.next()) { - ArrayList var6 = new ArrayList(); - String var7 = var3.getString("bungeeid"); - int var8 = var3.getInt("players"); - int var9 = var3.getInt("max_players"); - int var10 = var3.getInt("loading"); - int var11 = this.loading ? 1 : 0; - String var12 = var3.getString("state"); - String var13 = var3.getString("map"); - if (this.alivePlayers != var8 || this.maxPlayers != var9) { - var6.add(SkySignUpdateCause.PLAYERS); - } - - if (var11 != var10) { - var6.add(SkySignUpdateCause.LOADING); - } - - if (!this.state.toString().equals(var12)) { - var6.add(SkySignUpdateCause.STATE); - } - - if (!this.displayName.equals(var13)) { - var6.add(SkySignUpdateCause.MAP); - } - - SkySignUpdateCause var14 = null; - if (var6.size() == 1) { - var14 = (SkySignUpdateCause)var6.getFirst(); - } - - if (var6.size() >= 2) { - var14 = SkySignUpdateCause.ALL; - } - - this.alivePlayers = var8; - this.maxPlayers = var9; - this.loading = var10 == 1; - this.state = ArenaState.valueOf(var12); - this.displayName = var13; - if (!var6.isEmpty() && var1) { - SkySignUpdateCause finalVar1 = var14; - Bukkit.getScheduler().runTask(SkyWars.getPlugin(), () -> Bukkit.getServer().getPluginManager().callEvent(new SkySignUpdateEvent(var7, finalVar1))); - } - - var2.close(); - } - } catch (Throwable var32) { - var5 = var32; - throw var32; - } finally { - if (var4 != null) { - if (var5 != null) { - try { - var4.close(); - } catch (Throwable var31) { - var5.addSuppressed(var31); - } - } else { - var4.close(); - } - } + public Server(String name) { + super(name, "", 0, true, ArenaState.WAITING); + this.getData(false); + } + + public void getData(boolean var1) { + PreparedStatement statement = null; + ResultSet result = null; + + try { + Connection connection = DatabaseHandler.getDS().getConnection(); + Throwable ex = null; + + try { + statement = connection.prepareStatement(String.format("SELECT * FROM %s WHERE bungeeid= ?", DatabaseHandler.getDS().TABLE_SERVER)); + statement.setString(1, this.name); + statement.execute(); + result = statement.getResultSet(); + if (result.next()) { + List var6 = new ArrayList<>(); + String bungeeId = result.getString("bungeeid"); + int alivePlayers = result.getInt("players"); + int maxPlayers = result.getInt("max_players"); + int loading = result.getInt("loading"); + int var11 = this.loading ? 1 : 0; + String state = result.getString("state"); + String displayName = result.getString("map"); + + if (this.alivePlayers != alivePlayers || this.maxPlayers != maxPlayers) { + var6.add(SkySignUpdateCause.PLAYERS); + } + + if (var11 != loading) { + var6.add(SkySignUpdateCause.LOADING); + } - } - } catch (SQLException var34) { - var34.printStackTrace(); - } finally { - DatabaseHandler.getDS().close(var3); - DatabaseHandler.getDS().close(var2); - } + if (state != null) { + if (!this.state.name().equalsIgnoreCase(state.trim())) { + var6.add(SkySignUpdateCause.STATE); + } + } + + if (displayName != null) { + if (!Objects.equals(this.displayName, displayName)) { + var6.add(SkySignUpdateCause.MAP); + } + } else { + if (this.displayName != null && !this.displayName.isEmpty()) { + var6.add(SkySignUpdateCause.MAP); + } + } + + SkySignUpdateCause signUpdateCause = null; + if (var6.size() == 1) { + signUpdateCause = var6.get(0); + } + + if (var6.size() >= 2) { + signUpdateCause = SkySignUpdateCause.ALL; + } + + this.alivePlayers = alivePlayers; + this.maxPlayers = maxPlayers; + this.loading = loading == 1; + if (state != null) { + try { + this.state = ArenaState.valueOf(state.trim().toUpperCase()); + } catch (IllegalArgumentException iae) { + SkyWars.getPlugin().getLogger().warning("Invalid ArenaState in DB for server " + this.name + ": " + state); + } + } + this.displayName = (displayName == null) ? this.displayName : displayName; + if (!var6.isEmpty() && var1) { + SkySignUpdateCause finalVar1 = signUpdateCause; + Bukkit.getScheduler().runTask(SkyWars.getPlugin(), () -> Bukkit.getServer().getPluginManager().callEvent(new SkySignUpdateEvent(bungeeId, finalVar1))); + } + + statement.close(); + } + } catch (Throwable throwable) { + ex = throwable; + throw throwable; + } finally { + if (connection != null) { + if (ex != null) { + try { + connection.close(); + } catch (Throwable var31) { + ex.addSuppressed(var31); + } + } else { + connection.close(); + } + } + + } + } catch (SQLException ex) { + SkyWars.getPlugin().getLogger().log(Level.SEVERE, "SQL error while getting server data for " + this.name, ex); + } finally { + DatabaseHandler.getDS().close(result); + DatabaseHandler.getDS().close(statement); + } - } + } } diff --git a/spigot/src/main/java/fun/ogtimes/skywars/spigot/server/ServerManager.java b/spigot/src/main/java/fun/ogtimes/skywars/spigot/server/ServerManager.java index f1d3b84..9c6ed0e 100644 --- a/spigot/src/main/java/fun/ogtimes/skywars/spigot/server/ServerManager.java +++ b/spigot/src/main/java/fun/ogtimes/skywars/spigot/server/ServerManager.java @@ -5,11 +5,12 @@ import com.google.common.collect.Sets; import java.util.Collections; import java.util.HashMap; +import java.util.Map; import java.util.Set; import org.bukkit.Bukkit; public class ServerManager { - public static final HashMap servers = new HashMap<>(); + public static final Map servers = new HashMap<>(); public static void initServers() { DatabaseHandler.getDS().getServers(); @@ -17,8 +18,8 @@ public static void initServers() { Bukkit.getScheduler().runTaskTimerAsynchronously(SkyWars.getPlugin(), () -> { if (!SkyWars.disabling) { - for (Server var1 : getServers()) { - var1.getData(true); + for (Server server : getServers()) { + server.getData(true); } } @@ -31,7 +32,7 @@ public static Set getServers() { return Collections.unmodifiableSet(Sets.newHashSet(servers.values())); } - public static Server getServer(String var0) { - return servers.get(var0); + public static Server getServer(String server) { + return servers.get(server); } } diff --git a/spigot/src/main/java/fun/ogtimes/skywars/spigot/server/SkyServer.java b/spigot/src/main/java/fun/ogtimes/skywars/spigot/server/SkyServer.java index 9e6b0fb..c6cbf0d 100644 --- a/spigot/src/main/java/fun/ogtimes/skywars/spigot/server/SkyServer.java +++ b/spigot/src/main/java/fun/ogtimes/skywars/spigot/server/SkyServer.java @@ -5,30 +5,31 @@ import fun.ogtimes.skywars.spigot.database.DatabaseHandler; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; +import fun.ogtimes.skywars.spigot.instance.InstanceModeHandler; import org.bukkit.Bukkit; public class SkyServer { - public static String getProxyId() { - return SkyWars.getPlugin().getConfig().getString("server.bungeeid"); - } + public static String getProxyId() { + return "SkyWars-Game-" + InstanceModeHandler.INSTANCE.getProperties().getId(); + } - public static void load() { - Bukkit.getScheduler().runTaskAsynchronously(SkyWars.getPlugin(), () -> DatabaseHandler.getDS().loadServer()); - } + public static void load() { + Bukkit.getScheduler().runTaskAsynchronously(SkyWars.getPlugin(), () -> DatabaseHandler.getDS().loadServer()); + } - public static void setValues(Arena var0) { - if (SkyWars.isServerEnabled()) { - Bukkit.getScheduler().runTaskAsynchronously(SkyWars.getPlugin(), () -> DatabaseHandler.getDS().setServerData(var0)); - sendUpdateRequest(); - } + public static void setValues(Arena arena) { + if (SkyWars.isServerEnabled()) { + Bukkit.getScheduler().runTaskAsynchronously(SkyWars.getPlugin(), () -> DatabaseHandler.getDS().setServerData(arena)); + sendUpdateRequest(); + } - } + } - public static void sendUpdateRequest() { - Bukkit.getScheduler().runTaskLater(SkyWars.getPlugin(), () -> { - ByteArrayDataOutput var0 = ByteStreams.newDataOutput(); - var0.writeUTF(getProxyId()); - SkyWars.getPlugin().getServer().sendPluginMessage(SkyWars.getPlugin(), "skywars:sign-send", var0.toByteArray()); - }, 10L); - } + public static void sendUpdateRequest() { + Bukkit.getScheduler().runTaskLater(SkyWars.getPlugin(), () -> { + ByteArrayDataOutput var0 = ByteStreams.newDataOutput(); + var0.writeUTF(getProxyId()); + SkyWars.getPlugin().getServer().sendPluginMessage(SkyWars.getPlugin(), "skywars:sign-send", var0.toByteArray()); + }, 10L); + } } diff --git a/spigot/src/main/java/fun/ogtimes/skywars/spigot/utils/CustomConfig.java b/spigot/src/main/java/fun/ogtimes/skywars/spigot/utils/CustomConfig.java index bc4536b..3a44954 100644 --- a/spigot/src/main/java/fun/ogtimes/skywars/spigot/utils/CustomConfig.java +++ b/spigot/src/main/java/fun/ogtimes/skywars/spigot/utils/CustomConfig.java @@ -1,66 +1,66 @@ package fun.ogtimes.skywars.spigot.utils; -import fun.ogtimes.skywars.spigot.SkyWars; import java.io.File; import java.io.IOException; import java.util.logging.Level; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.java.JavaPlugin; public class CustomConfig { - SkyWars plugin; - private String name; - private File file; - private FileConfiguration fileConfig; + JavaPlugin plugin; + private String name; + private File file; + private FileConfiguration fileConfig; - public CustomConfig(String var1) { - this.name = var1; - } + public CustomConfig(String name) { + this.name = name; + } - public CustomConfig(SkyWars var1) { - this.plugin = var1; - } + public CustomConfig(JavaPlugin plugin) { + this.plugin = plugin; + } - public FileConfiguration getCustomConfig(CustomConfig var1) { - if (var1.fileConfig == null) { - this.reloadCustomConfig(var1); - } + public FileConfiguration getCustomConfig(CustomConfig config) { + if (config.fileConfig == null) { + this.reloadCustomConfig(config); + } - return var1.fileConfig; - } + return config.fileConfig; + } - public void reloadCustomConfig(CustomConfig var1) { - if (var1.fileConfig == null) { - var1.file = new File(this.plugin.getDataFolder(), var1.name + ".properties"); - } + public void reloadCustomConfig(CustomConfig config) { + if (config.fileConfig == null) { + config.file = new File(this.plugin.getDataFolder(), config.name + ".properties"); + } - var1.fileConfig = YamlConfiguration.loadConfiguration(var1.file); - if (var1.fileConfig != null) { - YamlConfiguration var2 = YamlConfiguration.loadConfiguration(var1.file); - var1.fileConfig.setDefaults(var2); - } + config.fileConfig = YamlConfiguration.loadConfiguration(config.file); + if (config.fileConfig != null) { + YamlConfiguration var2 = YamlConfiguration.loadConfiguration(config.file); + config.fileConfig.setDefaults(var2); + } - } + } - public void saveCustomConfig(CustomConfig var1) { - if (var1.fileConfig != null && var1.file != null) { - try { - this.getCustomConfig(var1).save(var1.file); - } catch (IOException var3) { - this.plugin.getLogger().log(Level.SEVERE, "Could not save config to " + var1.file, var3); - } + public void saveCustomConfig(CustomConfig config) { + if (config.fileConfig != null && config.file != null) { + try { + this.getCustomConfig(config).save(config.file); + } catch (IOException ex) { + this.plugin.getLogger().log(Level.SEVERE, "Could not save config to " + config.file, ex); + } - } - } + } + } - public void saveDefaultConfig(CustomConfig var1) { - if (var1.file == null) { - var1.file = new File(this.plugin.getDataFolder(), var1.name + ".properties"); - } + public void saveDefaultConfig(CustomConfig config) { + if (config.file == null) { + config.file = new File(this.plugin.getDataFolder(), config.name + ".properties"); + } - if (!var1.file.exists()) { - this.plugin.saveResource(var1.name + ".properties", false); - } + if (!config.file.exists()) { + this.plugin.saveResource(config.name + ".properties", false); + } - } + } } diff --git a/spigot/src/main/resources/database.yml b/spigot/src/main/resources/database.yml new file mode 100644 index 0000000..351fbf8 --- /dev/null +++ b/spigot/src/main/resources/database.yml @@ -0,0 +1,36 @@ +# SkyWars database configuration +# Edit these values to configure your database connection. +# Do NOT commit real credentials to version control. + +# type: "SQLite" or "MySQL" +type: SQLite + +sqlite: + # relative to plugin data folder + path: plugins/SkyWars/Database.db + +mysql: + host: localhost + port: 3306 + database: SkyWars + user: root + password: CHANGEME + useLog4Jdbc: false + pool: + maxPoolSize: 8 + minimumIdle: 1 + maxLifetimeMs: 180000 + +# NATS configuration (messaging between proxy and instances) +# Example: nats://127.0.0.1:4222 +nats: + url: nats://127.0.0.1:4222 + +tables: + data: SkyWars_Data + economy: SkyWars_Economy + servers: SkyWars_Servers + +debug: + debug-database: false + diff --git a/velocity/build.gradle.kts b/velocity/build.gradle.kts index 6e7f34c..25500ff 100644 --- a/velocity/build.gradle.kts +++ b/velocity/build.gradle.kts @@ -6,7 +6,10 @@ group = "fun.ogtimes.skywars" version = "1.0.0" dependencies { + implementation(project(":common")) + implementation("org.yaml:snakeyaml:2.5") + compileOnly("com.velocitypowered:velocity-api:3.3.0-SNAPSHOT") + annotationProcessor("com.velocitypowered:velocity-api:3.3.0-SNAPSHOT") - implementation("org.yaml:snakeyaml:2.5") } \ No newline at end of file diff --git a/velocity/src/main/java/fun/ogtimes/skywars/velocity/SkyWarsVelocity.java b/velocity/src/main/java/fun/ogtimes/skywars/velocity/SkyWarsVelocity.java index 1dd0862..a6eca2a 100644 --- a/velocity/src/main/java/fun/ogtimes/skywars/velocity/SkyWarsVelocity.java +++ b/velocity/src/main/java/fun/ogtimes/skywars/velocity/SkyWarsVelocity.java @@ -1,23 +1,37 @@ package fun.ogtimes.skywars.velocity; -import com.google.inject.Inject; +import javax.inject.Inject; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.connection.PluginMessageEvent; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; +import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; import com.velocitypowered.api.plugin.Plugin; import com.velocitypowered.api.plugin.annotation.DataDirectory; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier; import com.velocitypowered.api.proxy.server.RegisteredServer; +import fun.ogtimes.skywars.common.keepalive.KeepAliveListener; import org.slf4j.Logger; import org.yaml.snakeyaml.Yaml; +import fun.ogtimes.skywars.common.SkyWarsCommon; +import fun.ogtimes.skywars.common.instance.InstanceProperties; +import fun.ogtimes.skywars.common.nats.annotation.IncomingPacketHandler; +import fun.ogtimes.skywars.common.nats.packet.PacketListener; +import fun.ogtimes.skywars.common.nats.packet.impl.InstanceStartPacket; +import fun.ogtimes.skywars.common.nats.packet.impl.InstanceStopPacket; + import java.io.*; +import java.lang.reflect.Method; +import java.net.InetSocketAddress; import java.nio.file.Files; import java.nio.file.Path; +import java.time.Duration; import java.util.*; +import io.nats.client.Options; + /** * This code was made by jsexp, in case of any unauthorized * use, at least please leave credits. @@ -32,9 +46,9 @@ authors = {"OGTimes Development Team"} ) public class SkyWarsVelocity { - private final ProxyServer proxy; - private final Logger logger; - private final Path dataDirectory; + private final ProxyServer proxy; + private final Logger logger; + private final Path dataDirectory; private static final MinecraftChannelIdentifier SIGN_SEND_CHANNEL = MinecraftChannelIdentifier.from("skywars:sign-send"); @@ -44,6 +58,12 @@ public class SkyWarsVelocity { private Map config; private List skywarsLobbies; + private SkyWarsCommon common; + private final Set addedServers = new HashSet<>(); + + private PacketListener instancePacketListener; + private KeepAliveListener keepAliveListener; + @Inject public SkyWarsVelocity(ProxyServer proxy, Logger logger, @DataDirectory Path dataDirectory) { this.proxy = proxy; @@ -56,10 +76,121 @@ public void onProxyInitialization(ProxyInitializeEvent event) { proxy.getChannelRegistrar().register(SIGN_SEND_CHANNEL, SIGN_UPDATE_CHANNEL); loadConfig(); + initCommon(); logger.info("SkyWars Velocity plugin has been enabled!"); } + private void initCommon() { + String natsUrl = "nats://127.0.0.1:4222"; + if (config != null && config.containsKey("nats_url")) { + Object o = config.get("nats_url"); + if (o instanceof String) natsUrl = (String) o; + } + + try { + Options opts = Options.builder().server(natsUrl).connectionTimeout(Duration.ofSeconds(5)).build(); + common = new SkyWarsCommon(opts); + + instancePacketListener = new PacketListener() { + @IncomingPacketHandler + public void onInstanceStart(InstanceStartPacket packet) { + if (packet == null || packet.properties() == null) return; + InstanceProperties props = packet.properties(); + String id = props.getId(); + String serverName = "SkyWars-Game-" + id; + + try { + InetSocketAddress addr = new InetSocketAddress(props.getAddress(), props.getPort()); + com.velocitypowered.api.proxy.server.ServerInfo info = new com.velocitypowered.api.proxy.server.ServerInfo(serverName, addr); + RegisteredServer reg = proxy.registerServer(info); + addedServers.add(serverName); + logger.info("Registered instance server '{}' -> {}:{}", serverName, props.getAddress(), props.getPort()); + + } catch (Exception e) { + logger.error("Failed to register instance server {}", serverName, e); + } + } + + @IncomingPacketHandler + public void onInstanceStop(InstanceStopPacket packet) { + if (packet == null || packet.properties() == null) return; + InstanceProperties props = packet.properties(); + String id = props.getId(); + String serverName = "SkyWars-Game-" + id; + + try { + Optional serverOpt = proxy.getServer(serverName); + if (serverOpt.isPresent()) { + RegisteredServer server = serverOpt.get(); + boolean ok = tryUnregister(server, serverName); + if (!ok) { + logger.warn("Could not fully unregister server '{}', leaving it registered", serverName); + } else { + addedServers.remove(serverName); + } + } + } catch (Exception e) { + logger.error("Failed to unregister instance server {}", serverName, e); + } + } + }; + common.nats().registerListener(instancePacketListener); + + keepAliveListener = new fun.ogtimes.skywars.common.keepalive.KeepAliveListener() { + @Override + public void onInstanceAlive(InstanceProperties properties) { + String id = properties.getId(); + String serverName = "SkyWars-Game-" + id; + try { + Optional existing = proxy.getServer(serverName); + if (existing.isPresent()) return; + addedServers.add(serverName); + logger.info("Re-registered instance server '{}' from keepalive -> {}:{}", serverName, properties.getAddress(), properties.getPort()); + } catch (Exception e) { + logger.error("Failed to re-register instance server {} on keepalive", serverName, e); + } + } + + @Override + public void onInstanceOffline(InstanceProperties properties) { + String id = properties.getId(); + String serverName = "SkyWars-Game-" + id; + try { + Optional serverOpt = proxy.getServer(serverName); + if (serverOpt.isPresent()) { + RegisteredServer server = serverOpt.get(); + boolean ok = tryUnregister(server, serverName); + if (!ok) { + logger.warn("Could not fully unregister server '{}' after keepalive timeout, leaving it registered", serverName); + } else { + addedServers.remove(serverName); + logger.info("Unregistered instance server '{}' due to keepalive timeout", serverName); + } + } + } catch (Exception e) { + logger.error("Failed to handle offline instance server {} on keepalive timeout", serverName, e); + } + } + }; + common.keepAlive().registerListener(keepAliveListener); + + try { + common.nats().subscribe(); + } catch (Exception e) { + logger.error("Failed to subscribe to NATS channels", e); + } + + try { + common.keepAlive().startListening(); + } catch (Exception ignored) {} + + logger.info("Connected to NATS at {} and registered instance handlers", natsUrl); + } catch (Exception e) { + logger.error("Failed to init common/NATS connection: {}", e.getMessage(), e); + } + } + @Subscribe public void onPluginMessage(PluginMessageEvent event) { if (!(event.getSource() instanceof ServerConnection)) { @@ -150,6 +281,7 @@ private void createDefaultConfig(Path configPath) throws IOException { defaultServers.add("SkyWarsLobby1"); defaultServers.add("SkyWarsLobby2"); defaultConfig.put("skywarslobbies_servers", defaultServers); + defaultConfig.put("nats_url", "nats://127.0.0.1:4222"); Yaml yaml = new Yaml(); try (Writer writer = Files.newBufferedWriter(configPath)) { @@ -165,4 +297,73 @@ private void saveConfig(Path configPath) throws IOException { yaml.dump(config, writer); } } -} \ No newline at end of file + + @Subscribe + public void onProxyShutdown(ProxyShutdownEvent event) { + try { + if (common != null) { + try { + if (keepAliveListener != null) { + common.keepAlive().unregisterListener(keepAliveListener); + common.keepAlive().stopListening(); + } + } catch (Exception ignored) {} + try { + if (instancePacketListener != null) common.nats().unregisterListener(instancePacketListener); + } catch (Exception ignored) {} + try { + common.destroy(); + } catch (Exception ignored) {} + } + } catch (Exception ex) { + logger.error("Error while shutting down NATS handlers", ex); + } + } + + private boolean tryUnregister(RegisteredServer server, String serverName) { + try { + Method m = proxy.getClass().getMethod("unregisterServer", com.velocitypowered.api.proxy.server.ServerInfo.class); + m.invoke(proxy, server.getServerInfo()); + logger.info("Unregistered instance server '{}' via unregister(ServerInfo)", serverName); + return true; + } catch (NoSuchMethodException ignored) { + } catch (Exception e) { + logger.warn("unregister(ServerInfo) failed for '{}': {}", serverName, e.getMessage()); + } + + try { + Method m = proxy.getClass().getMethod("unregisterServer", RegisteredServer.class); + m.invoke(proxy, server); + logger.info("Unregistered instance server '{}' via unregister(RegisteredServer)", serverName); + return true; + } catch (NoSuchMethodException ignored) { + } catch (Exception e) { + logger.warn("unregister(RegisteredServer) failed for '{}': {}", serverName, e.getMessage()); + } + + try { + Method m = proxy.getClass().getMethod("unregisterServer", String.class); + m.invoke(proxy, server.getServerInfo().getName()); + logger.info("Unregistered instance server '{}' via unregister(String)", serverName); + return true; + } catch (NoSuchMethodException ignored) { + } catch (Exception e) { + logger.warn("unregister(String) failed for '{}': {}", serverName, e.getMessage()); + } + + try { + Collection all = proxy.getAllServers(); + boolean removed = all.remove(server); + if (removed) { + logger.info("Removed instance server '{}' from server list (collection remove)", serverName); + return true; + } + } catch (UnsupportedOperationException uoe) { + logger.warn("Server collection is immutable; cannot remove '{}': {}", serverName, uoe.getMessage()); + } catch (Exception e) { + logger.warn("Failed to remove server '{}' from server list: {}", serverName, e.getMessage()); + } + + return false; + } +}