diff --git a/legacy-api/build.gradle.kts b/api/build.gradle.kts
similarity index 79%
rename from legacy-api/build.gradle.kts
rename to api/build.gradle.kts
index 09fb2163..f0b264a2 100644
--- a/legacy-api/build.gradle.kts
+++ b/api/build.gradle.kts
@@ -1,5 +1,4 @@
dependencies {
- api("org.geysermc", "common", Versions.geyserVersion)
api("org.geysermc.cumulus", "cumulus", Versions.cumulusVersion)
api("org.geysermc.event", "events", Versions.eventsVersion)
diff --git a/legacy-api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java b/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java
similarity index 100%
rename from legacy-api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java
rename to api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java
diff --git a/legacy-api/src/main/java/org/geysermc/floodgate/api/InstanceHolder.java b/api/src/main/java/org/geysermc/floodgate/api/InstanceHolder.java
similarity index 100%
rename from legacy-api/src/main/java/org/geysermc/floodgate/api/InstanceHolder.java
rename to api/src/main/java/org/geysermc/floodgate/api/InstanceHolder.java
diff --git a/legacy-api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeData.java b/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeData.java
similarity index 100%
rename from legacy-api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeData.java
rename to api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeData.java
diff --git a/legacy-api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandler.java b/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandler.java
similarity index 100%
rename from legacy-api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandler.java
rename to api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandler.java
diff --git a/legacy-api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandlers.java b/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandlers.java
similarity index 100%
rename from legacy-api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandlers.java
rename to api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandlers.java
diff --git a/legacy-api/src/main/java/org/geysermc/floodgate/api/inject/InjectorAddon.java b/api/src/main/java/org/geysermc/floodgate/api/inject/InjectorAddon.java
similarity index 100%
rename from legacy-api/src/main/java/org/geysermc/floodgate/api/inject/InjectorAddon.java
rename to api/src/main/java/org/geysermc/floodgate/api/inject/InjectorAddon.java
diff --git a/legacy-api/src/main/java/org/geysermc/floodgate/api/inject/PlatformInjector.java b/api/src/main/java/org/geysermc/floodgate/api/inject/PlatformInjector.java
similarity index 100%
rename from legacy-api/src/main/java/org/geysermc/floodgate/api/inject/PlatformInjector.java
rename to api/src/main/java/org/geysermc/floodgate/api/inject/PlatformInjector.java
diff --git a/legacy-api/src/main/java/org/geysermc/floodgate/api/link/LinkRequest.java b/api/src/main/java/org/geysermc/floodgate/api/link/LinkRequest.java
similarity index 100%
rename from legacy-api/src/main/java/org/geysermc/floodgate/api/link/LinkRequest.java
rename to api/src/main/java/org/geysermc/floodgate/api/link/LinkRequest.java
diff --git a/legacy-api/src/main/java/org/geysermc/floodgate/api/link/LinkRequestResult.java b/api/src/main/java/org/geysermc/floodgate/api/link/LinkRequestResult.java
similarity index 100%
rename from legacy-api/src/main/java/org/geysermc/floodgate/api/link/LinkRequestResult.java
rename to api/src/main/java/org/geysermc/floodgate/api/link/LinkRequestResult.java
diff --git a/legacy-api/src/main/java/org/geysermc/floodgate/api/link/PlayerLink.java b/api/src/main/java/org/geysermc/floodgate/api/link/PlayerLink.java
similarity index 100%
rename from legacy-api/src/main/java/org/geysermc/floodgate/api/link/PlayerLink.java
rename to api/src/main/java/org/geysermc/floodgate/api/link/PlayerLink.java
diff --git a/legacy-api/src/main/java/org/geysermc/floodgate/api/logger/FloodgateLogger.java b/api/src/main/java/org/geysermc/floodgate/api/logger/FloodgateLogger.java
similarity index 100%
rename from legacy-api/src/main/java/org/geysermc/floodgate/api/logger/FloodgateLogger.java
rename to api/src/main/java/org/geysermc/floodgate/api/logger/FloodgateLogger.java
diff --git a/legacy-api/src/main/java/org/geysermc/floodgate/api/packet/PacketHandler.java b/api/src/main/java/org/geysermc/floodgate/api/packet/PacketHandler.java
similarity index 100%
rename from legacy-api/src/main/java/org/geysermc/floodgate/api/packet/PacketHandler.java
rename to api/src/main/java/org/geysermc/floodgate/api/packet/PacketHandler.java
diff --git a/legacy-api/src/main/java/org/geysermc/floodgate/api/packet/PacketHandlers.java b/api/src/main/java/org/geysermc/floodgate/api/packet/PacketHandlers.java
similarity index 100%
rename from legacy-api/src/main/java/org/geysermc/floodgate/api/packet/PacketHandlers.java
rename to api/src/main/java/org/geysermc/floodgate/api/packet/PacketHandlers.java
diff --git a/legacy-api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java b/api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java
similarity index 100%
rename from legacy-api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java
rename to api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java
diff --git a/legacy-api/src/main/java/org/geysermc/floodgate/api/unsafe/Unsafe.java b/api/src/main/java/org/geysermc/floodgate/api/unsafe/Unsafe.java
similarity index 100%
rename from legacy-api/src/main/java/org/geysermc/floodgate/api/unsafe/Unsafe.java
rename to api/src/main/java/org/geysermc/floodgate/api/unsafe/Unsafe.java
diff --git a/legacy-api/src/main/java/org/geysermc/floodgate/api/util/TriFunction.java b/api/src/main/java/org/geysermc/floodgate/api/util/TriFunction.java
similarity index 100%
rename from legacy-api/src/main/java/org/geysermc/floodgate/api/util/TriFunction.java
rename to api/src/main/java/org/geysermc/floodgate/api/util/TriFunction.java
diff --git a/core/src/main/java/org/geysermc/floodgate/util/BedrockData.java b/api/src/main/java/org/geysermc/floodgate/util/BedrockData.java
similarity index 100%
rename from core/src/main/java/org/geysermc/floodgate/util/BedrockData.java
rename to api/src/main/java/org/geysermc/floodgate/util/BedrockData.java
diff --git a/api/src/main/java/org/geysermc/floodgate/util/DeviceOs.java b/api/src/main/java/org/geysermc/floodgate/util/DeviceOs.java
new file mode 100644
index 00000000..beed5f19
--- /dev/null
+++ b/api/src/main/java/org/geysermc/floodgate/util/DeviceOs.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.floodgate.util;
+
+import lombok.AccessLevel;
+import lombok.RequiredArgsConstructor;
+
+@Deprecated
+@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
+public enum DeviceOs {
+ UNKNOWN("Unknown"),
+ GOOGLE("Android"),
+ IOS("iOS"),
+ OSX("macOS"),
+ AMAZON("Amazon"),
+ GEARVR("Gear VR"),
+ HOLOLENS("Hololens"),
+ UWP("Windows"),
+ WIN32("Windows x86"),
+ DEDICATED("Dedicated"),
+ TVOS("Apple TV"),
+ PS4("PS4"),
+ NX("Switch"),
+ XBOX("Xbox One"),
+ WINDOWS_PHONE("Windows Phone");
+
+ private final String displayName;
+
+ /**
+ * Get the DeviceOs instance from the identifier.
+ *
+ * @param id the DeviceOs identifier
+ * @return The DeviceOs or {@link #UNKNOWN} if the DeviceOs wasn't found
+ */
+ public static DeviceOs fromId(int id) {
+ DeviceOs[] VALUES = values();
+ return id < VALUES.length ? VALUES[id] : VALUES[0];
+ }
+
+ /**
+ * @return friendly display name of platform.
+ */
+ @Override
+ public String toString() {
+ return displayName;
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/org/geysermc/floodgate/util/InputMode.java b/api/src/main/java/org/geysermc/floodgate/util/InputMode.java
new file mode 100644
index 00000000..b58c8294
--- /dev/null
+++ b/api/src/main/java/org/geysermc/floodgate/util/InputMode.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.floodgate.util;
+
+@Deprecated
+public enum InputMode {
+ UNKNOWN,
+ KEYBOARD_MOUSE,
+ TOUCH,
+ CONTROLLER,
+ VR;
+
+ private static final InputMode[] VALUES = values();
+
+ /**
+ * Get the InputMode instance from the identifier.
+ *
+ * @param id the InputMode identifier
+ * @return The InputMode or {@link #UNKNOWN} if the DeviceOs wasn't found
+ */
+ public static InputMode fromId(int id) {
+ return VALUES.length > id ? VALUES[id] : VALUES[0];
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/org/geysermc/floodgate/util/LinkedPlayer.java b/api/src/main/java/org/geysermc/floodgate/util/LinkedPlayer.java
new file mode 100644
index 00000000..1f2d9560
--- /dev/null
+++ b/api/src/main/java/org/geysermc/floodgate/util/LinkedPlayer.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Floodgate
+ */
+
+package org.geysermc.floodgate.util;
+
+import java.util.UUID;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
+public final class LinkedPlayer implements Cloneable {
+ /**
+ * The Java username of the linked player
+ */
+ private final String javaUsername;
+ /**
+ * The Java UUID of the linked player
+ */
+ private final UUID javaUniqueId;
+ /**
+ * The UUID of the Bedrock player
+ */
+ private final UUID bedrockId;
+ /**
+ * If the LinkedPlayer is sent from a different platform. For example the LinkedPlayer is from
+ * Bungee but the data has been sent to the Bukkit server.
+ */
+ private boolean fromDifferentPlatform = false;
+
+ public static LinkedPlayer of(String javaUsername, UUID javaUniqueId, UUID bedrockId) {
+ return new LinkedPlayer(javaUsername, javaUniqueId, bedrockId);
+ }
+
+ public static LinkedPlayer fromString(String data) {
+ String[] split = data.split(";");
+ if (split.length != 3) {
+ return null;
+ }
+
+ LinkedPlayer player = new LinkedPlayer(
+ split[0], UUID.fromString(split[1]), UUID.fromString(split[2])
+ );
+ player.fromDifferentPlatform = true;
+ return player;
+ }
+
+ @Override
+ public String toString() {
+ return javaUsername + ';' + javaUniqueId.toString() + ';' + bedrockId.toString();
+ }
+
+ @Override
+ public LinkedPlayer clone() throws CloneNotSupportedException {
+ return (LinkedPlayer) super.clone();
+ }
+}
diff --git a/api/src/main/java/org/geysermc/floodgate/util/UiProfile.java b/api/src/main/java/org/geysermc/floodgate/util/UiProfile.java
new file mode 100644
index 00000000..8d9960ed
--- /dev/null
+++ b/api/src/main/java/org/geysermc/floodgate/util/UiProfile.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.floodgate.util;
+
+@Deprecated
+public enum UiProfile {
+ CLASSIC,
+ POCKET;
+
+ private static final UiProfile[] VALUES = values();
+
+ /**
+ * Get the UiProfile instance from the identifier.
+ *
+ * @param id the UiProfile identifier
+ * @return The UiProfile or {@link #CLASSIC} if the UiProfile wasn't found
+ */
+ public static UiProfile fromId(int id) {
+ return VALUES.length > id ? VALUES[id] : VALUES[0];
+ }
+}
diff --git a/build.gradle.kts b/build.gradle.kts
index 89e1952c..09dace78 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -11,7 +11,7 @@ allprojects {
}
val deployProjects = setOf(
- projects.legacyApi,
+ projects.api,
// for future Floodgate integration + Fabric
projects.core,
projects.bungee,
diff --git a/core/build.gradle.kts b/core/build.gradle.kts
index 639d1b61..e87e156e 100644
--- a/core/build.gradle.kts
+++ b/core/build.gradle.kts
@@ -6,7 +6,8 @@ plugins {
dependencies {
api("org.geysermc", "api", "3.0.0-SNAPSHOT")
- api("org.geysermc", "floodgate-legacy-api", "3.0.0-SNAPSHOT")
+ api(projects.api)
+// api("org.geysermc", "floodgate-legacy-api", "3.0.0-SNAPSHOT")
api("org.geysermc.configutils", "configutils", Versions.configUtilsVersion)
compileOnly(projects.ap)
diff --git a/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java b/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java
index 43f21567..9add6d8f 100644
--- a/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java
+++ b/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java
@@ -34,9 +34,7 @@ import lombok.AccessLevel;
import lombok.Getter;
import org.geysermc.api.Geyser;
import org.geysermc.api.GeyserApiBase;
-import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.InstanceHolder;
-import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
import org.geysermc.floodgate.api.impl.FloodgateApiWrapper;
import org.geysermc.floodgate.api.inject.PlatformInjector;
import org.geysermc.floodgate.api.link.PlayerLink;
diff --git a/core/src/main/java/org/geysermc/floodgate/addon/data/HandshakeDataImpl.java b/core/src/main/java/org/geysermc/floodgate/addon/data/HandshakeDataImpl.java
index 3a6398a2..480175e9 100644
--- a/core/src/main/java/org/geysermc/floodgate/addon/data/HandshakeDataImpl.java
+++ b/core/src/main/java/org/geysermc/floodgate/addon/data/HandshakeDataImpl.java
@@ -36,7 +36,7 @@ import org.geysermc.floodgate.util.LinkedPlayer;
import org.geysermc.floodgate.util.Utils;
@Getter
-public class HandshakeDataImpl {
+public class HandshakeDataImpl implements HandshakeData {
private final Channel channel;
private final boolean floodgatePlayer;
private final BedrockData bedrockData;
diff --git a/core/src/main/java/org/geysermc/floodgate/crypto/AesCipher.java b/core/src/main/java/org/geysermc/floodgate/crypto/AesCipher.java
new file mode 100644
index 00000000..d28b8e7e
--- /dev/null
+++ b/core/src/main/java/org/geysermc/floodgate/crypto/AesCipher.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Floodgate
+ */
+
+package org.geysermc.floodgate.crypto;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.security.Key;
+import java.security.SecureRandom;
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+public final class AesCipher implements FloodgateCipher {
+ public static final int IV_LENGTH = 12;
+ private static final int TAG_BIT_LENGTH = 128;
+ private static final String CIPHER_NAME = "AES/GCM/NoPadding";
+
+ private final SecureRandom secureRandom = new SecureRandom();
+ private final Topping topping;
+ private SecretKey secretKey;
+
+ public void init(Key key) {
+ if (!"AES".equals(key.getAlgorithm())) {
+ throw new RuntimeException(
+ "Algorithm was expected to be AES, but got " + key.getAlgorithm()
+ );
+ }
+ secretKey = (SecretKey) key;
+ }
+
+ public byte[] encrypt(byte[] data) throws Exception {
+ Cipher cipher = Cipher.getInstance(CIPHER_NAME);
+
+ byte[] iv = new byte[IV_LENGTH];
+ secureRandom.nextBytes(iv);
+
+ GCMParameterSpec spec = new GCMParameterSpec(TAG_BIT_LENGTH, iv);
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey, spec);
+ byte[] cipherText = cipher.doFinal(data);
+
+ if (topping != null) {
+ iv = topping.encode(iv);
+ cipherText = topping.encode(cipherText);
+ }
+
+ return ByteBuffer.allocate(HEADER.length + iv.length + cipherText.length + 1)
+ .put(HEADER)
+ .put(iv)
+ .put((byte) 0x21)
+ .put(cipherText)
+ .array();
+ }
+
+ public byte[] decrypt(byte[] cipherTextWithIv) throws Exception {
+ checkHeader(cipherTextWithIv);
+
+ Cipher cipher = Cipher.getInstance(CIPHER_NAME);
+
+ int bufferLength = cipherTextWithIv.length - HEADER.length;
+ ByteBuffer buffer = ByteBuffer.wrap(cipherTextWithIv, HEADER.length, bufferLength);
+
+ int ivLength = IV_LENGTH;
+
+ if (topping != null) {
+ int mark = buffer.position();
+
+ // we need the first index, the second is for the actual data
+ boolean found = false;
+ while (buffer.hasRemaining() && !found) {
+ if (buffer.get() == 0x21) {
+ found = true;
+ }
+ }
+
+ ivLength = buffer.position() - mark - 1; // don't include the splitter itself
+ // don't remove this cast, it'll cause problems if you remove it
+ ((Buffer) buffer).position(mark); // reset to the pre-while index
+ }
+
+ byte[] iv = new byte[ivLength];
+ buffer.get(iv);
+
+ // don't remove this cast, it'll cause problems if you remove it
+ ((Buffer) buffer).position(buffer.position() + 1); // skip splitter
+
+ byte[] cipherText = new byte[buffer.remaining()];
+ buffer.get(cipherText);
+
+ if (topping != null) {
+ iv = topping.decode(iv);
+ cipherText = topping.decode(cipherText);
+ }
+
+ GCMParameterSpec spec = new GCMParameterSpec(TAG_BIT_LENGTH, iv);
+ cipher.init(Cipher.DECRYPT_MODE, secretKey, spec);
+ return cipher.doFinal(cipherText);
+ }
+}
diff --git a/core/src/main/java/org/geysermc/floodgate/crypto/AesKeyProducer.java b/core/src/main/java/org/geysermc/floodgate/crypto/AesKeyProducer.java
new file mode 100644
index 00000000..fd5c37e9
--- /dev/null
+++ b/core/src/main/java/org/geysermc/floodgate/crypto/AesKeyProducer.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Floodgate
+ */
+
+package org.geysermc.floodgate.crypto;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+public final class AesKeyProducer implements KeyProducer {
+ public static int KEY_SIZE = 128;
+
+ @Override
+ public SecretKey produce() {
+ try {
+ KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
+ keyGenerator.init(KEY_SIZE, secureRandom());
+ return keyGenerator.generateKey();
+ } catch (Exception exception) {
+ throw new RuntimeException(exception);
+ }
+ }
+
+ @Override
+ public SecretKey produceFrom(byte[] keyFileData) {
+ try {
+ return new SecretKeySpec(keyFileData, "AES");
+ } catch (Exception exception) {
+ throw new RuntimeException(exception);
+ }
+ }
+
+ private SecureRandom secureRandom() throws NoSuchAlgorithmException {
+ // use Windows-PRNG for windows (default impl is SHA1PRNG)
+ if (System.getProperty("os.name").startsWith("Windows")) {
+ return SecureRandom.getInstance("Windows-PRNG");
+ } else {
+ try {
+ // NativePRNG (which should be the default on unix-systems) can still block your
+ // system. Even though it isn't as bad as NativePRNGBlocking, we still try to
+ // prevent that if possible
+ return SecureRandom.getInstance("NativePRNGNonBlocking");
+ } catch (NoSuchAlgorithmException ignored) {
+ // at this point we just have to go with the default impl even if it blocks
+ return new SecureRandom();
+ }
+ }
+ }
+}
diff --git a/core/src/main/java/org/geysermc/floodgate/crypto/Base64Topping.java b/core/src/main/java/org/geysermc/floodgate/crypto/Base64Topping.java
new file mode 100644
index 00000000..002a23f3
--- /dev/null
+++ b/core/src/main/java/org/geysermc/floodgate/crypto/Base64Topping.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.floodgate.crypto;
+
+import java.util.Base64;
+
+public final class Base64Topping implements Topping {
+ @Override
+ public byte[] encode(byte[] data) {
+ return Base64.getEncoder().encode(data);
+ }
+
+ @Override
+ public byte[] decode(byte[] data) {
+ return Base64.getDecoder().decode(data);
+ }
+}
diff --git a/core/src/main/java/org/geysermc/floodgate/crypto/FloodgateCipher.java b/core/src/main/java/org/geysermc/floodgate/crypto/FloodgateCipher.java
new file mode 100644
index 00000000..f6087a65
--- /dev/null
+++ b/core/src/main/java/org/geysermc/floodgate/crypto/FloodgateCipher.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Floodgate
+ */
+
+package org.geysermc.floodgate.crypto;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.security.Key;
+import org.geysermc.floodgate.util.InvalidFormatException;
+
+/**
+ * Responsible for both encrypting and decrypting data
+ */
+public interface FloodgateCipher {
+ int VERSION = 0;
+ byte[] IDENTIFIER = "^Floodgate^".getBytes(UTF_8);
+ byte[] HEADER = (new String(IDENTIFIER, UTF_8) + (char) (VERSION + 0x3E)).getBytes(UTF_8);
+
+ static int version(String data) {
+ if (data.length() <= HEADER.length) {
+ return -1;
+ }
+
+ for (int i = 0; i < IDENTIFIER.length; i++) {
+ if (IDENTIFIER[i] != data.charAt(i)) {
+ return -1;
+ }
+ }
+
+ return data.charAt(IDENTIFIER.length) - 0x3E;
+ }
+
+ /**
+ * Initializes the instance by giving it the key it needs to encrypt or decrypt data
+ *
+ * @param key the key used to encrypt and decrypt data
+ */
+ void init(Key key);
+
+ /**
+ * Encrypts the given data using the Key provided in {@link #init(Key)}
+ *
+ * @param data the data to encrypt
+ * @return the encrypted data
+ * @throws Exception when the encryption failed
+ */
+ byte[] encrypt(byte[] data) throws Exception;
+
+ /**
+ * Encrypts data from a String.
This method internally calls {@link #encrypt(byte[])}
+ *
+ * @param data the data to encrypt
+ * @return the encrypted data
+ * @throws Exception when the encryption failed
+ */
+ default byte[] encryptFromString(String data) throws Exception {
+ return encrypt(data.getBytes(UTF_8));
+ }
+
+ /**
+ * Decrypts the given data using the Key provided in {@link #init(Key)}
+ *
+ * @param data the data to decrypt
+ * @return the decrypted data
+ * @throws Exception when the decrypting failed
+ */
+ byte[] decrypt(byte[] data) throws Exception;
+
+ /**
+ * Decrypts a byte[] and turn it into a String.
This method internally calls {@link
+ * #decrypt(byte[])} and converts the returned byte[] into a String.
+ *
+ * @param data the data to encrypt
+ * @return the decrypted data in a UTF-8 String
+ * @throws Exception when the decrypting failed
+ */
+ default String decryptToString(byte[] data) throws Exception {
+ byte[] decrypted = decrypt(data);
+ if (decrypted == null) {
+ return null;
+ }
+ return new String(decrypted, UTF_8);
+ }
+
+ /**
+ * Decrypts a String.
This method internally calls {@link #decrypt(byte[])} by converting
+ * the UTF-8 String into a byte[]
+ *
+ * @param data the data to decrypt
+ * @return the decrypted data in a byte[]
+ * @throws Exception when the decrypting failed
+ */
+ default byte[] decryptFromString(String data) throws Exception {
+ return decrypt(data.getBytes(UTF_8));
+ }
+
+ /**
+ * Checks if the header is valid. This method will throw an InvalidFormatException when the
+ * header is invalid.
+ *
+ * @param data the data to check
+ * @throws InvalidFormatException when the header is invalid
+ */
+ default void checkHeader(byte[] data) throws InvalidFormatException {
+ if (data.length <= HEADER.length) {
+ throw new InvalidFormatException(
+ "Data length is smaller then header." +
+ "Needed " + HEADER.length + ", got " + data.length
+ );
+ }
+
+ for (int i = 0; i < IDENTIFIER.length; i++) {
+ if (IDENTIFIER[i] != data[i]) {
+ String identifier = new String(IDENTIFIER, UTF_8);
+ String received = new String(data, 0, IDENTIFIER.length, UTF_8);
+ throw new InvalidFormatException(
+ "Expected identifier " + identifier + ", got " + received
+ );
+ }
+ }
+ }
+}
diff --git a/core/src/main/java/org/geysermc/floodgate/crypto/KeyProducer.java b/core/src/main/java/org/geysermc/floodgate/crypto/KeyProducer.java
new file mode 100644
index 00000000..4ee00f36
--- /dev/null
+++ b/core/src/main/java/org/geysermc/floodgate/crypto/KeyProducer.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.floodgate.crypto;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.Key;
+
+public interface KeyProducer {
+ Key produce();
+ Key produceFrom(byte[] keyFileData);
+
+ default Key produceFrom(Path keyFileLocation) throws IOException {
+ return produceFrom(Files.readAllBytes(keyFileLocation));
+ }
+}
diff --git a/core/src/main/java/org/geysermc/floodgate/crypto/Topping.java b/core/src/main/java/org/geysermc/floodgate/crypto/Topping.java
new file mode 100644
index 00000000..3805c0bc
--- /dev/null
+++ b/core/src/main/java/org/geysermc/floodgate/crypto/Topping.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.floodgate.crypto;
+
+public interface Topping {
+ byte[] encode(byte[] data);
+ byte[] decode(byte[] data);
+}
diff --git a/core/src/main/java/org/geysermc/floodgate/news/NewsItem.java b/core/src/main/java/org/geysermc/floodgate/news/NewsItem.java
new file mode 100644
index 00000000..9a7b20a3
--- /dev/null
+++ b/core/src/main/java/org/geysermc/floodgate/news/NewsItem.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Floodgate
+ */
+
+package org.geysermc.floodgate.news;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import org.geysermc.floodgate.news.data.ItemData;
+
+public final class NewsItem {
+ private final int id;
+ private final boolean active;
+ private final NewsType type;
+ private final ItemData data;
+ private final String message;
+ private final Set actions;
+ private final String url;
+
+ private NewsItem(
+ int id, boolean active, NewsType type, ItemData data,
+ String message, Set actions, String url) {
+
+ this.id = id;
+ this.active = active;
+ this.type = type;
+ this.data = data;
+ this.message = message;
+ this.actions = Collections.unmodifiableSet(actions);
+ this.url = url;
+ }
+
+ public static NewsItem readItem(JsonObject newsItem) {
+ NewsType newsType = NewsType.getByName(newsItem.get("type").getAsString());
+ if (newsType == null) {
+ return null;
+ }
+
+ JsonObject messageObject = newsItem.getAsJsonObject("message");
+ NewsItemMessage itemMessage = NewsItemMessage.getById(messageObject.get("id").getAsInt());
+
+ String message = "Received an unknown news message type. Please update";
+ if (itemMessage != null) {
+ message = itemMessage.getFormattedMessage(messageObject.getAsJsonArray("args"));
+ }
+
+ Set actions = new HashSet<>();
+ for (JsonElement actionElement : newsItem.getAsJsonArray("actions")) {
+ NewsItemAction action = NewsItemAction.getByName(actionElement.getAsString());
+ if (action != null) {
+ actions.add(action);
+ }
+ }
+
+ return new NewsItem(
+ newsItem.get("id").getAsInt(),
+ newsItem.get("active").getAsBoolean(),
+ newsType,
+ newsType.read(newsItem.getAsJsonObject("data")),
+ message,
+ actions,
+ newsItem.get("url").getAsString()
+ );
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public boolean isActive() {
+ return active;
+ }
+
+ public NewsType getType() {
+ return type;
+ }
+
+ public ItemData getData() {
+ return data;
+ }
+
+ @SuppressWarnings("unchecked")
+ public T getDataAs(Class type) {
+ return (T) data;
+ }
+
+ public String getRawMessage() {
+ return message;
+ }
+
+ public String getMessage() {
+ return message + " See " + getUrl() + " for more information.";
+ }
+
+ public Set getActions() {
+ return actions;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+}
diff --git a/core/src/main/java/org/geysermc/floodgate/news/NewsItemAction.java b/core/src/main/java/org/geysermc/floodgate/news/NewsItemAction.java
new file mode 100644
index 00000000..00e34b62
--- /dev/null
+++ b/core/src/main/java/org/geysermc/floodgate/news/NewsItemAction.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.floodgate.news;
+
+public enum NewsItemAction {
+ ON_SERVER_STARTED,
+ ON_OPERATOR_JOIN,
+ BROADCAST_TO_CONSOLE,
+ BROADCAST_TO_OPERATORS;
+
+ private static final NewsItemAction[] VALUES = values();
+
+ public static NewsItemAction getByName(String actionName) {
+ for (NewsItemAction type : VALUES) {
+ if (type.name().equalsIgnoreCase(actionName)) {
+ return type;
+ }
+ }
+ return null;
+ }
+}
diff --git a/core/src/main/java/org/geysermc/floodgate/news/NewsItemMessage.java b/core/src/main/java/org/geysermc/floodgate/news/NewsItemMessage.java
new file mode 100644
index 00000000..9c2f3d15
--- /dev/null
+++ b/core/src/main/java/org/geysermc/floodgate/news/NewsItemMessage.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.floodgate.news;
+
+import com.google.gson.JsonArray;
+
+// {} is used for things that have to be filled in by the server,
+// {@} is for things that have to be filled in by us
+public enum NewsItemMessage {
+ UPDATE_AVAILABLE("There is an update available for {}. The newest version is: {}"),
+ UPDATE_RECOMMENDED(UPDATE_AVAILABLE + ". Your version is quite old, updating is recommend."),
+ UPDATE_HIGHLY_RECOMMENDED(UPDATE_AVAILABLE + ". We highly recommend updating because some important changes have been made."),
+ UPDATE_ANCIENT_VERSION(UPDATE_AVAILABLE + ". You are running an ancient version, updating is recommended."),
+
+ DOWNTIME_GENERIC("The {} is temporarily going down for maintenance soon."),
+ DOWNTIME_WITH_START("The {} is temporarily going down for maintenance on {}."),
+ DOWNTIME_TIMEFRAME(DOWNTIME_WITH_START + " The maintenance is expected to last till {}.");
+
+ private static final NewsItemMessage[] VALUES = values();
+
+ private final String messageFormat;
+ private final String[] messageSplitted;
+
+ NewsItemMessage(String messageFormat) {
+ this.messageFormat = messageFormat;
+ this.messageSplitted = messageFormat.split(" ");
+ }
+
+ public static NewsItemMessage getById(int id) {
+ return VALUES.length > id ? VALUES[id] : null;
+ }
+
+ public String getMessageFormat() {
+ return messageFormat;
+ }
+
+ public String getFormattedMessage(JsonArray serverArguments) {
+ int serverArgumentsIndex = 0;
+
+ StringBuilder message = new StringBuilder();
+ for (String split : messageSplitted) {
+ if (message.length() > 0) {
+ message.append(' ');
+ }
+
+ String result = split;
+
+ if (serverArgumentsIndex < serverArguments.size()) {
+ String argument = serverArguments.get(serverArgumentsIndex).getAsString();
+ result = result.replace("{}", argument);
+ if (!result.equals(split)) {
+ serverArgumentsIndex++;
+ }
+ }
+
+ message.append(result);
+ }
+ return message.toString();
+ }
+
+
+ @Override
+ public String toString() {
+ return getMessageFormat();
+ }
+}
diff --git a/core/src/main/java/org/geysermc/floodgate/news/NewsType.java b/core/src/main/java/org/geysermc/floodgate/news/NewsType.java
new file mode 100644
index 00000000..95f1f1ad
--- /dev/null
+++ b/core/src/main/java/org/geysermc/floodgate/news/NewsType.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Floodgate
+ */
+
+package org.geysermc.floodgate.news;
+
+import com.google.gson.JsonObject;
+import java.util.function.Function;
+import org.geysermc.floodgate.news.data.AnnouncementData;
+import org.geysermc.floodgate.news.data.BuildSpecificData;
+import org.geysermc.floodgate.news.data.CheckAfterData;
+import org.geysermc.floodgate.news.data.ConfigSpecificData;
+import org.geysermc.floodgate.news.data.ItemData;
+
+public enum NewsType {
+ BUILD_SPECIFIC(BuildSpecificData::read),
+ CHECK_AFTER(CheckAfterData::read),
+ ANNOUNCEMENT(AnnouncementData::read),
+ CONFIG_SPECIFIC(ConfigSpecificData::read);
+
+ private static final NewsType[] VALUES = values();
+
+ private final Function readFunction;
+
+ NewsType(Function readFunction) {
+ this.readFunction = readFunction;
+ }
+
+ public static NewsType getByName(String newsType) {
+ for (NewsType type : VALUES) {
+ if (type.name().equalsIgnoreCase(newsType)) {
+ return type;
+ }
+ }
+ return null;
+ }
+
+ public ItemData read(JsonObject data) {
+ return readFunction.apply(data);
+ }
+}
diff --git a/core/src/main/java/org/geysermc/floodgate/news/data/AnnouncementData.java b/core/src/main/java/org/geysermc/floodgate/news/data/AnnouncementData.java
new file mode 100644
index 00000000..71aae853
--- /dev/null
+++ b/core/src/main/java/org/geysermc/floodgate/news/data/AnnouncementData.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Floodgate
+ */
+
+package org.geysermc.floodgate.news.data;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.util.HashSet;
+import java.util.Set;
+
+public final class AnnouncementData implements ItemData {
+ private final Set including = new HashSet<>();
+ private final Set excluding = new HashSet<>();
+
+ private AnnouncementData() {}
+
+ public static AnnouncementData read(JsonObject data) {
+ AnnouncementData announcementData = new AnnouncementData();
+
+ if (data.has("including")) {
+ JsonArray including = data.getAsJsonArray("including");
+ for (JsonElement element : including) {
+ announcementData.including.add(element.getAsString());
+ }
+ }
+
+ if (data.has("excluding")) {
+ JsonArray including = data.getAsJsonArray("excluding");
+ for (JsonElement element : including) {
+ announcementData.excluding.add(element.getAsString());
+ }
+ }
+ return announcementData;
+ }
+
+ public boolean isAffected(String project) {
+ return !excluding.contains(project) && (including.isEmpty() || including.contains(project));
+ }
+}
diff --git a/core/src/main/java/org/geysermc/floodgate/news/data/BuildSpecificData.java b/core/src/main/java/org/geysermc/floodgate/news/data/BuildSpecificData.java
new file mode 100644
index 00000000..7f2c7360
--- /dev/null
+++ b/core/src/main/java/org/geysermc/floodgate/news/data/BuildSpecificData.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.floodgate.news.data;
+
+import com.google.gson.JsonObject;
+
+public final class BuildSpecificData implements ItemData {
+ private String branch;
+
+ private boolean allAffected;
+ private int affectedGreaterThan;
+ private int affectedLessThan;
+
+ private BuildSpecificData() {}
+
+ public static BuildSpecificData read(JsonObject data) {
+ BuildSpecificData updateData = new BuildSpecificData();
+ updateData.branch = data.get("branch").getAsString();
+
+ JsonObject affectedBuilds = data.getAsJsonObject("affected_builds");
+ if (affectedBuilds.has("all")) {
+ updateData.allAffected = affectedBuilds.get("all").getAsBoolean();
+ }
+ if (!updateData.allAffected) {
+ updateData.affectedGreaterThan = affectedBuilds.get("gt").getAsInt();
+ updateData.affectedLessThan = affectedBuilds.get("lt").getAsInt();
+ }
+ return updateData;
+ }
+
+ public boolean isAffected(String branch, int buildId) {
+ return this.branch.equals(branch) &&
+ (allAffected || buildId > affectedGreaterThan && buildId < affectedLessThan);
+ }
+
+ public String getBranch() {
+ return branch;
+ }
+}
diff --git a/core/src/main/java/org/geysermc/floodgate/news/data/CheckAfterData.java b/core/src/main/java/org/geysermc/floodgate/news/data/CheckAfterData.java
new file mode 100644
index 00000000..1e5fef4d
--- /dev/null
+++ b/core/src/main/java/org/geysermc/floodgate/news/data/CheckAfterData.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.floodgate.news.data;
+
+import com.google.gson.JsonObject;
+
+public final class CheckAfterData implements ItemData {
+ private long checkAfter;
+
+ private CheckAfterData() {}
+
+ public static CheckAfterData read(JsonObject data) {
+ CheckAfterData checkAfterData = new CheckAfterData();
+ checkAfterData.checkAfter = data.get("check_after").getAsLong();
+ return checkAfterData;
+ }
+
+ public long getCheckAfter() {
+ return checkAfter;
+ }
+}
diff --git a/core/src/main/java/org/geysermc/floodgate/news/data/ConfigSpecificData.java b/core/src/main/java/org/geysermc/floodgate/news/data/ConfigSpecificData.java
new file mode 100644
index 00000000..88b5897a
--- /dev/null
+++ b/core/src/main/java/org/geysermc/floodgate/news/data/ConfigSpecificData.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Floodgate
+ */
+
+package org.geysermc.floodgate.news.data;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+public final class ConfigSpecificData implements ItemData {
+ private final Map affectedKeys = new HashMap<>();
+
+ private ConfigSpecificData() {}
+
+ public static ConfigSpecificData read(JsonObject data) {
+ ConfigSpecificData configSpecificData = new ConfigSpecificData();
+
+ JsonArray entries = data.getAsJsonArray("entries");
+ for (JsonElement element : entries) {
+ JsonObject entry = element.getAsJsonObject();
+ String key = entry.get("key").getAsString();
+ String pattern = entry.get("pattern").getAsString();
+ configSpecificData.affectedKeys.put(key, Pattern.compile(pattern));
+ }
+ return configSpecificData;
+ }
+
+ public boolean isAffected(Map config) {
+ for (Map.Entry entry : affectedKeys.entrySet()) {
+ if (config.containsKey(entry.getKey())) {
+ String value = config.get(entry.getKey());
+ if (entry.getValue().matcher(value).matches()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/core/src/main/java/org/geysermc/floodgate/news/data/ItemData.java b/core/src/main/java/org/geysermc/floodgate/news/data/ItemData.java
new file mode 100644
index 00000000..64a1aedf
--- /dev/null
+++ b/core/src/main/java/org/geysermc/floodgate/news/data/ItemData.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.floodgate.news.data;
+
+public interface ItemData {
+}
diff --git a/core/src/main/java/org/geysermc/floodgate/player/FloodgateHandshakeHandler.java b/core/src/main/java/org/geysermc/floodgate/player/FloodgateHandshakeHandler.java
index 4c678a96..68f56bf2 100644
--- a/core/src/main/java/org/geysermc/floodgate/player/FloodgateHandshakeHandler.java
+++ b/core/src/main/java/org/geysermc/floodgate/player/FloodgateHandshakeHandler.java
@@ -241,7 +241,7 @@ public final class FloodgateHandshakeHandler {
BedrockData bedrockData,
String hostname) {
- HandshakeInjectedData handshakeData = new HandshakeDataImpl(channel, bedrockData != null,
+ HandshakeData handshakeData = new HandshakeDataImpl(channel, bedrockData != null,
bedrockData, config, null, hostname);
handshakeHandlers.callHandshakeHandlers(handshakeData);
@@ -276,13 +276,13 @@ public final class FloodgateHandshakeHandler {
@Getter
public static class HandshakeResult extends IllegalStateException {
private final ResultType resultType;
- private final HandshakeInjectedData handshakeData;
+ private final HandshakeData handshakeData;
private final BedrockData bedrockData;
private final Connection floodgatePlayer;
public InetSocketAddress getNewIp(Channel channel) {
if (floodgatePlayer != null) {
- return floodgatePlayer.socketAddress();
+ return (InetSocketAddress) floodgatePlayer.socketAddress();
}
if (handshakeData.getIp() != null) {
int port = ((InetSocketAddress) channel.remoteAddress()).getPort();
diff --git a/core/src/main/java/org/geysermc/floodgate/util/InvalidFormatException.java b/core/src/main/java/org/geysermc/floodgate/util/InvalidFormatException.java
new file mode 100644
index 00000000..e0630d48
--- /dev/null
+++ b/core/src/main/java/org/geysermc/floodgate/util/InvalidFormatException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.floodgate.util;
+
+public class InvalidFormatException extends Exception {
+ public InvalidFormatException(String message) {
+ super(message);
+ }
+}
diff --git a/core/src/main/java/org/geysermc/floodgate/util/WebsocketEventType.java b/core/src/main/java/org/geysermc/floodgate/util/WebsocketEventType.java
new file mode 100644
index 00000000..61e6c63b
--- /dev/null
+++ b/core/src/main/java/org/geysermc/floodgate/util/WebsocketEventType.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.floodgate.util;
+
+public enum WebsocketEventType {
+ /**
+ * Sent once we successfully connected to the server
+ */
+ SUBSCRIBER_CREATED(0),
+ /**
+ * Sent every time a subscriber got added or disconnected
+ */
+ SUBSCRIBER_COUNT(1),
+ /**
+ * Sent once the creator disconnected. After this packet the server will automatically close the
+ * connection once the queue size (sent in {@link #ADDED_TO_QUEUE} and {@link #SKIN_UPLOADED}
+ * reaches 0.
+ */
+ CREATOR_DISCONNECTED(4),
+
+ /**
+ * Sent every time a skin got added to the upload queue
+ */
+ ADDED_TO_QUEUE(2),
+ /**
+ * Sent every time a skin got successfully uploaded
+ */
+ SKIN_UPLOADED(3),
+
+ /**
+ * Sent every time a news item was added
+ */
+ NEWS_ADDED(6),
+
+ /**
+ * Sent when the server wants you to know something. Currently used for violations that aren't
+ * bad enough to close the connection
+ */
+ LOG_MESSAGE(5);
+
+ private static final WebsocketEventType[] VALUES;
+
+ static {
+ WebsocketEventType[] values = values();
+ VALUES = new WebsocketEventType[values.length];
+ for (WebsocketEventType value : values) {
+ VALUES[value.id] = value;
+ }
+ }
+
+ /**
+ * The ID is based of the time it got added. However, to keep the enum organized as time goes on,
+ * it looks nicer to sort the events based of categories.
+ */
+ private final int id;
+
+ WebsocketEventType(int id) {
+ this.id = id;
+ }
+
+ public static WebsocketEventType fromId(int id) {
+ return VALUES.length > id ? VALUES[id] : null;
+ }
+
+ public int id() {
+ return id;
+ }
+}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index c6fe2d2d..8ca9799c 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -62,7 +62,7 @@ pluginManagement {
rootProject.name = "floodgate-parent"
-include(":legacy-api")
+include(":api")
include(":ap")
include(":core")
include(":bungee")