diff --git a/bootstrap/standalone/build.gradle.kts b/bootstrap/standalone/build.gradle.kts index eaf895108..61460ce0f 100644 --- a/bootstrap/standalone/build.gradle.kts +++ b/bootstrap/standalone/build.gradle.kts @@ -14,6 +14,8 @@ dependencies { implementation(libs.bundles.jline) implementation(libs.bundles.log4j) + + implementation(libs.gson.runtime) } application { diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index d5635acf9..8afe2d9e6 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -26,9 +26,11 @@ package org.geysermc.geyser; import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; import io.netty.channel.epoll.Epoll; import io.netty.util.NettyRuntime; import io.netty.util.concurrent.DefaultThreadFactory; @@ -87,8 +89,10 @@ import org.geysermc.geyser.util.*; import org.geysermc.mcprotocollib.network.tcp.TcpSession; import java.io.File; +import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.lang.reflect.Type; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; @@ -112,6 +116,8 @@ public class GeyserImpl implements GeyserApi { .enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES) .enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES); + public static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + public static final String NAME = "Geyser"; public static final String GIT_VERSION = "${gitVersion}"; public static final String VERSION = "${version}"; @@ -527,11 +533,11 @@ public class GeyserImpl implements GeyserApi { File tokensFile = bootstrap.getSavedUserLoginsFolder().resolve(Constants.SAVED_REFRESH_TOKEN_FILE).toFile(); if (tokensFile.exists()) { - TypeReference> type = new TypeReference<>() { }; + Type type = new TypeToken>() { }.getType(); Map refreshTokenFile = null; - try { - refreshTokenFile = JSON_MAPPER.readValue(tokensFile, type); + try (FileReader reader = new FileReader(tokensFile)) { + refreshTokenFile = GSON.fromJson(reader, type); } catch (IOException e) { logger.error("Cannot load saved user tokens!", e); } @@ -824,11 +830,9 @@ public class GeyserImpl implements GeyserApi { scheduledThread.execute(() -> { // Ensure all writes are handled on the same thread File savedTokens = getBootstrap().getSavedUserLoginsFolder().resolve(Constants.SAVED_REFRESH_TOKEN_FILE).toFile(); - TypeReference> type = new TypeReference<>() { }; + Type type = new TypeToken>() { }.getType(); try (FileWriter writer = new FileWriter(savedTokens)) { - JSON_MAPPER.writerFor(type) - .withDefaultPrettyPrinter() - .writeValue(writer, savedRefreshTokens); + GSON.toJson(savedRefreshTokens, type, writer); } catch (IOException e) { getLogger().error("Unable to write saved refresh tokens!", e); } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java index 981c97595..84da73239 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java @@ -25,7 +25,8 @@ package org.geysermc.geyser.command.defaults; -import com.fasterxml.jackson.databind.JsonNode; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.util.PlatformType; @@ -179,7 +180,7 @@ public class ConnectionTestCommand extends GeyserCommand { CONNECTION_TEST_MOTD = connectionTestMotd; sender.sendMessage("Testing server connection to " + ip + " with port: " + port + " now. Please wait..."); - JsonNode output; + JsonObject output; try { String hostname = URLEncoder.encode(ip, StandardCharsets.UTF_8); output = WebUtils.getJson("https://checker.geysermc.org/ping?hostname=" + hostname + "&port=" + port); @@ -187,18 +188,18 @@ public class ConnectionTestCommand extends GeyserCommand { CONNECTION_TEST_MOTD = null; } - if (output.get("success").asBoolean()) { - JsonNode cache = output.get("cache"); + if (output.get("success").getAsBoolean()) { + JsonObject cache = output.getAsJsonObject("cache"); String when; - if (cache.get("fromCache").asBoolean()) { - when = cache.get("secondsSince").asInt() + " seconds ago"; + if (cache.get("fromCache").isJsonPrimitive()) { + when = cache.get("secondsSince").getAsBoolean() + " seconds ago"; } else { when = "now"; } - JsonNode ping = output.get("ping"); - JsonNode pong = ping.get("pong"); - String remoteMotd = pong.get("motd").asText(); + JsonObject ping = output.getAsJsonObject("ping"); + JsonObject pong = ping.getAsJsonObject("pong"); + String remoteMotd = pong.get("motd").getAsString(); if (!connectionTestMotd.equals(remoteMotd)) { sender.sendMessage("The MOTD did not match when we pinged the server (we got '" + remoteMotd + "'). " + "Did you supply the correct IP and port of your server?"); @@ -206,7 +207,7 @@ public class ConnectionTestCommand extends GeyserCommand { return; } - if (ping.get("tcpFirst").asBoolean()) { + if (ping.get("tcpFirst").getAsBoolean()) { sender.sendMessage("Your server hardware likely has some sort of firewall preventing people from joining easily. See https://geysermc.link/ovh-firewall for more information."); sendLinks(sender); return; @@ -218,9 +219,9 @@ public class ConnectionTestCommand extends GeyserCommand { } sender.sendMessage("Your server is likely unreachable from outside the network!"); - JsonNode message = output.get("message"); - if (message != null && !message.asText().isEmpty()) { - sender.sendMessage("Got the error message: " + message.asText()); + JsonElement message = output.get("message"); + if (message != null && !message.getAsString().isEmpty()) { + sender.sendMessage("Got the error message: " + message.getAsString()); } sendLinks(sender); } catch (Exception e) { diff --git a/core/src/main/java/org/geysermc/geyser/configuration/ConfigLoaderTemp.java b/core/src/main/java/org/geysermc/geyser/configuration/ConfigLoaderTemp.java index 161b1aff0..98c6d27a6 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/ConfigLoaderTemp.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/ConfigLoaderTemp.java @@ -52,6 +52,9 @@ public class ConfigLoaderTemp { --------------------------------"""; public static T load(Class configClass) throws IOException { + if (true) { + return null; // For now + } var loader = YamlConfigurationLoader.builder() .file(new File("newconfig.yml")) .defaultOptions(InterfaceDefaultOptions.get() diff --git a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java index 6989dc10a..bd8d85440 100644 --- a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java +++ b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java @@ -27,10 +27,11 @@ package org.geysermc.geyser.dump; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.JsonNode; import com.google.common.hash.Hashing; import com.google.common.io.ByteSource; import com.google.common.io.Files; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import lombok.Getter; @@ -249,9 +250,9 @@ public class DumpInfo { Map fields = new HashMap<>(); fields.put("content", FileUtils.readAllLines(GeyserImpl.getInstance().getBootstrap().getLogsPath()).collect(Collectors.joining("\n"))); - JsonNode logData = GeyserImpl.JSON_MAPPER.readTree(WebUtils.postForm("https://api.mclo.gs/1/log", fields)); + JsonObject logData = new JsonParser().parse(WebUtils.postForm("https://api.mclo.gs/1/log", fields)).getAsJsonObject(); - this.link = logData.get("url").textValue(); + this.link = logData.get("url").getAsString(); } catch (IOException ignored) { } } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/BiomeIdentifierRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/BiomeIdentifierRegistryLoader.java index 3205004e4..eb091f273 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/BiomeIdentifierRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/BiomeIdentifierRegistryLoader.java @@ -25,14 +25,16 @@ package org.geysermc.geyser.registry.loader; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.core.type.TypeReference; +import com.google.gson.annotations.SerializedName; +import com.google.gson.reflect.TypeToken; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import org.geysermc.geyser.GeyserImpl; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Type; import java.util.Map; public class BiomeIdentifierRegistryLoader implements RegistryLoader> { @@ -44,11 +46,11 @@ public class BiomeIdentifierRegistryLoader implements RegistryLoader> biomeEntriesType = new TypeReference<>() { }; + Type biomeEntriesType = new TypeToken>() { }.getType(); Map biomeEntries; try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow("mappings/biomes.json")) { - biomeEntries = GeyserImpl.JSON_MAPPER.readValue(stream, biomeEntriesType); + biomeEntries = GeyserImpl.GSON.fromJson(new InputStreamReader(stream), biomeEntriesType); } catch (IOException e) { throw new AssertionError("Unable to load Bedrock runtime biomes", e); } @@ -66,7 +68,7 @@ public class BiomeIdentifierRegistryLoader implements RegistryLoader the value */ public abstract class EffectRegistryLoader implements RegistryLoader { - private static final Map loadedFiles = new WeakHashMap<>(); - public void loadFile(String input) { - if (!loadedFiles.containsKey(input)) { - JsonNode effects; - try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow(input)) { - effects = GeyserImpl.JSON_MAPPER.readTree(stream); - } catch (Exception e) { - throw new AssertionError("Unable to load registrations for " + input, e); - } - loadedFiles.put(input, effects); + public JsonObject loadFile(String input) { + try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow(input)) { + return new JsonParser().parse(new InputStreamReader(stream)).getAsJsonObject(); + } catch (Exception e) { + throw new AssertionError("Unable to load registrations for " + input, e); } } - - public JsonNode get(String input) { - return loadedFiles.get(input); - } } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/EnchantmentRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/EnchantmentRegistryLoader.java index 8a0fb1f40..c1a50de96 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/EnchantmentRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/EnchantmentRegistryLoader.java @@ -25,7 +25,10 @@ package org.geysermc.geyser.registry.loader; -import com.fasterxml.jackson.databind.JsonNode; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import org.geysermc.geyser.GeyserImpl; @@ -35,41 +38,39 @@ import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.EnchantmentData; import java.io.InputStream; +import java.io.InputStreamReader; import java.util.EnumMap; import java.util.EnumSet; -import java.util.Iterator; import java.util.Map; public class EnchantmentRegistryLoader implements RegistryLoader> { @Override public Map load(String input) { - JsonNode enchantmentsNode; + JsonObject enchantmentsJson; try (InputStream enchantmentsStream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow(input)) { - enchantmentsNode = GeyserImpl.JSON_MAPPER.readTree(enchantmentsStream); + enchantmentsJson = new JsonParser().parse(new InputStreamReader(enchantmentsStream)).getAsJsonObject(); } catch (Exception e) { throw new AssertionError("Unable to load enchantment data", e); } Map enchantments = new EnumMap<>(JavaEnchantment.class); - Iterator> it = enchantmentsNode.fields(); - while (it.hasNext()) { - Map.Entry entry = it.next(); + for (Map.Entry entry : enchantmentsJson.entrySet()) { JavaEnchantment key = JavaEnchantment.getByJavaIdentifier(entry.getKey()); - JsonNode node = entry.getValue(); - int rarityMultiplier = node.get("anvil_cost").asInt(); - int maxLevel = node.get("max_level").asInt(); + JsonObject node = entry.getValue().getAsJsonObject(); + int rarityMultiplier = node.get("anvil_cost").getAsInt(); + int maxLevel = node.get("max_level").getAsInt(); EnumSet incompatibleEnchantments = EnumSet.noneOf(JavaEnchantment.class); - JsonNode incompatibleEnchantmentsNode = node.get("incompatible_enchantments"); - if (incompatibleEnchantmentsNode != null) { - for (JsonNode incompatibleNode : incompatibleEnchantmentsNode) { - incompatibleEnchantments.add(JavaEnchantment.getByJavaIdentifier(incompatibleNode.textValue())); + JsonArray incompatibleEnchantmentsJson = node.getAsJsonArray("incompatible_enchantments"); + if (incompatibleEnchantmentsJson != null) { + for (JsonElement incompatibleNode : incompatibleEnchantmentsJson) { + incompatibleEnchantments.add(JavaEnchantment.getByJavaIdentifier(incompatibleNode.getAsString())); } } IntSet validItems = new IntOpenHashSet(); - for (JsonNode itemNode : node.get("valid_items")) { - String javaIdentifier = itemNode.textValue(); + for (JsonElement itemNode : node.getAsJsonArray("valid_items")) { + String javaIdentifier = itemNode.getAsString(); Item item = Registries.JAVA_ITEM_IDENTIFIERS.get(javaIdentifier); if (item != null) { validItems.add(item.javaId()); diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/ParticleTypesRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/ParticleTypesRegistryLoader.java index a09d6d6d3..42e34a2d5 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/ParticleTypesRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/ParticleTypesRegistryLoader.java @@ -25,15 +25,15 @@ package org.geysermc.geyser.registry.loader; -import com.fasterxml.jackson.databind.JsonNode; -import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.LevelEventType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.registry.type.ParticleMapping; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType; -import java.util.Iterator; import java.util.Locale; import java.util.Map; @@ -44,16 +44,13 @@ public class ParticleTypesRegistryLoader extends EffectRegistryLoader load(String input) { - this.loadFile(input); - - Iterator> particlesIterator = this.get(input).fields(); + JsonObject particlesJson = this.loadFile(input); Map particles = new Object2ObjectOpenHashMap<>(); try { - while (particlesIterator.hasNext()) { - Map.Entry entry = particlesIterator.next(); + for (Map.Entry entry : particlesJson.entrySet()) { String key = entry.getKey().toUpperCase(Locale.ROOT); - JsonNode bedrockId = entry.getValue().get("bedrockId"); - JsonNode eventType = entry.getValue().get("eventType"); + JsonElement bedrockId = entry.getValue().getAsJsonObject().get("bedrockId"); + JsonElement eventType = entry.getValue().getAsJsonObject().get("eventType"); if (eventType == null && bedrockId == null) { GeyserImpl.getInstance().getLogger().debug("Skipping particle mapping " + key + " because no Bedrock equivalent exists."); continue; @@ -63,16 +60,16 @@ public class ParticleTypesRegistryLoader extends EffectRegistryLoader load(String input) { this.loadFile(input); - Iterator> effectsIterator = this.get(input).fields(); + JsonObject effectsJson = this.loadFile(input); Map soundEffects = new Object2ObjectOpenHashMap<>(); - while (effectsIterator.hasNext()) { - Map.Entry entry = effectsIterator.next(); - JsonNode node = entry.getValue(); + for (Map.Entry entry : effectsJson.entrySet()) { + JsonObject node = entry.getValue().getAsJsonObject(); try { - String type = node.get("type").asText(); + String type = node.get("type").getAsString(); LevelEvent javaEffect = null; LevelEventTranslator transformer = null; switch (type) { case "soundLevel" -> { javaEffect = org.geysermc.mcprotocollib.protocol.data.game.level.event.LevelEventType.valueOf(entry.getKey()); - LevelEventType levelEventType = org.cloudburstmc.protocol.bedrock.data.LevelEvent.valueOf(node.get("name").asText()); - int data = node.has("data") ? node.get("data").intValue() : 0; + LevelEventType levelEventType = org.cloudburstmc.protocol.bedrock.data.LevelEvent.valueOf(node.get("name").getAsString()); + int data = node.has("data") ? node.get("data").getAsInt() : 0; transformer = new SoundLevelEventTranslator(levelEventType, data); } case "soundEvent" -> { javaEffect = org.geysermc.mcprotocollib.protocol.data.game.level.event.LevelEventType.valueOf(entry.getKey()); - org.cloudburstmc.protocol.bedrock.data.SoundEvent soundEvent = org.cloudburstmc.protocol.bedrock.data.SoundEvent.valueOf(node.get("name").asText()); - String identifier = node.has("identifier") ? node.get("identifier").asText() : ""; - int extraData = node.has("extraData") ? node.get("extraData").intValue() : -1; + org.cloudburstmc.protocol.bedrock.data.SoundEvent soundEvent = org.cloudburstmc.protocol.bedrock.data.SoundEvent.valueOf(node.get("name").getAsString()); + String identifier = node.has("identifier") ? node.get("identifier").getAsString() : ""; + int extraData = node.has("extraData") ? node.get("extraData").getAsInt() : -1; transformer = new SoundEventEventTranslator(soundEvent, identifier, extraData); } case "playSound" -> { javaEffect = org.geysermc.mcprotocollib.protocol.data.game.level.event.LevelEventType.valueOf(entry.getKey()); - String name = node.get("name").asText(); - float volume = node.has("volume") ? node.get("volume").floatValue() : 1.0f; - boolean pitchSub = node.has("pitch_sub") && node.get("pitch_sub").booleanValue(); - float pitchMul = node.has("pitch_mul") ? node.get("pitch_mul").floatValue() : 1.0f; - float pitchAdd = node.has("pitch_add") ? node.get("pitch_add").floatValue() : 0.0f; - boolean relative = !node.has("relative") || node.get("relative").booleanValue(); + String name = node.get("name").getAsString(); + float volume = node.has("volume") ? node.get("volume").getAsFloat() : 1.0f; + boolean pitchSub = node.has("pitch_sub") && node.get("pitch_sub").getAsBoolean(); + float pitchMul = node.has("pitch_mul") ? node.get("pitch_mul").getAsFloat() : 1.0f; + float pitchAdd = node.has("pitch_add") ? node.get("pitch_add").getAsFloat() : 0.0f; + boolean relative = !node.has("relative") || node.get("relative").getAsBoolean(); transformer = new PlaySoundEventTranslator(name, volume, pitchSub, pitchMul, pitchAdd, relative); } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/SoundRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/SoundRegistryLoader.java index 318cc08d7..1212a9a18 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/SoundRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/SoundRegistryLoader.java @@ -25,14 +25,16 @@ package org.geysermc.geyser.registry.loader; -import com.fasterxml.jackson.databind.JsonNode; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.registry.type.SoundMapping; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; /** @@ -42,26 +44,24 @@ public class SoundRegistryLoader implements RegistryLoader load(String input) { - JsonNode soundsTree; + JsonObject soundsJson; try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow(input)) { - soundsTree = GeyserImpl.JSON_MAPPER.readTree(stream); + soundsJson = new JsonParser().parse(new InputStreamReader(stream)).getAsJsonObject(); } catch (IOException e) { throw new AssertionError("Unable to load sound mappings", e); } Map soundMappings = new HashMap<>(); - Iterator> soundsIterator = soundsTree.fields(); - while(soundsIterator.hasNext()) { - Map.Entry next = soundsIterator.next(); - JsonNode brMap = next.getValue(); - String javaSound = next.getKey(); + for (Map.Entry entry : soundsJson.entrySet()) { + JsonObject brMap = entry.getValue().getAsJsonObject(); + String javaSound = entry.getKey(); soundMappings.put(javaSound, new SoundMapping( javaSound, - brMap.has("bedrock_mapping") && brMap.get("bedrock_mapping").isTextual() ? brMap.get("bedrock_mapping").asText() : null, - brMap.has("playsound_mapping") && brMap.get("playsound_mapping").isTextual() ? brMap.get("playsound_mapping").asText() : null, - brMap.has("extra_data") && brMap.get("extra_data").isInt() ? brMap.get("extra_data").asInt() : -1, - brMap.has("identifier") && brMap.get("identifier").isTextual() ? brMap.get("identifier").asText() : null, - brMap.has("level_event") && brMap.get("level_event").isBoolean() && brMap.get("level_event").asBoolean() + brMap.has("bedrock_mapping") ? brMap.get("bedrock_mapping").getAsString() : null, + brMap.has("playsound_mapping") ? brMap.get("playsound_mapping").getAsString() : null, + brMap.has("extra_data") ? brMap.get("extra_data").getAsInt() : -1, + brMap.has("identifier") ? brMap.get("identifier").getAsString() : null, + brMap.has("level_event") && brMap.get("level_event").getAsBoolean() ) ); } diff --git a/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java b/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java index 5b16bc3a3..16a939304 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java +++ b/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java @@ -25,13 +25,11 @@ package org.geysermc.geyser.skin; -import com.fasterxml.jackson.databind.JsonNode; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import it.unimi.dsi.fastutil.bytes.ByteArrays; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; @@ -56,7 +54,9 @@ import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.util.*; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; import java.util.concurrent.*; import java.util.function.Predicate; @@ -486,13 +486,13 @@ public class SkinProvider { public static CompletableFuture<@Nullable String> requestTexturesFromUUID(String uuid) { return CompletableFuture.supplyAsync(() -> { try { - JsonNode node = WebUtils.getJson("https://sessionserver.mojang.com/session/minecraft/profile/" + uuid); - JsonNode properties = node.get("properties"); + JsonObject node = WebUtils.getJson("https://sessionserver.mojang.com/session/minecraft/profile/" + uuid); + JsonObject properties = node.getAsJsonObject("properties"); if (properties == null) { GeyserImpl.getInstance().getLogger().debug("No properties found in Mojang response for " + uuid); return null; } - return node.get("properties").get(0).get("value").asText(); + return node.getAsJsonArray("properties").get(0).getAsJsonObject().get("value").getAsString(); } catch (Exception e) { GeyserImpl.getInstance().getLogger().debug("Unable to request textures for " + uuid); if (GeyserImpl.getInstance().getConfig().isDebugMode()) { @@ -513,13 +513,13 @@ public class SkinProvider { return CompletableFuture.supplyAsync(() -> { try { // Offline skin, or no present UUID - JsonNode node = WebUtils.getJson("https://api.mojang.com/users/profiles/minecraft/" + username); - JsonNode id = node.get("id"); + JsonObject node = WebUtils.getJson("https://api.mojang.com/users/profiles/minecraft/" + username); + JsonElement id = node.get("id"); if (id == null) { GeyserImpl.getInstance().getLogger().debug("No UUID found in Mojang response for " + username); return null; } - return id.asText(); + return id.getAsString(); } catch (Exception e) { if (GeyserImpl.getInstance().getConfig().isDebugMode()) { e.printStackTrace(); diff --git a/core/src/main/java/org/geysermc/geyser/util/VersionCheckUtils.java b/core/src/main/java/org/geysermc/geyser/util/VersionCheckUtils.java index cf90a6bcd..91e7fcbdc 100644 --- a/core/src/main/java/org/geysermc/geyser/util/VersionCheckUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/VersionCheckUtils.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.util; -import com.fasterxml.jackson.databind.JsonNode; +import com.google.gson.JsonObject; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextReplacementConfig; import net.kyori.adventure.text.event.ClickEvent; @@ -92,9 +92,9 @@ public final class VersionCheckUtils { public static void checkForGeyserUpdate(Supplier recipient) { CompletableFuture.runAsync(() -> { try { - JsonNode json = WebUtils.getJson("https://api.geysermc.org/v2/versions/geyser"); - JsonNode bedrock = json.get("bedrock").get("protocol"); - int protocolVersion = bedrock.get("id").asInt(); + JsonObject json = WebUtils.getJson("https://api.geysermc.org/v2/versions/geyser"); + JsonObject bedrock = json.getAsJsonObject("bedrock").getAsJsonObject("protocol"); + int protocolVersion = bedrock.get("id").getAsInt(); if (GameProtocol.getBedrockCodec(protocolVersion) != null) { LATEST_BEDROCK_RELEASE = OptionalInt.empty(); // We support the latest version! No need to print a message. @@ -102,7 +102,7 @@ public final class VersionCheckUtils { } LATEST_BEDROCK_RELEASE = OptionalInt.of(protocolVersion); - final String newBedrockVersion = bedrock.get("name").asText(); + final String newBedrockVersion = bedrock.get("name").getAsString(); // Delayed for two reasons: save unnecessary processing, and wait to load locale if this is on join. GeyserCommandSource sender = recipient.get(); diff --git a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java index 1b7f2d9d9..0e4c7154a 100644 --- a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java @@ -26,6 +26,9 @@ package org.geysermc.geyser.util; import com.fasterxml.jackson.databind.JsonNode; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.stream.JsonReader; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; @@ -71,12 +74,14 @@ public class WebUtils { * @param reqURL URL to fetch * @return the response as JSON */ - public static JsonNode getJson(String reqURL) throws IOException { + public static JsonObject getJson(String reqURL) throws IOException { HttpURLConnection con = (HttpURLConnection) new URL(reqURL).openConnection(); con.setRequestProperty("User-Agent", getUserAgent()); con.setConnectTimeout(10000); con.setReadTimeout(10000); - return GeyserImpl.JSON_MAPPER.readTree(con.getInputStream()); + try (JsonReader reader = GeyserImpl.GSON.newJsonReader(new InputStreamReader(con.getInputStream()))) { + return new JsonParser().parse(reader).getAsJsonObject(); + } } /** diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 962b4a355..3a03f57c7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,8 @@ fastutil = "8.5.2" netty = "4.1.107.Final" netty-io-uring = "0.0.25.Final-SNAPSHOT" guava = "29.0-jre" -gson = "2.3.1" # Provided by Spigot 1.8.8 +gson = "2.3.1" # Provided by Spigot 1.8.8 TODO bump to 2.8.1 or similar (Spigot 1.16.5 version) after Merge +gson-runtime = "2.10.1" websocket = "1.5.1" protocol = "3.0.0.Beta1-20240411.165033-129" protocol-connection = "3.0.0.Beta1-20240411.165033-128" @@ -111,6 +112,7 @@ checker-qual = { group = "org.checkerframework", name = "checker-qual", version. commodore = { group = "me.lucko", name = "commodore", version.ref = "commodore" } guava = { group = "com.google.guava", name = "guava", version.ref = "guava" } gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } +gson-runtime = { group = "com.google.code.gson", name = "gson", version.ref = "gson-runtime" } junit = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" } mcauthlib = { group = "com.github.GeyserMC", name = "MCAuthLib", version.ref = "mcauthlib" } mcprotocollib = { group = "com.github.geysermc", name = "mcprotocollib", version.ref = "mcprotocollib" }