Merge branch 'future/nms'

feat/data-edit-commands
William 3 years ago
commit 41e4bc4fdb

@ -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<DataSerializer.AdvancementRecord> deserializeAdvancementData(String serializedAdvancementData) throws IOException {
public static List<DataSerializer.AdvancementRecordDate> deserializeAdvancementData(String serializedAdvancementData) throws IOException {
if (serializedAdvancementData.isEmpty()) {
return new ArrayList<>();
}
try {
return (ArrayList<DataSerializer.AdvancementRecord>) RedisMessage.deserialize(serializedAdvancementData);
List<?> deserialize = (List<?>) RedisMessage.deserialize(serializedAdvancementData);
if (!deserialize.isEmpty() && deserialize.get(0) instanceof AdvancementRecord) {
deserialize = ((List<AdvancementRecord>) deserialize).stream()
.map(o -> new AdvancementRecordDate(
o.advancementKey,
o.awardedAdvancementCriteria
)).toList();
}
return (List<AdvancementRecordDate>) 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<Advancement> serverAdvancements = Bukkit.getServer().advancementIterator();
ArrayList<DataSerializer.AdvancementRecord> advancementData = new ArrayList<>();
ArrayList<DataSerializer.AdvancementRecordDate> advancementData = new ArrayList<>();
while (serverAdvancements.hasNext()) {
final AdvancementProgress progress = player.getAdvancementProgress(serverAdvancements.next());
final NamespacedKey advancementKey = progress.getAdvancement().getKey();
final ArrayList<String> awardedCriteria = new ArrayList<>(progress.getAwardedCriteria());
advancementData.add(new DataSerializer.AdvancementRecord(advancementKey.getNamespace() + ":" + advancementKey.getKey(), awardedCriteria));
final Map<String, Date> 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<String> 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<String> awardedAdvancementCriteria) implements Serializable {
}
public record AdvancementRecordDate(String key, Map<String, Date> criteriaMap) implements Serializable {
AdvancementRecordDate(String key, List<String> criteriaList) {
this(key, new HashMap<>() {{
criteriaList.forEach(s -> put(s, Date.from(Instant.EPOCH)));
}});
}
}
public record StatisticData(HashMap<Statistic, Integer> untypedStatisticValues,
HashMap<Statistic, HashMap<Material, Integer>> blockStatisticValues,
HashMap<Statistic, HashMap<Material, Integer>> itemStatisticValues,

@ -20,8 +20,6 @@ import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import java.io.IOException;
import java.time.Instant;
import java.time.Period;
import java.util.*;
import java.util.logging.Level;
@ -160,7 +158,7 @@ public class PlayerSetter {
// Set the player's data from the PlayerData
try {
if (Settings.syncAdvancements) {
ArrayList<DataSerializer.AdvancementRecord> advancementRecords
List<DataSerializer.AdvancementRecordDate> advancementRecords
= DataSerializer.deserializeAdvancementData(data.getSerializedAdvancements());
if (Settings.useNativeImplementation) {
@ -171,7 +169,7 @@ public class PlayerSetter {
plugin.getLogger().log(Level.WARNING,
"Your server does not support a native implementation of achievements synchronization");
plugin.getLogger().log(Level.WARNING,
"Your server version {0}. Please disable using native implementation!", Bukkit.getVersion());
"Your server version is {0}. Please disable using native implementation!", Bukkit.getVersion());
Settings.useNativeImplementation = false;
setPlayerAdvancements(player, advancementRecords, data);
@ -280,16 +278,17 @@ public class PlayerSetter {
}
}
private static void nativeSyncPlayerAdvancements(final Player player, final List<DataSerializer.AdvancementRecord> advancementRecords) {
private static void nativeSyncPlayerAdvancements(final Player player, final List<DataSerializer.AdvancementRecordDate> advancementRecords) {
final Object playerAdvancements = AdvancementUtils.getPlayerAdvancements(player);
// Clear
AdvancementUtils.clearPlayerAdvancementsMap(playerAdvancements);
AdvancementUtils.clearPlayerAdvancements(playerAdvancements);
AdvancementUtils.clearVisibleAdvancements(playerAdvancements);
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,26 +297,21 @@ 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<String> criteriaList = advancementRecord.awardedAdvancementCriteria();
Map<String, Date> criteriaList = advancementRecord.criteriaMap();
{
Map<String, Object> 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);
}
});
synchronized (playerAdvancements) {
AdvancementUtils.markPlayerAdvancementsFirst(playerAdvancements);
AdvancementUtils.ensureAllVisible(playerAdvancements);
AdvancementUtils.ensureAllVisible(playerAdvancements); // Set all completed advancement is visible
AdvancementUtils.markPlayerAdvancementsFirst(playerAdvancements); // Mark the sending of visible advancement as the first
}
}
@ -327,7 +321,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<DataSerializer.AdvancementRecord> advancementData, PlayerData data) {
private static void setPlayerAdvancements(Player player, List<DataSerializer.AdvancementRecordDate> advancementData, PlayerData data) {
// Temporarily disable advancement announcing if needed
boolean announceAdvancementUpdate = false;
if (Boolean.TRUE.equals(player.getWorld().getGameRuleValue(GameRule.ANNOUNCE_ADVANCEMENTS))) {
@ -345,13 +339,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<String> 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;

@ -9,19 +9,20 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;
import java.util.Set;
public class AdvancementUtils {
public final static Class<?> PLAYER_ADVANCEMENT;
private final static Field PLAYER_ADVANCEMENTS_MAP;
private final static Field PLAYER_VISIBLE_SET;
private final static Field PLAYER_ADVANCEMENTS;
private final static Field CRITERIA_MAP;
private final static Field CRITERIA_DATE;
private final static Field IS_FIRST_PACKET;
private final static Method GET_HANDLE;
private final static Method START_PROGRESS;
private final static Method ENSURE_ALL_VISIBLE;
private final static Class<?> ADVANCEMENT_PROGRESS;
private final static Class<?> CRITERION_PROGRESS;
@ -43,21 +44,24 @@ 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"));
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));
PLAYER_VISIBLE_SET = ThrowSupplier.get(() -> PLAYER_ADVANCEMENT.getDeclaredField("i"));
PLAYER_VISIBLE_SET.setAccessible(true);
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);
}
public static void markPlayerAdvancementsFirst(Object playerAdvancements) {
public static void markPlayerAdvancementsFirst(final Object playerAdvancements) {
try {
IS_FIRST_PACKET.set(playerAdvancements, true);
} catch (IllegalAccessException e) {
@ -74,7 +78,7 @@ public class AdvancementUtils {
}
}
public static void clearPlayerAdvancementsMap(final Object playerAdvancement) {
public static void clearPlayerAdvancements(final Object playerAdvancement) {
try {
((Map<?, ?>) PLAYER_ADVANCEMENTS_MAP.get(playerAdvancement))
.clear();
@ -130,4 +134,12 @@ public class AdvancementUtils {
}
}
public static void clearVisibleAdvancements(final Object playerAdvancements) {
try {
((Set<?>) PLAYER_VISIBLE_SET.get(playerAdvancements))
.clear();
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}

@ -119,7 +119,7 @@ public class BungeeRedisListener extends RedisListener {
if (player.isConnected()) {
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_SET,
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, playerData.getPlayerUUID(), message.getMessageTarget().targetClusterId()),
RedisMessage.serialize(playerData))
serializedPlayerData)
.send();
// Send synchronisation complete message

Loading…
Cancel
Save