diff --git a/bukkit/src/main/java/me/william278/husksync/bukkit/data/DataSerializer.java b/bukkit/src/main/java/me/william278/husksync/bukkit/data/DataSerializer.java index 3a8a7de2..2235d252 100644 --- a/bukkit/src/main/java/me/william278/husksync/bukkit/data/DataSerializer.java +++ b/bukkit/src/main/java/me/william278/husksync/bukkit/data/DataSerializer.java @@ -16,6 +16,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.Serializable; +import java.time.Instant; import java.util.*; public class DataSerializer { @@ -207,17 +208,23 @@ public class DataSerializer { playerLocation.getYaw(), playerLocation.getPitch(), player.getWorld().getName(), player.getWorld().getEnvironment())); } - public record PlayerLocation(double x, double y, double z, float yaw, float pitch, - String worldName, World.Environment environment) implements Serializable { - } - @SuppressWarnings("unchecked") // Ignore the unchecked cast here - public static ArrayList deserializeAdvancementData(String serializedAdvancementData) throws IOException { + public static List deserializeAdvancementData(String serializedAdvancementData) throws IOException { if (serializedAdvancementData.isEmpty()) { return new ArrayList<>(); } try { - return (ArrayList) RedisMessage.deserialize(serializedAdvancementData); + List deserialize = (List) RedisMessage.deserialize(serializedAdvancementData); + + if (!deserialize.isEmpty() && deserialize.get(0) instanceof AdvancementRecord) { + deserialize = ((List) deserialize).stream() + .map(o -> new AdvancementRecordDate( + o.advancementKey, + o.awardedAdvancementCriteria + )).toList(); + } + + return (List) deserialize; } catch (ClassNotFoundException e) { throw new IOException("Unable to decode class type.", e); } @@ -225,22 +232,21 @@ public class DataSerializer { public static String getSerializedAdvancements(Player player) throws IOException { Iterator serverAdvancements = Bukkit.getServer().advancementIterator(); - ArrayList advancementData = new ArrayList<>(); + ArrayList advancementData = new ArrayList<>(); while (serverAdvancements.hasNext()) { final AdvancementProgress progress = player.getAdvancementProgress(serverAdvancements.next()); final NamespacedKey advancementKey = progress.getAdvancement().getKey(); - final ArrayList awardedCriteria = new ArrayList<>(progress.getAwardedCriteria()); - advancementData.add(new DataSerializer.AdvancementRecord(advancementKey.getNamespace() + ":" + advancementKey.getKey(), awardedCriteria)); + + final Map awardedCriteria = new HashMap<>(); + progress.getAwardedCriteria().forEach(s -> awardedCriteria.put(s, progress.getDateAwarded(s))); + + advancementData.add(new DataSerializer.AdvancementRecordDate(advancementKey.getNamespace() + ":" + advancementKey.getKey(), awardedCriteria)); } return RedisMessage.serialize(advancementData); } - public record AdvancementRecord(String advancementKey, - ArrayList awardedAdvancementCriteria) implements Serializable { - } - public static DataSerializer.StatisticData deserializeStatisticData(String serializedStatisticData) throws IOException { if (serializedStatisticData.isEmpty()) { return new DataSerializer.StatisticData(new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>()); @@ -288,6 +294,22 @@ public class DataSerializer { return RedisMessage.serialize(statisticData); } + public record PlayerLocation(double x, double y, double z, float yaw, float pitch, + String worldName, World.Environment environment) implements Serializable { + } + + public record AdvancementRecord(String advancementKey, + ArrayList awardedAdvancementCriteria) implements Serializable { + } + + public record AdvancementRecordDate(String key, Map criteriaMap) implements Serializable { + AdvancementRecordDate(String key, List criteriaList) { + this(key, new HashMap<>() {{ + criteriaList.forEach(s -> put(s, Date.from(Instant.EPOCH))); + }}); + } + } + public record StatisticData(HashMap untypedStatisticValues, HashMap> blockStatisticValues, HashMap> itemStatisticValues, diff --git a/bukkit/src/main/java/me/william278/husksync/bukkit/util/PlayerSetter.java b/bukkit/src/main/java/me/william278/husksync/bukkit/util/PlayerSetter.java index b1795d36..eb4c3a35 100644 --- a/bukkit/src/main/java/me/william278/husksync/bukkit/util/PlayerSetter.java +++ b/bukkit/src/main/java/me/william278/husksync/bukkit/util/PlayerSetter.java @@ -160,7 +160,7 @@ public class PlayerSetter { // Set the player's data from the PlayerData try { if (Settings.syncAdvancements) { - ArrayList advancementRecords + List advancementRecords = DataSerializer.deserializeAdvancementData(data.getSerializedAdvancements()); if (Settings.useNativeImplementation) { @@ -280,7 +280,7 @@ public class PlayerSetter { } } - private static void nativeSyncPlayerAdvancements(final Player player, final List advancementRecords) { + private static void nativeSyncPlayerAdvancements(final Player player, final List advancementRecords) { final Object playerAdvancements = AdvancementUtils.getPlayerAdvancements(player); // Clear @@ -288,8 +288,8 @@ public class PlayerSetter { advancementRecords.forEach(advancementRecord -> { NamespacedKey namespacedKey = Objects.requireNonNull( - NamespacedKey.fromString(advancementRecord.advancementKey()), - "Invalid Namespaced key of " + advancementRecord.advancementKey() + NamespacedKey.fromString(advancementRecord.key()), + "Invalid Namespaced key of " + advancementRecord.key() ); Advancement bukkitAdvancement = Bukkit.getAdvancement(namespacedKey); @@ -298,20 +298,16 @@ public class PlayerSetter { return; } - // todo: sync date of get advancement - Date date = Date.from(Instant.now().minus(Period.ofWeeks(1))); - Object advancement = AdvancementUtils.getHandle(bukkitAdvancement); - List criteriaList = advancementRecord.awardedAdvancementCriteria(); + Map criteriaList = advancementRecord.criteriaMap(); { Map nativeCriteriaMap = new HashMap<>(); - criteriaList.forEach(criteria -> + criteriaList.forEach((criteria, date) -> nativeCriteriaMap.put(criteria, AdvancementUtils.newCriterionProgress(date)) ); Object nativeAdvancementProgress = AdvancementUtils.newAdvancementProgress(nativeCriteriaMap); AdvancementUtils.startProgress(playerAdvancements, advancement, nativeAdvancementProgress); - } }); @@ -327,7 +323,7 @@ public class PlayerSetter { * @param player The player to set the advancements of * @param advancementData The ArrayList of {@link DataSerializer.AdvancementRecord}s to set */ - private static void setPlayerAdvancements(Player player, ArrayList advancementData, PlayerData data) { + private static void setPlayerAdvancements(Player player, List advancementData, PlayerData data) { // Temporarily disable advancement announcing if needed boolean announceAdvancementUpdate = false; if (Boolean.TRUE.equals(player.getWorld().getGameRuleValue(GameRule.ANNOUNCE_ADVANCEMENTS))) { @@ -345,13 +341,13 @@ public class PlayerSetter { boolean correctExperienceCheck = false; // Determines whether the experience might have changed warranting an update Advancement advancement = serverAdvancements.next(); AdvancementProgress playerProgress = player.getAdvancementProgress(advancement); - for (DataSerializer.AdvancementRecord record : advancementData) { + for (DataSerializer.AdvancementRecordDate record : advancementData) { // If the advancement is one on the data - if (record.advancementKey().equals(advancement.getKey().getNamespace() + ":" + advancement.getKey().getKey())) { + if (record.key().equals(advancement.getKey().getNamespace() + ":" + advancement.getKey().getKey())) { // Award all criteria that the player does not have that they do on the cache ArrayList currentlyAwardedCriteria = new ArrayList<>(playerProgress.getAwardedCriteria()); - for (String awardCriteria : record.awardedAdvancementCriteria()) { + for (String awardCriteria : record.criteriaMap().keySet()) { if (!playerProgress.getAwardedCriteria().contains(awardCriteria)) { Bukkit.getScheduler().runTask(plugin, () -> player.getAdvancementProgress(advancement).awardCriteria(awardCriteria)); correctExperienceCheck = true; diff --git a/bukkit/src/main/java/me/william278/husksync/bukkit/util/nms/AdvancementUtils.java b/bukkit/src/main/java/me/william278/husksync/bukkit/util/nms/AdvancementUtils.java index 4d4b40ec..a7b991fb 100644 --- a/bukkit/src/main/java/me/william278/husksync/bukkit/util/nms/AdvancementUtils.java +++ b/bukkit/src/main/java/me/william278/husksync/bukkit/util/nms/AdvancementUtils.java @@ -43,17 +43,17 @@ public class AdvancementUtils { Class ADVANCEMENT = ThrowSupplier.get(() -> Class.forName("net.minecraft.advancements.Advancement")); - Class PLAYER_ADVANCEMENTS = MinecraftVersionUtils.getMinecraftClass("AdvancementDataPlayer"); - PLAYER_ADVANCEMENTS_MAP = ThrowSupplier.get(() -> PLAYER_ADVANCEMENTS.getDeclaredField("h")); + Class PLAYER_ADVANCEMENT = MinecraftVersionUtils.getMinecraftClass("AdvancementDataPlayer"); + PLAYER_ADVANCEMENTS_MAP = ThrowSupplier.get(() -> PLAYER_ADVANCEMENT.getDeclaredField("h")); PLAYER_ADVANCEMENTS_MAP.setAccessible(true); - START_PROGRESS = ThrowSupplier.get(() -> PLAYER_ADVANCEMENTS.getDeclaredMethod("a", ADVANCEMENT, ADVANCEMENT_PROGRESS)); + START_PROGRESS = ThrowSupplier.get(() -> PLAYER_ADVANCEMENT.getDeclaredMethod("a", ADVANCEMENT, ADVANCEMENT_PROGRESS)); START_PROGRESS.setAccessible(true); - ENSURE_ALL_VISIBLE = ThrowSupplier.get(() -> PLAYER_ADVANCEMENTS.getDeclaredMethod("c")); + ENSURE_ALL_VISIBLE = ThrowSupplier.get(() -> PLAYER_ADVANCEMENT.getDeclaredMethod("c")); ENSURE_ALL_VISIBLE.setAccessible(true); - IS_FIRST_PACKET = ThrowSupplier.get(() -> PLAYER_ADVANCEMENTS.getDeclaredField("n")); + IS_FIRST_PACKET = ThrowSupplier.get(() -> PLAYER_ADVANCEMENT.getDeclaredField("n")); IS_FIRST_PACKET.setAccessible(true); }