From 07c52e2a38d5654a6816782bf2b1d1149584022a Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Tue, 29 Dec 2020 15:21:04 -0800 Subject: [PATCH] Advancements API --- Spigot-API-Patches/0244-Advancement-API.patch | 4160 ++++++++++++++ .../0623-Advancement-API.patch | 4803 +++++++++++++++++ 2 files changed, 8963 insertions(+) create mode 100644 Spigot-API-Patches/0244-Advancement-API.patch create mode 100644 Spigot-Server-Patches/0623-Advancement-API.patch diff --git a/Spigot-API-Patches/0244-Advancement-API.patch b/Spigot-API-Patches/0244-Advancement-API.patch new file mode 100644 index 000000000000..38096bdf92a0 --- /dev/null +++ b/Spigot-API-Patches/0244-Advancement-API.patch @@ -0,0 +1,4160 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 29 Dec 2020 15:19:52 -0800 +Subject: [PATCH] Advancement API + + +diff --git a/src/main/java/io/papermc/paper/advancements/AdvancementDisplay.java b/src/main/java/io/papermc/paper/advancements/AdvancementDisplay.java +new file mode 100644 +index 0000000000000000000000000000000000000000..40f8f03525c49f71647c088fa6f19397fbb67714 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/AdvancementDisplay.java +@@ -0,0 +1,103 @@ ++package io.papermc.paper.advancements; ++ ++import org.bukkit.NamespacedKey; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class AdvancementDisplay { ++ ++ private final String title; // TODO Component ++ private final String description; // TODO Component ++ private final ItemStack icon; ++ private final NamespacedKey background; ++ private final AdvancementFrameType frameType; ++ private final boolean showToast; ++ private final boolean announceToChat; ++ private final boolean hidden; ++ ++ public AdvancementDisplay(String title, String description, ItemStack icon, NamespacedKey background, AdvancementFrameType frameType, boolean showToast, boolean announceToChat, boolean hidden) { // TODO Component ++ this.title = title; ++ this.description = description; ++ this.icon = icon; ++ this.background = background; ++ this.frameType = frameType; ++ this.showToast = showToast; ++ this.announceToChat = announceToChat; ++ this.hidden = hidden; ++ } ++ ++ public String title() { // TODO Component ++ return null; ++ } ++ ++ public String description() { // TODO Component ++ return null; ++ } ++ ++ public ItemStack getIcon() { ++ return icon; ++ } ++ ++ public NamespacedKey getBackground() { ++ return background; ++ } ++ ++ public AdvancementFrameType getFrame() { ++ return frameType; ++ } ++ ++ public boolean getShowToast() { ++ return showToast; ++ } ++ ++ public boolean getAnnounceToChat() { ++ return announceToChat; ++ } ++ ++ public boolean getHidden() { ++ return hidden; ++ } ++ ++ @Override ++ public String toString() { ++ return "CraftAdvancementDisplay{" + ++ "title='" + title + '\'' + ++ ", description='" + description + '\'' + ++ ", icon=" + icon + ++ ", background=" + background + ++ ", frameType=" + frameType + ++ ", showToast=" + showToast + ++ ", announceToChat=" + announceToChat + ++ ", hidden=" + hidden + ++ '}'; ++ } ++ ++ public enum AdvancementFrameType { ++ TASK("task"), ++ CHALLENGE("challenge"), ++ GOAL("goal"); ++ ++ private String text; ++ AdvancementFrameType (String text) { ++ this.text = text; ++ } ++ ++ public String getText() { ++ return text; ++ } ++ ++ @Nullable ++ public static AdvancementFrameType getByText(@Nullable String text) { ++ if (text == null) return null; ++ for (AdvancementFrameType value : AdvancementFrameType.values()) { ++ if (value.getText().equals(text)) return value; ++ } ++ return null; ++ } ++ } ++ ++ public static interface Builder { ++ ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/AdvancementRewards.java b/src/main/java/io/papermc/paper/advancements/AdvancementRewards.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4e6e62e5712a1eaace1528a0b6f76af589897154 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/AdvancementRewards.java +@@ -0,0 +1,104 @@ ++package io.papermc.paper.advancements; ++ ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.Contract; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++import java.util.Collection; ++ ++public class AdvancementRewards { ++ ++ private int exp = 0; ++ private Collection loot; ++ private Collection recipes; ++ private NamespacedKey function = null; ++ ++ public AdvancementRewards(int exp, Collection loot, Collection recipes, NamespacedKey function) { ++ this.exp = exp; ++ this.loot = loot; ++ this.recipes = recipes; ++ this.function = function; ++ } ++ ++ public AdvancementRewards() { } ++ ++ public int getExp() { ++ return exp; ++ } ++ ++ public Collection getLoot() { ++ return loot; ++ } ++ ++ public Collection getRecipes() { ++ return recipes; ++ } ++ ++ public NamespacedKey getFunction() { ++ return function; ++ } ++ ++ @Override ++ public String toString() { ++ return "CraftAdvancementRewards{" + ++ "exp=" + exp + ++ ", loot=" + loot + ++ ", recipes=" + recipes + ++ ", function=" + function + ++ '}'; ++ } ++ ++ public AdvancementRewardsBuilder edit() { ++ return new AdvancementRewardsBuilder(this); ++ } ++ ++ public static boolean isEmpty(AdvancementRewards advancementRewards) { ++ return advancementRewards.getExp() == 0 && advancementRewards.getRecipes().size() == 0 && advancementRewards.getLoot().size() == 0 && advancementRewards.getFunction() == null; ++ } ++ ++ public static AdvancementRewardsBuilder builder() { ++ return new AdvancementRewardsBuilder(); ++ } ++ ++ public static final class AdvancementRewardsBuilder { ++ private int exp = 0; ++ private Collection loot; ++ private Collection recipes; ++ private NamespacedKey function = null; ++ ++ private AdvancementRewardsBuilder() { } ++ ++ private AdvancementRewardsBuilder(AdvancementRewards rewards) { ++ this.exp = rewards.exp; ++ this.loot = rewards.loot; ++ this.recipes = rewards.recipes; ++ this.function = rewards.function; ++ } ++ ++ public AdvancementRewardsBuilder exp(int exp) { ++ this.exp = exp; ++ return this; ++ } ++ ++ public AdvancementRewardsBuilder loot(Collection loot) { ++ this.loot = loot; ++ return this; ++ } ++ ++ public AdvancementRewardsBuilder recipes(Collection recipes) { ++ this.recipes = recipes; ++ return this; ++ } ++ ++ public AdvancementRewardsBuilder function(NamespacedKey function) { ++ this.function = function; ++ return this; ++ } ++ ++ @NotNull ++ public AdvancementRewards build() { ++ return new AdvancementRewards(exp, loot, recipes, function); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/AdvancementsManager.java b/src/main/java/io/papermc/paper/advancements/AdvancementsManager.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5e6d6f879703ea284dfe41c5c956210bb4b9aa57 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/AdvancementsManager.java +@@ -0,0 +1,12 @@ ++package io.papermc.paper.advancements; ++ ++import org.bukkit.advancement.Advancement; ++import org.jetbrains.annotations.NotNull; ++ ++public interface AdvancementsManager { ++ ++ @NotNull ++ Advancement createAdvancement(@NotNull String key); ++ ++ void reload(); ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/AbstractLocationTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/AbstractLocationTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2ed06121c696defb5d7728d2bd8584693c39ca44 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/AbstractLocationTrigger.java +@@ -0,0 +1,61 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.LocationCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public abstract class AbstractLocationTrigger extends PlayerTrigger { ++ ++ private final LocationCondition location; ++ ++ protected AbstractLocationTrigger(@NotNull NamespacedKey key, @NotNull EntityPredicatesCondition player, @NotNull LocationCondition location) { ++ super(key, player); ++ this.location = location; ++ } ++ ++ @NotNull ++ public LocationCondition getLocation() { ++ return location; ++ } ++ ++ public static class LocationTrigger extends AbstractLocationTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("location"); ++ ++ public LocationTrigger(@NotNull EntityPredicatesCondition player, @NotNull LocationCondition location) { ++ super(KEY, player, location); ++ } ++ } ++ ++ public static class SleptInBedTrigger extends AbstractLocationTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("slept_in_bed"); ++ ++ public SleptInBedTrigger(@NotNull EntityPredicatesCondition player, @NotNull LocationCondition location) { ++ super(KEY, player, location); ++ } ++ } ++ ++ public static class HeroOfTheVillageTrigger extends AbstractLocationTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("hero_of_the_village"); ++ ++ public HeroOfTheVillageTrigger(@NotNull EntityPredicatesCondition player, @NotNull LocationCondition location) { ++ super(KEY, player, location); ++ } ++ } ++ ++ public static class VoluntaryExileTrigger extends AbstractLocationTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("voluntary_exile"); ++ ++ public VoluntaryExileTrigger(@NotNull EntityPredicatesCondition player, @NotNull LocationCondition location) { ++ super(KEY, player, location); ++ } ++ } ++ ++ ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/BeeNestDestroyedTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/BeeNestDestroyedTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6698f7d821602a8942070bcee15d4ba7c7fc82d9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/BeeNestDestroyedTrigger.java +@@ -0,0 +1,41 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import org.bukkit.Material; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class BeeNestDestroyedTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("bee_nest_destroyed"); ++ ++ private final Material block; ++ private final ItemCondition item; ++ private final IntegerRange numOfBees; ++ ++ public BeeNestDestroyedTrigger(@NotNull EntityPredicatesCondition player, @Nullable Material block, @NotNull ItemCondition item, @NotNull IntegerRange numOfBees) { ++ super(KEY, player); ++ this.block = block; ++ this.item = item; ++ this.numOfBees = numOfBees; ++ } ++ ++ @Nullable ++ public Material getBlock() { ++ return block; ++ } ++ ++ @NotNull ++ public ItemCondition getItem() { ++ return item; ++ } ++ ++ @NotNull ++ public IntegerRange getNumOfBees() { ++ return numOfBees; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/BredAnimalsTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/BredAnimalsTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e147077dce8c5ce847e9b5800d1eab92c23ccd90 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/BredAnimalsTrigger.java +@@ -0,0 +1,38 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class BredAnimalsTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("bred_animals"); ++ ++ private final EntityPredicatesCondition parent; ++ private final EntityPredicatesCondition partner; ++ private final EntityPredicatesCondition child; ++ ++ public BredAnimalsTrigger(@NotNull EntityPredicatesCondition player, @NotNull EntityPredicatesCondition parent, @NotNull EntityPredicatesCondition partner, @NotNull EntityPredicatesCondition child) { ++ super(KEY, player); ++ this.parent = parent; ++ this.partner = partner; ++ this.child = child; ++ } ++ ++ @NotNull ++ public EntityPredicatesCondition getParent() { ++ return parent; ++ } ++ ++ @NotNull ++ public EntityPredicatesCondition getPartner() { ++ return partner; ++ } ++ ++ @NotNull ++ public EntityPredicatesCondition getChild() { ++ return child; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/BrewedPotionTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/BrewedPotionTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b441e932cccaa5cebe92f52125a9d4def02c5fbe +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/BrewedPotionTrigger.java +@@ -0,0 +1,25 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import org.bukkit.NamespacedKey; ++import org.bukkit.potion.PotionEffectType; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class BrewedPotionTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("brewed_potion"); ++ ++ private final PotionEffectType effectType; ++ ++ public BrewedPotionTrigger(@NotNull EntityPredicatesCondition player, @Nullable PotionEffectType effectType) { ++ super(KEY, player); ++ this.effectType = effectType; ++ } ++ ++ @Nullable ++ public PotionEffectType getEffectType() { ++ return effectType; ++} ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/ChangedDimensionTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/ChangedDimensionTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a695374f4a3db6785e31d48410dc53109090ccfa +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/ChangedDimensionTrigger.java +@@ -0,0 +1,32 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import org.bukkit.NamespacedKey; ++import org.bukkit.World; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class ChangedDimensionTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("changed_dimension"); ++ ++ private final NamespacedKey from; ++ private final NamespacedKey to; ++ ++ public ChangedDimensionTrigger(@NotNull EntityPredicatesCondition player, @Nullable NamespacedKey from, @Nullable NamespacedKey to) { ++ super(KEY, player); ++ this.from = from; ++ this.to = to; ++ } ++ ++ @Nullable ++ public NamespacedKey getFrom() { ++ return from; ++ } ++ ++ @Nullable ++ public NamespacedKey getTo() { ++ return to; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/ChanneledLightningTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/ChanneledLightningTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b64e07fbdb2bf82376e4f622fffc252cc3812ec1 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/ChanneledLightningTrigger.java +@@ -0,0 +1,23 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class ChanneledLightningTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("channeled_lightning"); ++ ++ private final EntityPredicatesCondition[] victims; ++ ++ public ChanneledLightningTrigger(@NotNull EntityPredicatesCondition player, @NotNull EntityPredicatesCondition[] victims) { ++ super(KEY, player); ++ this.victims = victims; ++ } ++ ++ @NotNull ++ public EntityPredicatesCondition[] getVictims() { ++ return victims; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/ConstructBeaconTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/ConstructBeaconTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0a8c83d3d3fb2a2204ea4616f0ce2b3da601b7fe +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/ConstructBeaconTrigger.java +@@ -0,0 +1,25 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class ConstructBeaconTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("construct_beacon"); ++ ++ private final IntegerRange level; ++ ++ public ConstructBeaconTrigger(@NotNull EntityPredicatesCondition player, IntegerRange level) { ++ super(KEY, player); ++ this.level = level; ++ } ++ ++ @NotNull ++ public IntegerRange getLevel() { ++ return level; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/ConsumeItemTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/ConsumeItemTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..01d0b517e78d012cd8b45cdfeb355f32de37a649 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/ConsumeItemTrigger.java +@@ -0,0 +1,24 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class ConsumeItemTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("consume_item"); ++ ++ private final ItemCondition item; ++ ++ public ConsumeItemTrigger(@NotNull EntityPredicatesCondition player, @NotNull ItemCondition item) { ++ super(KEY, player); ++ this.item = item; ++ } ++ ++ @NotNull ++ public ItemCondition getItem() { ++ return item; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/CuredZombieVillagerTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/CuredZombieVillagerTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..20c95064d752528d4fc485b21be994b9810d16f3 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/CuredZombieVillagerTrigger.java +@@ -0,0 +1,31 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class CuredZombieVillagerTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("cured_zombie_villager"); ++ ++ private final EntityPredicatesCondition zombie; ++ private final EntityPredicatesCondition villager; ++ ++ public CuredZombieVillagerTrigger(@NotNull EntityPredicatesCondition player, @NotNull EntityPredicatesCondition zombie, @NotNull EntityPredicatesCondition villager) { ++ super(KEY, player); ++ this.zombie = zombie; ++ this.villager = villager; ++ } ++ ++ @NotNull ++ public EntityPredicatesCondition getZombie() { ++ return zombie; ++ } ++ ++ @NotNull ++ public EntityPredicatesCondition getVillager() { ++ return villager; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/EffectsChangedTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/EffectsChangedTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4d696fd195d20e527ffa42c2d97b2a1abe12924d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/EffectsChangedTrigger.java +@@ -0,0 +1,24 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EffectsCondition; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class EffectsChangedTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("effects_changed"); ++ ++ private final EffectsCondition effects; ++ ++ public EffectsChangedTrigger(@NotNull EntityPredicatesCondition player, @NotNull EffectsCondition effects) { ++ super(KEY, player); ++ this.effects = effects; ++ } ++ ++ @NotNull ++ public EffectsCondition getEffects() { ++ return effects; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/EnchantedItemTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/EnchantedItemTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d5549381c7eecb31f2899732173d5371b1b5d403 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/EnchantedItemTrigger.java +@@ -0,0 +1,32 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class EnchantedItemTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("enchanted_item"); ++ ++ private final ItemCondition item; ++ private final IntegerRange levels; ++ ++ public EnchantedItemTrigger(@NotNull EntityPredicatesCondition player, @NotNull ItemCondition item, @NotNull IntegerRange levels) { ++ super(KEY, player); ++ this.item = item; ++ this.levels = levels; ++ } ++ ++ @NotNull ++ public ItemCondition getItem() { ++ return item; ++ } ++ ++ @NotNull ++ public IntegerRange getLevels() { ++ return levels; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/EnterBlockTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/EnterBlockTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..66ba93013bad1df4b9c5cbef65e0baaa0c69eb6e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/EnterBlockTrigger.java +@@ -0,0 +1,33 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.StateCondition; ++import org.bukkit.Material; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class EnterBlockTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("enter_block"); ++ ++ private final Material block; ++ private final StateCondition state; ++ ++ public EnterBlockTrigger(@NotNull EntityPredicatesCondition player, @Nullable Material block, @NotNull StateCondition state) { ++ super(KEY, player); ++ this.block = block; ++ this.state = state; ++ } ++ ++ @Nullable ++ public Material getBlock() { ++ return block; ++ } ++ ++ @NotNull ++ public StateCondition getState() { ++ return state; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/EntityHurtPlayerTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/EntityHurtPlayerTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1fe6f336526f559eff44b57f197e467de2c2d1ae +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/EntityHurtPlayerTrigger.java +@@ -0,0 +1,24 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.DamageCondition; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class EntityHurtPlayerTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("entity_hurt_player"); ++ ++ private final DamageCondition damageCondition; ++ ++ public EntityHurtPlayerTrigger(@NotNull EntityPredicatesCondition player, @NotNull DamageCondition damageCondition) { ++ super(KEY, player); ++ this.damageCondition = damageCondition; ++ } ++ ++ @NotNull ++ public DamageCondition getDamageCondition() { ++ return damageCondition; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/FilledBucketTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/FilledBucketTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..93d977487ce7b9e05a87a72a4537dc94ac394288 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/FilledBucketTrigger.java +@@ -0,0 +1,24 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class FilledBucketTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("filled_bucket"); ++ ++ private final ItemCondition item; ++ ++ public FilledBucketTrigger(@NotNull EntityPredicatesCondition player, @NotNull ItemCondition item) { ++ super(KEY, player); ++ this.item = item; ++ } ++ ++ @NotNull ++ public ItemCondition getItem() { ++ return item; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/FishingRodHookedTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/FishingRodHookedTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..fbac2260a21eff2d8fe73be13011799ddbb15a07 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/FishingRodHookedTrigger.java +@@ -0,0 +1,38 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class FishingRodHookedTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("fishing_rod_hooked"); ++ ++ private final ItemCondition rod; ++ private final EntityPredicatesCondition entity; ++ private final ItemCondition item; ++ ++ public FishingRodHookedTrigger(@NotNull EntityPredicatesCondition player, @NotNull ItemCondition rod, @NotNull EntityPredicatesCondition entity, @NotNull ItemCondition item) { ++ super(KEY, player); ++ this.rod = rod; ++ this.entity = entity; ++ this.item = item; ++ } ++ ++ @NotNull ++ public ItemCondition getRod() { ++ return rod; ++ } ++ ++ @NotNull ++ public EntityPredicatesCondition getEntity() { ++ return entity; ++ } ++ ++ @NotNull ++ public ItemCondition getItem() { ++ return item; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/GenerateLootTableTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/GenerateLootTableTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..df4c18b075a0d06a24d42d1054820ef9c2290256 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/GenerateLootTableTrigger.java +@@ -0,0 +1,23 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class GenerateLootTableTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("player_generates_container_loot"); ++ ++ private final NamespacedKey loottable; ++ ++ public GenerateLootTableTrigger(@NotNull EntityPredicatesCondition player, @NotNull NamespacedKey loottable) { ++ super(KEY, player); ++ this.loottable = loottable; ++ } ++ ++ @NotNull ++ public NamespacedKey getLoottable() { ++ return loottable; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/ImpossibleTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/ImpossibleTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..82b3f606901970a05c9ae354598662bce9a8167f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/ImpossibleTrigger.java +@@ -0,0 +1,12 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import org.bukkit.NamespacedKey; ++ ++public class ImpossibleTrigger extends Trigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("impossible"); ++ ++ public ImpossibleTrigger() { ++ super(KEY); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/InteractBlockTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/InteractBlockTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..12540d88ebcb829027690b0c9c9ff2e8e42d5cd8 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/InteractBlockTrigger.java +@@ -0,0 +1,32 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import io.papermc.paper.advancements.triggers.conditions.LocationCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class InteractBlockTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("item_used_on_block"); ++ ++ private final LocationCondition location; ++ private final ItemCondition item; ++ ++ public InteractBlockTrigger(@NotNull EntityPredicatesCondition player, @NotNull LocationCondition location, @NotNull ItemCondition item) { ++ super(KEY, player); ++ this.location = location; ++ this.item = item; ++ } ++ ++ @NotNull ++ public LocationCondition getLocation() { ++ return location; ++ } ++ ++ @NotNull ++ public ItemCondition getItem() { ++ return item; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/InventoryChangedTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/InventoryChangedTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..cb324edbfabe0f09bcf67cfad50feaa5f23738db +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/InventoryChangedTrigger.java +@@ -0,0 +1,46 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition.ItemsCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class InventoryChangedTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("inventory_changed"); ++ ++ private final IntegerRange occupied; ++ private final IntegerRange full; ++ private final IntegerRange empty; ++ private final ItemsCondition items; ++ ++ public InventoryChangedTrigger(@NotNull EntityPredicatesCondition player, @NotNull IntegerRange occupied, @NotNull IntegerRange full, @NotNull IntegerRange empty, @NotNull ItemsCondition items) { ++ super(KEY, player); ++ this.occupied = occupied; ++ this.full = full; ++ this.empty = empty; ++ this.items = items; ++ } ++ ++ @NotNull ++ public IntegerRange getOccupied() { ++ return occupied; ++ } ++ ++ @NotNull ++ public IntegerRange getFull() { ++ return full; ++ } ++ ++ @NotNull ++ public IntegerRange getEmpty() { ++ return empty; ++ } ++ ++ @NotNull ++ public ItemsCondition getItems() { ++ return items; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/ItemDurabilityChangeTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/ItemDurabilityChangeTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b3d2313a47dbda0dcc2a2e6dc05e925a98ec27a7 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/ItemDurabilityChangeTrigger.java +@@ -0,0 +1,40 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class ItemDurabilityChangeTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("item_durability_changed"); ++ ++ private final ItemCondition item; ++ private final IntegerRange durability; ++ private final IntegerRange delta; ++ ++ public ItemDurabilityChangeTrigger(@Nullable EntityPredicatesCondition player, @NotNull ItemCondition item, @NotNull IntegerRange durability, @NotNull IntegerRange delta) { ++ super(KEY, player); ++ this.item = item; ++ this.durability = durability; ++ this.delta = delta; ++ } ++ ++ @NotNull ++ public ItemCondition getItem() { ++ return item; ++ } ++ ++ @NotNull ++ public IntegerRange getDurability() { ++ return durability; ++ } ++ ++ @NotNull ++ public IntegerRange getDelta() { ++ return delta; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/KilledByCrossbowTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/KilledByCrossbowTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d7346563616aebc028816f20a725db8bc57d490f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/KilledByCrossbowTrigger.java +@@ -0,0 +1,31 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class KilledByCrossbowTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("killed_by_crossbow"); ++ ++ private final EntityPredicatesCondition[] victims; ++ private final IntegerRange uniqueEntityTypes; ++ ++ public KilledByCrossbowTrigger(@NotNull EntityPredicatesCondition player, @NotNull EntityPredicatesCondition[] victims, @NotNull IntegerRange uniqueEntityTypes) { ++ super(KEY, player); ++ this.victims = victims; ++ this.uniqueEntityTypes = uniqueEntityTypes; ++ } ++ ++ @NotNull ++ public EntityPredicatesCondition[] getVictims() { ++ return victims; ++ } ++ ++ @NotNull ++ public IntegerRange getUniqueEntityTypes() { ++ return uniqueEntityTypes; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/KilledTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/KilledTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3f866a0cb0663e956600cde45383e53d909e66d4 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/KilledTrigger.java +@@ -0,0 +1,47 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.DamageSourceCondition; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public abstract class KilledTrigger extends PlayerTrigger { ++ ++ private final EntityPredicatesCondition entityPredicates; ++ private final DamageSourceCondition damageSource; ++ ++ protected KilledTrigger(@NotNull NamespacedKey key, @NotNull EntityPredicatesCondition player, @NotNull EntityPredicatesCondition entityPredicates, @NotNull DamageSourceCondition damageSource) { ++ super(key, player); ++ this.entityPredicates = entityPredicates; ++ this.damageSource = damageSource; ++ } ++ ++ @NotNull ++ public EntityPredicatesCondition getEntityPredicates() { ++ return entityPredicates; ++ } ++ ++ @NotNull ++ public DamageSourceCondition getDamageSource() { ++ return damageSource; ++ } ++ ++ public static class PlayerKilledEntityTrigger extends KilledTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("player_killed_entity"); ++ ++ public PlayerKilledEntityTrigger(@NotNull EntityPredicatesCondition player, @NotNull EntityPredicatesCondition entityPredicates, @NotNull DamageSourceCondition damageSource) { ++ super(KEY, player, entityPredicates, damageSource); ++ } ++ } ++ ++ public static class EntityKilledPlayerTrigger extends KilledTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("entity_killed_player"); ++ ++ public EntityKilledPlayerTrigger(@NotNull EntityPredicatesCondition player, @NotNull EntityPredicatesCondition entityPredicates, @NotNull DamageSourceCondition damageSource) { ++ super(KEY, player, entityPredicates, damageSource); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/LevitationTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/LevitationTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a0a25f6f71d94c43590d19629fe6a5f22f63bf2d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/LevitationTrigger.java +@@ -0,0 +1,33 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.DistanceCondition; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class LevitationTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("levitation"); ++ ++ private final DistanceCondition distance; ++ private final IntegerRange duration; ++ ++ public LevitationTrigger(@NotNull EntityPredicatesCondition player, @NotNull DistanceCondition distance, @NotNull IntegerRange duration) { ++ super(KEY, player); ++ this.distance = distance; ++ this.duration = duration; ++ } ++ ++ @NotNull ++ public DistanceCondition getDistance() { ++ return distance; ++ } ++ ++ @NotNull ++ public IntegerRange getDuration() { ++ return duration; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/NetherTravelTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/NetherTravelTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..01f6a871553d0e09206b89b365ef493487c15bc1 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/NetherTravelTrigger.java +@@ -0,0 +1,39 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.DistanceCondition; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.LocationCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class NetherTravelTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("nether_travel"); ++ ++ private final LocationCondition entered; ++ private final LocationCondition exited; ++ private final DistanceCondition distance; ++ ++ public NetherTravelTrigger(@NotNull EntityPredicatesCondition player, @NotNull LocationCondition entered, @NotNull LocationCondition exited, @NotNull DistanceCondition distance) { ++ super(KEY, player); ++ this.entered = entered; ++ this.exited = exited; ++ this.distance = distance; ++ } ++ ++ @NotNull ++ public LocationCondition getEntered() { ++ return entered; ++ } ++ ++ @NotNull ++ public LocationCondition getExited() { ++ return exited; ++ } ++ ++ @NotNull ++ public DistanceCondition getDistance() { ++ return distance; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/PlacedBlockTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/PlacedBlockTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..fa7a14a6d2f8ebf421bd51ef409980b4e636260b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/PlacedBlockTrigger.java +@@ -0,0 +1,49 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import io.papermc.paper.advancements.triggers.conditions.LocationCondition; ++import io.papermc.paper.advancements.triggers.conditions.StateCondition; ++import org.bukkit.Material; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class PlacedBlockTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("placed_block"); ++ ++ private final Material block; ++ private final StateCondition state; ++ private final LocationCondition location; ++ private final ItemCondition item; ++ ++ public PlacedBlockTrigger(@NotNull EntityPredicatesCondition player, @Nullable Material block, @NotNull StateCondition state, @NotNull LocationCondition location, @NotNull ItemCondition item) { ++ super(KEY, player); ++ this.block = block; ++ this.state = state; ++ this.location = location; ++ this.item = item; ++ } ++ ++ @Nullable ++ public Material getBlock() { ++ return block; ++ } ++ ++ @NotNull ++ public StateCondition getState() { ++ return state; ++ } ++ ++ @NotNull ++ public LocationCondition getLocation() { ++ return location; ++ } ++ ++ @NotNull ++ public ItemCondition getItem() { ++ return item; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/PlayerHurtEntityTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/PlayerHurtEntityTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..298fedc840fbad0ea18ef9c0f4a5727a82a7a939 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/PlayerHurtEntityTrigger.java +@@ -0,0 +1,31 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.DamageCondition; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class PlayerHurtEntityTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("player_hurt_entity"); ++ ++ private final DamageCondition damage; ++ private final EntityPredicatesCondition entityPredicates; ++ ++ public PlayerHurtEntityTrigger(@NotNull EntityPredicatesCondition player, @NotNull DamageCondition damage, @NotNull EntityPredicatesCondition entityPredicates) { ++ super(KEY, player); ++ this.damage = damage; ++ this.entityPredicates = entityPredicates; ++ } ++ ++ @NotNull ++ public DamageCondition getDamage() { ++ return damage; ++ } ++ ++ @NotNull ++ public EntityPredicatesCondition getEntityPredicates() { ++ return entityPredicates; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/PlayerInteractWithEntityTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/PlayerInteractWithEntityTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..beafd7e80bdcfc5fd9fce8d74665891298f0026b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/PlayerInteractWithEntityTrigger.java +@@ -0,0 +1,31 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class PlayerInteractWithEntityTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("player_interacted_with_entity"); ++ ++ private final ItemCondition item; ++ private final EntityPredicatesCondition entity; ++ ++ public PlayerInteractWithEntityTrigger(@NotNull EntityPredicatesCondition player, @NotNull ItemCondition item, @NotNull EntityPredicatesCondition entity) { ++ super(KEY, player); ++ this.item = item; ++ this.entity = entity; ++ } ++ ++ @NotNull ++ public ItemCondition getItem() { ++ return item; ++ } ++ ++ @NotNull ++ public EntityPredicatesCondition getEntity() { ++ return entity; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/RecipeUnlockedTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/RecipeUnlockedTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3797dd0311fc45f4c8ff749a83e1649df6b92d7b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/RecipeUnlockedTrigger.java +@@ -0,0 +1,23 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class RecipeUnlockedTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("recipe_unlocked"); ++ ++ private final NamespacedKey recipe; ++ ++ public RecipeUnlockedTrigger(@NotNull EntityPredicatesCondition player, @NotNull NamespacedKey recipe) { ++ super(KEY, player); ++ this.recipe = recipe; ++ } ++ ++ @NotNull ++ public NamespacedKey getRecipe() { ++ return recipe; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/ShotCrossbowTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/ShotCrossbowTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0c5bc36d41ace9a65e0ed151ccc141193c97de54 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/ShotCrossbowTrigger.java +@@ -0,0 +1,24 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class ShotCrossbowTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("shot_crossbow"); ++ ++ private final ItemCondition item; ++ ++ public ShotCrossbowTrigger(@NotNull EntityPredicatesCondition player, @NotNull ItemCondition item) { ++ super(KEY, player); ++ this.item = item; ++ } ++ ++ @NotNull ++ public ItemCondition getItem() { ++ return item; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/SlideDownBlockTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/SlideDownBlockTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..750177e931275f56152127d38c68ec366b83e6e6 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/SlideDownBlockTrigger.java +@@ -0,0 +1,33 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.StateCondition; ++import org.bukkit.Material; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class SlideDownBlockTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("slide_down_block"); ++ ++ private final Material block; ++ private final StateCondition state; ++ ++ public SlideDownBlockTrigger(@NotNull EntityPredicatesCondition player, @Nullable Material block, @NotNull StateCondition state) { ++ super(KEY, player); ++ this.block = block; ++ this.state = state; ++ } ++ ++ @Nullable ++ public Material getBlock() { ++ return block; ++ } ++ ++ @NotNull ++ public StateCondition getState() { ++ return state; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/SummonedEntityTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/SummonedEntityTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..209038d6741a990c29e9c1a26a19f423a1494589 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/SummonedEntityTrigger.java +@@ -0,0 +1,24 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class SummonedEntityTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("summoned_entity"); ++ ++ private final EntityPredicatesCondition entityPredicates; ++ ++ public SummonedEntityTrigger(@NotNull EntityPredicatesCondition player, @NotNull EntityPredicatesCondition entityPredicates) { ++ super(KEY, player); ++ this.entityPredicates = entityPredicates; ++ } ++ ++ @NotNull ++ public EntityPredicatesCondition getEntityPredicates() { ++ return entityPredicates; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/TamedAnimalTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/TamedAnimalTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5d29af792cda2df94fb15a15dfd6920d8f06b9f9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/TamedAnimalTrigger.java +@@ -0,0 +1,23 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class TamedAnimalTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("tame_animal"); ++ ++ private final EntityPredicatesCondition tamedEntity; ++ ++ public TamedAnimalTrigger(@NotNull EntityPredicatesCondition player, @NotNull EntityPredicatesCondition tamedEntity) { ++ super(KEY, player); ++ this.tamedEntity = tamedEntity; ++ } ++ ++ @NotNull ++ public EntityPredicatesCondition getTamedEntity() { ++ return tamedEntity; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/TargetHitTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/TargetHitTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1fe8b672a50291e4a368747458dd2b072764f518 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/TargetHitTrigger.java +@@ -0,0 +1,31 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class TargetHitTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("target_hit"); ++ ++ private final IntegerRange signalStrength; ++ private final EntityPredicatesCondition projectile; ++ ++ public TargetHitTrigger(@NotNull EntityPredicatesCondition player, @NotNull IntegerRange signalStrength, @NotNull EntityPredicatesCondition projectile) { ++ super(KEY, player); ++ this.signalStrength = signalStrength; ++ this.projectile = projectile; ++ } ++ ++ @NotNull ++ public IntegerRange getSignalStrength() { ++ return signalStrength; ++ } ++ ++ @NotNull ++ public EntityPredicatesCondition getProjectile() { ++ return projectile; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/ThrownItemPickedUpTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/ThrownItemPickedUpTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1382e4cd5a2cc334fc2b16b1114cd76a6d5adbac +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/ThrownItemPickedUpTrigger.java +@@ -0,0 +1,31 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class ThrownItemPickedUpTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("thrown_item_picked_up_by_entity"); ++ ++ private final ItemCondition item; ++ private final EntityPredicatesCondition entity; ++ ++ public ThrownItemPickedUpTrigger(@NotNull EntityPredicatesCondition player, @NotNull ItemCondition item, @NotNull EntityPredicatesCondition entity) { ++ super(KEY, player); ++ this.item = item; ++ this.entity = entity; ++ } ++ ++ @NotNull ++ public ItemCondition getItem() { ++ return item; ++ } ++ ++ @NotNull ++ public EntityPredicatesCondition getEntity() { ++ return entity; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/TickTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/TickTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..51caa6dce9b2da56bede68a682f4693575ea0f72 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/TickTrigger.java +@@ -0,0 +1,19 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class TickTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("tick"); ++ ++ public TickTrigger(@NotNull EntityPredicatesCondition player) { ++ super(KEY, player); ++ } ++ ++ public TickTrigger() { ++ super(KEY, EntityPredicatesCondition.ANY); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/Trigger.java b/src/main/java/io/papermc/paper/advancements/triggers/Trigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7653b6ab3148eb921d1ba4bfba8115aaf736f23c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/Trigger.java +@@ -0,0 +1,37 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public abstract class Trigger implements Keyed { ++ ++ private final NamespacedKey key; ++ ++ public Trigger(NamespacedKey key) { ++ this.key = key; ++ } ++ ++ @NotNull ++ @Override ++ public NamespacedKey getKey() { ++ return key; ++ } ++ ++ public abstract static class PlayerTrigger extends Trigger { ++ ++ private final EntityPredicatesCondition player; ++ ++ public PlayerTrigger(@NotNull NamespacedKey key, @NotNull EntityPredicatesCondition player) { ++ super(key); ++ this.player = player; ++ } ++ ++ @NotNull ++ public EntityPredicatesCondition getPlayer() { ++ return player; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/UsedEnderEyeTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/UsedEnderEyeTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..63e0d43794fbc8ee3db9bb6bc24f964b99d3ff15 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/UsedEnderEyeTrigger.java +@@ -0,0 +1,25 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.FloatRange; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class UsedEnderEyeTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("used_ender_eye"); ++ ++ private final FloatRange distance; ++ ++ public UsedEnderEyeTrigger(@NotNull EntityPredicatesCondition player, @NotNull FloatRange distance) { ++ super(KEY, player); ++ this.distance = distance; ++ } ++ ++ @NotNull ++ public FloatRange getDistance() { ++ return distance; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/UsedTotemTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/UsedTotemTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..65758fe9a0630a323e598d5dadd1eb2d9f25ddca +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/UsedTotemTrigger.java +@@ -0,0 +1,24 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public class UsedTotemTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("used_totem"); ++ ++ private final ItemCondition item; ++ ++ public UsedTotemTrigger(@NotNull EntityPredicatesCondition player, @NotNull ItemCondition item) { ++ super(KEY, player); ++ this.item = item; ++ } ++ ++ @NotNull ++ public ItemCondition getItem() { ++ return item; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/VillagerTradeTrigger.java b/src/main/java/io/papermc/paper/advancements/triggers/VillagerTradeTrigger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0b41f4cfaac2e7d081cd2877145089bd0d4420e9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/VillagerTradeTrigger.java +@@ -0,0 +1,32 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class VillagerTradeTrigger extends PlayerTrigger { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("villager_trade"); ++ ++ private final EntityPredicatesCondition villager; ++ private final ItemCondition item; ++ ++ public VillagerTradeTrigger(@NotNull EntityPredicatesCondition player, @NotNull EntityPredicatesCondition villager, @NotNull ItemCondition item) { ++ super(KEY, player); ++ this.villager = villager; ++ this.item = item; ++ } ++ ++ @NotNull ++ public EntityPredicatesCondition getVillager() { ++ return villager; ++ } ++ ++ @NotNull ++ public ItemCondition getItem() { ++ return item; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/BlockCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/BlockCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4ca64f1bea8ecc6d446ec12e2abcf61b43df61a6 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/BlockCondition.java +@@ -0,0 +1,61 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import org.bukkit.Material; ++import org.bukkit.Tag; ++import org.jetbrains.annotations.Contract; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public final class BlockCondition { ++ ++ public static final BlockCondition ANY = new BlockCondition(null, null, StateCondition.ANY); ++ ++ private final Material block; ++ private final Tag blockTag; ++ private final StateCondition state; ++ ++ private BlockCondition(@Nullable Material block, @Nullable Tag blockTag, @NotNull StateCondition state) { ++ this.block = block; ++ this.blockTag = blockTag; ++ this.state = state; ++ } ++ ++ @NotNull ++ @Contract(value = "_, _, _ -> new", pure = true) ++ public static BlockCondition of(@Nullable Material block, @Nullable Tag blockTag, @Nullable StateCondition state) { ++ return new BlockCondition(block, blockTag, state); ++ } ++ ++ @Nullable ++ public Material getBlock() { ++ return this.block; ++ } ++ ++ @Nullable ++ public Tag getBlockTag() { ++ return this.blockTag; ++ } ++ ++ @Nullable ++ public StateCondition getState() { ++ return this.state; ++ } ++ ++ @NotNull ++ @Contract("_ -> new") ++ public BlockCondition withBlock(Material block) { ++ return of(block, getBlockTag(), getState()); ++ } ++ ++ @NotNull ++ @Contract("_ -> new") ++ public BlockCondition withBlockTag(Tag blockTag) { ++ return of(getBlock(), blockTag, getState()); ++ } ++ ++ @NotNull ++ @Contract("_ -> new") ++ public BlockCondition withState(StateCondition state) { ++ return of(getBlock(), getBlockTag(), state); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/DamageCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/DamageCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..87c07949d6b092828a1c28498b3e9377b9ec6645 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/DamageCondition.java +@@ -0,0 +1,83 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.FloatRange; ++ ++public class DamageCondition { ++ ++ public static final DamageCondition ANY = DamageCondition.builder().build(); ++ ++ private final FloatRange dealtDamage; ++ private final FloatRange takenDamage; ++ private final EntityCondition entity; ++ private final Boolean blocked; ++ private final DamageSourceCondition damageType; ++ ++ public DamageCondition(FloatRange dealtDamage, FloatRange takenDamage, EntityCondition entity, Boolean blocked, DamageSourceCondition damageType) { ++ this.dealtDamage = dealtDamage; ++ this.takenDamage = takenDamage; ++ this.entity = entity; ++ this.blocked = blocked; ++ this.damageType = damageType; ++ } ++ ++ public FloatRange getDealtDamage() { ++ return dealtDamage; ++ } ++ ++ public FloatRange getTakenDamage() { ++ return takenDamage; ++ } ++ ++ public EntityCondition getEntity() { ++ return entity; ++ } ++ ++ public Boolean getBlocked() { ++ return blocked; ++ } ++ ++ public DamageSourceCondition getDamageType() { ++ return damageType; ++ } ++ ++ public static DamageConditionBuilder builder() { ++ return new DamageConditionBuilder(); ++ } ++ ++ private static final class DamageConditionBuilder { ++ private FloatRange dealtDamage = FloatRange.ANY; ++ private FloatRange takenDamage = FloatRange.ANY; ++ private EntityCondition entity = EntityCondition.ANY; ++ private Boolean blocked = null; ++ private DamageSourceCondition flags = DamageSourceCondition.ANY; ++ ++ public DamageConditionBuilder dealtDamage(FloatRange dealtDamage) { ++ this.dealtDamage = dealtDamage; ++ return this; ++ } ++ ++ public DamageConditionBuilder takenDamage(FloatRange takenDamage) { ++ this.takenDamage = takenDamage; ++ return this; ++ } ++ ++ public DamageConditionBuilder entity(EntityCondition entity) { ++ this.entity = entity; ++ return this; ++ } ++ ++ public DamageConditionBuilder blocked(Boolean blocked) { ++ this.blocked = blocked; ++ return this; ++ } ++ ++ public DamageConditionBuilder flags(DamageSourceCondition flags) { ++ this.flags = flags; ++ return this; ++ } ++ ++ public DamageCondition build() { ++ return new DamageCondition(dealtDamage, takenDamage, entity, blocked, flags); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/DamageSourceCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/DamageSourceCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ba2a5831987ce79b537fdf554698227797ce19b2 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/DamageSourceCondition.java +@@ -0,0 +1,141 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++public class DamageSourceCondition { ++ ++ public static final DamageSourceCondition ANY = builder().build(); ++ ++ private final Boolean isProjectile; ++ private final Boolean isExplosion; ++ private final Boolean bypassesArmor; ++ private final Boolean bypassesInvulnerability; ++ private final Boolean bypassesMagic; ++ private final Boolean isFire; ++ private final Boolean isMagic; ++ private final Boolean isLightning; ++ private final EntityCondition direct; ++ private final EntityCondition source; ++ ++ public DamageSourceCondition(Boolean isProjectile, Boolean isExplosion, Boolean bypassesArmor, Boolean bypassesInvulnerability, Boolean bypassesMagic, Boolean isFire, Boolean isMagic, Boolean isLightning, EntityCondition direct, EntityCondition source) { ++ this.isProjectile = isProjectile; ++ this.isExplosion = isExplosion; ++ this.bypassesArmor = bypassesArmor; ++ this.bypassesInvulnerability = bypassesInvulnerability; ++ this.bypassesMagic = bypassesMagic; ++ this.isFire = isFire; ++ this.isMagic = isMagic; ++ this.isLightning = isLightning; ++ this.direct = direct; ++ this.source = source; ++ } ++ ++ public Boolean getProjectile() { ++ return isProjectile; ++ } ++ ++ public Boolean getExplosion() { ++ return isExplosion; ++ } ++ ++ public Boolean getBypassesArmor() { ++ return bypassesArmor; ++ } ++ ++ public Boolean getBypassesInvulnerability() { ++ return bypassesInvulnerability; ++ } ++ ++ public Boolean getBypassesMagic() { ++ return bypassesMagic; ++ } ++ ++ public Boolean getFire() { ++ return isFire; ++ } ++ ++ public Boolean getMagic() { ++ return isMagic; ++ } ++ ++ public Boolean getLightning() { ++ return isLightning; ++ } ++ ++ public EntityCondition getDirect() { ++ return direct; ++ } ++ ++ public EntityCondition getSource() { ++ return source; ++ } ++ ++ public static DamageFlagsConditionBuilder builder() { ++ return new DamageFlagsConditionBuilder(); ++ } ++ ++ private static final class DamageFlagsConditionBuilder { ++ private Boolean isProjectile = null; ++ private Boolean isExplosion = null; ++ private Boolean bypassesArmor = null; ++ private Boolean bypassesInvulnerability = null; ++ private Boolean bypassesMagic = null; ++ private Boolean isFire = null; ++ private Boolean isMagic = null; ++ private Boolean isLightning = null; ++ private EntityCondition direct = EntityCondition.ANY; ++ private EntityCondition source = EntityCondition.ANY; ++ ++ public DamageFlagsConditionBuilder isProjectile(Boolean isProjectile) { ++ this.isProjectile = isProjectile; ++ return this; ++ } ++ ++ public DamageFlagsConditionBuilder isExplosion(Boolean isExplosion) { ++ this.isExplosion = isExplosion; ++ return this; ++ } ++ ++ public DamageFlagsConditionBuilder bypassesArmor(Boolean bypassesArmor) { ++ this.bypassesArmor = bypassesArmor; ++ return this; ++ } ++ ++ public DamageFlagsConditionBuilder bypassesInvulnerability(Boolean bypassesInvulnerability) { ++ this.bypassesInvulnerability = bypassesInvulnerability; ++ return this; ++ } ++ ++ public DamageFlagsConditionBuilder bypassesMagic(Boolean bypassesMagic) { ++ this.bypassesMagic = bypassesMagic; ++ return this; ++ } ++ ++ public DamageFlagsConditionBuilder isFire(Boolean isFire) { ++ this.isFire = isFire; ++ return this; ++ } ++ ++ public DamageFlagsConditionBuilder isMagic(Boolean isMagic) { ++ this.isMagic = isMagic; ++ return this; ++ } ++ ++ public DamageFlagsConditionBuilder isLightning(Boolean isLightning) { ++ this.isLightning = isLightning; ++ return this; ++ } ++ ++ public DamageFlagsConditionBuilder direct(EntityCondition direct) { ++ this.direct = direct; ++ return this; ++ } ++ ++ public DamageFlagsConditionBuilder source(EntityCondition source) { ++ this.source = source; ++ return this; ++ } ++ ++ public DamageSourceCondition build() { ++ return new DamageSourceCondition(isProjectile, isExplosion, bypassesArmor, bypassesInvulnerability, bypassesMagic, isFire, isMagic, isLightning, direct, source); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/DistanceCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/DistanceCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6f47579aebb0891f9671c54d99aec9dfe0b025d6 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/DistanceCondition.java +@@ -0,0 +1,83 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.FloatRange; ++ ++public class DistanceCondition { ++ ++ public static final DistanceCondition ANY = new DistanceCondition(FloatRange.ANY, FloatRange.ANY, FloatRange.ANY, FloatRange.ANY, FloatRange.ANY); ++ ++ private final FloatRange xRange; ++ private final FloatRange yRange; ++ private final FloatRange zRange; ++ private final FloatRange absoluteRange; ++ private final FloatRange horizontalRange; ++ ++ public DistanceCondition(FloatRange xRange, FloatRange yRange, FloatRange zRange, FloatRange absoluteRange, FloatRange horizontalRange) { ++ this.xRange = xRange; ++ this.yRange = yRange; ++ this.zRange = zRange; ++ this.absoluteRange = absoluteRange; ++ this.horizontalRange = horizontalRange; ++ } ++ ++ public FloatRange getXRange() { ++ return xRange; ++ } ++ ++ public FloatRange getYRange() { ++ return yRange; ++ } ++ ++ public FloatRange getZRange() { ++ return zRange; ++ } ++ ++ public FloatRange getAbsoluteRange() { ++ return absoluteRange; ++ } ++ ++ public FloatRange getHorizontalRange() { ++ return horizontalRange; ++ } ++ ++ public static DistanceConditionBuilder builder() { ++ return new DistanceConditionBuilder(); ++ } ++ ++ private static final class DistanceConditionBuilder { ++ private FloatRange xRange = FloatRange.ANY; ++ private FloatRange yRange = FloatRange.ANY; ++ private FloatRange zRange = FloatRange.ANY; ++ private FloatRange absoluteRange = FloatRange.ANY; ++ private FloatRange horizontalRange = FloatRange.ANY; ++ ++ public DistanceConditionBuilder xRange(FloatRange xRange) { ++ this.xRange = xRange; ++ return this; ++ } ++ ++ public DistanceConditionBuilder yRange(FloatRange yRange) { ++ this.yRange = yRange; ++ return this; ++ } ++ ++ public DistanceConditionBuilder zRange(FloatRange zRange) { ++ this.zRange = zRange; ++ return this; ++ } ++ ++ public DistanceConditionBuilder absoluteRange(FloatRange absoluteRange) { ++ this.absoluteRange = absoluteRange; ++ return this; ++ } ++ ++ public DistanceConditionBuilder horizontalRange(FloatRange horizontalRange) { ++ this.horizontalRange = horizontalRange; ++ return this; ++ } ++ ++ public DistanceCondition build() { ++ return new DistanceCondition(xRange, yRange, zRange, absoluteRange, horizontalRange); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/EffectsCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EffectsCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..df5328709a16423c87c6d67b9d176a170c849d86 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EffectsCondition.java +@@ -0,0 +1,88 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import org.bukkit.potion.PotionEffectType; ++ ++import java.util.Collections; ++import java.util.Map; ++ ++public class EffectsCondition { ++ ++ public static final EffectsCondition ANY = new EffectsCondition(Collections.emptyMap()); ++ ++ private final Map effectInfoMap; ++ ++ public EffectsCondition(Map effectInfoMap) { ++ this.effectInfoMap = effectInfoMap; ++ } ++ ++ public Map getEffectInfoMap() { ++ return effectInfoMap; ++ } ++ ++ public static class EffectInfo { ++ ++ private final IntegerRange amplifer; ++ private final IntegerRange duration; ++ private final Boolean ambient; ++ private final Boolean visible; ++ ++ public EffectInfo(IntegerRange amplifer, IntegerRange duration, Boolean ambient, Boolean visible) { ++ this.amplifer = amplifer; ++ this.duration = duration; ++ this.ambient = ambient; ++ this.visible = visible; ++ } ++ ++ public IntegerRange getAmplifer() { ++ return amplifer; ++ } ++ ++ public IntegerRange getDuration() { ++ return duration; ++ } ++ ++ public Boolean getAmbient() { ++ return ambient; ++ } ++ ++ public Boolean getVisible() { ++ return visible; ++ } ++ ++ public static EffectInfoBuilder builder() { ++ return new EffectInfoBuilder(); ++ } ++ ++ private static class EffectInfoBuilder { ++ private IntegerRange amplifier = IntegerRange.ANY; ++ private IntegerRange duration = IntegerRange.ANY; ++ private Boolean ambient = null; ++ private Boolean visible = null; ++ ++ public EffectInfoBuilder amplifier(IntegerRange amplifier) { ++ this.amplifier = amplifier; ++ return this; ++ } ++ ++ public EffectInfoBuilder duration(IntegerRange duration) { ++ this.duration = duration; ++ return this; ++ } ++ ++ public EffectInfoBuilder ambient(Boolean ambient) { ++ this.ambient = ambient; ++ return this; ++ } ++ ++ public EffectInfoBuilder visible(Boolean visible) { ++ this.visible = visible; ++ return this; ++ } ++ ++ public EffectInfo build() { ++ return new EffectInfo(amplifier, duration, ambient, visible); ++ } ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/EnchantmentCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EnchantmentCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9acec05c0034f98d7b2da829dd747e661c6944f9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EnchantmentCondition.java +@@ -0,0 +1,47 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import org.bukkit.enchantments.Enchantment; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++import java.util.HashSet; ++import java.util.Set; ++ ++public class EnchantmentCondition { ++ ++ public static final EnchantmentCondition ANY = new EnchantmentCondition(null, IntegerRange.ANY); ++ ++ private Enchantment enchantment; ++ private IntegerRange levelRange; ++ ++ public EnchantmentCondition(@Nullable Enchantment enchantment, @NotNull IntegerRange levelRange) { ++ this.enchantment = enchantment; ++ this.levelRange = levelRange; ++ } ++ ++ public Enchantment getEnchantment() { ++ return enchantment; ++ } ++ ++ public void setEnchantment(Enchantment enchantment) { ++ this.enchantment = enchantment; ++ } ++ ++ public IntegerRange getLevelRange() { ++ return levelRange; ++ } ++ ++ public void setLevelRange(IntegerRange levelRange) { ++ this.levelRange = levelRange; ++ } ++ ++ public static class EnchantmentsCondition extends HashSet { ++ ++ public static final EnchantmentsCondition ANY = new EnchantmentsCondition(new HashSet<>(0)); ++ ++ public EnchantmentsCondition(Set enchantments) { ++ this.addAll(enchantments); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..68dcac86579e9ba819f4adf580a9740b9fd0604c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityCondition.java +@@ -0,0 +1,186 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import io.papermc.paper.advancements.triggers.conditions.predicates.PredicateCondition; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class EntityCondition { ++ ++ public static final EntityCondition ANY = builder().build(); ++ ++ private final EntityTypeCondition entityType; ++ private final DistanceCondition distanceToPlayer; ++ private final LocationCondition location; ++ private final EffectsCondition effects; ++ private final EntityFlagsCondition flags; ++ private final EntityEquipmentCondition equipment; ++ private final PlayerCondition player; ++ private final FishingHookCondition fishingHook; ++ private final EntityCondition vehicle; ++ private final EntityCondition target; ++ private final String team; ++ private final NamespacedKey catType; ++ ++ public EntityCondition(@NotNull EntityTypeCondition entityType, @NotNull DistanceCondition distanceToPlayer, @NotNull LocationCondition location, @NotNull EffectsCondition effects, @NotNull EntityFlagsCondition flags, @NotNull EntityEquipmentCondition equipment, @NotNull PlayerCondition player, @NotNull FishingHookCondition fishingHook, @NotNull EntityCondition vehicle, @NotNull EntityCondition target, @Nullable String team, @Nullable NamespacedKey catType) { ++ this.entityType = entityType; ++ this.distanceToPlayer = distanceToPlayer; ++ this.location = location; ++ this.effects = effects; ++ this.flags = flags; ++ this.equipment = equipment; ++ this.player = player; ++ this.fishingHook = fishingHook; ++ this.vehicle = vehicle; ++ this.target = target; ++ this.team = team; ++ this.catType = catType; ++ } ++ ++ public EntityTypeCondition getEntityType() { ++ return entityType; ++ } ++ ++ public DistanceCondition getDistanceToPlayer() { ++ return distanceToPlayer; ++ } ++ ++ public LocationCondition getLocation() { ++ return location; ++ } ++ ++ public EffectsCondition getEffects() { ++ return effects; ++ } ++ ++ public EntityFlagsCondition getFlags() { ++ return flags; ++ } ++ ++ public EntityEquipmentCondition getEquipment() { ++ return equipment; ++ } ++ ++ public PlayerCondition getPlayer() { ++ return player; ++ } ++ ++ public FishingHookCondition getFishingHook() { ++ return fishingHook; ++ } ++ ++ public EntityCondition getVehicle() { ++ return vehicle; ++ } ++ ++ public EntityCondition getTarget() { ++ return target; ++ } ++ ++ public String getTeam() { ++ return team; ++ } ++ ++ public NamespacedKey getCatType() { ++ return catType; ++ } ++ ++ public static EntityConditionBuilder builder() { ++ return new EntityConditionBuilder(); ++ } ++ ++ private static final class EntityConditionBuilder { ++ private EntityTypeCondition entityType = EntityTypeCondition.ANY; ++ private DistanceCondition distanceToPlayer = DistanceCondition.ANY; ++ private LocationCondition location = LocationCondition.ANY; ++ private EffectsCondition effects = EffectsCondition.ANY; ++ private EntityFlagsCondition flags = EntityFlagsCondition.ANY; ++ private EntityEquipmentCondition equipment = EntityEquipmentCondition.ANY; ++ private PlayerCondition player = PlayerCondition.ANY; ++ private FishingHookCondition fishingHook = FishingHookCondition.ANY; ++ private EntityCondition vehicle = EntityCondition.ANY; ++ private EntityCondition target = EntityCondition.ANY; ++ private String team = null; ++ private NamespacedKey catType = null; ++ ++ public EntityConditionBuilder entityType(EntityTypeCondition entityType) { ++ this.entityType = entityType; ++ return this; ++ } ++ ++ public EntityConditionBuilder distanceToPlayer(DistanceCondition distanceToPlayer) { ++ this.distanceToPlayer = distanceToPlayer; ++ return this; ++ } ++ ++ public EntityConditionBuilder location(LocationCondition location) { ++ this.location = location; ++ return this; ++ } ++ ++ public EntityConditionBuilder effects(EffectsCondition effects) { ++ this.effects = effects; ++ return this; ++ } ++ ++ public EntityConditionBuilder flags(EntityFlagsCondition flags) { ++ this.flags = flags; ++ return this; ++ } ++ ++ public EntityConditionBuilder equipment(EntityEquipmentCondition equipment) { ++ this.equipment = equipment; ++ return this; ++ } ++ ++ public EntityConditionBuilder player(PlayerCondition player) { ++ this.player = player; ++ return this; ++ } ++ ++ public EntityConditionBuilder fishingHook(FishingHookCondition fishingHook) { ++ this.fishingHook = fishingHook; ++ return this; ++ } ++ ++ public EntityConditionBuilder vehicle(EntityCondition vehicle) { ++ this.vehicle = vehicle; ++ return this; ++ } ++ ++ public EntityConditionBuilder target(EntityCondition target) { ++ this.target = target; ++ return this; ++ } ++ ++ public EntityConditionBuilder team(String team) { ++ this.team = team; ++ return this; ++ } ++ ++ public EntityConditionBuilder catType(NamespacedKey catType) { ++ this.catType = catType; ++ return this; ++ } ++ ++ public EntityCondition build() { ++ return new EntityCondition(entityType, distanceToPlayer, location, effects, flags, equipment, player, fishingHook, vehicle, target, team, catType); ++ } ++ } ++ ++ public static class EntityPredicatesCondition { ++ ++ public static final EntityPredicatesCondition ANY = new EntityPredicatesCondition(new PredicateCondition[0]); ++ public static final EntityPredicatesCondition[] ANY_ARRAY = new EntityPredicatesCondition[0]; ++ ++ private final PredicateCondition[] predicates; ++ ++ public EntityPredicatesCondition(PredicateCondition[] predicates) { ++ this.predicates = predicates; ++ } ++ ++ public PredicateCondition[] getPredicates() { ++ return predicates; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityEquipmentCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityEquipmentCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9d4ad043ea6ac1fe317c22e07ac3258c6f1ef146 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityEquipmentCondition.java +@@ -0,0 +1,93 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++public class EntityEquipmentCondition { ++ ++ public static final EntityEquipmentCondition ANY = new EntityEquipmentCondition(ItemCondition.ANY, ItemCondition.ANY, ItemCondition.ANY, ItemCondition.ANY, ItemCondition.ANY, ItemCondition.ANY); ++ ++ private final ItemCondition headItem; ++ private final ItemCondition chestItem; ++ private final ItemCondition legsItem; ++ private final ItemCondition feetItem; ++ private final ItemCondition mainHand; ++ private final ItemCondition offHand; ++ ++ public EntityEquipmentCondition(ItemCondition headItem, ItemCondition chestItem, ItemCondition legsItem, ItemCondition feetItem, ItemCondition mainHand, ItemCondition offHand) { ++ this.headItem = headItem; ++ this.chestItem = chestItem; ++ this.legsItem = legsItem; ++ this.feetItem = feetItem; ++ this.mainHand = mainHand; ++ this.offHand = offHand; ++ } ++ ++ public ItemCondition getHeadItem() { ++ return headItem; ++ } ++ ++ public ItemCondition getChestItem() { ++ return chestItem; ++ } ++ ++ public ItemCondition getLegsItem() { ++ return legsItem; ++ } ++ ++ public ItemCondition getFeetItem() { ++ return feetItem; ++ } ++ ++ public ItemCondition getMainHand() { ++ return mainHand; ++ } ++ ++ public ItemCondition getOffHand() { ++ return offHand; ++ } ++ ++ public static EntityEquipmentConditionBuilder builder() { ++ return new EntityEquipmentConditionBuilder(); ++ } ++ ++ private static final class EntityEquipmentConditionBuilder { ++ private ItemCondition headItem; ++ private ItemCondition chestItem; ++ private ItemCondition legsItem; ++ private ItemCondition feetItem; ++ private ItemCondition mainHand; ++ private ItemCondition offHand; ++ ++ public EntityEquipmentConditionBuilder headItem(ItemCondition headItem) { ++ this.headItem = headItem; ++ return this; ++ } ++ ++ public EntityEquipmentConditionBuilder chestItem(ItemCondition chestItem) { ++ this.chestItem = chestItem; ++ return this; ++ } ++ ++ public EntityEquipmentConditionBuilder legsItem(ItemCondition legsItem) { ++ this.legsItem = legsItem; ++ return this; ++ } ++ ++ public EntityEquipmentConditionBuilder feetItem(ItemCondition feetItem) { ++ this.feetItem = feetItem; ++ return this; ++ } ++ ++ public EntityEquipmentConditionBuilder mainHand(ItemCondition mainHand) { ++ this.mainHand = mainHand; ++ return this; ++ } ++ ++ public EntityEquipmentConditionBuilder offHand(ItemCondition offHand) { ++ this.offHand = offHand; ++ return this; ++ } ++ ++ public EntityEquipmentCondition build() { ++ return new EntityEquipmentCondition(headItem, chestItem, legsItem, feetItem, mainHand, offHand); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityFlagsCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityFlagsCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9fe6ccc852256e8843171fb7bb2987cb11fece51 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityFlagsCondition.java +@@ -0,0 +1,81 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++public class EntityFlagsCondition { ++ ++ public static final EntityFlagsCondition ANY = new EntityFlagsCondition(null, null, null, null, null); ++ ++ private final Boolean isOnFire; ++ private final Boolean isSneaking; ++ private final Boolean isSprinting; ++ private final Boolean isSwimming; ++ private final Boolean isBaby; ++ ++ public EntityFlagsCondition(Boolean isOnFire, Boolean isSneaking, Boolean isSprinting, Boolean isSwimming, Boolean isBaby) { ++ this.isOnFire = isOnFire; ++ this.isSneaking = isSneaking; ++ this.isSprinting = isSprinting; ++ this.isSwimming = isSwimming; ++ this.isBaby = isBaby; ++ } ++ ++ public Boolean getOnFire() { ++ return isOnFire; ++ } ++ ++ public Boolean getSneaking() { ++ return isSneaking; ++ } ++ ++ public Boolean getSprinting() { ++ return isSprinting; ++ } ++ ++ public Boolean getSwimming() { ++ return isSwimming; ++ } ++ ++ public Boolean getBaby() { ++ return isBaby; ++ } ++ ++ public static EntityFlagsConditionBuilder builder() { ++ return new EntityFlagsConditionBuilder(); ++ } ++ ++ private static final class EntityFlagsConditionBuilder { ++ private Boolean isOnFire; ++ private Boolean isSneaking; ++ private Boolean isSprinting; ++ private Boolean isSwimming; ++ private Boolean isBaby; ++ ++ public EntityFlagsConditionBuilder isOnFire(Boolean isOnFire) { ++ this.isOnFire = isOnFire; ++ return this; ++ } ++ ++ public EntityFlagsConditionBuilder isSneaking(Boolean isSneaking) { ++ this.isSneaking = isSneaking; ++ return this; ++ } ++ ++ public EntityFlagsConditionBuilder isSprinting(Boolean isSprinting) { ++ this.isSprinting = isSprinting; ++ return this; ++ } ++ ++ public EntityFlagsConditionBuilder isSwimming(Boolean isSwimming) { ++ this.isSwimming = isSwimming; ++ return this; ++ } ++ ++ public EntityFlagsConditionBuilder isBaby(Boolean isBaby) { ++ this.isBaby = isBaby; ++ return this; ++ } ++ ++ public EntityFlagsCondition build() { ++ return new EntityFlagsCondition(isOnFire, isSneaking, isSprinting, isSwimming, isBaby); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityScorePredicateCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityScorePredicateCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..88754807570c30305b0ca4c088b5fdf198565841 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityScorePredicateCondition.java +@@ -0,0 +1,30 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import io.papermc.paper.advancements.triggers.conditions.predicates.EntityTarget; ++import io.papermc.paper.advancements.triggers.conditions.predicates.PredicateCondition; ++import io.papermc.paper.advancements.triggers.conditions.predicates.values.ValueRange; ++import org.bukkit.NamespacedKey; ++ ++import java.util.Map; ++ ++public class EntityScorePredicateCondition extends PredicateCondition { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("entity_scores"); ++ ++ private final Map scores; ++ private final EntityTarget target; ++ ++ public EntityScorePredicateCondition(Map scores, EntityTarget target) { ++ super(KEY); ++ this.scores = scores; ++ this.target = target; ++ } ++ ++ public Map getScores() { ++ return scores; ++ } ++ ++ public EntityTarget getTarget() { ++ return target; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityTypeCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityTypeCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..676b4aacb1caf93ffc4e378879791f3a7fbfbf72 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityTypeCondition.java +@@ -0,0 +1,46 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.gson.JsonElement; ++import com.google.gson.JsonNull; ++import com.google.gson.JsonPrimitive; ++import org.bukkit.Tag; ++import org.bukkit.entity.EntityType; ++import org.jetbrains.annotations.NotNull; ++ ++public abstract class EntityTypeCondition { ++ ++ public static final EntityTypeCondition ANY = new EntityTypeCondition() { ++ @Override ++ public JsonElement getJson() { ++ return JsonNull.INSTANCE; ++ } ++ }; ++ ++ public abstract JsonElement getJson(); ++ ++ public static class EntityTypeTypeCondition extends EntityTypeCondition { ++ private final EntityType entityType; ++ ++ public EntityTypeTypeCondition(@NotNull EntityType entityType) { ++ this.entityType = entityType; ++ } ++ ++ @Override ++ public JsonElement getJson() { ++ return new JsonPrimitive(entityType.getKey().toString()); ++ } ++ } ++ ++ public static class EntityTypeTagCondition extends EntityTypeCondition { ++ private final Tag entityTypeTag; ++ ++ public EntityTypeTagCondition(@NotNull Tag entityTypeTag) { ++ this.entityTypeTag = entityTypeTag; ++ } ++ ++ @Override ++ public JsonElement getJson() { ++ return new JsonPrimitive("#" + entityTypeTag.getKey().toString()); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/FishingHookCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/FishingHookCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..89affabfac76224323e1b0bc391134c7633d9161 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/FishingHookCondition.java +@@ -0,0 +1,16 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++public class FishingHookCondition { ++ ++ public static final FishingHookCondition ANY = new FishingHookCondition(false); ++ ++ private final boolean inOpenWater; ++ ++ public FishingHookCondition(boolean inOpenWater) { ++ this.inOpenWater = inOpenWater; ++ } ++ ++ public boolean isInOpenWater() { ++ return inOpenWater; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/FluidCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/FluidCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ce635f0cef8bd88962012097df227fb74303dd1c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/FluidCondition.java +@@ -0,0 +1,60 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import org.bukkit.Fluid; ++import org.bukkit.Tag; ++ ++public class FluidCondition { ++ ++ public static final FluidCondition ANY = FluidCondition.builder().build(); ++ ++ private final Tag fluidTag; ++ private final Fluid fluid; ++ private final StateCondition state; ++ ++ public FluidCondition(Tag fluidTag, Fluid fluid, StateCondition state) { ++ this.fluidTag = fluidTag; ++ this.fluid = fluid; ++ this.state = state; ++ } ++ ++ public Tag getFluidTag() { ++ return fluidTag; ++ } ++ ++ public Fluid getFluid() { ++ return fluid; ++ } ++ ++ public StateCondition getState() { ++ return state; ++ } ++ ++ public static FluidConditionBuilder builder() { ++ return new FluidConditionBuilder(); ++ } ++ ++ private static final class FluidConditionBuilder { ++ private Tag fluidTag; ++ private Fluid fluid; ++ private StateCondition state; ++ ++ public FluidConditionBuilder fluidTag(Tag fluidTag) { ++ this.fluidTag = fluidTag; ++ return this; ++ } ++ ++ public FluidConditionBuilder fluid(Fluid fluid) { ++ this.fluid = fluid; ++ return this; ++ } ++ ++ public FluidConditionBuilder state(StateCondition state) { ++ this.state = state; ++ return this; ++ } ++ ++ public FluidCondition build() { ++ return new FluidCondition(fluidTag, fluid, state); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/ItemCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/ItemCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3cd2d0dbe046000883f050372fdd97086fd44292 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/ItemCondition.java +@@ -0,0 +1,124 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import io.papermc.paper.advancements.triggers.conditions.EnchantmentCondition.EnchantmentsCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import org.bukkit.Material; ++import org.bukkit.Tag; ++import org.bukkit.potion.PotionType; ++ ++import java.util.HashSet; ++import java.util.Set; ++ ++public class ItemCondition { ++ ++ public static final ItemCondition ANY = new ItemCondition(null, null, IntegerRange.ANY, IntegerRange.ANY, EnchantmentsCondition.ANY, EnchantmentsCondition.ANY, null); ++ ++ private final Tag materialTag; ++ private final Material material; ++ private final IntegerRange count; ++ private final IntegerRange durability; ++ private final EnchantmentsCondition enchantments; ++ private final EnchantmentsCondition storedEnchantments; ++ private final PotionType potionType; ++ ++ public ItemCondition(Tag materialTag, Material material, IntegerRange count, IntegerRange durability, EnchantmentsCondition enchantments, EnchantmentsCondition storedEnchantments, PotionType potionType) { ++ this.materialTag = materialTag; ++ this.material = material; ++ this.count = count; ++ this.durability = durability; ++ this.enchantments = enchantments; ++ this.storedEnchantments = storedEnchantments; ++ this.potionType = potionType; ++ } ++ ++ public Tag getMaterialTag() { ++ return materialTag; ++ } ++ ++ public Material getMaterial() { ++ return material; ++ } ++ ++ public IntegerRange getCount() { ++ return count; ++ } ++ ++ public IntegerRange getDurability() { ++ return durability; ++ } ++ ++ public EnchantmentsCondition getEnchantments() { ++ return enchantments; ++ } ++ ++ public EnchantmentsCondition getStoredEnchantments() { ++ return storedEnchantments; ++ } ++ ++ public PotionType getPotionType() { ++ return potionType; ++ } ++ ++ public static ItemConditionBuilder builder() { ++ return new ItemConditionBuilder(); ++ } ++ ++ private static final class ItemConditionBuilder { ++ private Tag materialTag; ++ private Material material; ++ private IntegerRange count; ++ private IntegerRange durability; ++ private EnchantmentsCondition enchantments; ++ private EnchantmentsCondition storedEnchantments; ++ private PotionType potionType; ++ ++ public ItemConditionBuilder materialTag(Tag materialTag) { ++ this.materialTag = materialTag; ++ return this; ++ } ++ ++ public ItemConditionBuilder material(Material material) { ++ this.material = material; ++ return this; ++ } ++ ++ public ItemConditionBuilder count(IntegerRange count) { ++ this.count = count; ++ return this; ++ } ++ ++ public ItemConditionBuilder durability(IntegerRange durability) { ++ this.durability = durability; ++ return this; ++ } ++ ++ public ItemConditionBuilder enchantments(EnchantmentsCondition enchantments) { ++ this.enchantments = enchantments; ++ return this; ++ } ++ ++ public ItemConditionBuilder storedEnchantments(EnchantmentsCondition storedEnchantments) { ++ this.storedEnchantments = storedEnchantments; ++ return this; ++ } ++ ++ public ItemConditionBuilder potionType(PotionType potionType) { ++ this.potionType = potionType; ++ return this; ++ } ++ ++ public ItemCondition build() { ++ return new ItemCondition(materialTag, material, count, durability, enchantments, storedEnchantments, potionType); ++ } ++ } ++ ++ ++ public static class ItemsCondition extends HashSet { ++ ++ public static final ItemsCondition ANY = new ItemsCondition(new HashSet<>(0)); ++ ++ public ItemsCondition(Set items) { ++ this.addAll(items); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/LightCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/LightCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..087ed5239e5e04d3f70490e9c718d95260365c84 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/LightCondition.java +@@ -0,0 +1,24 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import org.jetbrains.annotations.NotNull; ++ ++public class LightCondition { ++ ++ public static final LightCondition DEFAULT = new LightCondition(IntegerRange.ANY); ++ ++ private IntegerRange range; ++ ++ public LightCondition(@NotNull IntegerRange range) { ++ this.range = range; ++ } ++ ++ @NotNull ++ public IntegerRange getRange() { ++ return range; ++ } ++ ++ public void setRange(@NotNull IntegerRange range) { ++ this.range = range; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/LocationCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/LocationCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2b8ac3520039815f922207e968bad4564d51617e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/LocationCondition.java +@@ -0,0 +1,150 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.FloatRange; ++import org.bukkit.NamespacedKey; ++import org.bukkit.block.Biome; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class LocationCondition { ++ ++ public static final LocationCondition ANY = new LocationCondition(FloatRange.ANY, FloatRange.ANY, FloatRange.ANY, null, null, null, null, LightCondition.DEFAULT, BlockCondition.ANY); ++ ++ private FloatRange xRange; ++ private FloatRange yRange; ++ private FloatRange zRange; ++ private Biome biome; ++ private LocationFeature feature; ++ private NamespacedKey dimension; ++ private Boolean smokey; ++ private LightCondition light; ++ private BlockCondition block; ++ // TODO fluid ++ ++ ++ public LocationCondition(@NotNull FloatRange xRange, @NotNull FloatRange yRange, @NotNull FloatRange zRange, Biome biome, LocationFeature feature, NamespacedKey dimension, Boolean smokey, @NotNull LightCondition light, @NotNull BlockCondition block) { ++ this.xRange = xRange; ++ this.yRange = yRange; ++ this.zRange = zRange; ++ this.biome = biome; ++ this.feature = feature; ++ this.dimension = dimension; ++ this.smokey = smokey; ++ this.light = light; ++ this.block = block; ++ } ++ ++ public FloatRange getXRange() { ++ return xRange; ++ } ++ ++ public void setXRange(FloatRange xRange) { ++ this.xRange = xRange; ++ } ++ ++ public FloatRange getYRange() { ++ return yRange; ++ } ++ ++ public void setYRange(FloatRange yRange) { ++ this.yRange = yRange; ++ } ++ ++ public FloatRange getZRange() { ++ return zRange; ++ } ++ ++ public void setZRange(FloatRange zRange) { ++ this.zRange = zRange; ++ } ++ ++ public Biome getBiome() { ++ return biome; ++ } ++ ++ public void setBiome(Biome biome) { ++ this.biome = biome; ++ } ++ ++ public LocationFeature getFeature() { ++ return feature; ++ } ++ ++ public void setFeature(LocationFeature feature) { ++ this.feature = feature; ++ } ++ ++ public NamespacedKey getDimension() { ++ return dimension; ++ } ++ ++ public void setDimension(NamespacedKey dimension) { ++ this.dimension = dimension; ++ } ++ ++ @Nullable ++ public Boolean isSmokey() { ++ return smokey; ++ } ++ ++ public void setSmokey(@Nullable Boolean smokey) { ++ this.smokey = smokey; ++ } ++ ++ public LightCondition getLight() { ++ return light; ++ } ++ ++ public void setLight(LightCondition light) { ++ this.light = light; ++ } ++ ++ public BlockCondition getBlock() { ++ return block; ++ } ++ ++ public void setBlock(BlockCondition block) { ++ this.block = block; ++ } ++ ++ public enum LocationFeature { ++ BASTION_REMNANT("bastion_remnant"), ++ BURIED_TREASURE("buried_treasure"), ++ END_CITY("endcity"), ++ NETHER_FORTRESS("fortress"), ++ WOODLAND_MANSION("mansion"), ++ MINESHAFT("mineshaft"), ++ OCEAN_MONUMENT("monument"), ++ NETHER_FOSSIL("nether_fossil"), ++ OCEAN_RUINS("ocean_ruins"), ++ PILLAGER_OUTPOST("pillager_outpost"), ++ RUINED_PORTAL("ruined_portal"), ++ SHIPWRECK("shipwreck"), ++ STRONGHOLD("stronghold"), ++ DESERT_TEMPLE("desert_pyramid"), ++ IGLOO("igloo"), ++ JUNGLE_TEMPLE("jungle_pyramid"), ++ WITCH_HUT("swamp_hut"), ++ VILLAGE("village"); ++ ++ private String idText; ++ ++ LocationFeature(@NotNull String idText) { ++ this.idText = idText; ++ } ++ ++ @NotNull ++ public String getIdText() { ++ return this.idText; ++ } ++ ++ @Nullable ++ public static LocationFeature getByIdText(@Nullable String idText) { ++ if (idText == null) return null; ++ for (LocationFeature feature : LocationFeature.values()) { ++ if (feature.getIdText().equals(idText)) return feature; ++ } ++ return null; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/PlayerCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/PlayerCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c68dda2da00f56ddd29f7a0233ebd22104f21ff6 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/PlayerCondition.java +@@ -0,0 +1,128 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.common.collect.Maps; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonPrimitive; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import it.unimi.dsi.fastutil.objects.Object2BooleanMap; ++import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap; ++import org.bukkit.GameMode; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Statistic; ++ ++import java.util.Map; ++ ++public class PlayerCondition { ++ ++ public static final PlayerCondition ANY = new PlayerCondition(IntegerRange.ANY, null, Maps.newHashMap(), new Object2BooleanOpenHashMap<>(), Maps.newHashMap()); ++ ++ private final IntegerRange level; ++ private final GameMode gameMode; ++ private final Map stats; ++ private final Object2BooleanMap recipes; ++ private final Map advancements; ++ ++ public PlayerCondition(IntegerRange level, GameMode gameMode, Map stats, Object2BooleanMap recipes, Map advancements) { ++ this.level = level; ++ this.gameMode = gameMode; ++ this.stats = stats; ++ this.recipes = recipes; ++ this.advancements = advancements; ++ } ++ ++ public IntegerRange getLevel() { ++ return level; ++ } ++ ++ public GameMode getGameMode() { ++ return gameMode; ++ } ++ ++ public Map getStats() { ++ return stats; ++ } ++ ++ public Object2BooleanMap getRecipes() { ++ return recipes; ++ } ++ ++ public Map getAdvancements() { ++ return advancements; ++ } ++ ++ public static PlayerConditionBuilder builder() { ++ return new PlayerConditionBuilder(); ++ } ++ ++ private static final class PlayerConditionBuilder { ++ private IntegerRange level = IntegerRange.ANY; ++ private GameMode gameMode = null; ++ private Map stats = Maps.newHashMap(); ++ private Object2BooleanMap recipes = new Object2BooleanOpenHashMap<>(); ++ private Map advancements = Maps.newHashMap(); ++ ++ public PlayerConditionBuilder level(IntegerRange level) { ++ this.level = level; ++ return this; ++ } ++ ++ public PlayerConditionBuilder gameMode(GameMode gameMode) { ++ this.gameMode = gameMode; ++ return this; ++ } ++ ++ public PlayerConditionBuilder stats(Map stats) { ++ this.stats = stats; ++ return this; ++ } ++ ++ public PlayerConditionBuilder recipes(Object2BooleanMap recipes) { ++ this.recipes = recipes; ++ return this; ++ } ++ ++ public PlayerConditionBuilder advancements(Map advancements) { ++ this.advancements = advancements; ++ return this; ++ } ++ ++ public PlayerCondition build() { ++ return new PlayerCondition(level, gameMode, stats, recipes, advancements); ++ } ++ } ++ ++ public static class AdvancementCriterionsCondition implements AdvancementCondition { ++ ++ private final Object2BooleanMap criterionsMap; ++ ++ public AdvancementCriterionsCondition(Object2BooleanMap criterionsMap) { ++ this.criterionsMap = criterionsMap; ++ } ++ ++ @Override ++ public JsonElement toJson() { ++ JsonObject jsonObject = new JsonObject(); ++ this.criterionsMap.forEach(jsonObject::addProperty); ++ return jsonObject; ++ } ++ } ++ ++ public static class AdvancementDoneCondition implements AdvancementCondition { ++ ++ private final boolean done; ++ ++ public AdvancementDoneCondition(boolean done) { ++ this.done = done; ++ } ++ ++ @Override ++ public JsonElement toJson() { ++ return new JsonPrimitive(this.done); ++ } ++ } ++ ++ public interface AdvancementCondition { ++ JsonElement toJson(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/StateCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/StateCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..71af6dbc131fbc6aa0aea762aa433a1c11ef2524 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/StateCondition.java +@@ -0,0 +1,89 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.common.collect.ImmutableList; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonPrimitive; ++ ++import java.util.List; ++ ++public class StateCondition { ++ ++ public static final StateCondition ANY = new StateCondition(ImmutableList.of()); ++ ++ private final List properties; ++ ++ public StateCondition(List properties) { ++ this.properties = properties; ++ } ++ ++ public List getProperties() { ++ return properties; ++ } ++ ++ public static class ExactProperty extends AbstractProperty { ++ ++ private final String value; ++ ++ public ExactProperty(String name, String value) { ++ super(name); ++ this.value = value; ++ } ++ ++ public String getValue() { ++ return value; ++ } ++ ++ @Override ++ public JsonElement toJson() { ++ return new JsonPrimitive(this.value); ++ } ++ } ++ ++ public static class RangedProperty extends AbstractProperty { ++ ++ private final String min; ++ private final String max; ++ ++ public RangedProperty(String name, String min, String max) { ++ super(name); ++ this.min = min; ++ this.max = max; ++ } ++ ++ public String getMin() { ++ return min; ++ } ++ ++ public String getMax() { ++ return max; ++ } ++ ++ @Override ++ public JsonElement toJson() { ++ JsonObject jsonObject = new JsonObject(); ++ if (this.min != null) { ++ jsonObject.addProperty("min", this.min); ++ } ++ if (this.max != null) { ++ jsonObject.addProperty("max", this.max); ++ } ++ return jsonObject; ++ } ++ } ++ ++ public abstract static class AbstractProperty { ++ ++ private final String name; ++ ++ public AbstractProperty(String name) { ++ this.name = name; ++ } ++ ++ public String getName() { ++ return name; ++ } ++ ++ abstract public JsonElement toJson(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/ValueCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/ValueCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..21b8cb734544ed6fd6fbc73337bb02bf981ae604 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/ValueCondition.java +@@ -0,0 +1,42 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import org.jetbrains.annotations.Nullable; ++ ++public abstract class ValueCondition { ++ ++ private final T min; ++ private final T max; ++ ++ public ValueCondition(@Nullable T min, @Nullable T max) { ++ this.min = min; ++ this.max = max; ++ } ++ ++ public T getMin() { ++ return min; ++ } ++ ++ public T getMax() { ++ return max; ++ } ++ ++ public boolean isAnyRange() { ++ return this.min == null && this.max == null; ++ } ++ ++ public static class FloatRange extends ValueCondition { ++ public static final FloatRange ANY = new FloatRange(null, null); ++ ++ public FloatRange(@Nullable Float min, @Nullable Float max) { ++ super(min, max); ++ } ++ } ++ ++ public static class IntegerRange extends ValueCondition { ++ public static final IntegerRange ANY = new IntegerRange(null, null); ++ ++ public IntegerRange(@Nullable Integer min, @Nullable Integer max) { ++ super(min, max); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/AlternativePredicateCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/AlternativePredicateCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1330f67f50c1eb73ee68f4e51f3394b23a37960a +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/AlternativePredicateCondition.java +@@ -0,0 +1,19 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import org.bukkit.NamespacedKey; ++ ++public class AlternativePredicateCondition extends PredicateCondition { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("alternative"); ++ ++ private final PredicateCondition[] terms; ++ ++ public AlternativePredicateCondition(PredicateCondition[] terms) { ++ super(KEY); ++ this.terms = terms; ++ } ++ ++ public PredicateCondition[] getTerms() { ++ return terms; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/BlockStatePropertyPredicateCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/BlockStatePropertyPredicateCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6a810d3a3ff679de8e1a4c01a1f3738e8c1edc81 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/BlockStatePropertyPredicateCondition.java +@@ -0,0 +1,27 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import io.papermc.paper.advancements.triggers.conditions.StateCondition; ++import org.bukkit.Material; ++import org.bukkit.NamespacedKey; ++ ++public class BlockStatePropertyPredicateCondition extends PredicateCondition { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("block_state_property"); ++ ++ private final Material block; ++ private final StateCondition state; ++ ++ public BlockStatePropertyPredicateCondition(Material block, StateCondition state) { ++ super(KEY); ++ this.block = block; ++ this.state = state; ++ } ++ ++ public Material getBlock() { ++ return block; ++ } ++ ++ public StateCondition getState() { ++ return state; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/BonusTablePredicateCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/BonusTablePredicateCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8f3d0aafa351d8bf7bc72a50e3d1064c786b591b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/BonusTablePredicateCondition.java +@@ -0,0 +1,26 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import org.bukkit.NamespacedKey; ++import org.bukkit.enchantments.Enchantment; ++ ++public class BonusTablePredicateCondition extends PredicateCondition { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("table_bonus"); ++ ++ private final Enchantment enchantment; ++ private final float[] chances; ++ ++ public BonusTablePredicateCondition(Enchantment enchantment, float[] chances) { ++ super(KEY); ++ this.enchantment = enchantment; ++ this.chances = chances; ++ } ++ ++ public Enchantment getEnchantment() { ++ return enchantment; ++ } ++ ++ public float[] getChances() { ++ return chances; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/DamageSourcePropertiesPredicateCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/DamageSourcePropertiesPredicateCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ae5a29bdadaa032a67947ee68652c6dc7a0df096 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/DamageSourcePropertiesPredicateCondition.java +@@ -0,0 +1,20 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import io.papermc.paper.advancements.triggers.conditions.DamageSourceCondition; ++import org.bukkit.NamespacedKey; ++ ++public class DamageSourcePropertiesPredicateCondition extends PredicateCondition { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("damage_source_properties"); ++ ++ private final DamageSourceCondition damageType; ++ ++ public DamageSourcePropertiesPredicateCondition(DamageSourceCondition damageType) { ++ super(KEY); ++ this.damageType = damageType; ++ } ++ ++ public DamageSourceCondition getDamageType() { ++ return damageType; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/EntityPropertyPredicateCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/EntityPropertyPredicateCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..91563bdc2b4b48b80ee3604e3b0970e91381dcba +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/EntityPropertyPredicateCondition.java +@@ -0,0 +1,26 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition; ++import org.bukkit.NamespacedKey; ++ ++public class EntityPropertyPredicateCondition extends PredicateCondition { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("entity_properties"); ++ ++ private final EntityCondition entity; ++ private final EntityTarget target; ++ ++ public EntityPropertyPredicateCondition(EntityCondition entity, EntityTarget target) { ++ super(KEY); ++ this.entity = entity; ++ this.target = target; ++ } ++ ++ public EntityCondition getEntity() { ++ return entity; ++ } ++ ++ public EntityTarget getTarget() { ++ return target; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/EntityTarget.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/EntityTarget.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9dc528862e9dda00ce9a5c2da2b8f4af0e7d86af +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/EntityTarget.java +@@ -0,0 +1,29 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import org.jetbrains.annotations.Nullable; ++ ++public enum EntityTarget { ++ THIS("this"), ++ KILLER("killer"), ++ DIRECT_KILLER("direct_killer"), ++ KILLER_PLAYER("killer_player"), ++ ; ++ ++ private final String name; ++ ++ EntityTarget(String name) { ++ this.name = name; ++ } ++ ++ public String getName() { ++ return name; ++ } ++ ++ public static EntityTarget getByName(@Nullable String name) { ++ if (name == null) return null; ++ for (EntityTarget target : EntityTarget.values()) { ++ if (target.getName().equalsIgnoreCase(name)) return target; ++ } ++ return null; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/InvertedPredicateCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/InvertedPredicateCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9177798b0135f3eca4e3c61cb1ddd58f541eee47 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/InvertedPredicateCondition.java +@@ -0,0 +1,19 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import org.bukkit.NamespacedKey; ++ ++public class InvertedPredicateCondition extends PredicateCondition { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("inverted"); ++ ++ private final PredicateCondition term; ++ ++ public InvertedPredicateCondition(PredicateCondition term) { ++ super(KEY); ++ this.term = term; ++ } ++ ++ public PredicateCondition getTerm() { ++ return term; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/KilledByPlayerPredicateCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/KilledByPlayerPredicateCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4df477de3f0b974e6edd7613a83c1a8705fd9d9f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/KilledByPlayerPredicateCondition.java +@@ -0,0 +1,13 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import org.bukkit.NamespacedKey; ++ ++public class KilledByPlayerPredicateCondition extends PredicateCondition { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("killed_by_player"); ++ public static final KilledByPlayerPredicateCondition INSTANCE = new KilledByPlayerPredicateCondition(); ++ ++ private KilledByPlayerPredicateCondition() { ++ super(KEY); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/LocationCheckPredicateCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/LocationCheckPredicateCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0afe2028925a8fa2539337844dd88b2f7c53687c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/LocationCheckPredicateCondition.java +@@ -0,0 +1,27 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import io.papermc.paper.advancements.triggers.conditions.LocationCondition; ++import org.bukkit.Location; ++import org.bukkit.NamespacedKey; ++ ++public class LocationCheckPredicateCondition extends PredicateCondition { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("location_check"); ++ ++ private final LocationCondition location; ++ private final Location blockPosition; ++ ++ public LocationCheckPredicateCondition(LocationCondition location, Location blockPosition) { ++ super(KEY); ++ this.location = location; ++ this.blockPosition = blockPosition; ++ } ++ ++ public LocationCondition getLocation() { ++ return location; ++ } ++ ++ public Location getBlockPosition() { ++ return blockPosition; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/MatchToolPredicateCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/MatchToolPredicateCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e70ad372a953927199107d45abbccd967853c1a2 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/MatchToolPredicateCondition.java +@@ -0,0 +1,20 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import org.bukkit.NamespacedKey; ++ ++public class MatchToolPredicateCondition extends PredicateCondition { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("match_tool"); ++ ++ private final ItemCondition item; ++ ++ public MatchToolPredicateCondition(ItemCondition item) { ++ super(KEY); ++ this.item = item; ++ } ++ ++ public ItemCondition getItem() { ++ return item; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/PredicateCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/PredicateCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d560343e025898f5503995dea2e5e5d14fe3a1e8 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/PredicateCondition.java +@@ -0,0 +1,20 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++public abstract class PredicateCondition implements Keyed { ++ ++ private final NamespacedKey key; ++ ++ public PredicateCondition(NamespacedKey key) { ++ this.key = key; ++ } ++ ++ @NotNull ++ @Override ++ public NamespacedKey getKey() { ++ return key; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/RandomChancePredicateCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/RandomChancePredicateCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5f499c921ffd68c21fc95bd7227799f704f54d97 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/RandomChancePredicateCondition.java +@@ -0,0 +1,19 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import org.bukkit.NamespacedKey; ++ ++public class RandomChancePredicateCondition extends PredicateCondition { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("random_chance"); ++ ++ private final float chance; ++ ++ public RandomChancePredicateCondition(float chance) { ++ super(KEY); ++ this.chance = chance; ++ } ++ ++ public float getChance() { ++ return chance; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/RandomChanceWithLootingPredicateCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/RandomChanceWithLootingPredicateCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3fcbb52c94db69b5b703d0243f36c354649fb2eb +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/RandomChanceWithLootingPredicateCondition.java +@@ -0,0 +1,25 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import org.bukkit.NamespacedKey; ++ ++public class RandomChanceWithLootingPredicateCondition extends PredicateCondition { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("random_chance_with_looting"); ++ ++ private final float precent; ++ private final float multipler; ++ ++ public RandomChanceWithLootingPredicateCondition(float precent, float multipler) { ++ super(KEY); ++ this.precent = precent; ++ this.multipler = multipler; ++ } ++ ++ public float getPrecent() { ++ return precent; ++ } ++ ++ public float getMultipler() { ++ return multipler; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/ReferencePredicateCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/ReferencePredicateCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2cafe262d953900b7412ca683176c847653924b6 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/ReferencePredicateCondition.java +@@ -0,0 +1,19 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import org.bukkit.NamespacedKey; ++ ++public class ReferencePredicateCondition extends PredicateCondition { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("reference"); ++ ++ private final NamespacedKey reference; ++ ++ public ReferencePredicateCondition(NamespacedKey reference) { ++ super(KEY); ++ this.reference = reference; ++ } ++ ++ public NamespacedKey getReference() { ++ return reference; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/SurvivesExplosionPredicateCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/SurvivesExplosionPredicateCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8c08d0c94185c22b8bdd53adb78d721432261f1a +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/SurvivesExplosionPredicateCondition.java +@@ -0,0 +1,13 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import org.bukkit.NamespacedKey; ++ ++public class SurvivesExplosionPredicateCondition extends PredicateCondition { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("survives_explosion"); ++ public static final SurvivesExplosionPredicateCondition INSTANCE = new SurvivesExplosionPredicateCondition(); ++ ++ private SurvivesExplosionPredicateCondition() { ++ super(KEY); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/TimeCheckPredicateCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/TimeCheckPredicateCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7bf3dce3313a03852ecafe054342177eb96c6ef3 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/TimeCheckPredicateCondition.java +@@ -0,0 +1,26 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import io.papermc.paper.advancements.triggers.conditions.predicates.values.ValueRange; ++import org.bukkit.NamespacedKey; ++ ++public class TimeCheckPredicateCondition extends PredicateCondition { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("time_check"); ++ ++ private final Long period; ++ private final ValueRange value; ++ ++ public TimeCheckPredicateCondition(Long period, ValueRange value) { ++ super(KEY); ++ this.period = period; ++ this.value = value; ++ } ++ ++ public Long getPeriod() { ++ return period; ++ } ++ ++ public ValueRange getValue() { ++ return value; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/WeatherCheckPredicateCondition.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/WeatherCheckPredicateCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a9f367bd87e74ca4a4e7af6b3572f49cac82cb99 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/WeatherCheckPredicateCondition.java +@@ -0,0 +1,25 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import org.bukkit.NamespacedKey; ++ ++public class WeatherCheckPredicateCondition extends PredicateCondition { ++ ++ public static final NamespacedKey KEY = NamespacedKey.minecraft("weather_check"); ++ ++ private final Boolean isRaining; ++ private final Boolean isThundering; ++ ++ public WeatherCheckPredicateCondition(Boolean isRaining, Boolean isThundering) { ++ super(KEY); ++ this.isRaining = isRaining; ++ this.isThundering = isThundering; ++ } ++ ++ public Boolean getRaining() { ++ return isRaining; ++ } ++ ++ public Boolean getThundering() { ++ return isThundering; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/values/Value.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/values/Value.java +new file mode 100644 +index 0000000000000000000000000000000000000000..82253896ffb58d3eac8536e81c7a3882ec5d429f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/values/Value.java +@@ -0,0 +1,12 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates.values; ++ ++import org.bukkit.NamespacedKey; ++ ++public interface Value { ++ ++ NamespacedKey CONSTANT = NamespacedKey.minecraft("constant"); ++ NamespacedKey UNIFORM = NamespacedKey.minecraft("uniform"); ++ NamespacedKey BINOMIAL = NamespacedKey.minecraft("binomial"); ++ ++ NamespacedKey getType(); ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/values/ValueRange.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/values/ValueRange.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e6f9164bfb12b15f75df7aeeb75cc4e03bd63603 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/values/ValueRange.java +@@ -0,0 +1,32 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates.values; ++ ++import org.bukkit.NamespacedKey; ++ ++public class ValueRange implements Value { ++ ++ private final float min; ++ private final float max; ++ ++ public ValueRange(float min, float max) { ++ this.min = min; ++ this.max = max; ++ } ++ ++ public ValueRange(float value) { ++ this.min = value; ++ this.max = value; ++ } ++ ++ @Override ++ public NamespacedKey getType() { ++ return UNIFORM; ++ } ++ ++ public float getMin() { ++ return min; ++ } ++ ++ public float getMax() { ++ return max; ++ } ++} +diff --git a/src/main/java/org/bukkit/Statistic.java b/src/main/java/org/bukkit/Statistic.java +index 5cb41f417eb87d4aecd61de30f2a44cec5a9a4cd..5d94461f12e2996be966a299f34bc09447732a03 100644 +--- a/src/main/java/org/bukkit/Statistic.java ++++ b/src/main/java/org/bukkit/Statistic.java +@@ -2,6 +2,7 @@ package org.bukkit; + + import java.util.Locale; + import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; + + /** + * Represents a countable statistic, which is tracked by the server. +@@ -173,4 +174,19 @@ public enum Statistic implements Keyed { + */ + ENTITY; + } ++ // Paper start ++ /** ++ * Get a statistic by its namespaced key. ++ * @param key namespaced key ++ * @return the statistic or null ++ */ ++ @Nullable ++ public static Statistic getByKey(@Nullable NamespacedKey key) { ++ if (key == null) return null; ++ for (Statistic statistic : Statistic.values()) { ++ if (statistic.getKey().equals(key)) return statistic; ++ } ++ return null; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/advancement/Advancement.java b/src/main/java/org/bukkit/advancement/Advancement.java +index 7c5009974ac8d64d0e738e60cec45acb0d4ca89a..af40afabb86c4d61359d1777a61b83b35fb446f1 100644 +--- a/src/main/java/org/bukkit/advancement/Advancement.java ++++ b/src/main/java/org/bukkit/advancement/Advancement.java +@@ -17,4 +17,22 @@ public interface Advancement extends Keyed { + */ + @NotNull + Collection getCriteria(); ++ // Paper start ++ @org.jetbrains.annotations.Nullable ++ Advancement getParent(); ++ ++ void setParent(@org.jetbrains.annotations.Nullable Advancement parent); ++ ++ @org.jetbrains.annotations.Nullable ++ io.papermc.paper.advancements.AdvancementDisplay getAdvancementDisplay(); ++ ++ @org.jetbrains.annotations.Nullable ++ io.papermc.paper.advancements.AdvancementRewards getAdvancementRewards(); ++ ++ @NotNull ++ java.util.Map getTriggers(); ++ ++ @NotNull ++ String[][] getRequirements(); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/block/Biome.java b/src/main/java/org/bukkit/block/Biome.java +index 52a527bb5f6e5b133d9f75556bf72242928b703b..bed401a0deaf995d20279b52d4151452a5c3ae6b 100644 +--- a/src/main/java/org/bukkit/block/Biome.java ++++ b/src/main/java/org/bukkit/block/Biome.java +@@ -100,4 +100,15 @@ public enum Biome implements Keyed { + public NamespacedKey getKey() { + return key; + } ++ ++ // Paper start ++ @org.jetbrains.annotations.Nullable ++ public static Biome getByKey(@org.jetbrains.annotations.Nullable NamespacedKey key) { ++ if (key == null) return null; ++ for (Biome value : Biome.values()) { ++ if (value.getKey().equals(key)) return value; ++ } ++ return null; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/EntityType.java b/src/main/java/org/bukkit/entity/EntityType.java +index 692b75eb78405874077c850bfc72e247ccc80860..2def2fc93b66a739224f80592bf089f539552787 100644 +--- a/src/main/java/org/bukkit/entity/EntityType.java ++++ b/src/main/java/org/bukkit/entity/EntityType.java +@@ -425,4 +425,20 @@ public enum EntityType implements Keyed { + String getTranslationKey() { + return org.bukkit.Bukkit.getUnsafe().getTranslationKey(this); + } ++ // Paper start ++ ++ /** ++ * Get EntityType by NamespacedKey ++ * @param key namespace:key ++ * @return EntityType if found, or null if not ++ */ ++ @Nullable ++ public static EntityType getByKey(@Nullable NamespacedKey key) { ++ if (key == null) return null; ++ for (EntityType entityType : EntityType.values()) { ++ if (entityType.getKey().toString().equals(key.toString())) return entityType; ++ } ++ return null; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/potion/PotionEffectType.java b/src/main/java/org/bukkit/potion/PotionEffectType.java +index b5790aaac67f5b73f941147008d21a92d716b254..3b3a1357fe729ae42912dddfa595ce6dfe9327ca 100644 +--- a/src/main/java/org/bukkit/potion/PotionEffectType.java ++++ b/src/main/java/org/bukkit/potion/PotionEffectType.java +@@ -11,7 +11,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents a type of potion and its effect on an entity. + */ +-public abstract class PotionEffectType { ++public abstract class PotionEffectType implements org.bukkit.Keyed { // Paper + /** + * Increases movement speed. + */ +@@ -330,4 +330,19 @@ public abstract class PotionEffectType { + public static PotionEffectType[] values() { + return Arrays.copyOfRange(byId, 1, byId.length); + } ++ // Paper start ++ /** ++ * Gets the PotionEffectType by namespaced key ++ * @param key namespaced:key ++ * @return the requested type or null if not found ++ */ ++ @Nullable ++ public static PotionEffectType getByKey(@Nullable org.bukkit.NamespacedKey key) { ++ if (key == null) return null; ++ for (PotionEffectType effectType : PotionEffectType.values()) { ++ if (effectType.getKey().toString().equals(key.toString())) return effectType; ++ } ++ return null; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/potion/PotionEffectTypeWrapper.java b/src/main/java/org/bukkit/potion/PotionEffectTypeWrapper.java +index 47d46edc49c8a35ff9e8b462ea045f192f98d1f4..721c26a33590277b3e48ca383538b25850a259de 100644 +--- a/src/main/java/org/bukkit/potion/PotionEffectTypeWrapper.java ++++ b/src/main/java/org/bukkit/potion/PotionEffectTypeWrapper.java +@@ -39,4 +39,11 @@ public class PotionEffectTypeWrapper extends PotionEffectType { + public Color getColor() { + return getType().getColor(); + } ++ // Paper start ++ @NotNull ++ @Override ++ public org.bukkit.NamespacedKey getKey() { ++ return getType().getKey(); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/potion/PotionType.java b/src/main/java/org/bukkit/potion/PotionType.java +index af7dea669cd394db2498e8d9dc88bbd8eac4b83b..2488bead274c35aad2050419448222b3fadb7ea2 100644 +--- a/src/main/java/org/bukkit/potion/PotionType.java ++++ b/src/main/java/org/bukkit/potion/PotionType.java +@@ -6,38 +6,41 @@ import org.jetbrains.annotations.Nullable; + * This enum reflects and matches each potion state that can be obtained from + * the Creative mode inventory + */ +-public enum PotionType { +- UNCRAFTABLE(null, false, false), +- WATER(null, false, false), +- MUNDANE(null, false, false), +- THICK(null, false, false), +- AWKWARD(null, false, false), +- NIGHT_VISION(PotionEffectType.NIGHT_VISION, false, true), +- INVISIBILITY(PotionEffectType.INVISIBILITY, false, true), +- JUMP(PotionEffectType.JUMP, true, true), +- FIRE_RESISTANCE(PotionEffectType.FIRE_RESISTANCE, false, true), +- SPEED(PotionEffectType.SPEED, true, true), +- SLOWNESS(PotionEffectType.SLOW, true, true), +- WATER_BREATHING(PotionEffectType.WATER_BREATHING, false, true), +- INSTANT_HEAL(PotionEffectType.HEAL, true, false), +- INSTANT_DAMAGE(PotionEffectType.HARM, true, false), +- POISON(PotionEffectType.POISON, true, true), +- REGEN(PotionEffectType.REGENERATION, true, true), +- STRENGTH(PotionEffectType.INCREASE_DAMAGE, true, true), +- WEAKNESS(PotionEffectType.WEAKNESS, false, true), +- LUCK(PotionEffectType.LUCK, false, false), +- TURTLE_MASTER(PotionEffectType.SLOW, true, true), // TODO: multiple effects +- SLOW_FALLING(PotionEffectType.SLOW_FALLING, false, true), ++public enum PotionType implements org.bukkit.Keyed { // Paper start - Add keys ++ UNCRAFTABLE(null, false, false, "empty"), ++ WATER(null, false, false, "water"), ++ MUNDANE(null, false, false, "mundane"), ++ THICK(null, false, false, "think"), ++ AWKWARD(null, false, false, "awkward"), ++ NIGHT_VISION(PotionEffectType.NIGHT_VISION, false, true, "night_vision"), ++ INVISIBILITY(PotionEffectType.INVISIBILITY, false, true, "invisibility"), ++ JUMP(PotionEffectType.JUMP, true, true, "leaping"), ++ FIRE_RESISTANCE(PotionEffectType.FIRE_RESISTANCE, false, true, "fire_resistance"), ++ SPEED(PotionEffectType.SPEED, true, true, "swiftness"), ++ SLOWNESS(PotionEffectType.SLOW, true, true, "slowness"), ++ WATER_BREATHING(PotionEffectType.WATER_BREATHING, false, true, "water_breathing"), ++ INSTANT_HEAL(PotionEffectType.HEAL, true, false, "healing"), ++ INSTANT_DAMAGE(PotionEffectType.HARM, true, false, "harming"), ++ POISON(PotionEffectType.POISON, true, true, "poison"), ++ REGEN(PotionEffectType.REGENERATION, true, true, "regeneration"), ++ STRENGTH(PotionEffectType.INCREASE_DAMAGE, true, true, "strength"), ++ WEAKNESS(PotionEffectType.WEAKNESS, false, true, "weakness"), ++ LUCK(PotionEffectType.LUCK, false, false, "luvk"), ++ TURTLE_MASTER(PotionEffectType.SLOW, true, true, "turtle_master"), // TODO: multiple effects ++ SLOW_FALLING(PotionEffectType.SLOW_FALLING, false, true, "slow_falling"), ++ // Paper end + ; + + private final PotionEffectType effect; + private final boolean upgradeable; + private final boolean extendable; ++ private final org.bukkit.NamespacedKey key; // Paper + +- PotionType(/*@Nullable*/ PotionEffectType effect, boolean upgradeable, boolean extendable) { ++ PotionType(/*@Nullable*/ PotionEffectType effect, boolean upgradeable, boolean extendable, String key) { // Paper + this.effect = effect; + this.upgradeable = upgradeable; + this.extendable = extendable; ++ this.key = org.bukkit.NamespacedKey.minecraft(key); // Paper + } + + @Nullable +@@ -90,4 +93,28 @@ public enum PotionType { + } + return null; + } ++ // Paper start ++ /** ++ * Get the namespaced key for this potion type ++ * @return key in the minecraft namespace ++ */ ++ @Override ++ public @org.jetbrains.annotations.NotNull org.bukkit.NamespacedKey getKey() { ++ return this.key; ++ } ++ ++ /** ++ * Gets the PotionType based on the NamespacedKey ++ * @param key the namespace:key ++ * @return the PotionType or null if not found ++ */ ++ @Nullable ++ public static PotionType getByKey(@Nullable org.bukkit.NamespacedKey key) { ++ if (key == null) return null; ++ for (PotionType potionType : PotionType.values()) { ++ if (potionType.key.toString().equals(key.toString())) return potionType; ++ } ++ return null; ++ } ++ // Paper end + } diff --git a/Spigot-Server-Patches/0623-Advancement-API.patch b/Spigot-Server-Patches/0623-Advancement-API.patch new file mode 100644 index 000000000000..f3eebdbb72fe --- /dev/null +++ b/Spigot-Server-Patches/0623-Advancement-API.patch @@ -0,0 +1,4803 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 29 Dec 2020 15:19:32 -0800 +Subject: [PATCH] Advancement API + + +diff --git a/src/main/java/io/papermc/paper/advancements/AdvancementDisplayAdapter.java b/src/main/java/io/papermc/paper/advancements/AdvancementDisplayAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8c3886a5587eb6df76c8267596315b3ba53344f4 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/AdvancementDisplayAdapter.java +@@ -0,0 +1,51 @@ ++package io.papermc.paper.advancements; ++ ++public class AdvancementDisplayAdapter implements com.google.gson.JsonDeserializer, com.google.gson.JsonSerializer { ++ ++ private static final String TITLE = "title"; ++ private static final String DESCRIPTION = "description"; ++ private static final String ICON = "icon"; ++ private static final String FRAME = "frame"; ++ private static final String BACKGROUND = "background"; ++ private static final String SHOW_TOAST = "show_toast"; ++ private static final String ANNOUNCE_TO_CHAT = "announce_to_chat"; ++ private static final String HIDDEN = "hidden"; ++ ++ @Override ++ public io.papermc.paper.advancements.AdvancementDisplay deserialize(com.google.gson.JsonElement json, java.lang.reflect.Type typeOfT, com.google.gson.JsonDeserializationContext context) throws com.google.gson.JsonParseException { ++ com.google.gson.JsonObject jsonObject = json.getAsJsonObject(); ++ String title = org.bukkit.craftbukkit.util.CraftChatMessage.fromComponent(net.minecraft.server.IChatBaseComponent.ChatSerializer.a(jsonObject.get(TITLE))); // TODO Component ++ String description = org.bukkit.craftbukkit.util.CraftChatMessage.fromComponent(net.minecraft.server.IChatBaseComponent.ChatSerializer.a(jsonObject.get(DESCRIPTION))); // TODO Component ++ org.bukkit.inventory.ItemStack icon = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(net.minecraft.server.AdvancementDisplay.deserializeItemStack(net.minecraft.server.ChatDeserializer.getJsonObject(jsonObject, ICON))); ++ org.bukkit.NamespacedKey background = org.bukkit.craftbukkit.util.CraftNamespacedKey.fromStringOrNull(io.papermc.paper.util.PaperChatDeserializer.getStringOrDefault(jsonObject, BACKGROUND, (String) null)); ++ io.papermc.paper.advancements.AdvancementDisplay.AdvancementFrameType frameType = io.papermc.paper.advancements.AdvancementDisplay.AdvancementFrameType.getByText(io.papermc.paper.util.PaperChatDeserializer.getStringOrDefault(jsonObject, FRAME, io.papermc.paper.advancements.AdvancementDisplay.AdvancementFrameType.TASK.getText())); ++ boolean showToast = io.papermc.paper.util.PaperChatDeserializer.getBooleanOrDefault(jsonObject, SHOW_TOAST, true); ++ boolean announceToChat = io.papermc.paper.util.PaperChatDeserializer.getBooleanOrDefault(jsonObject, ANNOUNCE_TO_CHAT, true); ++ boolean hidden = io.papermc.paper.util.PaperChatDeserializer.getBooleanOrDefault(jsonObject, HIDDEN, false); ++ return new io.papermc.paper.advancements.AdvancementDisplay(title, description, icon, background, frameType, showToast, announceToChat, hidden); ++ } ++ ++ @Override ++ public com.google.gson.JsonElement serialize(io.papermc.paper.advancements.AdvancementDisplay src, java.lang.reflect.Type typeOfSrc, com.google.gson.JsonSerializationContext context) { ++ com.google.gson.JsonObject jsonObject = new com.google.gson.JsonObject(); ++ jsonObject.add(TITLE, net.minecraft.server.IChatBaseComponent.ChatSerializer.b(org.bukkit.craftbukkit.util.CraftChatMessage.fromStringOrNull(src.title()))); // TODO Component ++ jsonObject.add(DESCRIPTION, net.minecraft.server.IChatBaseComponent.ChatSerializer.b(org.bukkit.craftbukkit.util.CraftChatMessage.fromStringOrNull(src.description()))); // TODO Component ++ jsonObject.add(ICON, serializeItemStack(src.getIcon())); ++ jsonObject.addProperty(FRAME, src.getFrame().getText()); ++ if (src.getBackground() != null) jsonObject.addProperty(BACKGROUND, src.getBackground().toString()); ++ jsonObject.addProperty(SHOW_TOAST, src.getShowToast()); ++ jsonObject.addProperty(ANNOUNCE_TO_CHAT, src.getAnnounceToChat()); ++ jsonObject.addProperty(HIDDEN, src.getHidden()); ++ return jsonObject; ++ } ++ ++ private static com.google.gson.JsonElement serializeItemStack(org.bukkit.inventory.ItemStack itemStack) { ++ net.minecraft.server.ItemStack nmsItemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(itemStack); ++ com.google.gson.JsonObject jsonObject = new com.google.gson.JsonObject(); ++ jsonObject.addProperty("item", net.minecraft.server.IRegistry.ITEM.getKey(nmsItemStack.getItem()).toString()); ++ if (nmsItemStack.hasTag()) { ++ jsonObject.addProperty("nbt", nmsItemStack.getTag().toString()); ++ } ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/AdvancementRewardsAdapter.java b/src/main/java/io/papermc/paper/advancements/AdvancementRewardsAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..844059ad961e2276e3e424267eb6298cc8e92a3c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/AdvancementRewardsAdapter.java +@@ -0,0 +1,61 @@ ++package io.papermc.paper.advancements; ++ ++public class AdvancementRewardsAdapter implements com.google.gson.JsonDeserializer, com.google.gson.JsonSerializer { ++ ++ private static final String RECIPES = "recipes"; ++ private static final String LOOT = "loot"; ++ private static final String EXP = "experience"; ++ private static final String FUNCTION = "function"; ++ ++ @Override ++ public io.papermc.paper.advancements.AdvancementRewards deserialize(com.google.gson.JsonElement json, java.lang.reflect.Type typeOfT, com.google.gson.JsonDeserializationContext context) throws com.google.gson.JsonParseException { ++ com.google.gson.JsonObject jsonObject = json.getAsJsonObject(); ++ int exp = io.papermc.paper.util.PaperChatDeserializer.getIntOrDefault(jsonObject, EXP, 0); ++ com.google.gson.JsonArray lootArray = io.papermc.paper.util.PaperChatDeserializer.getJsonArrayOrDefault(jsonObject, LOOT, new com.google.gson.JsonArray()); ++ java.util.List loot = new java.util.ArrayList<>(lootArray.size()); ++ for (int i = 0; i < loot.size(); i++) { ++ loot.set(i, org.bukkit.craftbukkit.util.CraftNamespacedKey.fromString(net.minecraft.server.ChatDeserializer.getStringRaw(lootArray.get(i), LOOT + "[" + i + "]"))); ++ } ++ com.google.gson.JsonArray recipeArray = io.papermc.paper.util.PaperChatDeserializer.getJsonArrayOrDefault(jsonObject, RECIPES, new com.google.gson.JsonArray()); ++ java.util.List recipes = new java.util.ArrayList<>(recipeArray.size()); ++ for (int i = 0; i < recipes.size(); i++) { ++ recipes.set(i, org.bukkit.craftbukkit.util.CraftNamespacedKey.fromString(net.minecraft.server.ChatDeserializer.getStringRaw(lootArray.get(i), RECIPES + "[" + i + "]"))); ++ } ++ org.bukkit.NamespacedKey function = null; ++ if (jsonObject.has("function")) { ++ function = org.bukkit.craftbukkit.util.CraftNamespacedKey.fromString(net.minecraft.server.ChatDeserializer.getString(jsonObject, FUNCTION)); ++ } ++ return new io.papermc.paper.advancements.AdvancementRewards(exp, loot, recipes, function); ++ } ++ ++ @Override ++ public com.google.gson.JsonElement serialize(io.papermc.paper.advancements.AdvancementRewards src, java.lang.reflect.Type typeOfSrc, com.google.gson.JsonSerializationContext context) { ++ if (io.papermc.paper.advancements.AdvancementRewards.isEmpty(src)) { ++ return com.google.gson.JsonNull.INSTANCE; ++ } else { ++ com.google.gson.JsonObject jsonObject = new com.google.gson.JsonObject(); ++ if (src.getExp() != 0) { ++ jsonObject.addProperty(EXP, src.getExp()); ++ } ++ com.google.gson.JsonArray jsonArray; ++ if (src.getLoot().size() > 0) { ++ jsonArray = new com.google.gson.JsonArray(); ++ for (org.bukkit.NamespacedKey lootKey : src.getLoot()) { ++ jsonArray.add(lootKey.toString()); ++ } ++ jsonObject.add(LOOT, jsonArray); ++ } ++ if (src.getRecipes().size() > 0) { ++ jsonArray = new com.google.gson.JsonArray(); ++ for (org.bukkit.NamespacedKey recipeKey : src.getRecipes()) { ++ jsonArray.add(recipeKey.toString()); ++ } ++ jsonObject.add(RECIPES, jsonArray); ++ } ++ if (src.getFunction() != null) { ++ jsonObject.addProperty(FUNCTION, src.getFunction().toString()); ++ } ++ return jsonObject; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/AdvancementTriggers.java b/src/main/java/io/papermc/paper/advancements/AdvancementTriggers.java +new file mode 100644 +index 0000000000000000000000000000000000000000..26ce9c892ea63056b78e37efc138f598074daaa1 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/AdvancementTriggers.java +@@ -0,0 +1,157 @@ ++package io.papermc.paper.advancements; ++ ++import com.google.common.collect.Maps; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonObject; ++import io.papermc.paper.advancements.triggers.AbstractLocationTrigger.HeroOfTheVillageTrigger; ++import io.papermc.paper.advancements.triggers.AbstractLocationTrigger.LocationTrigger; ++import io.papermc.paper.advancements.triggers.AbstractLocationTrigger.SleptInBedTrigger; ++import io.papermc.paper.advancements.triggers.AbstractLocationTrigger.VoluntaryExileTrigger; ++import io.papermc.paper.advancements.triggers.AbstractLocationTriggerAdapter; ++import io.papermc.paper.advancements.triggers.AbstractLocationTriggerAdapter.HeroOfTheVillageTriggerAdapter; ++import io.papermc.paper.advancements.triggers.AbstractLocationTriggerAdapter.LocationTriggerAdapter; ++import io.papermc.paper.advancements.triggers.AbstractLocationTriggerAdapter.SleptInBedTriggerAdapter; ++import io.papermc.paper.advancements.triggers.AbstractLocationTriggerAdapter.VoluntaryExileTriggerAdapter; ++import io.papermc.paper.advancements.triggers.BredAnimalsTrigger; ++import io.papermc.paper.advancements.triggers.BredAnimalsTriggerAdapter; ++import io.papermc.paper.advancements.triggers.BrewedPotionTrigger; ++import io.papermc.paper.advancements.triggers.BrewedPotionTriggerAdapter; ++import io.papermc.paper.advancements.triggers.ChangedDimensionTrigger; ++import io.papermc.paper.advancements.triggers.ChangedDimensionTriggerAdapter; ++import io.papermc.paper.advancements.triggers.ChanneledLightningTrigger; ++import io.papermc.paper.advancements.triggers.ConstructBeaconTrigger; ++import io.papermc.paper.advancements.triggers.ConstructBeaconTriggerAdapter; ++import io.papermc.paper.advancements.triggers.ConsumeItemTrigger; ++import io.papermc.paper.advancements.triggers.ConsumeItemTriggerAdapter; ++import io.papermc.paper.advancements.triggers.CuredZombieVillagerTrigger; ++import io.papermc.paper.advancements.triggers.CuredZombieVillagerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.EffectsChangedTrigger; ++import io.papermc.paper.advancements.triggers.EffectsChangedTriggerAdapter; ++import io.papermc.paper.advancements.triggers.EnchantedItemTrigger; ++import io.papermc.paper.advancements.triggers.EnchantedItemTriggerAdapter; ++import io.papermc.paper.advancements.triggers.EntityHurtPlayerTrigger; ++import io.papermc.paper.advancements.triggers.FilledBucketTrigger; ++import io.papermc.paper.advancements.triggers.FilledBucketTriggerAdapter; ++import io.papermc.paper.advancements.triggers.FishingRodHookedTrigger; ++import io.papermc.paper.advancements.triggers.FishingRodHookedTriggerAdapter; ++import io.papermc.paper.advancements.triggers.GenerateLootTableTrigger; ++import io.papermc.paper.advancements.triggers.GenerateLootTableTriggerAdapter; ++import io.papermc.paper.advancements.triggers.InteractBlockTrigger; ++import io.papermc.paper.advancements.triggers.InteractBlockTriggerAdapter; ++import io.papermc.paper.advancements.triggers.ItemDurabilityChangeTrigger; ++import io.papermc.paper.advancements.triggers.ItemDurabilityChangeTriggerAdapter; ++import io.papermc.paper.advancements.triggers.KilledByCrossbowTrigger; ++import io.papermc.paper.advancements.triggers.KilledByCrossbowTriggerAdapter; ++import io.papermc.paper.advancements.triggers.LevitationTrigger; ++import io.papermc.paper.advancements.triggers.LevitationTriggerAdapter; ++import io.papermc.paper.advancements.triggers.NetherTravelTrigger; ++import io.papermc.paper.advancements.triggers.NetherTravelTriggerAdapter; ++import io.papermc.paper.advancements.triggers.PlacedBlockTrigger; ++import io.papermc.paper.advancements.triggers.PlacedBlockTriggerAdapter; ++import io.papermc.paper.advancements.triggers.PlayerInteractWithEntityTrigger; ++import io.papermc.paper.advancements.triggers.PlayerInteractWithEntityTriggerAdapter; ++import io.papermc.paper.advancements.triggers.ShotCrossbowTrigger; ++import io.papermc.paper.advancements.triggers.ShotCrossbowTriggerAdapter; ++import io.papermc.paper.advancements.triggers.SlideDownBlockTrigger; ++import io.papermc.paper.advancements.triggers.SlideDownBlockTriggerAdapter; ++import io.papermc.paper.advancements.triggers.SummonedEntityTrigger; ++import io.papermc.paper.advancements.triggers.SummonedEntityTriggerAdapter; ++import io.papermc.paper.advancements.triggers.TamedAnimalTrigger; ++import io.papermc.paper.advancements.triggers.TamedAnimalTriggerAdapter; ++import io.papermc.paper.advancements.triggers.TargetHitTrigger; ++import io.papermc.paper.advancements.triggers.TargetHitTriggerAdapter; ++import io.papermc.paper.advancements.triggers.ThrownItemPickedUpTrigger; ++import io.papermc.paper.advancements.triggers.ThrownItemPickedUpTriggerAdapter; ++import io.papermc.paper.advancements.triggers.TickTrigger; ++import io.papermc.paper.advancements.triggers.TickTriggerAdapter; ++import io.papermc.paper.advancements.triggers.TriggerAdapter; ++import io.papermc.paper.advancements.triggers.BeeNestDestroyedTrigger; ++import io.papermc.paper.advancements.triggers.BeeNestDestroyedTriggerAdapter; ++import io.papermc.paper.advancements.triggers.EnterBlockTrigger; ++import io.papermc.paper.advancements.triggers.EnterBlockTriggerAdapter; ++import io.papermc.paper.advancements.triggers.ImpossibleTrigger; ++import io.papermc.paper.advancements.triggers.ImpossibleTriggerAdapter; ++import io.papermc.paper.advancements.triggers.InventoryChangedTrigger; ++import io.papermc.paper.advancements.triggers.InventoryChangedTriggerAdapter; ++import io.papermc.paper.advancements.triggers.KilledTrigger.EntityKilledPlayerTrigger; ++import io.papermc.paper.advancements.triggers.KilledTrigger.PlayerKilledEntityTrigger; ++import io.papermc.paper.advancements.triggers.KilledTriggerAdapter.EntityKilledPlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.KilledTriggerAdapter.PlayerKilledEntityTriggerAdapter; ++import io.papermc.paper.advancements.triggers.PlayerHurtEntityTrigger; ++import io.papermc.paper.advancements.triggers.PlayerHurtEntityTriggerAdapter; ++import io.papermc.paper.advancements.triggers.RecipeUnlockedTrigger; ++import io.papermc.paper.advancements.triggers.RecipeUnlockedTriggerAdapter; ++import io.papermc.paper.advancements.triggers.UsedEnderEyeTrigger; ++import io.papermc.paper.advancements.triggers.UsedEnderEyeTriggerAdapter; ++import io.papermc.paper.advancements.triggers.UsedTotemTrigger; ++import io.papermc.paper.advancements.triggers.UsedTotemTriggerAdapter; ++import io.papermc.paper.advancements.triggers.VillagerTradeTrigger; ++import io.papermc.paper.advancements.triggers.VillagerTradeTriggerAdapter; ++import net.minecraft.server.ChatDeserializer; ++import org.bukkit.NamespacedKey; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++ ++import java.util.Map; ++ ++public class AdvancementTriggers { ++ ++ public static final Map> TRIGGER_MAP = Maps.newHashMap(); ++ ++ static { ++ TRIGGER_MAP.put(ImpossibleTrigger.KEY, new ImpossibleTriggerAdapter()); ++ TRIGGER_MAP.put(PlayerKilledEntityTrigger.KEY, new PlayerKilledEntityTriggerAdapter()); ++ TRIGGER_MAP.put(EntityKilledPlayerTrigger.KEY, new EntityKilledPlayerTriggerAdapter()); ++ TRIGGER_MAP.put(EnterBlockTrigger.KEY, new EnterBlockTriggerAdapter()); ++ TRIGGER_MAP.put(InventoryChangedTrigger.KEY, new InventoryChangedTriggerAdapter()); ++ TRIGGER_MAP.put(RecipeUnlockedTrigger.KEY, new RecipeUnlockedTriggerAdapter()); ++ TRIGGER_MAP.put(PlayerHurtEntityTrigger.KEY, new PlayerHurtEntityTriggerAdapter()); ++ TRIGGER_MAP.put(EntityHurtPlayerTrigger.KEY, new EntityKilledPlayerTriggerAdapter()); ++ TRIGGER_MAP.put(EnchantedItemTrigger.KEY, new EnchantedItemTriggerAdapter()); ++ TRIGGER_MAP.put(FilledBucketTrigger.KEY, new FilledBucketTriggerAdapter()); ++ TRIGGER_MAP.put(BrewedPotionTrigger.KEY, new BrewedPotionTriggerAdapter()); ++ TRIGGER_MAP.put(ConstructBeaconTrigger.KEY, new ConstructBeaconTriggerAdapter()); ++ TRIGGER_MAP.put(UsedEnderEyeTrigger.KEY, new UsedEnderEyeTriggerAdapter()); ++ TRIGGER_MAP.put(SummonedEntityTrigger.KEY, new SummonedEntityTriggerAdapter()); ++ TRIGGER_MAP.put(BredAnimalsTrigger.KEY, new BredAnimalsTriggerAdapter()); ++ TRIGGER_MAP.put(LocationTrigger.KEY, new LocationTriggerAdapter()); ++ TRIGGER_MAP.put(SleptInBedTrigger.KEY, new SleptInBedTriggerAdapter()); ++ TRIGGER_MAP.put(CuredZombieVillagerTrigger.KEY, new CuredZombieVillagerTriggerAdapter()); ++ TRIGGER_MAP.put(VillagerTradeTrigger.KEY, new VillagerTradeTriggerAdapter()); ++ TRIGGER_MAP.put(ItemDurabilityChangeTrigger.KEY, new ItemDurabilityChangeTriggerAdapter()); ++ TRIGGER_MAP.put(LevitationTrigger.KEY, new LevitationTriggerAdapter()); ++ TRIGGER_MAP.put(ChangedDimensionTrigger.KEY, new ChangedDimensionTriggerAdapter()); ++ TRIGGER_MAP.put(TickTrigger.KEY, new TickTriggerAdapter()); ++ TRIGGER_MAP.put(TamedAnimalTrigger.KEY, new TamedAnimalTriggerAdapter()); ++ TRIGGER_MAP.put(PlacedBlockTrigger.KEY, new PlacedBlockTriggerAdapter()); ++ TRIGGER_MAP.put(ConsumeItemTrigger.KEY, new ConsumeItemTriggerAdapter()); ++ TRIGGER_MAP.put(EffectsChangedTrigger.KEY, new EffectsChangedTriggerAdapter()); ++ TRIGGER_MAP.put(UsedTotemTrigger.KEY, new UsedTotemTriggerAdapter()); ++ TRIGGER_MAP.put(NetherTravelTrigger.KEY, new NetherTravelTriggerAdapter()); ++ TRIGGER_MAP.put(FishingRodHookedTrigger.KEY, new FishingRodHookedTriggerAdapter()); ++ TRIGGER_MAP.put(ChanneledLightningTrigger.KEY, new ChangedDimensionTriggerAdapter()); ++ TRIGGER_MAP.put(ShotCrossbowTrigger.KEY, new ShotCrossbowTriggerAdapter()); ++ TRIGGER_MAP.put(KilledByCrossbowTrigger.KEY, new KilledByCrossbowTriggerAdapter()); ++ TRIGGER_MAP.put(HeroOfTheVillageTrigger.KEY, new HeroOfTheVillageTriggerAdapter()); ++ TRIGGER_MAP.put(VoluntaryExileTrigger.KEY, new VoluntaryExileTriggerAdapter()); ++ TRIGGER_MAP.put(SlideDownBlockTrigger.KEY, new SlideDownBlockTriggerAdapter()); ++ TRIGGER_MAP.put(BeeNestDestroyedTrigger.KEY, new BeeNestDestroyedTriggerAdapter()); ++ TRIGGER_MAP.put(TargetHitTrigger.KEY, new TargetHitTriggerAdapter()); ++ TRIGGER_MAP.put(InteractBlockTrigger.KEY, new InteractBlockTriggerAdapter()); ++ TRIGGER_MAP.put(GenerateLootTableTrigger.KEY, new GenerateLootTableTriggerAdapter()); ++ TRIGGER_MAP.put(ThrownItemPickedUpTrigger.KEY, new ThrownItemPickedUpTriggerAdapter()); ++ TRIGGER_MAP.put(PlayerInteractWithEntityTrigger.KEY, new PlayerInteractWithEntityTriggerAdapter()); ++ ++ for (TriggerAdapter adapter : TRIGGER_MAP.values()) { ++ CraftAdvancementsManager.addHierarchyAdapter(adapter.getTriggerClass(), adapter); ++ } ++ } ++ ++ public static void init() { } ++ ++ ++ private static final String TRIGGER = "trigger"; ++ public static NamespacedKey getTrigerKey(JsonElement jsonElement) { ++ JsonObject jsonObject = ChatDeserializer.asJsonObject(jsonElement, "criteria"); ++ return CraftNamespacedKey.fromString(ChatDeserializer.getString(jsonObject, TRIGGER)); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/CraftAdvancementsManager.java b/src/main/java/io/papermc/paper/advancements/CraftAdvancementsManager.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8fcab9b49c801b591208cc7d80b7e672e72c0fb3 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/CraftAdvancementsManager.java +@@ -0,0 +1,113 @@ ++package io.papermc.paper.advancements; ++ ++import com.google.gson.Gson; ++import com.google.gson.GsonBuilder; ++import io.papermc.paper.advancements.triggers.conditions.BlockCondition; ++import io.papermc.paper.advancements.triggers.conditions.BlockConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.DamageCondition; ++import io.papermc.paper.advancements.triggers.conditions.DamageConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.DamageSourceCondition; ++import io.papermc.paper.advancements.triggers.conditions.DamageTypeConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.DistanceCondition; ++import io.papermc.paper.advancements.triggers.conditions.DistanceConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EffectsCondition; ++import io.papermc.paper.advancements.triggers.conditions.EffectsCondition.EffectInfo; ++import io.papermc.paper.advancements.triggers.conditions.EffectsConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EffectsConditionAdapter.EffectInfoAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EnchantmentCondition; ++import io.papermc.paper.advancements.triggers.conditions.EnchantmentCondition.EnchantmentsCondition; ++import io.papermc.paper.advancements.triggers.conditions.EnchantmentConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EnchantmentConditionAdapter.EnchantmentsConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.EntityConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityConditionAdapter.EntityPredicatesConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityEquipmentCondition; ++import io.papermc.paper.advancements.triggers.conditions.EntityEquipmentConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityFlagsCondition; ++import io.papermc.paper.advancements.triggers.conditions.EntityFlagsConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityTypeCondition; ++import io.papermc.paper.advancements.triggers.conditions.EntityTypeConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.FishingHookCondition; ++import io.papermc.paper.advancements.triggers.conditions.FishingHookConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.FluidCondition; ++import io.papermc.paper.advancements.triggers.conditions.FluidConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition.ItemsCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.ItemConditionAdapter.ItemsConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.LightCondition; ++import io.papermc.paper.advancements.triggers.conditions.LightConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.LocationCondition; ++import io.papermc.paper.advancements.triggers.conditions.LocationConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.StateCondition; ++import io.papermc.paper.advancements.triggers.conditions.StateConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.FloatRange; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import io.papermc.paper.advancements.triggers.conditions.ValueConditionAdapter; ++import io.papermc.paper.advancements.triggers.conditions.ValueConditionAdapter.FloatRangeAdapter; ++import io.papermc.paper.advancements.triggers.conditions.ValueConditionAdapter.IntegerRangeAdapter; ++import io.papermc.paper.advancements.triggers.conditions.predicates.PredicateConditions; ++import org.bukkit.advancement.Advancement; ++import org.bukkit.craftbukkit.advancement.CraftAdvancement.AdvancementSerialization; ++import org.bukkit.craftbukkit.advancement.CraftAdvancement.CraftSerializedAdvancement; ++ ++public class CraftAdvancementsManager implements AdvancementsManager { ++ ++ private static final GsonBuilder GSON_BUILDER; ++ private static Gson ADVANCEMENTS_GSON; ++ static { ++ GSON_BUILDER = new GsonBuilder(); ++ GSON_BUILDER.registerTypeAdapter(AdvancementDisplay.class, new AdvancementDisplayAdapter()); ++ GSON_BUILDER.registerTypeAdapter(AdvancementRewards.class, new AdvancementRewardsAdapter()); ++ GSON_BUILDER.registerTypeAdapter(CraftSerializedAdvancement.class, new AdvancementSerialization()); ++ GSON_BUILDER.registerTypeAdapter(BlockCondition.class, new BlockConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(DamageCondition.class, new DamageConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(DamageSourceCondition.class, new DamageTypeConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(DistanceCondition.class, new DistanceConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(EffectsCondition.class, new EffectsConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(EffectInfo.class, new EffectInfoAdapter()); ++ GSON_BUILDER.registerTypeAdapter(EnchantmentCondition.class, new EnchantmentConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(EnchantmentsCondition.class, new EnchantmentsConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(EntityCondition.class, new EntityConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(EntityPredicatesCondition.class, new EntityPredicatesConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(EntityEquipmentCondition.class, new EntityEquipmentConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(EntityFlagsCondition.class, new EntityFlagsConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(EntityTypeCondition.class, new EntityTypeConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(FishingHookCondition.class, new FishingHookConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(FluidCondition.class, new FluidConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(ItemCondition.class, new ItemConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(ItemsCondition.class, new ItemsConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(LightCondition.class, new LightConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(LocationCondition.class, new LocationConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(StateCondition.class, new StateConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(ValueCondition.class, new ValueConditionAdapter()); ++ GSON_BUILDER.registerTypeAdapter(FloatRange.class, new FloatRangeAdapter()); ++ GSON_BUILDER.registerTypeAdapter(IntegerRange.class, new IntegerRangeAdapter()); ++ ++ PredicateConditions.init(); ++ AdvancementTriggers.init(); ++ } ++ ++ public static Gson getGson() { ++ if (ADVANCEMENTS_GSON == null) { ++ ADVANCEMENTS_GSON = GSON_BUILDER.create(); ++ } ++ return ADVANCEMENTS_GSON; ++ } ++ ++ public static void addHierarchyAdapter(Class clazz, Object adapter) { ++ GSON_BUILDER.registerTypeHierarchyAdapter(clazz, adapter); ++ } ++ ++ @Override ++ public Advancement createAdvancement(String key) { ++ return null; ++ } ++ ++ @Override ++ public void reload() { ++ ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/PlayerConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/PlayerConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b4808a6e210736e8d222560359a2cc2880dc1513 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/PlayerConditionAdapter.java +@@ -0,0 +1,158 @@ ++package io.papermc.paper.advancements; ++ ++import com.google.common.base.Enums; ++import com.google.common.base.MoreObjects; ++import com.google.common.collect.Maps; ++import com.google.gson.JsonArray; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonNull; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import io.papermc.paper.advancements.triggers.conditions.PlayerCondition; ++import io.papermc.paper.advancements.triggers.conditions.PlayerCondition.AdvancementCondition; ++import io.papermc.paper.advancements.triggers.conditions.PlayerCondition.AdvancementCriterionsCondition; ++import io.papermc.paper.advancements.triggers.conditions.PlayerCondition.AdvancementDoneCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import io.papermc.paper.util.PaperChatDeserializer; ++import it.unimi.dsi.fastutil.objects.Object2BooleanMap; ++import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap; ++import net.minecraft.server.ChatDeserializer; ++import net.minecraft.server.CriterionConditionPlayer; ++import net.minecraft.server.IRegistry; ++import net.minecraft.server.MinecraftKey; ++import net.minecraft.server.StatisticWrapper; ++import org.bukkit.GameMode; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Statistic; ++import org.bukkit.craftbukkit.CraftStatistic; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++ ++import java.lang.reflect.Type; ++import java.util.Iterator; ++import java.util.Locale; ++import java.util.Map; ++import java.util.Map.Entry; ++ ++public class PlayerConditionAdapter implements JsonDeserializer, JsonSerializer { ++ ++ private static final String PLAYER = "player"; ++ private static final String LEVEL = "level"; ++ private static final String GAMEMODE = "gamemode"; ++ private static final String STATS = "stats"; ++ private static final String TYPE = "type"; ++ private static final String STAT = "stat"; ++ private static final String VALUE = "value"; ++ private static final String RECIPES = "recipes"; ++ private static final String ADVANCEMENTS = "advancements"; ++ ++ @Override ++ public PlayerCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject jsonObject = ChatDeserializer.asJsonObject(json, "player"); ++ IntegerRange level = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(LEVEL), IntegerRange.class), IntegerRange.ANY); ++ GameMode gameMode = Enums.getIfPresent(GameMode.class, PaperChatDeserializer.getStringOrDefault(jsonObject, GAMEMODE, "").toUpperCase(Locale.ROOT)).orNull(); ++ Map statMap = Maps.newHashMap(); ++ JsonArray jsonArray = PaperChatDeserializer.getJsonArrayOrDefault(jsonObject, STATS, null); ++ if (jsonArray != null) { ++ Iterator iterator = jsonArray.iterator(); ++ while (iterator.hasNext()) { ++ JsonObject statsObj = ChatDeserializer.asJsonObject(iterator.next(), "stats entry"); ++ MinecraftKey minecraftKey = new MinecraftKey(ChatDeserializer.getString(jsonObject, TYPE)); ++ StatisticWrapper statisticWrapper = IRegistry.STATS.get(minecraftKey); ++ if (statisticWrapper == null) { ++ throw new JsonParseException("Invalid stat type: " + minecraftKey); ++ } ++ MinecraftKey minecraftKey1 = new MinecraftKey(ChatDeserializer.getString(jsonObject, STAT)); ++ Statistic statistic = CraftStatistic.getBukkitStatistic(CriterionConditionPlayer.getStat(statisticWrapper, minecraftKey)); ++ IntegerRange value = MoreObjects.firstNonNull(context.deserialize(statsObj.get(VALUE), IntegerRange.class), IntegerRange.ANY); ++ statMap.put(statistic, value); ++ } ++ } ++ ++ Object2BooleanMap recipeMap = new Object2BooleanOpenHashMap<>(); ++ JsonObject recipeObj = PaperChatDeserializer.getJsonObjectOrDefault(jsonObject, RECIPES, new JsonObject()); ++ Iterator> iterator = recipeObj.entrySet().iterator(); ++ while (iterator.hasNext()) { ++ Entry entry = iterator.next(); ++ NamespacedKey key = CraftNamespacedKey.fromString(entry.getKey()); ++ boolean isPresent = ChatDeserializer.asBoolean(entry.getValue(), "recipe present"); ++ recipeMap.put(key, isPresent); ++ } ++ ++ Map advancementMap = Maps.newHashMap(); ++ JsonObject advancementObj = PaperChatDeserializer.getJsonObjectOrDefault(jsonObject, ADVANCEMENTS, new JsonObject()); ++ iterator = advancementObj.entrySet().iterator(); ++ while (iterator.hasNext()) { ++ Entry entry = iterator.next(); ++ NamespacedKey key = CraftNamespacedKey.fromString(entry.getKey()); ++ advancementMap.put(key, context.deserialize(entry.getValue(), AdvancementCondition.class)); ++ } ++ return new PlayerCondition(level, gameMode, statMap, recipeMap, advancementMap); ++ } ++ ++ @Override ++ public JsonElement serialize(PlayerCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src == PlayerCondition.ANY) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(LEVEL, context.serialize(src.getLevel())); ++ if (src.getGameMode() != null) { ++ jsonObject.addProperty(GAMEMODE, src.getGameMode().name().toLowerCase(Locale.ROOT)); ++ } ++ if (!src.getStats().isEmpty()) { ++ JsonArray jsonArray = new JsonArray(); ++ src.getStats().forEach((statistic, integerRange) -> { ++ JsonObject statObj = new JsonObject(); ++ net.minecraft.server.Statistic nmsStat = CraftStatistic.getNMSStatistic(statistic); ++ statObj.addProperty(TYPE, IRegistry.STATS.getKey(nmsStat.getWrapper()).toString()); ++ statObj.addProperty(STAT, CriterionConditionPlayer.getKey(nmsStat).toString()); ++ statObj.add(VALUE, context.serialize(integerRange)); ++ jsonArray.add(statObj); ++ }); ++ jsonObject.add(STATS, jsonArray); ++ } ++ if (!src.getRecipes().isEmpty()) { ++ JsonObject recipeObj = new JsonObject(); ++ src.getRecipes().forEach((key, done) -> { ++ recipeObj.addProperty(key.toString(), done); ++ }); ++ jsonObject.add(RECIPES, recipeObj); ++ } ++ if (!src.getAdvancements().isEmpty()) { ++ JsonObject advancementsObj = new JsonObject(); ++ src.getAdvancements().forEach((key, advancementCondition) -> { ++ advancementsObj.add(key.toString(), advancementCondition.toJson()); ++ }); ++ jsonObject.add(ADVANCEMENTS, advancementsObj); ++ } ++ return jsonObject; ++ } ++ } ++ ++ public static class AdvancementConditionAdapter implements JsonDeserializer, JsonSerializer { ++ @Override ++ public AdvancementCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ if (json.isJsonPrimitive()) { ++ boolean done = json.getAsBoolean(); ++ return new AdvancementDoneCondition(done); ++ } else { ++ Object2BooleanMap criterionsMap = new Object2BooleanOpenHashMap<>(); ++ JsonObject criterionObj = ChatDeserializer.asJsonObject(json, "criterion data"); ++ criterionObj.entrySet().forEach(entry -> { ++ boolean done = ChatDeserializer.asBoolean(entry.getValue(), "criterion test"); ++ criterionsMap.put(entry.getKey(), done); ++ }); ++ return new AdvancementCriterionsCondition(criterionsMap); ++ } ++ } ++ ++ @Override ++ public JsonElement serialize(AdvancementCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ return src.toJson(); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/AbstractLocationTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/AbstractLocationTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8f691159e172fe63fdae661422fec8f58c6d806f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/AbstractLocationTriggerAdapter.java +@@ -0,0 +1,87 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.AbstractLocationTrigger.HeroOfTheVillageTrigger; ++import io.papermc.paper.advancements.triggers.AbstractLocationTrigger.LocationTrigger; ++import io.papermc.paper.advancements.triggers.AbstractLocationTrigger.SleptInBedTrigger; ++import io.papermc.paper.advancements.triggers.AbstractLocationTrigger.VoluntaryExileTrigger; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.LocationCondition; ++import io.papermc.paper.util.PaperChatDeserializer; ++ ++import java.lang.reflect.Type; ++import java.util.function.Function; ++ ++public abstract class AbstractLocationTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String LOCATION = "location"; ++ ++ public AbstractLocationTriggerAdapter(Class clazz) { ++ super(clazz); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(T trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(LOCATION, context.serialize(trigger.getLocation())); ++ return jsonObject; ++ } ++ ++ protected T deserialize(JsonObject jsonObject, JsonDeserializationContext context, Function createFunction) { ++ JsonObject locationObj = PaperChatDeserializer.getJsonObjectOrDefault(jsonObject, LOCATION, jsonObject); ++ LocationCondition location = MoreObjects.firstNonNull(context.deserialize(locationObj, LocationCondition.class), LocationCondition.ANY); ++ return createFunction.apply(location); ++ } ++ ++ public static class LocationTriggerAdapter extends AbstractLocationTriggerAdapter { ++ ++ public LocationTriggerAdapter() { ++ super(LocationTrigger.class); ++ } ++ ++ @Override ++ public LocationTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ return deserialize(jsonObject, context, locationCondition -> new LocationTrigger(player, locationCondition)); ++ } ++ } ++ ++ public static class SleptInBedTriggerAdapter extends AbstractLocationTriggerAdapter { ++ ++ public SleptInBedTriggerAdapter() { ++ super(SleptInBedTrigger.class); ++ } ++ ++ @Override ++ public SleptInBedTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ return deserialize(jsonObject, context, locationCondition -> new SleptInBedTrigger(player, locationCondition)); ++ } ++ } ++ ++ public static class HeroOfTheVillageTriggerAdapter extends AbstractLocationTriggerAdapter { ++ ++ public HeroOfTheVillageTriggerAdapter() { ++ super(HeroOfTheVillageTrigger.class); ++ } ++ ++ @Override ++ public HeroOfTheVillageTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ return deserialize(jsonObject, context, locationCondition -> new HeroOfTheVillageTrigger(player, locationCondition)); ++ } ++ } ++ ++ public static class VoluntaryExileTriggerAdapter extends AbstractLocationTriggerAdapter { ++ ++ public VoluntaryExileTriggerAdapter() { ++ super(VoluntaryExileTrigger.class); ++ } ++ ++ @Override ++ public VoluntaryExileTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ return deserialize(jsonObject, context, locationCondition -> new VoluntaryExileTrigger(player, locationCondition)); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/BeeNestDestroyedTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/BeeNestDestroyedTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..573c684979ca22ae45dead424629203372bad429 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/BeeNestDestroyedTriggerAdapter.java +@@ -0,0 +1,56 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSyntaxException; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import net.minecraft.server.Block; ++import net.minecraft.server.ChatDeserializer; ++import net.minecraft.server.IRegistry; ++import net.minecraft.server.MinecraftKey; ++import org.bukkit.Material; ++import org.bukkit.craftbukkit.util.CraftMagicNumbers; ++ ++import java.lang.reflect.Type; ++ ++public class BeeNestDestroyedTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String BLOCK = "block"; ++ private static final String ITEM = "item"; ++ private static final String NUM_OF_BEES = "num_bees_inside"; ++ ++ public BeeNestDestroyedTriggerAdapter() { ++ super(BeeNestDestroyedTrigger.class); ++ } ++ ++ @Override ++ public BeeNestDestroyedTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ Material block = null; ++ if (jsonObject.has(BLOCK)) { ++ MinecraftKey minecraftkey = new MinecraftKey(ChatDeserializer.getString(jsonObject, "block")); ++ ++ block = CraftMagicNumbers.getMaterial((Block) IRegistry.BLOCK.getOptional(minecraftkey).orElseThrow(() -> { ++ return new JsonSyntaxException("Unknown block type '" + minecraftkey + "'"); ++ })); ++ } ++ ItemCondition item = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ITEM), ItemCondition.class), ItemCondition.ANY); ++ IntegerRange numOfBees = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(NUM_OF_BEES), IntegerRange.class), IntegerRange.ANY); ++ return new BeeNestDestroyedTrigger(player, block, item, numOfBees); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(BeeNestDestroyedTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ if (trigger.getBlock() != null) { ++ jsonObject.addProperty(BLOCK, trigger.getBlock().getKey().toString()); ++ } ++ jsonObject.add(ITEM, context.serialize(trigger.getItem())); ++ jsonObject.add(NUM_OF_BEES, context.serialize(trigger.getNumOfBees())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/BredAnimalsTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/BredAnimalsTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4148f0c4f4e1ac253c4a99f22bdf066a0f8f8b1e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/BredAnimalsTriggerAdapter.java +@@ -0,0 +1,38 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++ ++import java.lang.reflect.Type; ++ ++public class BredAnimalsTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String PARENT = "parent"; ++ private static final String PARTNER = "partner"; ++ private static final String CHILD = "child"; ++ ++ public BredAnimalsTriggerAdapter() { ++ super(BredAnimalsTrigger.class); ++ } ++ ++ @Override ++ public BredAnimalsTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ EntityPredicatesCondition parent = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(PARENT), EntityPredicatesCondition.class), EntityPredicatesCondition.ANY); ++ EntityPredicatesCondition partner = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(PARTNER), EntityPredicatesCondition.class), EntityPredicatesCondition.ANY); ++ EntityPredicatesCondition child = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(CHILD), EntityPredicatesCondition.class), EntityPredicatesCondition.ANY); ++ return new BredAnimalsTrigger(player, parent, partner, child); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(BredAnimalsTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(PARENT, context.serialize(trigger.getParent())); ++ jsonObject.add(PARTNER, context.serialize(trigger.getPartner())); ++ jsonObject.add(CHILD, context.serialize(trigger.getChild())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/BrewedPotionTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/BrewedPotionTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..aaf9fed69e5e42e6863bc117e28f7841a7cf3fc3 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/BrewedPotionTriggerAdapter.java +@@ -0,0 +1,45 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.destroystokyo.paper.utils.PaperPluginLogger; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import net.minecraft.server.ChatDeserializer; ++import org.bukkit.NamespacedKey; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++import org.bukkit.potion.PotionEffectType; ++ ++import java.lang.reflect.Type; ++ ++public class BrewedPotionTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String POTION = "potion"; ++ ++ public BrewedPotionTriggerAdapter() { ++ super(BrewedPotionTrigger.class); ++ } ++ ++ @Override ++ public BrewedPotionTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ PotionEffectType effectType = null; ++ if (jsonObject.has(POTION)) { ++ NamespacedKey key = CraftNamespacedKey.fromString(ChatDeserializer.getString(jsonObject, POTION)); ++ effectType = PotionEffectType.getByKey(key); ++ if (effectType == null) { ++ PaperPluginLogger.getGlobal().warning("Did not recognize '" + key + "'"); ++ } ++ } ++ return new BrewedPotionTrigger(player, effectType); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(BrewedPotionTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ if (trigger.getEffectType() != null) { ++ jsonObject.addProperty(POTION, trigger.getEffectType().getKey().toString()); ++ } ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/ChangedDimensionTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/ChangedDimensionTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..871a61a39748212d2b1f9cea5d5c001ddbd3414e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/ChangedDimensionTriggerAdapter.java +@@ -0,0 +1,48 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.util.PaperChatDeserializer; ++import net.minecraft.server.ChatDeserializer; ++import net.minecraft.server.IRegistry; ++import net.minecraft.server.MinecraftKey; ++import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.ResourceKey; ++import org.bukkit.Bukkit; ++import org.bukkit.NamespacedKey; ++import org.bukkit.World; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++ ++import java.lang.reflect.Type; ++ ++public class ChangedDimensionTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String FROM = "from"; ++ private static final String TO = "to"; ++ ++ public ChangedDimensionTriggerAdapter() { ++ super(ChangedDimensionTrigger.class); ++ } ++ ++ @Override ++ public ChangedDimensionTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ NamespacedKey from = CraftNamespacedKey.fromStringOrNull(PaperChatDeserializer.getStringOrDefault(jsonObject, FROM, null)); ++ NamespacedKey to = CraftNamespacedKey.fromStringOrNull(PaperChatDeserializer.getStringOrDefault(jsonObject, TO, null)); ++ return new ChangedDimensionTrigger(player, from, to); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(ChangedDimensionTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ if (trigger.getFrom() != null) { ++ jsonObject.addProperty(FROM, trigger.getFrom().toString()); ++ } ++ if (trigger.getTo() != null) { ++ jsonObject.addProperty(TO, trigger.getTo().toString()); ++ } ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/ChanneledLightningTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/ChanneledLightningTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a4400058b745ade2dcbc10a0bb750a5c83af5101 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/ChanneledLightningTriggerAdapter.java +@@ -0,0 +1,32 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++ ++import java.lang.reflect.Type; ++ ++public class ChanneledLightningTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String VICTIMS = "victims"; ++ ++ public ChanneledLightningTriggerAdapter() { ++ super(ChanneledLightningTrigger.class); ++ } ++ ++ @Override ++ public ChanneledLightningTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ EntityPredicatesCondition[] victims = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(VICTIMS), EntityPredicatesCondition[].class), EntityPredicatesCondition.ANY_ARRAY); ++ return new ChanneledLightningTrigger(player, victims); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(ChanneledLightningTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(VICTIMS, context.serialize(trigger.getVictims())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/ConstructBeaconTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/ConstructBeaconTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..fd5f01d670b2d495bdb991cf0316a22c9279d367 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/ConstructBeaconTriggerAdapter.java +@@ -0,0 +1,33 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++ ++import java.lang.reflect.Type; ++ ++public class ConstructBeaconTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String LEVEL = "level"; ++ ++ public ConstructBeaconTriggerAdapter() { ++ super(ConstructBeaconTrigger.class); ++ } ++ ++ @Override ++ public ConstructBeaconTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ IntegerRange level = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(LEVEL), IntegerRange.class), IntegerRange.ANY); ++ return new ConstructBeaconTrigger(player, level); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(ConstructBeaconTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(LEVEL, context.serialize(trigger.getLevel())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/ConsumeItemTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/ConsumeItemTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..df3d585998be1a2f9d31180e28b830b39aa8c6b8 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/ConsumeItemTriggerAdapter.java +@@ -0,0 +1,33 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++ ++import java.lang.reflect.Type; ++ ++public class ConsumeItemTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String ITEM = "item"; ++ ++ public ConsumeItemTriggerAdapter() { ++ super(ConsumeItemTrigger.class); ++ } ++ ++ @Override ++ public ConsumeItemTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ ItemCondition item = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ITEM), ItemCondition.class), ItemCondition.ANY); ++ return new ConsumeItemTrigger(player, item); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(ConsumeItemTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(ITEM, context.serialize(trigger.getItem())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/CuredZombieVillagerTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/CuredZombieVillagerTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..cc78eba65e4f29673debf2d0788576af39b7d617 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/CuredZombieVillagerTriggerAdapter.java +@@ -0,0 +1,35 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++ ++import java.lang.reflect.Type; ++ ++public class CuredZombieVillagerTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String ZOMBIE = "zombie"; ++ private static final String VILLAGER = "villager"; ++ ++ public CuredZombieVillagerTriggerAdapter() { ++ super(CuredZombieVillagerTrigger.class); ++ } ++ ++ @Override ++ public CuredZombieVillagerTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ EntityPredicatesCondition zombie = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ZOMBIE), EntityPredicatesCondition.class), EntityPredicatesCondition.ANY); ++ EntityPredicatesCondition villager = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(VILLAGER), EntityPredicatesCondition.class), EntityPredicatesCondition.ANY); ++ return new CuredZombieVillagerTrigger(player, zombie, villager); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(CuredZombieVillagerTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(ZOMBIE, context.serialize(trigger.getZombie())); ++ jsonObject.add(VILLAGER, context.serialize(trigger.getVillager())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/EffectsChangedTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/EffectsChangedTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2f863203d81b9e99190fbd3dbd5c62d1f60fab2e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/EffectsChangedTriggerAdapter.java +@@ -0,0 +1,33 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EffectsCondition; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++ ++import java.lang.reflect.Type; ++ ++public class EffectsChangedTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String EFFECTS = "effects"; ++ ++ public EffectsChangedTriggerAdapter() { ++ super(EffectsChangedTrigger.class); ++ } ++ ++ @Override ++ public EffectsChangedTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ EffectsCondition effects = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(EFFECTS), EffectsCondition.class), EffectsCondition.ANY); ++ return new EffectsChangedTrigger(player, effects); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(EffectsChangedTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(EFFECTS, context.serialize(trigger.getEffects())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/EnchantedItemTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/EnchantedItemTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4d022b44338b2c555a834809e162e4fa7e240db8 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/EnchantedItemTriggerAdapter.java +@@ -0,0 +1,37 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++ ++import java.lang.reflect.Type; ++ ++public class EnchantedItemTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String ITEM = "item"; ++ private static final String LEVELS = "levels"; ++ ++ public EnchantedItemTriggerAdapter() { ++ super(EnchantedItemTrigger.class); ++ } ++ ++ @Override ++ public EnchantedItemTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ ItemCondition item = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ITEM), ItemCondition.class), ItemCondition.ANY); ++ IntegerRange levels = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(LEVELS), IntegerRange.class), IntegerRange.ANY); ++ return new EnchantedItemTrigger(player, item, levels); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(EnchantedItemTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(ITEM, context.serialize(trigger.getItem())); ++ jsonObject.add(LEVELS, context.serialize(trigger.getLevels())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/EnterBlockTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/EnterBlockTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a3ec3de0d2bed8d3f655ff2151b125e30c59d2df +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/EnterBlockTriggerAdapter.java +@@ -0,0 +1,52 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSyntaxException; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.StateCondition; ++import net.minecraft.server.Block; ++import net.minecraft.server.ChatDeserializer; ++import net.minecraft.server.IRegistry; ++import net.minecraft.server.MinecraftKey; ++import org.bukkit.Material; ++import org.bukkit.craftbukkit.util.CraftMagicNumbers; ++ ++import java.lang.reflect.Type; ++ ++public class EnterBlockTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String BLOCK = "block"; ++ private static final String STATE = "state"; ++ ++ public EnterBlockTriggerAdapter() { ++ super(EnterBlockTrigger.class); ++ } ++ ++ @Override ++ public EnterBlockTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ Material block = null; ++ if (jsonObject.has(BLOCK)) { ++ MinecraftKey minecraftkey = new MinecraftKey(ChatDeserializer.getString(jsonObject, "block")); ++ ++ block = CraftMagicNumbers.getMaterial((Block) IRegistry.BLOCK.getOptional(minecraftkey).orElseThrow(() -> { ++ return new JsonSyntaxException("Unknown block type '" + minecraftkey + "'"); ++ })); ++ } ++ StateCondition state = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(STATE), StateCondition.class), StateCondition.ANY); ++ return new EnterBlockTrigger(player, block, state); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(EnterBlockTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ if (trigger.getBlock() != null) { ++ jsonObject.addProperty(BLOCK, trigger.getBlock().getKey().toString()); ++ } ++ jsonObject.add(STATE, context.serialize(trigger.getState())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/EntityHurtPlayerTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/EntityHurtPlayerTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..09464d7324d4c353c0416e56891cf3604debde4f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/EntityHurtPlayerTriggerAdapter.java +@@ -0,0 +1,33 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.DamageCondition; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++ ++import java.lang.reflect.Type; ++ ++public class EntityHurtPlayerTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String DAMAGE = "damage"; ++ ++ public EntityHurtPlayerTriggerAdapter() { ++ super(EntityHurtPlayerTrigger.class); ++ } ++ ++ @Override ++ public EntityHurtPlayerTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ DamageCondition damage = MoreObjects.firstNonNull(context.deserialize(jsonObject, DamageCondition.class), DamageCondition.ANY); ++ return new EntityHurtPlayerTrigger(player, damage); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(EntityHurtPlayerTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(DAMAGE, context.serialize(trigger.getDamageCondition())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/FilledBucketTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/FilledBucketTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d16ad870abdee31172b6a24b6c7b085c9fc6d847 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/FilledBucketTriggerAdapter.java +@@ -0,0 +1,33 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++ ++import java.lang.reflect.Type; ++ ++public class FilledBucketTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String ITEM = "item"; ++ ++ public FilledBucketTriggerAdapter() { ++ super(FilledBucketTrigger.class); ++ } ++ ++ @Override ++ public FilledBucketTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ ItemCondition item = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ITEM), ItemCondition.class), ItemCondition.ANY); ++ return new FilledBucketTrigger(player, item); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(FilledBucketTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(ITEM, context.serialize(trigger.getItem())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/FishingRodHookedTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/FishingRodHookedTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e58ee2047322b33dc5d870a30caf9910c484c8e6 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/FishingRodHookedTriggerAdapter.java +@@ -0,0 +1,39 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++ ++import java.lang.reflect.Type; ++ ++public class FishingRodHookedTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String ENTITY = "entity"; ++ private static final String ITEM = "item"; ++ private static final String ROD = "rod"; ++ ++ public FishingRodHookedTriggerAdapter() { ++ super(FishingRodHookedTrigger.class); ++ } ++ ++ @Override ++ public FishingRodHookedTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ ItemCondition rod = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ROD), ItemCondition.class), ItemCondition.ANY); ++ EntityPredicatesCondition entity = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ENTITY), EntityPredicatesCondition.class), EntityPredicatesCondition.ANY); ++ ItemCondition item = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ITEM), ItemCondition.class), ItemCondition.ANY); ++ return new FishingRodHookedTrigger(player, rod, entity, item); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(FishingRodHookedTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(ROD, context.serialize(trigger.getRod())); ++ jsonObject.add(ENTITY, context.serialize(trigger.getEntity())); ++ jsonObject.add(ITEM, context.serialize(trigger.getItem())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/GenerateLootTableTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/GenerateLootTableTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..fb61f1258d761a422ac654e8dacbb378d7a43a26 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/GenerateLootTableTriggerAdapter.java +@@ -0,0 +1,34 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import net.minecraft.server.ChatDeserializer; ++import org.bukkit.NamespacedKey; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++ ++import java.lang.reflect.Type; ++ ++public class GenerateLootTableTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String LOOT_TABLE = "loot_table"; ++ ++ public GenerateLootTableTriggerAdapter() { ++ super(GenerateLootTableTrigger.class); ++ } ++ ++ @Override ++ public GenerateLootTableTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ NamespacedKey loottable = CraftNamespacedKey.fromString(ChatDeserializer.getString(jsonObject, LOOT_TABLE)); ++ return new GenerateLootTableTrigger(player, loottable); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(GenerateLootTableTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.addProperty(LOOT_TABLE, trigger.getLoottable().toString()); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/ImpossibleTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/ImpossibleTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b428d9ce17ddd6a875af3c33c27ff6a884b90fef +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/ImpossibleTriggerAdapter.java +@@ -0,0 +1,26 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++ ++import java.lang.reflect.Type; ++ ++public class ImpossibleTriggerAdapter extends TriggerAdapter { ++ ++ public ImpossibleTriggerAdapter() { ++ super(ImpossibleTrigger.class); ++ } ++ ++ @Override ++ public ImpossibleTrigger deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ return new ImpossibleTrigger(); ++ } ++ ++ @Override ++ public JsonElement serialize(ImpossibleTrigger src, Type typeOfSrc, JsonSerializationContext context) { ++ return new JsonObject(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/InteractBlockTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/InteractBlockTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9ad7c47c85e3d3d065f77da1f21a339bf9106fc9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/InteractBlockTriggerAdapter.java +@@ -0,0 +1,37 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import io.papermc.paper.advancements.triggers.conditions.LocationCondition; ++ ++import java.lang.reflect.Type; ++ ++public class InteractBlockTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private final static String LOCATION = "location"; ++ private final static String ITEM = "item"; ++ ++ public InteractBlockTriggerAdapter() { ++ super(InteractBlockTrigger.class); ++ } ++ ++ @Override ++ public InteractBlockTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ LocationCondition location = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(LOCATION), LocationCondition.class), LocationCondition.ANY); ++ ItemCondition item = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ITEM), ItemCondition.class), ItemCondition.ANY); ++ return new InteractBlockTrigger(player, location, item); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(InteractBlockTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(LOCATION, context.serialize(trigger.getLocation())); ++ jsonObject.add(ITEM, context.serialize(trigger.getItem())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/InventoryChangedTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/InventoryChangedTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c4fbe7f43a8ed3848c004e6b3f2539821d378ac3 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/InventoryChangedTriggerAdapter.java +@@ -0,0 +1,59 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonArray; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition.ItemsCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import io.papermc.paper.util.PaperChatDeserializer; ++ ++import java.lang.reflect.Type; ++ ++public class InventoryChangedTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String ITEMS = "items"; ++ private static final String SLOTS = "slots"; ++ private static final String EMPTY = "empty"; ++ private static final String OCCUPIED = "occupied"; ++ private static final String FULL = "full"; ++ ++ public InventoryChangedTriggerAdapter() { ++ super(InventoryChangedTrigger.class); ++ } ++ ++ @Override ++ public InventoryChangedTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ JsonObject slotsObj = PaperChatDeserializer.getJsonObjectOrDefault(jsonObject, SLOTS, new JsonObject()); ++ IntegerRange occupied = MoreObjects.firstNonNull(context.deserialize(slotsObj.get(OCCUPIED), IntegerRange.class), IntegerRange.ANY); ++ IntegerRange full = MoreObjects.firstNonNull(context.deserialize(slotsObj.get(FULL), IntegerRange.class), IntegerRange.ANY); ++ IntegerRange empty = MoreObjects.firstNonNull(context.deserialize(slotsObj.get(EMPTY), IntegerRange.class), IntegerRange.ANY); ++ ItemsCondition items = MoreObjects.firstNonNull(context.deserialize(slotsObj.get(ITEMS), ItemsCondition.class), ItemsCondition.ANY); ++ return new InventoryChangedTrigger(player, occupied, full, empty, items); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(InventoryChangedTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ if (!trigger.getEmpty().isAnyRange() || !trigger.getFull().isAnyRange() || !trigger.getOccupied().isAnyRange()) { ++ JsonObject slots = new JsonObject(); ++ slots.add(OCCUPIED, context.serialize(trigger.getOccupied())); ++ slots.add(FULL, context.serialize(trigger.getFull())); ++ slots.add(EMPTY, context.serialize(trigger.getEmpty())); ++ jsonObject.add(SLOTS, slots); ++ } ++ ++ if (trigger.getItems().size() > 0) { ++ JsonArray items = new JsonArray(); ++ for (ItemCondition item : trigger.getItems()) { ++ items.add(context.serialize(item)); ++ } ++ jsonObject.add(ITEMS, items); ++ } ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/ItemDurabilityChangeTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/ItemDurabilityChangeTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e2c5c7b2ad5546a401ee5eb871a3fd0131994bb8 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/ItemDurabilityChangeTriggerAdapter.java +@@ -0,0 +1,40 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++ ++import java.lang.reflect.Type; ++ ++public class ItemDurabilityChangeTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String DELTA = "delta"; ++ private static final String DURABILITY = "durability"; ++ private static final String ITEM = "item"; ++ ++ public ItemDurabilityChangeTriggerAdapter() { ++ super(ItemDurabilityChangeTrigger.class); ++ } ++ ++ @Override ++ public ItemDurabilityChangeTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ ItemCondition item = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ITEM), ItemCondition.class), ItemCondition.ANY); ++ IntegerRange durability = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(DURABILITY), IntegerRange.class), IntegerRange.ANY); ++ IntegerRange delta = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(DELTA), IntegerRange.class), IntegerRange.ANY); ++ return new ItemDurabilityChangeTrigger(player, item, durability, delta); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(ItemDurabilityChangeTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(ITEM, context.serialize(trigger.getItem())); ++ jsonObject.add(DURABILITY, context.serialize(trigger.getDurability())); ++ jsonObject.add(DELTA, context.serialize(trigger.getDelta())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/KilledByCrossbowTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/KilledByCrossbowTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..993ae41d972430b1ab12b361ba9cbf5300be0325 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/KilledByCrossbowTriggerAdapter.java +@@ -0,0 +1,36 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++ ++import java.lang.reflect.Type; ++ ++public class KilledByCrossbowTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String VICTIMS = "victims"; ++ private static final String UNIQUE_ENTITY_TYPES = "unique_entity_types"; ++ ++ public KilledByCrossbowTriggerAdapter() { ++ super(KilledByCrossbowTrigger.class); ++ } ++ ++ @Override ++ public KilledByCrossbowTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ EntityPredicatesCondition[] victims = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(VICTIMS), EntityPredicatesCondition[].class), EntityPredicatesCondition.ANY_ARRAY); ++ IntegerRange uniqueEntityTypes = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(UNIQUE_ENTITY_TYPES), IntegerRange.class), IntegerRange.ANY); ++ return new KilledByCrossbowTrigger(player, victims, uniqueEntityTypes); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(KilledByCrossbowTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(VICTIMS, context.serialize(trigger.getVictims())); ++ jsonObject.add(UNIQUE_ENTITY_TYPES, context.serialize(trigger.getUniqueEntityTypes())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/KilledTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/KilledTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..119f2145bc7bc694ccc460d08967ba1b702e2826 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/KilledTriggerAdapter.java +@@ -0,0 +1,62 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.KilledTrigger.EntityKilledPlayerTrigger; ++import io.papermc.paper.advancements.triggers.KilledTrigger.PlayerKilledEntityTrigger; ++import io.papermc.paper.advancements.triggers.conditions.DamageSourceCondition; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++ ++import java.lang.reflect.Type; ++import java.util.function.BiFunction; ++ ++public abstract class KilledTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String ENTITY = "entity"; ++ private static final String KILLING_BLOW = "killing_blow"; ++ ++ protected KilledTriggerAdapter(Class triggerClass) { ++ super(triggerClass); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(C trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(ENTITY, context.serialize(trigger.getEntityPredicates())); ++ jsonObject.add(KILLING_BLOW, context.serialize(trigger.getDamageSource())); ++ return jsonObject; ++ } ++ ++ protected C deserialize(JsonObject jsonObject, JsonDeserializationContext context, BiFunction createFunction) { ++ EntityPredicatesCondition entityPredicates = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ENTITY), EntityPredicatesCondition.class), EntityPredicatesCondition.ANY); ++ DamageSourceCondition damageSource = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(KILLING_BLOW), DamageSourceCondition.class), DamageSourceCondition.ANY); ++ return createFunction.apply(entityPredicates, damageSource); ++ } ++ ++ public static class PlayerKilledEntityTriggerAdapter extends KilledTriggerAdapter { ++ ++ public PlayerKilledEntityTriggerAdapter() { ++ super(PlayerKilledEntityTrigger.class); ++ } ++ ++ @Override ++ public PlayerKilledEntityTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ return deserialize(jsonObject, context, (entityPredicatesCondition, damageSourceCondition) -> new PlayerKilledEntityTrigger(player, entityPredicatesCondition, damageSourceCondition)); ++ } ++ } ++ ++ public static class EntityKilledPlayerTriggerAdapter extends KilledTriggerAdapter { ++ ++ public EntityKilledPlayerTriggerAdapter() { ++ super(EntityKilledPlayerTrigger.class); ++ } ++ ++ @Override ++ public EntityKilledPlayerTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ return deserialize(jsonObject, context, (entityPredicatesCondition, damageSourceCondition) -> new EntityKilledPlayerTrigger(player, entityPredicatesCondition, damageSourceCondition)); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/LevitationTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/LevitationTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7d9529040eda858d6af6bd9b772217c7fb2dc3a1 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/LevitationTriggerAdapter.java +@@ -0,0 +1,37 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.DistanceCondition; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++ ++import java.lang.reflect.Type; ++ ++public class LevitationTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String DISTANCE = "distance"; ++ private static final String DURATION = "duration"; ++ ++ public LevitationTriggerAdapter() { ++ super(LevitationTrigger.class); ++ } ++ ++ @Override ++ public LevitationTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ DistanceCondition distance = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(DISTANCE), DistanceCondition.class), DistanceCondition.ANY); ++ IntegerRange duration = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(DURATION), IntegerRange.class), IntegerRange.ANY); ++ return new LevitationTrigger(player, distance, duration); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(LevitationTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(DISTANCE, context.serialize(trigger.getDistance())); ++ jsonObject.add(DURATION, context.serialize(trigger.getDuration())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/NetherTravelTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/NetherTravelTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..bf5153db305e53117d8e8cd1e4f1415ad4c85268 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/NetherTravelTriggerAdapter.java +@@ -0,0 +1,40 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.DistanceCondition; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.LocationCondition; ++ ++import java.lang.reflect.Type; ++ ++public class NetherTravelTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String DISTANCE = "distance"; ++ private static final String ENTERED = "entered"; ++ private static final String EXITED = "exited"; ++ ++ public NetherTravelTriggerAdapter() { ++ super(NetherTravelTrigger.class); ++ } ++ ++ @Override ++ public NetherTravelTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ LocationCondition entered = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ENTERED), LocationCondition.class), LocationCondition.ANY); ++ LocationCondition exited = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(EXITED), LocationCondition.class), LocationCondition.ANY); ++ DistanceCondition distance = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(DISTANCE), DistanceCondition.class), DistanceCondition.ANY); ++ return new NetherTravelTrigger(player, entered, exited, distance); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(NetherTravelTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(ENTERED, context.serialize(trigger.getEntered())); ++ jsonObject.add(EXITED, context.serialize(trigger.getEntered())); ++ jsonObject.add(DISTANCE, context.serialize(trigger.getDistance())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/PlacedBlockTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/PlacedBlockTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..815ce8f2e4c8c1b76cee1cb2562b41c3d7d3821a +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/PlacedBlockTriggerAdapter.java +@@ -0,0 +1,59 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSyntaxException; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++import io.papermc.paper.advancements.triggers.conditions.LocationCondition; ++import io.papermc.paper.advancements.triggers.conditions.StateCondition; ++import net.minecraft.server.Block; ++import net.minecraft.server.ChatDeserializer; ++import net.minecraft.server.IRegistry; ++import net.minecraft.server.MinecraftKey; ++import org.bukkit.Material; ++import org.bukkit.craftbukkit.util.CraftMagicNumbers; ++ ++import java.lang.reflect.Type; ++ ++public class PlacedBlockTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String ITEM = "item"; ++ private static final String STATE = "state"; ++ private static final String BLOCK = "block"; ++ private static final String LOCATION = "location"; ++ ++ public PlacedBlockTriggerAdapter() { ++ super(PlacedBlockTrigger.class); ++ } ++ ++ @Override ++ public PlacedBlockTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ Material block = null; ++ if (jsonObject.has(BLOCK)) { ++ MinecraftKey minecraftkey = new MinecraftKey(ChatDeserializer.getString(jsonObject, BLOCK)); ++ block = CraftMagicNumbers.getMaterial(IRegistry.BLOCK.getOptional(minecraftkey).orElseThrow(() -> { ++ return new JsonSyntaxException("Unknown block type '" + minecraftkey + "'"); ++ })); ++ } ++ StateCondition state = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(STATE), StateCondition.class), StateCondition.ANY); ++ LocationCondition location = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(LOCATION), LocationCondition.class), LocationCondition.ANY); ++ ItemCondition item = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ITEM), ItemCondition.class), ItemCondition.ANY); ++ return new PlacedBlockTrigger(player, block, state, location, item); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(PlacedBlockTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ if (trigger.getBlock() != null) { ++ jsonObject.addProperty(BLOCK, trigger.getBlock().getKey().toString()); ++ } ++ jsonObject.add(STATE, context.serialize(trigger.getState())); ++ jsonObject.add(LOCATION, context.serialize(trigger.getLocation())); ++ jsonObject.add(ITEM, context.serialize(trigger.getItem())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/PlayerHurtEntityTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/PlayerHurtEntityTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..00f1f50e1507a162c1f2822e3e4dfd1bb7ac2021 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/PlayerHurtEntityTriggerAdapter.java +@@ -0,0 +1,33 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.DamageCondition; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++ ++import java.lang.reflect.Type; ++ ++public class PlayerHurtEntityTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String DAMAGE = "damage"; ++ private static final String ENTITY = "entity"; ++ ++ public PlayerHurtEntityTriggerAdapter() { ++ super(PlayerHurtEntityTrigger.class); ++ } ++ ++ @Override ++ public PlayerHurtEntityTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ DamageCondition damage = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(DAMAGE), DamageCondition.class), DamageCondition.ANY); ++ EntityPredicatesCondition entityPredicates = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ENTITY), EntityPredicatesCondition.class), EntityPredicatesCondition.ANY); ++ return new PlayerHurtEntityTrigger(player, damage, entityPredicates); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(PlayerHurtEntityTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ return null; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/PlayerInteractWithEntityTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/PlayerInteractWithEntityTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..115965d45c607ff9f505257cef7cf332ddac8cc2 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/PlayerInteractWithEntityTriggerAdapter.java +@@ -0,0 +1,36 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++ ++import java.lang.reflect.Type; ++ ++public class PlayerInteractWithEntityTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String ITEM = "item"; ++ private static final String ENTITY = "entity"; ++ ++ public PlayerInteractWithEntityTriggerAdapter() { ++ super(PlayerInteractWithEntityTrigger.class); ++ } ++ ++ @Override ++ public PlayerInteractWithEntityTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ ItemCondition item = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ITEM), ItemCondition.class), ItemCondition.ANY); ++ EntityPredicatesCondition entity = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ENTITY), EntityPredicatesCondition.class), EntityPredicatesCondition.ANY); ++ return new PlayerInteractWithEntityTrigger(player, item, entity); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(PlayerInteractWithEntityTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(ITEM, context.serialize(trigger.getItem())); ++ jsonObject.add(ENTITY, context.serialize(trigger.getEntity())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/RecipeUnlockedTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/RecipeUnlockedTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..88be13e2400d5cd500dd120ffad8181d01780249 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/RecipeUnlockedTriggerAdapter.java +@@ -0,0 +1,34 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import net.minecraft.server.ChatDeserializer; ++import org.bukkit.NamespacedKey; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++ ++import java.lang.reflect.Type; ++ ++public class RecipeUnlockedTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String RECIPE = "recipe"; ++ ++ public RecipeUnlockedTriggerAdapter() { ++ super(RecipeUnlockedTrigger.class); ++ } ++ ++ @Override ++ public RecipeUnlockedTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ NamespacedKey recipe = CraftNamespacedKey.fromString(ChatDeserializer.getString(jsonObject, RECIPE)); ++ return new RecipeUnlockedTrigger(player, recipe); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(RecipeUnlockedTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.addProperty(RECIPE, trigger.getRecipe().toString()); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/ShotCrossbowTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/ShotCrossbowTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..656613ecd804088278e46f26c4e3e7b93a45064c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/ShotCrossbowTriggerAdapter.java +@@ -0,0 +1,33 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++ ++import java.lang.reflect.Type; ++ ++public class ShotCrossbowTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String ITEM = "item"; ++ ++ public ShotCrossbowTriggerAdapter() { ++ super(ShotCrossbowTrigger.class); ++ } ++ ++ @Override ++ public ShotCrossbowTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ ItemCondition item = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ITEM), ItemCondition.class), ItemCondition.ANY); ++ return new ShotCrossbowTrigger(player, item); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(ShotCrossbowTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(ITEM, context.serialize(trigger.getItem())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/SlideDownBlockTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/SlideDownBlockTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d2c1a1cd07dfb5c9f4f5c83d4bc79cc15d080864 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/SlideDownBlockTriggerAdapter.java +@@ -0,0 +1,51 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSyntaxException; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.StateCondition; ++import net.minecraft.server.Block; ++import net.minecraft.server.ChatDeserializer; ++import net.minecraft.server.IRegistry; ++import net.minecraft.server.MinecraftKey; ++import org.bukkit.Material; ++import org.bukkit.craftbukkit.util.CraftMagicNumbers; ++ ++import java.lang.reflect.Type; ++ ++public class SlideDownBlockTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String BLOCK = "block"; ++ private static final String STATE = "state"; ++ ++ public SlideDownBlockTriggerAdapter() { ++ super(SlideDownBlockTrigger.class); ++ } ++ ++ @Override ++ public SlideDownBlockTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ Material block = null; ++ if (jsonObject.has(BLOCK)) { ++ MinecraftKey minecraftkey = new MinecraftKey(ChatDeserializer.getString(jsonObject, BLOCK)); ++ block = CraftMagicNumbers.getMaterial(IRegistry.BLOCK.getOptional(minecraftkey).orElseThrow(() -> { ++ return new JsonSyntaxException("Unknown block type '" + minecraftkey + "'"); ++ })); ++ } ++ StateCondition state = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(STATE), StateCondition.class), StateCondition.ANY); ++ return new SlideDownBlockTrigger(player, block, state); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(SlideDownBlockTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ if (trigger.getBlock() != null) { ++ jsonObject.addProperty(BLOCK, trigger.getBlock().getKey().toString()); ++ } ++ jsonObject.add(STATE, context.serialize(trigger.getState())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/SummonedEntityTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/SummonedEntityTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..aadb85877e21c713c959602a51054eb4f4086204 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/SummonedEntityTriggerAdapter.java +@@ -0,0 +1,32 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++ ++import java.lang.reflect.Type; ++ ++public class SummonedEntityTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String ENTITY = "entity"; ++ ++ public SummonedEntityTriggerAdapter() { ++ super(SummonedEntityTrigger.class); ++ } ++ ++ @Override ++ public SummonedEntityTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ EntityPredicatesCondition entityPredicates = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ENTITY), EntityPredicatesCondition.class), EntityPredicatesCondition.ANY); ++ return new SummonedEntityTrigger(player, entityPredicates); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(SummonedEntityTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(ENTITY, context.serialize(trigger.getEntityPredicates())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/TamedAnimalTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/TamedAnimalTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..99f2f1a6fcf478e17faa7cc624af25b6a65fd552 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/TamedAnimalTriggerAdapter.java +@@ -0,0 +1,32 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++ ++import java.lang.reflect.Type; ++ ++public class TamedAnimalTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String ENTITY = "entity"; ++ ++ public TamedAnimalTriggerAdapter() { ++ super(TamedAnimalTrigger.class); ++ } ++ ++ @Override ++ public TamedAnimalTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ EntityPredicatesCondition tamedEntity = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ENTITY), EntityPredicatesCondition.class), EntityPredicatesCondition.ANY); ++ return new TamedAnimalTrigger(player, tamedEntity); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(TamedAnimalTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(ENTITY, context.serialize(trigger.getTamedEntity())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/TargetHitTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/TargetHitTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9fad879cd8bcb9766b9a4336589a27759aeb2c50 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/TargetHitTriggerAdapter.java +@@ -0,0 +1,36 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++ ++import java.lang.reflect.Type; ++ ++public class TargetHitTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String SIGNAL_STRENGTH = "signal_strength"; ++ private static final String PROJECTILE = "projectile"; ++ ++ public TargetHitTriggerAdapter() { ++ super(TargetHitTrigger.class); ++ } ++ ++ @Override ++ public TargetHitTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ IntegerRange signalStrength = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(SIGNAL_STRENGTH), IntegerRange.class), IntegerRange.ANY); ++ EntityPredicatesCondition projectile = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(PROJECTILE), EntityPredicatesCondition.class), EntityPredicatesCondition.ANY); ++ return new TargetHitTrigger(player, signalStrength, projectile); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(TargetHitTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(SIGNAL_STRENGTH, context.serialize(trigger.getSignalStrength())); ++ jsonObject.add(PROJECTILE, context.serialize(trigger.getProjectile())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/ThrownItemPickedUpTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/ThrownItemPickedUpTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3fe2b22e7f70b240d0aa25431c4e817ca6c3dbab +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/ThrownItemPickedUpTriggerAdapter.java +@@ -0,0 +1,36 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++ ++import java.lang.reflect.Type; ++ ++public class ThrownItemPickedUpTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String ITEM = "item"; ++ private static final String ENTITY = "entity"; ++ ++ public ThrownItemPickedUpTriggerAdapter() { ++ super(ThrownItemPickedUpTrigger.class); ++ } ++ ++ @Override ++ public ThrownItemPickedUpTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ ItemCondition item = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ITEM), ItemCondition.class), ItemCondition.ANY); ++ EntityPredicatesCondition entity = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ENTITY), EntityPredicatesCondition.class), EntityPredicatesCondition.ANY); ++ return new ThrownItemPickedUpTrigger(player, item, entity); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(ThrownItemPickedUpTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(ITEM, context.serialize(trigger.getItem())); ++ jsonObject.add(ENTITY, context.serialize(trigger.getEntity())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/TickTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/TickTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3a57f2f860122bae9703a97a4de4187d03266165 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/TickTriggerAdapter.java +@@ -0,0 +1,26 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++ ++import java.lang.reflect.Type; ++ ++public class TickTriggerAdapter extends PlayerTriggerAdapter { ++ ++ public TickTriggerAdapter() { ++ super(TickTrigger.class); ++ } ++ ++ @Override ++ public TickTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ return new TickTrigger(player); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(TickTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ return new JsonObject(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/TriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/TriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..10e124cd2b29f336147a0f062c7f8320f85e7018 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/TriggerAdapter.java +@@ -0,0 +1,54 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import io.papermc.paper.advancements.triggers.Trigger.PlayerTrigger; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import net.minecraft.server.ChatDeserializer; ++ ++import java.lang.reflect.Type; ++ ++public abstract class TriggerAdapter implements JsonDeserializer, JsonSerializer { ++ ++ private final Class triggerClass; ++ ++ protected TriggerAdapter(Class triggerClass) { ++ this.triggerClass = triggerClass; ++ } ++ ++ public Class getTriggerClass() { ++ return triggerClass; ++ } ++ ++ public abstract static class PlayerTriggerAdapter extends TriggerAdapter { ++ ++ private static final String PLAYER = "player"; ++ ++ public PlayerTriggerAdapter(Class clazz) { ++ super(clazz); ++ } ++ ++ @Override ++ public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject jsonObject = ChatDeserializer.asJsonObject(json, "base advancement"); ++ return deserializeTrigger(jsonObject, typeOfT, context, MoreObjects.firstNonNull(context.deserialize(jsonObject.get(PLAYER), EntityPredicatesCondition.class), EntityPredicatesCondition.ANY)); ++ } ++ ++ public abstract T deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player); ++ ++ @Override ++ public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = serializeTrigger(src, typeOfSrc, context); ++ jsonObject.add(PLAYER, context.serialize(src.getPlayer())); ++ return jsonObject; ++ } ++ ++ public abstract JsonObject serializeTrigger(T trigger, Type typeOfSrc, JsonSerializationContext context); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/UsedEnderEyeTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/UsedEnderEyeTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9d81f96e7ed1eb0335cdb4437f8fdd6296461c60 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/UsedEnderEyeTriggerAdapter.java +@@ -0,0 +1,34 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.FloatRange; ++ ++import java.lang.reflect.Type; ++ ++public class UsedEnderEyeTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String DISTANCE = "distance"; ++ ++ public UsedEnderEyeTriggerAdapter() { ++ super(UsedEnderEyeTrigger.class); ++ } ++ ++ @Override ++ public UsedEnderEyeTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ FloatRange distance = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(DISTANCE), FloatRange.class), FloatRange.ANY); ++ return new UsedEnderEyeTrigger(player, distance); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(UsedEnderEyeTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ // NOTE: MC doesn't seem to do this for just this specific trigger, idk what's up with that, maybe a MC bug ++ jsonObject.add(DISTANCE, context.serialize(trigger.getDistance())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/UsedTotemTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/UsedTotemTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1975167f1af87ace8bdac311b94d467a99d5f8e9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/UsedTotemTriggerAdapter.java +@@ -0,0 +1,33 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++ ++import java.lang.reflect.Type; ++ ++public class UsedTotemTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String ITEM = "item"; ++ ++ public UsedTotemTriggerAdapter() { ++ super(UsedTotemTrigger.class); ++ } ++ ++ @Override ++ public UsedTotemTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ ItemCondition item = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ITEM), ItemCondition.class), ItemCondition.ANY); ++ return new UsedTotemTrigger(player, item); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(UsedTotemTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(ITEM, context.serialize(trigger.getItem())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/VillagerTradeTriggerAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/VillagerTradeTriggerAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c608cf88e39e94d1fa1b38bcf200995a1b8952e8 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/VillagerTradeTriggerAdapter.java +@@ -0,0 +1,36 @@ ++package io.papermc.paper.advancements.triggers; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.TriggerAdapter.PlayerTriggerAdapter; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++ ++import java.lang.reflect.Type; ++ ++public class VillagerTradeTriggerAdapter extends PlayerTriggerAdapter { ++ ++ private static final String VILLAGER = "villager"; ++ private static final String ITEM = "item"; ++ ++ public VillagerTradeTriggerAdapter() { ++ super(VillagerTradeTrigger.class); ++ } ++ ++ @Override ++ public VillagerTradeTrigger deserializeTrigger(JsonObject jsonObject, Type typeOfT, JsonDeserializationContext context, EntityPredicatesCondition player) { ++ EntityPredicatesCondition villager = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(VILLAGER), EntityPredicatesCondition.class), EntityPredicatesCondition.ANY); ++ ItemCondition item = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ITEM), ItemCondition.class), ItemCondition.ANY); ++ return new VillagerTradeTrigger(player, villager, item); ++ } ++ ++ @Override ++ public JsonObject serializeTrigger(VillagerTradeTrigger trigger, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(ITEM, context.serialize(trigger.getItem())); ++ jsonObject.add(VILLAGER, context.serialize(trigger.getVillager())); ++ return jsonObject; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/BlockConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/BlockConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c6dac4511e703789e2a8c1de953b3bd051dbd10a +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/BlockConditionAdapter.java +@@ -0,0 +1,49 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonNull; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import net.minecraft.server.ChatDeserializer; ++import net.minecraft.server.MinecraftKey; ++import net.minecraft.server.TagsInstance; ++import org.bukkit.Material; ++import org.bukkit.Tag; ++import org.bukkit.craftbukkit.tag.CraftBlockTag; ++import org.bukkit.craftbukkit.util.CraftMagicNumbers; ++ ++import java.lang.reflect.Type; ++ ++public class BlockConditionAdapter implements JsonDeserializer, JsonSerializer { ++ ++ private static final String BLOCK = "block"; ++ private static final String TAG = "tag"; ++ private static final String STATE = "state"; ++ ++ @Override ++ public BlockCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject obj = json.getAsJsonObject(); ++ Material block = obj.has(BLOCK) ? CraftMagicNumbers.getMaterial(ChatDeserializer.getItem(obj, BLOCK)) : null; ++ Tag blockTag = obj.has(TAG) ? new CraftBlockTag(TagsInstance.a().getBlockTags(), new MinecraftKey(ChatDeserializer.getString(obj, TAG))) : null; ++ StateCondition state = MoreObjects.firstNonNull(context.deserialize(obj.get(STATE), StateCondition.class), StateCondition.ANY); ++ return new BlockConditionBuilder().setBlock(block).setBlockTag(blockTag).setState(state).createBlockCondition(); ++ } ++ ++ @Override ++ public JsonElement serialize(BlockCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src == BlockCondition.ANY) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonObject jsonObject = new JsonObject(); ++ if (src.getBlock() != null) jsonObject.addProperty(BLOCK, src.getBlock().getKey().toString()); ++ if (src.getBlockTag() != null) jsonObject.addProperty(TAG, src.getBlockTag().getKey().toString()); ++ jsonObject.add(STATE, context.serialize(src.getState())); ++ return jsonObject; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/DamageConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/DamageConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ff4ad20aa6b3a5c87e6f78e6f7fe1586a67639f0 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/DamageConditionAdapter.java +@@ -0,0 +1,52 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonNull; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.FloatRange; ++import net.minecraft.server.ChatDeserializer; ++ ++import java.lang.reflect.Type; ++ ++public class DamageConditionAdapter implements JsonDeserializer, JsonSerializer { ++ ++ private final String BLOCKED = "blocked"; ++ private final String DEALT = "dealt"; ++ private final String SOURCE_ENTITY = "source_entity"; ++ private final String TAKEN = "taken"; ++ private final String TYPE = "type"; ++ ++ @Override ++ public DamageCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject jsonObject = ChatDeserializer.asJsonObject(json, "damage"); ++ FloatRange dealtDamage = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(DEALT), FloatRange.class), FloatRange.ANY); ++ FloatRange takenDamage = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(TAKEN), FloatRange.class), FloatRange.ANY); ++ Boolean blocked = jsonObject.has(BLOCKED) ? ChatDeserializer.getBoolean(jsonObject, BLOCKED) : null; ++ EntityCondition source = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(SOURCE_ENTITY), EntityCondition.class), EntityCondition.ANY); ++ DamageSourceCondition damageType = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(TYPE), DamageSourceCondition.class), DamageSourceCondition.ANY); ++ return new DamageCondition(dealtDamage, takenDamage, source, blocked, damageType); ++ } ++ ++ @Override ++ public JsonElement serialize(DamageCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src == DamageCondition.ANY) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(DEALT, context.serialize(src.getDealtDamage())); ++ jsonObject.add(TAKEN, context.serialize(src.getTakenDamage())); ++ jsonObject.add(SOURCE_ENTITY, context.serialize(src.getEntity())); ++ jsonObject.add(TYPE, context.serialize(src.getDamageType())); ++ if (src.getBlocked() != null) { ++ jsonObject.addProperty(BLOCKED, src.getBlocked()); ++ } ++ return jsonObject; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/DamageTypeConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/DamageTypeConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8647fd55d1e5560ce8426b1dae7e593aad43b7cc +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/DamageTypeConditionAdapter.java +@@ -0,0 +1,68 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonNull; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import net.minecraft.server.ChatDeserializer; ++ ++import java.lang.reflect.Type; ++ ++public class DamageTypeConditionAdapter implements JsonDeserializer, JsonSerializer { ++ ++ private final String BYPASSES_ARMOR = "bypasses_armor"; ++ private final String BYPASSES_INVULNERABILITY = "bypasses_invulnerability"; ++ private final String BYPASSES_MAGIC = "bypasses_magic"; ++ private final String IS_EXPLOSION = "is_explosion"; ++ private final String IS_FIRE = "is_fire"; ++ private final String IS_MAGIC = "is_magic"; ++ private final String IS_PROJECTILE = "is_projectile"; ++ private final String IS_LIGHTNING = "is_lightning"; ++ private final String DIRECT_ENTITY = "direct_entity"; ++ private final String SOURCE_ENTITY = "source_entity"; ++ ++ @Override ++ public DamageSourceCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject jsonObject = ChatDeserializer.asJsonObject(json, "damage flags"); ++ Boolean bypassesArmor = getBooleanOrNull(jsonObject, BYPASSES_ARMOR); ++ Boolean bypassesInvulnerability = getBooleanOrNull(jsonObject, BYPASSES_INVULNERABILITY); ++ Boolean bypassesMagic = getBooleanOrNull(jsonObject, BYPASSES_MAGIC); ++ Boolean isExplosion = getBooleanOrNull(jsonObject, IS_EXPLOSION); ++ Boolean isFire = getBooleanOrNull(jsonObject, IS_FIRE); ++ Boolean isMagic = getBooleanOrNull(jsonObject, IS_MAGIC); ++ Boolean isProjectile = getBooleanOrNull(jsonObject, IS_PROJECTILE); ++ Boolean isLightning = getBooleanOrNull(jsonObject, IS_LIGHTNING); ++ EntityCondition direct = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(DIRECT_ENTITY), EntityCondition.class), EntityCondition.ANY); ++ EntityCondition source = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(SOURCE_ENTITY), EntityCondition.class), EntityCondition.ANY); ++ return new DamageSourceCondition(isProjectile, isExplosion, bypassesArmor, bypassesInvulnerability, bypassesMagic, isFire, isMagic, isLightning, direct, source); ++ } ++ ++ private static Boolean getBooleanOrNull(JsonObject jsonObject, String key) { ++ return jsonObject.has(key) ? ChatDeserializer.getBoolean(jsonObject, key) : null; ++ } ++ ++ @Override ++ public JsonElement serialize(DamageSourceCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src == DamageSourceCondition.ANY) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.addProperty(IS_PROJECTILE, src.getProjectile()); ++ jsonObject.addProperty(IS_EXPLOSION, src.getExplosion()); ++ jsonObject.addProperty(BYPASSES_ARMOR, src.getBypassesArmor()); ++ jsonObject.addProperty(BYPASSES_INVULNERABILITY, src.getBypassesInvulnerability()); ++ jsonObject.addProperty(BYPASSES_MAGIC, src.getBypassesMagic()); ++ jsonObject.addProperty(IS_FIRE, src.getFire()); ++ jsonObject.addProperty(IS_MAGIC, src.getMagic()); ++ jsonObject.addProperty(IS_LIGHTNING, src.getLightning()); ++ jsonObject.add(DIRECT_ENTITY, context.serialize(src.getDirect())); ++ jsonObject.add(SOURCE_ENTITY, context.serialize(src.getSource())); ++ return jsonObject; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/DistanceConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/DistanceConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d7726576858986049873c1a9a26f23a9ec5b364f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/DistanceConditionAdapter.java +@@ -0,0 +1,50 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonNull; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.FloatRange; ++ ++import java.lang.reflect.Type; ++ ++public class DistanceConditionAdapter implements JsonDeserializer, JsonSerializer { ++ ++ private static final String X = "x"; ++ private static final String Y = "y"; ++ private static final String Z = "z"; ++ private static final String ABSOLUTE = "absolute"; ++ private static final String HORIZONTAL = "horizontal"; ++ ++ @Override ++ public DistanceCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject jsonObject = json.getAsJsonObject(); ++ return new DistanceCondition( ++ MoreObjects.firstNonNull(context.deserialize(jsonObject.get(X), FloatRange.class), FloatRange.ANY), ++ MoreObjects.firstNonNull(context.deserialize(jsonObject.get(Y), FloatRange.class), FloatRange.ANY), ++ MoreObjects.firstNonNull(context.deserialize(jsonObject.get(Z), FloatRange.class), FloatRange.ANY), ++ MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ABSOLUTE), FloatRange.class), FloatRange.ANY), ++ MoreObjects.firstNonNull(context.deserialize(jsonObject.get(HORIZONTAL), FloatRange.class), FloatRange.ANY) ++ ); ++ } ++ ++ @Override ++ public JsonElement serialize(DistanceCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src == DistanceCondition.ANY) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(X, context.serialize(src.getXRange())); ++ jsonObject.add(Y, context.serialize(src.getYRange())); ++ jsonObject.add(Z, context.serialize(src.getZRange())); ++ jsonObject.add(ABSOLUTE, context.serialize(src.getAbsoluteRange())); ++ jsonObject.add(HORIZONTAL, context.serialize(src.getHorizontalRange())); ++ return jsonObject; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/EffectsConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EffectsConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7be1a19e8f6ba8d486e5aa31370be27c80f7e44b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EffectsConditionAdapter.java +@@ -0,0 +1,86 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.common.base.MoreObjects; ++import com.google.common.collect.Maps; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonNull; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import com.google.gson.JsonSyntaxException; ++import io.papermc.paper.advancements.triggers.conditions.EffectsCondition.EffectInfo; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import io.papermc.paper.util.PaperChatDeserializer; ++import net.minecraft.server.ChatDeserializer; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++import org.bukkit.potion.PotionEffectType; ++ ++import java.lang.reflect.Type; ++import java.util.Iterator; ++import java.util.Map; ++import java.util.Map.Entry; ++ ++public class EffectsConditionAdapter implements JsonDeserializer, JsonSerializer { ++ @Override ++ public EffectsCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject jsonObject = json.getAsJsonObject(); ++ Map effectInfoMap = Maps.newLinkedHashMap(); ++ Iterator> iterator = jsonObject.entrySet().iterator(); ++ while (iterator.hasNext()) { ++ Entry entry = iterator.next(); ++ PotionEffectType type = PotionEffectType.getByKey(CraftNamespacedKey.fromStringOrNull(entry.getKey())); ++ if (type == null) { ++ throw new JsonSyntaxException("Unknown effect '" + entry.getKey() + "'"); ++ } ++ EffectInfo effectInfo = context.deserialize(ChatDeserializer.asJsonObject(entry.getValue(), entry.getKey()), EffectInfo.class); ++ effectInfoMap.put(type, effectInfo); ++ } ++ return new EffectsCondition(effectInfoMap); ++ } ++ ++ @Override ++ public JsonElement serialize(EffectsCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src == EffectsCondition.ANY) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonObject jsonObject = new JsonObject(); ++ Iterator> iterator = src.getEffectInfoMap().entrySet().iterator(); ++ while (iterator.hasNext()) { ++ Entry entry = iterator.next(); ++ jsonObject.add(entry.getKey().getKey().toString(), context.serialize(entry.getValue())); ++ } ++ return jsonObject; ++ } ++ } ++ ++ public static class EffectInfoAdapter implements JsonDeserializer, JsonSerializer { ++ ++ private static final String AMPLIFIER = "amplifier"; ++ private static final String DURATION = "duration"; ++ private static final String AMBIENT = "ambient"; ++ private static final String VISIBLE = "visible"; ++ ++ @Override ++ public EffectInfo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject jsonObject = json.getAsJsonObject(); ++ IntegerRange amplifier = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(AMPLIFIER), IntegerRange.class), IntegerRange.ANY); ++ IntegerRange duration = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(DURATION), IntegerRange.class), IntegerRange.ANY); ++ Boolean ambient = PaperChatDeserializer.getBooleanOrDefault(jsonObject, AMBIENT, null); ++ Boolean visible = PaperChatDeserializer.getBooleanOrDefault(jsonObject, VISIBLE, null); ++ return new EffectInfo(amplifier, duration, ambient, visible); ++ } ++ ++ @Override ++ public JsonElement serialize(EffectInfo src, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(AMPLIFIER, context.serialize(src.getAmplifer())); ++ jsonObject.add(DURATION, context.serialize(src.getDuration())); ++ jsonObject.addProperty(AMBIENT, src.getAmbient()); ++ jsonObject.addProperty(VISIBLE, src.getVisible()); ++ return jsonObject; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/EnchantmentConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EnchantmentConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c589bdef498419d0e0992806652a5fd63be64592 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EnchantmentConditionAdapter.java +@@ -0,0 +1,76 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonArray; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonNull; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import io.papermc.paper.advancements.triggers.conditions.EnchantmentCondition.EnchantmentsCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++import org.bukkit.enchantments.Enchantment; ++ ++import java.lang.reflect.Type; ++import java.util.HashSet; ++import java.util.Set; ++ ++public class EnchantmentConditionAdapter implements JsonDeserializer, JsonSerializer { ++ ++ private static final String ENCHANTMENT = "enchantment"; ++ private static final String LEVELS = "levels"; ++ ++ @Override ++ public EnchantmentCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject jsonObject = json.getAsJsonObject(); ++ Enchantment enchantment = null; ++ if (jsonObject.has(ENCHANTMENT)) { ++ enchantment = Enchantment.getByKey(CraftNamespacedKey.fromStringOrNull(jsonObject.get(ENCHANTMENT).getAsString())); ++ } ++ IntegerRange range = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(LEVELS), IntegerRange.class), IntegerRange.ANY); ++ return new EnchantmentCondition(enchantment, range); ++ } ++ ++ @Override ++ public JsonElement serialize(EnchantmentCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src == EnchantmentCondition.ANY) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonObject jsonObject = new JsonObject(); ++ if (src.getEnchantment() != null) { ++ jsonObject.addProperty(ENCHANTMENT, src.getEnchantment().getKey().toString()); ++ } ++ jsonObject.add(LEVELS, context.serialize(src.getLevelRange())); ++ return jsonObject; ++ } ++ } ++ ++ public static class EnchantmentsConditionAdapter implements JsonDeserializer, JsonSerializer { ++ @Override ++ public EnchantmentsCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ Set enchantments = new HashSet<>(); ++ JsonArray jsonArray = json.getAsJsonArray(); ++ for (JsonElement element : jsonArray) { ++ enchantments.add(context.deserialize(element, EnchantmentCondition.class)); ++ } ++ return new EnchantmentsCondition(enchantments); ++ } ++ ++ @Override ++ public JsonElement serialize(EnchantmentsCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src == EnchantmentsCondition.ANY) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonArray jsonArray = new JsonArray(); ++ for (EnchantmentCondition enchantment : src) { ++ jsonArray.add(context.serialize(enchantment)); ++ } ++ return jsonArray; ++ } ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d61cceae6832848ea421853ea3b918265c71ea67 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityConditionAdapter.java +@@ -0,0 +1,111 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonArray; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonNull; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition.EntityPredicatesCondition; ++import io.papermc.paper.advancements.triggers.conditions.predicates.EntityPropertyPredicateCondition; ++import io.papermc.paper.advancements.triggers.conditions.predicates.EntityTarget; ++import io.papermc.paper.advancements.triggers.conditions.predicates.PredicateCondition; ++import net.minecraft.server.ChatDeserializer; ++import org.bukkit.NamespacedKey; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++ ++import java.lang.reflect.Type; ++ ++public class EntityConditionAdapter implements JsonDeserializer, JsonSerializer { ++ ++ private static final String TYPE = "type"; ++ private static final String DISTANCE = "distance"; ++ private static final String LOCATION = "location"; ++ private static final String EFFECTS = "effects"; ++ private static final String FLAGS = "flags"; ++ private static final String EQUIPMENT = "equipment"; ++ private static final String PLAYER = "player"; ++ private static final String FISHING_HOOK = "fishing_hook"; ++ private static final String VEHICLE = "vehicle"; ++ private static final String TARGETED_ENTITY = "targeted_entity"; ++ private static final String TEAM = "team"; ++ private static final String CAT_TYPE = "catType"; ++ ++ @Override ++ public EntityCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject jsonObject = ChatDeserializer.asJsonObject(json, "entity"); ++ EntityTypeCondition entityType = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(TYPE), EntityTypeCondition.class), EntityTypeCondition.ANY); ++ DistanceCondition distance = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(DISTANCE), DistanceCondition.class), DistanceCondition.ANY); ++ LocationCondition location = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(LOCATION), LocationCondition.class), LocationCondition.ANY); ++ EffectsCondition effects = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(EFFECTS), EffectsCondition.class), EffectsCondition.ANY); ++ EntityFlagsCondition flags = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(FLAGS), EntityFlagsCondition.class), EntityFlagsCondition.ANY); ++ EntityEquipmentCondition equipment = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(EQUIPMENT), EntityEquipmentCondition.class), EntityEquipmentCondition.ANY); ++ PlayerCondition player = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(PLAYER), PlayerCondition.class), PlayerCondition.ANY); ++ FishingHookCondition fishingHook = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(FISHING_HOOK), FishingHookCondition.class), FishingHookCondition.ANY); ++ EntityCondition vehicle = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(VEHICLE), EntityCondition.class), EntityCondition.ANY); ++ EntityCondition target = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(TARGETED_ENTITY), EntityCondition.class), EntityCondition.ANY); ++ String team = io.papermc.paper.util.PaperChatDeserializer.getStringOrDefault(jsonObject, TEAM, null); ++ NamespacedKey catType = jsonObject.has(CAT_TYPE) ? CraftNamespacedKey.fromString(ChatDeserializer.getString(jsonObject, CAT_TYPE)) : null; ++ return new EntityCondition(entityType, distance, location, effects, flags, equipment, player, fishingHook, vehicle, target, team, catType); ++ } ++ ++ @Override ++ public JsonElement serialize(EntityCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src == EntityCondition.ANY) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(TYPE, context.serialize(src.getEntityType())); ++ jsonObject.add(DISTANCE, context.serialize(src.getDistanceToPlayer())); ++ jsonObject.add(LOCATION, context.serialize(src.getLocation())); ++ jsonObject.add(EFFECTS, context.serialize(src.getEffects())); ++ jsonObject.add(FLAGS, context.serialize(src.getFlags())); ++ jsonObject.add(EQUIPMENT, context.serialize(src.getEquipment())); ++ jsonObject.add(PLAYER, context.serialize(src.getPlayer())); ++ jsonObject.add(FISHING_HOOK, context.serialize(src.getFishingHook())); ++ jsonObject.add(VEHICLE, context.serialize(src.getVehicle())); ++ jsonObject.add(TARGETED_ENTITY, context.serialize(src.getTarget())); ++ jsonObject.addProperty(TEAM, src.getTeam()); ++ if (src.getCatType() != null) { ++ jsonObject.addProperty(CAT_TYPE, src.getCatType().toString()); ++ } ++ return jsonObject; ++ } ++ } ++ ++ public static class EntityPredicatesConditionAdapter implements JsonDeserializer, JsonSerializer { ++ ++ @Override ++ public EntityPredicatesCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ if (json.isJsonArray()) { ++ PredicateCondition[] predicates = context.deserialize(json, PredicateCondition[].class); ++ return new EntityPredicatesCondition(predicates); ++ } else { ++ EntityCondition entity = context.deserialize(json, EntityCondition.class); ++ PredicateCondition[] predicateConditions; ++ if (entity != null) { ++ return new EntityPredicatesCondition(new PredicateCondition[] { new EntityPropertyPredicateCondition(entity, EntityTarget.THIS) }); ++ } else { ++ return EntityPredicatesCondition.ANY; ++ } ++ } ++ } ++ ++ @Override ++ public JsonElement serialize(EntityPredicatesCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src.getPredicates().length == 0) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonArray predicatesArray = new JsonArray(); ++ for (PredicateCondition predicate : src.getPredicates()) { ++ predicatesArray.add(context.serialize(predicate)); ++ } ++ return predicatesArray; ++ } ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityEquipmentConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityEquipmentConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5de14246b8b617b5cea2e7839bd8868dff23e142 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityEquipmentConditionAdapter.java +@@ -0,0 +1,51 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonNull; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++ ++import java.lang.reflect.Type; ++ ++public class EntityEquipmentConditionAdapter implements JsonDeserializer, JsonSerializer { ++ ++ private static final String MAIN = "mainhand"; ++ private static final String OFF = "offhand"; ++ private static final String HEAD = "head"; ++ private static final String CHEST = "chest"; ++ private static final String LEGS = "legs"; ++ private static final String FEET = "feet"; ++ ++ @Override ++ public EntityEquipmentCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject jsonObject = json.getAsJsonObject(); ++ ItemCondition head = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(HEAD), ItemCondition.class), ItemCondition.ANY); ++ ItemCondition chest = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(CHEST), ItemCondition.class), ItemCondition.ANY); ++ ItemCondition legs = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(LEGS), ItemCondition.class), ItemCondition.ANY); ++ ItemCondition feet = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(FEET), ItemCondition.class), ItemCondition.ANY); ++ ItemCondition mainHand = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(MAIN), ItemCondition.class), ItemCondition.ANY); ++ ItemCondition offHand = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(OFF), ItemCondition.class), ItemCondition.ANY); ++ return new EntityEquipmentCondition(head, chest, legs, feet, mainHand, offHand); ++ } ++ ++ @Override ++ public JsonElement serialize(EntityEquipmentCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src == EntityEquipmentCondition.ANY) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(HEAD, context.serialize(src.getHeadItem())); ++ jsonObject.add(CHEST, context.serialize(src.getChestItem())); ++ jsonObject.add(LEGS, context.serialize(src.getLegsItem())); ++ jsonObject.add(FEET, context.serialize(src.getFeetItem())); ++ jsonObject.add(MAIN, context.serialize(src.getMainHand())); ++ jsonObject.add(OFF, context.serialize(src.getOffHand())); ++ return jsonObject; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityFlagsConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityFlagsConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..298103a54bf1a65ffec3640ac20b70d05fcb73c7 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityFlagsConditionAdapter.java +@@ -0,0 +1,52 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonNull; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import net.minecraft.server.ChatDeserializer; ++ ++import java.lang.reflect.Type; ++ ++public class EntityFlagsConditionAdapter implements JsonDeserializer, JsonSerializer { ++ ++ private final String IS_ON_FIRE = "is_on_fire"; ++ private final String IS_SNEAKING = "is_sneaking"; ++ private final String IS_SPRINTING = "is_sprinting"; ++ private final String IS_SWIMMING = "is_swimming"; ++ private final String IS_BABY = "is_baby"; ++ ++ @Override ++ public EntityFlagsCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject jsonObject = json.getAsJsonObject(); ++ Boolean isOnFire = getBooleanOrNull(jsonObject, IS_ON_FIRE); ++ Boolean isSneaking = getBooleanOrNull(jsonObject, IS_SNEAKING); ++ Boolean isSprinting = getBooleanOrNull(jsonObject, IS_SPRINTING); ++ Boolean isSwimming = getBooleanOrNull(jsonObject, IS_SWIMMING); ++ Boolean isBaby = getBooleanOrNull(jsonObject, IS_BABY); ++ return new EntityFlagsCondition(isOnFire, isSneaking, isSprinting, isSwimming, isBaby); ++ } ++ ++ private static Boolean getBooleanOrNull(JsonObject jsonObject, String key) { ++ return jsonObject.has(key) ? ChatDeserializer.getBoolean(jsonObject, key) : null; ++ } ++ ++ @Override ++ public JsonElement serialize(EntityFlagsCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src == EntityFlagsCondition.ANY) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.addProperty(IS_ON_FIRE, src.getOnFire()); ++ jsonObject.addProperty(IS_SNEAKING, src.getSneaking()); ++ jsonObject.addProperty(IS_SPRINTING, src.getSprinting()); ++ jsonObject.addProperty(IS_SWIMMING, src.getSwimming()); ++ jsonObject.addProperty(IS_BABY, src.getBaby()); ++ return jsonObject; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityTypeConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityTypeConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d875eef24e9c22c62e20014def54dbf46b017ba1 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/EntityTypeConditionAdapter.java +@@ -0,0 +1,40 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import com.google.gson.JsonSyntaxException; ++import io.papermc.paper.advancements.triggers.conditions.EntityTypeCondition.EntityTypeTagCondition; ++import io.papermc.paper.advancements.triggers.conditions.EntityTypeCondition.EntityTypeTypeCondition; ++import io.papermc.paper.tag.CraftEntityTag; ++import net.minecraft.server.MinecraftKey; ++import net.minecraft.server.TagsInstance; ++import org.bukkit.craftbukkit.tag.CraftTag; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++import org.bukkit.entity.EntityType; ++ ++import java.lang.reflect.Type; ++ ++public class EntityTypeConditionAdapter implements JsonDeserializer, JsonSerializer { ++ @Override ++ public EntityTypeCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ String value = json.getAsString(); ++ if (value.startsWith("#")) { ++ return new EntityTypeTagCondition(new CraftEntityTag(TagsInstance.a().getEntityTags(), new MinecraftKey(value.substring(1)))); ++ } else { ++ EntityType type = EntityType.getByKey(CraftNamespacedKey.fromStringOrNull(value)); ++ if (type == null) { ++ throw new JsonSyntaxException("Unknown entity type '" + value + "'"); ++ } ++ return new EntityTypeTypeCondition(type); ++ } ++ } ++ ++ @Override ++ public JsonElement serialize(EntityTypeCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ return null; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/FishingHookConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/FishingHookConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0a9a4651435593802fec87c319cb3c2896c92ead +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/FishingHookConditionAdapter.java +@@ -0,0 +1,37 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonNull; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonPrimitive; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import net.minecraft.server.ChatDeserializer; ++ ++import java.lang.reflect.Type; ++ ++public class FishingHookConditionAdapter implements JsonDeserializer, JsonSerializer { ++ ++ private static final String IN_OPEN_WATER = "in_open_water"; ++ ++ @Override ++ public FishingHookCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject jsonObject = ChatDeserializer.asJsonObject(json, "fishing hook"); ++ JsonElement inOpenWaterElement = jsonObject.get(IN_OPEN_WATER); ++ return inOpenWaterElement != null ? new FishingHookCondition(ChatDeserializer.asBoolean(inOpenWaterElement, IN_OPEN_WATER)) : FishingHookCondition.ANY; ++ } ++ ++ @Override ++ public JsonElement serialize(FishingHookCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src == FishingHookCondition.ANY) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(IN_OPEN_WATER, new JsonPrimitive(src.isInOpenWater())); ++ return jsonObject; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/FluidConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/FluidConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..61f588c010588914258c8579e712621c04979c3e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/FluidConditionAdapter.java +@@ -0,0 +1,62 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonNull; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import net.minecraft.server.ChatDeserializer; ++import net.minecraft.server.IRegistry; ++import net.minecraft.server.MinecraftKey; ++import net.minecraft.server.TagsInstance; ++import org.bukkit.Fluid; ++import org.bukkit.Tag; ++import org.bukkit.craftbukkit.tag.CraftFluidTag; ++import org.bukkit.craftbukkit.util.CraftMagicNumbers; ++ ++import java.lang.reflect.Type; ++ ++public class FluidConditionAdapter implements JsonDeserializer, JsonSerializer { ++ ++ private static final String FLUID = "fluid"; ++ private static final String TAG = "tag"; ++ private static final String STATE = "state"; ++ ++ @Override ++ public FluidCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject jsonObject = ChatDeserializer.asJsonObject(json, FLUID); ++ Fluid fluid = null; ++ if (jsonObject.has(FLUID)) { ++ MinecraftKey fluidKey = new MinecraftKey(ChatDeserializer.getString(jsonObject, FLUID)); ++ fluid = CraftMagicNumbers.getFluid(IRegistry.FLUID.get(fluidKey)); ++ } ++ Tag fluidTag = null; ++ if (jsonObject.has(TAG)) { ++ MinecraftKey tagKey = new MinecraftKey(ChatDeserializer.getString(jsonObject, TAG)); ++ fluidTag = new CraftFluidTag(TagsInstance.a().getFluidTags(), tagKey); ++ } ++ StateCondition state = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(STATE), StateCondition.class), StateCondition.ANY); ++ return new FluidCondition(fluidTag, fluid, state); ++ } ++ ++ @Override ++ public JsonElement serialize(FluidCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src == FluidCondition.ANY) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonObject jsonObject = new JsonObject(); ++ if (src.getFluid() != null) { ++ jsonObject.addProperty(FLUID, src.getFluid().getKey().toString()); ++ } ++ if (src.getFluidTag() != null) { ++ jsonObject.addProperty(TAG, src.getFluidTag().getKey().toString()); ++ } ++ jsonObject.add(STATE, context.serialize(src.getState())); ++ return jsonObject; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/ItemConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/ItemConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b7bdf67f5f89ced54621b7640a48e13dce51aed5 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/ItemConditionAdapter.java +@@ -0,0 +1,110 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonArray; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonNull; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import io.papermc.paper.advancements.triggers.conditions.EnchantmentCondition.EnchantmentsCondition; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition.ItemsCondition; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import io.papermc.paper.util.PaperChatDeserializer; ++import net.minecraft.server.ChatDeserializer; ++import net.minecraft.server.MinecraftKey; ++import net.minecraft.server.TagsInstance; ++import org.bukkit.Material; ++import org.bukkit.Tag; ++import org.bukkit.craftbukkit.tag.CraftItemTag; ++import org.bukkit.craftbukkit.util.CraftMagicNumbers; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++import org.bukkit.potion.PotionType; ++ ++import java.lang.reflect.Type; ++import java.util.HashSet; ++import java.util.Set; ++ ++public class ItemConditionAdapter implements JsonDeserializer, JsonSerializer { ++ ++ private static final String COUNT = "count"; ++ private static final String DURABILITY = "durability"; ++ private static final String ENCHANTMENTS = "enchantments"; ++ private static final String STORED_ENCHANTMENTS = "stored_enchantments"; ++ private static final String ITEM = "item"; ++ private static final String TAG = "tag"; ++ private static final String POTION = "potion"; ++ ++ @Override ++ public ItemCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject jsonObject = json.getAsJsonObject(); ++ IntegerRange count = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(COUNT), IntegerRange.class), IntegerRange.ANY); ++ IntegerRange durability = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(DURABILITY), IntegerRange.class), IntegerRange.ANY); ++ Material material = null; ++ if (jsonObject.has(ITEM)) { ++ material = CraftMagicNumbers.getMaterial(ChatDeserializer.getItem(jsonObject, ITEM)); ++ } ++ Tag tag = null; ++ if (jsonObject.has(TAG)) { ++ tag = new CraftItemTag(TagsInstance.a().getItemTags(), new MinecraftKey(ChatDeserializer.getString(jsonObject, TAG))); ++ } ++ PotionType potionType = null; ++ if (jsonObject.has(POTION)) { ++ potionType = PotionType.getByKey(CraftNamespacedKey.fromStringOrNull(PaperChatDeserializer.getStringOrDefault(jsonObject, POTION, null))); ++ } ++ EnchantmentsCondition enchantments = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(ENCHANTMENTS), EnchantmentsCondition.class), EnchantmentsCondition.ANY); ++ EnchantmentsCondition storedEnchantments = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(STORED_ENCHANTMENTS), EnchantmentsCondition.class), EnchantmentsCondition.ANY); ++ return new ItemCondition(tag, material, count, durability, enchantments, storedEnchantments, potionType); ++ } ++ ++ @Override ++ public JsonElement serialize(ItemCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src == ItemCondition.ANY) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonObject jsonObject = new JsonObject(); ++ if (src.getMaterial() != null) { ++ jsonObject.addProperty(ITEM, src.getMaterial().getKey().toString()); ++ } ++ if (src.getMaterialTag() != null) { ++ jsonObject.addProperty(TAG, src.getMaterialTag().getKey().toString()); ++ } ++ jsonObject.add(COUNT, context.serialize(src.getCount())); ++ jsonObject.add(DURABILITY, context.serialize(src.getDurability())); ++ jsonObject.add(ENCHANTMENTS, context.serialize(src.getEnchantments())); ++ jsonObject.add(STORED_ENCHANTMENTS, context.serialize(src.getStoredEnchantments())); ++ if (src.getPotionType() != null) { ++ jsonObject.addProperty(POTION, src.getPotionType().getKey().toString()); ++ } ++ return jsonObject; ++ } ++ } ++ ++ public static class ItemsConditionAdapter implements JsonDeserializer, JsonSerializer { ++ @Override ++ public ItemsCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ Set items = new HashSet<>(); ++ JsonArray jsonArray = json.getAsJsonArray(); ++ for (JsonElement element : jsonArray) { ++ items.add(context.deserialize(element, ItemCondition.class)); ++ } ++ return new ItemsCondition(items); ++ } ++ ++ @Override ++ public JsonElement serialize(ItemsCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src == ItemsCondition.ANY) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonArray jsonArray = new JsonArray(); ++ for (ItemCondition item : src) { ++ jsonArray.add(context.serialize(item)); ++ } ++ return jsonArray; ++ } ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/LightConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/LightConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9c93dde762856a04be4223f14f0b02cdad2921b3 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/LightConditionAdapter.java +@@ -0,0 +1,37 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonNull; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++ ++import java.lang.reflect.Type; ++ ++public class LightConditionAdapter implements JsonDeserializer, JsonSerializer { ++ ++ private static final String LIGHT = "light"; ++ ++ @Override ++ public LightCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject obj = json.getAsJsonObject(); ++ IntegerRange range = MoreObjects.firstNonNull(context.deserialize(obj.get(LIGHT), IntegerRange.class), IntegerRange.ANY); ++ return new LightCondition(range); ++ } ++ ++ @Override ++ public JsonElement serialize(LightCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src == LightCondition.DEFAULT) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.add(LIGHT, context.serialize(src.getRange())); ++ return jsonObject; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/LocationConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/LocationConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0af8f1923573361fdc54fc3ec2e2ddd4c7390805 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/LocationConditionAdapter.java +@@ -0,0 +1,80 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonNull; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import io.papermc.paper.advancements.triggers.conditions.LocationCondition.LocationFeature; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.FloatRange; ++import io.papermc.paper.util.PaperChatDeserializer; ++import org.bukkit.NamespacedKey; ++import org.bukkit.block.Biome; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++ ++import java.lang.reflect.Type; ++ ++public class LocationConditionAdapter implements JsonDeserializer, JsonSerializer { ++ ++ private static final String X = "x"; ++ private static final String Y = "y"; ++ private static final String Z = "z"; ++ private static final String POSITION = "position"; ++ private static final String BIOME = "biome"; ++ private static final String FEATURE = "feature"; ++ private static final String DIMENSION = "dimension"; ++ private static final String SMOKEY = "smokey"; ++ private static final String LIGHT = "light"; ++ private static final String BLOCK = "block"; ++ ++ @Override ++ public LocationCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject obj = json.getAsJsonObject(); ++ JsonObject position = PaperChatDeserializer.getJsonObjectOrDefault(obj, POSITION, new JsonObject()); ++ FloatRange xRange = MoreObjects.firstNonNull(context.deserialize(position.get(X), FloatRange.class), FloatRange.ANY); ++ FloatRange yRange = MoreObjects.firstNonNull(context.deserialize(position.get(Y), FloatRange.class), FloatRange.ANY); ++ FloatRange zRange = MoreObjects.firstNonNull(context.deserialize(position.get(Z), FloatRange.class), FloatRange.ANY); ++ NamespacedKey dimension = CraftNamespacedKey.fromStringOrNull(PaperChatDeserializer.getStringOrDefault(obj, DIMENSION, null)); ++ Boolean smokey = obj.has(SMOKEY) ? obj.get(SMOKEY).getAsBoolean() : null; ++ LightCondition light = MoreObjects.firstNonNull(context.deserialize(obj.get(LIGHT), LightCondition.class), LightCondition.DEFAULT); ++ BlockCondition block = MoreObjects.firstNonNull(context.deserialize(obj.get(BLOCK), BlockCondition.class), BlockCondition.ANY); ++ Biome biome = Biome.getByKey(CraftNamespacedKey.fromStringOrNull(PaperChatDeserializer.getStringOrDefault(obj, BIOME, null))); ++ LocationFeature locationFeature = LocationFeature.getByIdText(PaperChatDeserializer.getStringOrDefault(obj, FEATURE, null)); ++ return new LocationCondition(xRange, yRange, zRange, biome, locationFeature, dimension, smokey, light, block); ++ } ++ ++ @Override ++ public JsonElement serialize(LocationCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src == LocationCondition.ANY) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonObject jsonObject = new JsonObject(); ++ if (!src.getXRange().isAnyRange() || !src.getYRange().isAnyRange() || !src.getZRange().isAnyRange()) { ++ JsonObject positionObj = new JsonObject(); ++ positionObj.add(X, context.serialize(src.getXRange())); ++ positionObj.add(Y, context.serialize(src.getYRange())); ++ positionObj.add(Z, context.serialize(src.getZRange())); ++ jsonObject.add(POSITION, positionObj); ++ } ++ if (src.getDimension() != null) { ++ jsonObject.addProperty(DIMENSION, src.getDimension().toString()); ++ } ++ if (src.getFeature() != null) { ++ jsonObject.addProperty(FEATURE, src.getFeature().getIdText()); ++ } ++ if (src.getBiome() != null) { ++ jsonObject.addProperty(BIOME, src.getBiome().getKey().toString()); ++ } ++ if (src.isSmokey() != null) { ++ jsonObject.addProperty(SMOKEY, src.isSmokey()); ++ } ++ jsonObject.add(LIGHT, context.serialize(src.getLight())); ++ jsonObject.add(BLOCK, context.serialize(src.getBlock())); ++ return jsonObject; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/StateConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/StateConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3efb16fb93742d4221165c9206008132347be648 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/StateConditionAdapter.java +@@ -0,0 +1,61 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.common.collect.Lists; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonNull; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import io.papermc.paper.advancements.triggers.conditions.StateCondition.AbstractProperty; ++import io.papermc.paper.advancements.triggers.conditions.StateCondition.ExactProperty; ++import io.papermc.paper.advancements.triggers.conditions.StateCondition.RangedProperty; ++import io.papermc.paper.util.PaperChatDeserializer; ++import net.minecraft.server.ChatDeserializer; ++ ++import java.lang.reflect.Type; ++import java.util.Iterator; ++import java.util.List; ++import java.util.Map.Entry; ++ ++public class StateConditionAdapter implements JsonDeserializer, JsonSerializer { ++ @Override ++ public StateCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject jsonObject = ChatDeserializer.asJsonObject(json, "properties"); ++ List properties = Lists.newArrayList(); ++ Iterator> iterator = jsonObject.entrySet().iterator(); ++ while (iterator.hasNext()) { ++ Entry entry = iterator.next(); ++ properties.add(deserializeProperty(entry.getKey(), entry.getValue())); ++ } ++ return new StateCondition(properties); ++ } ++ ++ @Override ++ public JsonElement serialize(StateCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src == StateCondition.ANY) { ++ return JsonNull.INSTANCE; ++ } else { ++ JsonObject jsonObject = new JsonObject(); ++ if (!src.getProperties().isEmpty()) { ++ src.getProperties().forEach(abstractProperty -> { ++ jsonObject.add(abstractProperty.getName(), abstractProperty.toJson()); ++ }); ++ } ++ return jsonObject; ++ } ++ } ++ ++ public static AbstractProperty deserializeProperty(String name, JsonElement element) { ++ if (element.isJsonPrimitive()) { ++ return new ExactProperty(name, element.getAsString()); ++ } else { ++ JsonObject jsonObject = ChatDeserializer.asJsonObject(element, "value"); ++ String min = PaperChatDeserializer.getStringOrDefault(jsonObject, "min", null); ++ String max = PaperChatDeserializer.getStringOrDefault(jsonObject, "max", null); ++ return (min != null && min.equals(max) ? new ExactProperty(name, min) : new RangedProperty(name, min, max)); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/ValueConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/ValueConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3629310bd35e32a146dbf361eb3217fb1c12e733 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/ValueConditionAdapter.java +@@ -0,0 +1,73 @@ ++package io.papermc.paper.advancements.triggers.conditions; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonNull; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonPrimitive; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.FloatRange; ++import io.papermc.paper.advancements.triggers.conditions.ValueCondition.IntegerRange; ++import net.minecraft.server.ChatDeserializer; ++ ++import java.lang.reflect.Type; ++ ++public class ValueConditionAdapter implements JsonSerializer { ++ ++ private static final String VALUE = "value"; ++ private static final String MIN = "min"; ++ private static final String MAX = "max"; ++ ++ @Override ++ public JsonElement serialize(ValueCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src.isAnyRange()) { ++ return JsonNull.INSTANCE; ++ } else if (src.getMin() != null && src.getMin().equals(src.getMax())) { ++ return new JsonPrimitive(src.getMin()); ++ } else { ++ JsonObject jsonObject = new JsonObject(); ++ if (src.getMin() != null) { ++ jsonObject.addProperty(MIN, src.getMin()); ++ } ++ if (src.getMax() != null) { ++ jsonObject.addProperty(MAX, src.getMax()); ++ } ++ return jsonObject; ++ } ++ } ++ ++ public static class FloatRangeAdapter implements JsonDeserializer { ++ ++ @Override ++ public FloatRange deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ if (ChatDeserializer.b(json)) { ++ float value = ChatDeserializer.asFloat(json, VALUE); ++ return new FloatRange(value, value); ++ } else { ++ JsonObject jsonObject = ChatDeserializer.asJsonObject(json, VALUE); ++ Float min = jsonObject.has(MIN) ? jsonObject.get(MIN).getAsFloat() : null; ++ Float max = jsonObject.has(MAX) ? jsonObject.get(MAX).getAsFloat() : null; ++ return new FloatRange(min, max); ++ } ++ } ++ } ++ ++ public static class IntegerRangeAdapter implements JsonDeserializer { ++ ++ @Override ++ public IntegerRange deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ if (ChatDeserializer.b(json)) { ++ int value = ChatDeserializer.asInt(json, VALUE); ++ return new IntegerRange(value, value); ++ } else { ++ JsonObject jsonObject = ChatDeserializer.asJsonObject(json, VALUE); ++ Integer min = jsonObject.has(MIN) ? jsonObject.get(MIN).getAsInt() : null; ++ Integer max = jsonObject.has(MAX) ? jsonObject.get(MAX).getAsInt() : null; ++ return new IntegerRange(min, max); ++ } ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/AlternativePredicateConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/AlternativePredicateConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..35f431a6fa39f6b285f6653407409f9dbfd0fd33 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/AlternativePredicateConditionAdapter.java +@@ -0,0 +1,22 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import net.minecraft.server.ChatDeserializer; ++ ++public class AlternativePredicateConditionAdapter extends PredicateConditionAdapter { ++ ++ private static final String TERMS = "terms"; ++ ++ @Override ++ public AlternativePredicateCondition deserialize(JsonObject jsonObject, JsonDeserializationContext context) { ++ PredicateCondition[] terms = ChatDeserializer.getDeserializedType(jsonObject, TERMS, context, PredicateCondition[].class); ++ return new AlternativePredicateCondition(terms); ++ } ++ ++ @Override ++ public void serialize(JsonObject jsonObject, AlternativePredicateCondition condition, JsonSerializationContext context) { ++ jsonObject.add(TERMS, context.serialize(condition.getTerms())); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/BlockStatePropertyPredicateConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/BlockStatePropertyPredicateConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..89105645d97e11e5409123779b86182b30bda29e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/BlockStatePropertyPredicateConditionAdapter.java +@@ -0,0 +1,36 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.conditions.StateCondition; ++import net.minecraft.server.Block; ++import net.minecraft.server.ChatDeserializer; ++import net.minecraft.server.IRegistry; ++import net.minecraft.server.MinecraftKey; ++import org.bukkit.Material; ++import org.bukkit.craftbukkit.util.CraftMagicNumbers; ++ ++public class BlockStatePropertyPredicateConditionAdapter extends PredicateConditionAdapter { ++ ++ private static final String BLOCK = "block"; ++ private static final String PROPERTIES = "properties"; ++ ++ @Override ++ public BlockStatePropertyPredicateCondition deserialize(JsonObject jsonObject, JsonDeserializationContext context) { ++ MinecraftKey key = new MinecraftKey(ChatDeserializer.getString(jsonObject, BLOCK)); ++ Material block = CraftMagicNumbers.getMaterial((Block) IRegistry.BLOCK.getOptional(key).orElseThrow(() -> { ++ return new IllegalArgumentException("Can't find block " + key); ++ })); ++ StateCondition state = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(PROPERTIES), StateCondition.class), StateCondition.ANY); ++ // TODO verify states on block ++ return new BlockStatePropertyPredicateCondition(block, state); ++ } ++ ++ @Override ++ public void serialize(JsonObject jsonObject, BlockStatePropertyPredicateCondition condition, JsonSerializationContext context) { ++ jsonObject.addProperty(BLOCK, condition.getBlock().getKey().toString()); ++ jsonObject.add(PROPERTIES, context.serialize(condition.getState())); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/BonusTablePredicateConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/BonusTablePredicateConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5a2d1fed17920fcb10696f537f407ae6d8fe7279 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/BonusTablePredicateConditionAdapter.java +@@ -0,0 +1,27 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import net.minecraft.server.ChatDeserializer; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++import org.bukkit.enchantments.Enchantment; ++ ++public class BonusTablePredicateConditionAdapter extends PredicateConditionAdapter { ++ ++ private static final String ENCHANTMENT = "enchantment"; ++ private static final String CHANCES = "chances"; ++ ++ @Override ++ public BonusTablePredicateCondition deserialize(JsonObject jsonObject, JsonDeserializationContext context) { ++ Enchantment enchantment = Enchantment.getByKey(CraftNamespacedKey.fromString(ChatDeserializer.getString(jsonObject, ENCHANTMENT))); ++ float[] chances = ChatDeserializer.getDeserializedType(jsonObject, CHANCES, context, float[].class); ++ return new BonusTablePredicateCondition(enchantment, chances); ++ } ++ ++ @Override ++ public void serialize(JsonObject jsonObject, BonusTablePredicateCondition condition, JsonSerializationContext context) { ++ jsonObject.addProperty(ENCHANTMENT, condition.getEnchantment().getKey().toString()); ++ jsonObject.add(CHANCES, context.serialize(condition.getChances())); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/DamageSourcePropertiesPredicateConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/DamageSourcePropertiesPredicateConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..baf279db9bc27784c6f823bd068e5fc4fe0898b6 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/DamageSourcePropertiesPredicateConditionAdapter.java +@@ -0,0 +1,23 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.conditions.DamageSourceCondition; ++ ++public class DamageSourcePropertiesPredicateConditionAdapter extends PredicateConditionAdapter { ++ ++ private static final String PREDICATE = "predicate"; ++ ++ @Override ++ public DamageSourcePropertiesPredicateCondition deserialize(JsonObject jsonObject, JsonDeserializationContext context) { ++ DamageSourceCondition damageType = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(PREDICATE), DamageSourceCondition.class), DamageSourceCondition.ANY); ++ return new DamageSourcePropertiesPredicateCondition(damageType); ++ } ++ ++ @Override ++ public void serialize(JsonObject jsonObject, DamageSourcePropertiesPredicateCondition condition, JsonSerializationContext context) { ++ jsonObject.add(PREDICATE, context.serialize(condition.getDamageType())); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/EntityPropertyPredicateConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/EntityPropertyPredicateConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..bbc3d925abc6c5442ab64b9412d537cbe72d922d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/EntityPropertyPredicateConditionAdapter.java +@@ -0,0 +1,26 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.conditions.EntityCondition; ++import net.minecraft.server.ChatDeserializer; ++ ++public class EntityPropertyPredicateConditionAdapter extends PredicateConditionAdapter { ++ ++ private static final String PREDICATE = "predicate"; ++ private static final String ENTITY = "entity"; ++ ++ @Override ++ public EntityPropertyPredicateCondition deserialize(JsonObject jsonObject, JsonDeserializationContext context) { ++ EntityCondition entity = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(PREDICATE), EntityCondition.class), EntityCondition.ANY); ++ return new EntityPropertyPredicateCondition(entity, EntityTarget.getByName(ChatDeserializer.getString(jsonObject, ENTITY))); ++ } ++ ++ @Override ++ public void serialize(JsonObject jsonObject, EntityPropertyPredicateCondition condition, JsonSerializationContext context) { ++ jsonObject.add(PREDICATE, context.serialize(condition.getEntity())); ++ jsonObject.addProperty(ENTITY, condition.getTarget().getName()); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/EntityScorePredicateConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/EntityScorePredicateConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..10985ca19ba1a4983ed5e32305dfca509c0845bf +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/EntityScorePredicateConditionAdapter.java +@@ -0,0 +1,44 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import com.google.common.collect.Maps; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.conditions.EntityScorePredicateCondition; ++import io.papermc.paper.advancements.triggers.conditions.predicates.values.ValueRange; ++import net.minecraft.server.ChatDeserializer; ++ ++import java.util.Iterator; ++import java.util.Map; ++import java.util.Map.Entry; ++ ++public class EntityScorePredicateConditionAdapter extends PredicateConditionAdapter { ++ ++ private static final String SCORES = "scores"; ++ private static final String ENTITY = "entity"; ++ ++ @Override ++ public EntityScorePredicateCondition deserialize(JsonObject jsonObject, JsonDeserializationContext context) { ++ Map scores = Maps.newLinkedHashMap(); ++ Iterator> iterator = ChatDeserializer.getJsonObject(jsonObject, SCORES).entrySet().iterator(); ++ while (iterator.hasNext()) { ++ Entry entry = iterator.next(); ++ scores.put(entry.getKey(), ChatDeserializer.asDeserializedType(entry.getValue(), "score", context, ValueRange.class)); ++ } ++ EntityTarget target = EntityTarget.getByName(ChatDeserializer.getString(jsonObject, ENTITY)); ++ return new EntityScorePredicateCondition(scores, target); ++ } ++ ++ @Override ++ public void serialize(JsonObject jsonObject, EntityScorePredicateCondition condition, JsonSerializationContext context) { ++ JsonObject scores = new JsonObject(); ++ Iterator> iterator = condition.getScores().entrySet().iterator(); ++ while (iterator.hasNext()) { ++ Entry entry = iterator.next(); ++ jsonObject.add(entry.getKey(), context.serialize(entry.getValue())); ++ } ++ jsonObject.add(SCORES, scores); ++ jsonObject.addProperty(ENTITY, condition.getTarget().getName()); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/InvertedPredicateConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/InvertedPredicateConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c701b341191351b71012ff0c6a0c94e5fdab340f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/InvertedPredicateConditionAdapter.java +@@ -0,0 +1,22 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import net.minecraft.server.ChatDeserializer; ++ ++public class InvertedPredicateConditionAdapter extends PredicateConditionAdapter { ++ ++ private static final String TERM = "term"; ++ ++ @Override ++ public InvertedPredicateCondition deserialize(JsonObject jsonObject, JsonDeserializationContext context) { ++ PredicateCondition term = ChatDeserializer.getDeserializedType(jsonObject, TERM, context, PredicateCondition.class); ++ return new InvertedPredicateCondition(term); ++ } ++ ++ @Override ++ public void serialize(JsonObject jsonObject, InvertedPredicateCondition condition, JsonSerializationContext context) { ++ jsonObject.add(TERM, context.serialize(condition.getTerm())); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/KilledByPlayerPredicateConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/KilledByPlayerPredicateConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..da045821481650bbe7395702d9dcdb21a0dc1a51 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/KilledByPlayerPredicateConditionAdapter.java +@@ -0,0 +1,16 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++ ++public class KilledByPlayerPredicateConditionAdapter extends PredicateConditionAdapter { ++ ++ @Override ++ public KilledByPlayerPredicateCondition deserialize(JsonObject jsonObject, JsonDeserializationContext context) { ++ return KilledByPlayerPredicateCondition.INSTANCE; ++ } ++ ++ @Override ++ public void serialize(JsonObject jsonObject, KilledByPlayerPredicateCondition condition, JsonSerializationContext context) { } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/LocationCheckPredicateConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/LocationCheckPredicateConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..af6928b6f157f7769e87347bc58947bf4f7be199 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/LocationCheckPredicateConditionAdapter.java +@@ -0,0 +1,40 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.conditions.LocationCondition; ++import io.papermc.paper.util.PaperChatDeserializer; ++import org.bukkit.Location; ++ ++public class LocationCheckPredicateConditionAdapter extends PredicateConditionAdapter { ++ ++ private static final String PREDICATE = "predicate"; ++ private static final String OFFSET_X = "offsetX"; ++ private static final String OFFSET_Y = "offsetY"; ++ private static final String OFFSET_Z = "offsetZ"; ++ ++ @Override ++ public LocationCheckPredicateCondition deserialize(JsonObject jsonObject, JsonDeserializationContext context) { ++ LocationCondition location = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(PREDICATE), LocationCondition.class), LocationCondition.ANY); ++ int x = PaperChatDeserializer.getIntOrDefault(jsonObject, OFFSET_X, 0); ++ int y = PaperChatDeserializer.getIntOrDefault(jsonObject, OFFSET_Y, 0); ++ int z = PaperChatDeserializer.getIntOrDefault(jsonObject, OFFSET_Z, 0); ++ return new LocationCheckPredicateCondition(location, new Location(null, x, y, z)); ++ } ++ ++ @Override ++ public void serialize(JsonObject jsonObject, LocationCheckPredicateCondition condition, JsonSerializationContext context) { ++ jsonObject.add(PREDICATE, context.serialize(condition.getLocation())); ++ if (condition.getBlockPosition().getBlockX() != 0) { ++ jsonObject.addProperty(OFFSET_X, condition.getBlockPosition().getBlockX()); ++ } ++ if (condition.getBlockPosition().getBlockY() != 0) { ++ jsonObject.addProperty(OFFSET_Y, condition.getBlockPosition().getBlockY()); ++ } ++ if (condition.getBlockPosition().getBlockZ() != 0) { ++ jsonObject.addProperty(OFFSET_Z, condition.getBlockPosition().getBlockZ()); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/MatchToolPredicateConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/MatchToolPredicateConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..baeea64ddcd975bbce3924a80d1a9ca40aa716bf +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/MatchToolPredicateConditionAdapter.java +@@ -0,0 +1,23 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import com.google.common.base.MoreObjects; ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.conditions.ItemCondition; ++ ++public class MatchToolPredicateConditionAdapter extends PredicateConditionAdapter { ++ ++ private static final String PREDICATE = "predicate"; ++ ++ @Override ++ public MatchToolPredicateCondition deserialize(JsonObject jsonObject, JsonDeserializationContext context) { ++ ItemCondition item = MoreObjects.firstNonNull(context.deserialize(jsonObject.get(PREDICATE), ItemCondition.class), ItemCondition.ANY); ++ return new MatchToolPredicateCondition(item); ++ } ++ ++ @Override ++ public void serialize(JsonObject jsonObject, MatchToolPredicateCondition condition, JsonSerializationContext context) { ++ jsonObject.add(PREDICATE, context.serialize(condition.getItem())); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/PredicateConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/PredicateConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b86b79cc5df2af140e38109209052361dfb480b9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/PredicateConditionAdapter.java +@@ -0,0 +1,52 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import net.minecraft.server.ChatDeserializer; ++import org.bukkit.NamespacedKey; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++ ++import java.lang.reflect.Type; ++ ++public abstract class PredicateConditionAdapter { ++ ++ public abstract T deserialize(JsonObject jsonObject, JsonDeserializationContext context); ++ ++ public abstract void serialize(JsonObject jsonObject, T condition, JsonSerializationContext context); ++ ++ public static class PredicateGsonAdapter implements JsonDeserializer, JsonSerializer { ++ ++ private static final String CONDITION = "condition"; ++ ++ @Override ++ public PredicateCondition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ JsonObject jsonObject = ChatDeserializer.asJsonObject(json, "loot condition"); ++ NamespacedKey key = CraftNamespacedKey.fromStringOrNull(ChatDeserializer.getString(jsonObject, CONDITION)); ++ return getAdapter(key).deserialize(jsonObject, context); ++ } ++ ++ @Override ++ public JsonElement serialize(PredicateCondition src, Type typeOfSrc, JsonSerializationContext context) { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.addProperty(CONDITION, src.getKey().toString()); ++ getAdapter(src.getKey()).serialize(jsonObject,src, context); ++ return jsonObject; ++ } ++ ++ private static PredicateConditionAdapter getAdapter(NamespacedKey key) { ++ if (key == null) { ++ throw new JsonParseException("Unrecognized key '" + key + "'"); ++ } ++ PredicateConditionAdapter adapter = PredicateConditions.getAdapter(key); ++ if (adapter == null) { ++ throw new JsonParseException("Could not find adapter for '" + key + "'"); ++ } ++ return (PredicateConditionAdapter) adapter; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/PredicateConditions.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/PredicateConditions.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2a13d695a91f96e1cd1502b9388ec0f80c874a36 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/PredicateConditions.java +@@ -0,0 +1,49 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import com.google.common.collect.Maps; ++import io.papermc.paper.advancements.CraftAdvancementsManager; ++import io.papermc.paper.advancements.triggers.conditions.EntityScorePredicateCondition; ++import io.papermc.paper.advancements.triggers.conditions.predicates.PredicateConditionAdapter.PredicateGsonAdapter; ++import io.papermc.paper.advancements.triggers.conditions.predicates.values.ValueRange; ++import io.papermc.paper.advancements.triggers.conditions.predicates.values.ValueRangeAdapter; ++import org.bukkit.NamespacedKey; ++ ++import java.util.Map; ++ ++public class PredicateConditions { ++ ++ private static Map> LOOT_ITEM_CONDITION_ADAPTER_MAP = Maps.newHashMap(); ++ ++ static { ++ CraftAdvancementsManager.addHierarchyAdapter(ValueRange.class, new ValueRangeAdapter()); ++ ++ register(InvertedPredicateCondition.KEY, new InvertedPredicateConditionAdapter()); ++ register(AlternativePredicateCondition.KEY, new AlternativePredicateConditionAdapter()); ++ register(RandomChancePredicateCondition.KEY, new RandomChangePredicateConditionAdapter()); ++ register(RandomChanceWithLootingPredicateCondition.KEY, new RandomChanceWithLootingPredicateConditionAdapter()); ++ register(EntityPropertyPredicateCondition.KEY, new EntityPropertyPredicateConditionAdapter()); ++ register(KilledByPlayerPredicateCondition.KEY, new KilledByPlayerPredicateConditionAdapter()); ++ register(EntityScorePredicateCondition.KEY, new EntityScorePredicateConditionAdapter()); ++ register(BlockStatePropertyPredicateCondition.KEY, new BlockStatePropertyPredicateConditionAdapter()); ++ register(MatchToolPredicateCondition.KEY, new MatchToolPredicateConditionAdapter()); ++ register(BonusTablePredicateCondition.KEY, new BonusTablePredicateConditionAdapter()); ++ register(SurvivesExplosionPredicateCondition.KEY, new SurvivesExplosionPredicateConditionAdapter()); ++ register(DamageSourcePropertiesPredicateCondition.KEY, new DamageSourcePropertiesPredicateConditionAdapter()); ++ register(LocationCheckPredicateCondition.KEY, new LocationCheckPredicateConditionAdapter()); ++ register(WeatherCheckPredicateCondition.KEY, new WeatherCheckPredicateConditionAdapter()); ++ register(ReferencePredicateCondition.KEY, new ReferencePredicateConditionAdapter()); ++ register(TimeCheckPredicateCondition.KEY, new TimeCheckPredicateConditionAdapter()); ++ ++ CraftAdvancementsManager.addHierarchyAdapter(PredicateCondition.class, new PredicateGsonAdapter()); ++ } ++ ++ public static void init() { }; ++ ++ private static > void register(NamespacedKey key, A adapter) { ++ LOOT_ITEM_CONDITION_ADAPTER_MAP.put(key, adapter); ++ } ++ ++ public static PredicateConditionAdapter getAdapter(NamespacedKey key) { ++ return LOOT_ITEM_CONDITION_ADAPTER_MAP.get(key); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/RandomChanceWithLootingPredicateConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/RandomChanceWithLootingPredicateConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a8387a77eae58490a4cc24fc290347f99cb46e98 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/RandomChanceWithLootingPredicateConditionAdapter.java +@@ -0,0 +1,23 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import net.minecraft.server.ChatDeserializer; ++ ++public class RandomChanceWithLootingPredicateConditionAdapter extends PredicateConditionAdapter { ++ ++ private static final String CHANCE = "chance"; ++ private static final String MULTIPLER = "looting_multiplier"; ++ ++ @Override ++ public RandomChanceWithLootingPredicateCondition deserialize(JsonObject jsonObject, JsonDeserializationContext context) { ++ return new RandomChanceWithLootingPredicateCondition(ChatDeserializer.getFloat(jsonObject, CHANCE), ChatDeserializer.getFloat(jsonObject, MULTIPLER)); ++ } ++ ++ @Override ++ public void serialize(JsonObject jsonObject, RandomChanceWithLootingPredicateCondition condition, JsonSerializationContext context) { ++ jsonObject.addProperty(CHANCE, condition.getPrecent()); ++ jsonObject.addProperty(MULTIPLER, condition.getMultipler()); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/RandomChangePredicateConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/RandomChangePredicateConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4c9f86c27809596b846ccf36fb36dcd236ebcf23 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/RandomChangePredicateConditionAdapter.java +@@ -0,0 +1,21 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import net.minecraft.server.ChatDeserializer; ++ ++public class RandomChangePredicateConditionAdapter extends PredicateConditionAdapter { ++ ++ private static final String CHANCE = "chance"; ++ ++ @Override ++ public RandomChancePredicateCondition deserialize(JsonObject jsonObject, JsonDeserializationContext context) { ++ return new RandomChancePredicateCondition(ChatDeserializer.getFloat(jsonObject, CHANCE)); ++ } ++ ++ @Override ++ public void serialize(JsonObject jsonObject, RandomChancePredicateCondition condition, JsonSerializationContext context) { ++ jsonObject.addProperty(CHANCE, condition.getChance()); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/ReferencePredicateConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/ReferencePredicateConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..dc305be6d39ddefc33fe42e0e42d23d48794b00d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/ReferencePredicateConditionAdapter.java +@@ -0,0 +1,26 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import net.minecraft.server.ChatDeserializer; ++import org.bukkit.NamespacedKey; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++ ++import javax.print.attribute.standard.MediaSize.NA; ++ ++public class ReferencePredicateConditionAdapter extends PredicateConditionAdapter { ++ ++ private static final String NAME = "name"; ++ ++ @Override ++ public ReferencePredicateCondition deserialize(JsonObject jsonObject, JsonDeserializationContext context) { ++ NamespacedKey reference = CraftNamespacedKey.fromString(ChatDeserializer.getString(jsonObject, NAME)); ++ return new ReferencePredicateCondition(reference); ++ } ++ ++ @Override ++ public void serialize(JsonObject jsonObject, ReferencePredicateCondition condition, JsonSerializationContext context) { ++ jsonObject.addProperty(NAME, condition.getReference().toString()); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/SurvivesExplosionPredicateConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/SurvivesExplosionPredicateConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e72f3820d71e57fa5a6eb2acb65dc897364a3347 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/SurvivesExplosionPredicateConditionAdapter.java +@@ -0,0 +1,16 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++ ++public class SurvivesExplosionPredicateConditionAdapter extends PredicateConditionAdapter { ++ ++ @Override ++ public SurvivesExplosionPredicateCondition deserialize(JsonObject jsonObject, JsonDeserializationContext context) { ++ return SurvivesExplosionPredicateCondition.INSTANCE; ++ } ++ ++ @Override ++ public void serialize(JsonObject jsonObject, SurvivesExplosionPredicateCondition condition, JsonSerializationContext context) { } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/TimeCheckPredicateConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/TimeCheckPredicateConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..be50b7977277468964d411525ed01a1628ec58a6 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/TimeCheckPredicateConditionAdapter.java +@@ -0,0 +1,26 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import io.papermc.paper.advancements.triggers.conditions.predicates.values.ValueRange; ++import net.minecraft.server.ChatDeserializer; ++ ++public class TimeCheckPredicateConditionAdapter extends PredicateConditionAdapter { ++ ++ private static final String PERIOD = "period"; ++ private static final String VALUE = "value"; ++ ++ @Override ++ public TimeCheckPredicateCondition deserialize(JsonObject jsonObject, JsonDeserializationContext context) { ++ Long peroid = jsonObject.has(PERIOD) ? ChatDeserializer.getLong(jsonObject, PERIOD) : null; ++ ValueRange value = ChatDeserializer.getDeserializedType(jsonObject, VALUE, context, ValueRange.class); ++ return new TimeCheckPredicateCondition(peroid, value); ++ } ++ ++ @Override ++ public void serialize(JsonObject jsonObject, TimeCheckPredicateCondition condition, JsonSerializationContext context) { ++ jsonObject.addProperty(PERIOD, condition.getPeriod()); ++ jsonObject.add(VALUE, context.serialize(condition.getValue())); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/WeatherCheckPredicateConditionAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/WeatherCheckPredicateConditionAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7869e9a4a1ed46f6abc25b6abafcd9503590b9f3 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/WeatherCheckPredicateConditionAdapter.java +@@ -0,0 +1,25 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonSerializationContext; ++import net.minecraft.server.ChatDeserializer; ++ ++public class WeatherCheckPredicateConditionAdapter extends PredicateConditionAdapter { ++ ++ private static final String RAINING = "raining"; ++ private static final String THUNDERING = "thundering"; ++ ++ @Override ++ public WeatherCheckPredicateCondition deserialize(JsonObject jsonObject, JsonDeserializationContext context) { ++ Boolean isRaining = jsonObject.has(RAINING) ? ChatDeserializer.getBoolean(jsonObject, RAINING) : null; ++ Boolean isThundering = jsonObject.has(THUNDERING) ? ChatDeserializer.getBoolean(jsonObject, THUNDERING) : null; ++ return new WeatherCheckPredicateCondition(isRaining, isThundering); ++ } ++ ++ @Override ++ public void serialize(JsonObject jsonObject, WeatherCheckPredicateCondition condition, JsonSerializationContext context) { ++ jsonObject.addProperty(RAINING, condition.getRaining()); ++ jsonObject.addProperty(THUNDERING, condition.getThundering()); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/values/ValueRangeAdapter.java b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/values/ValueRangeAdapter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..bbc852021b2701c674b5daa6d91573e5c3cdcc24 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancements/triggers/conditions/predicates/values/ValueRangeAdapter.java +@@ -0,0 +1,44 @@ ++package io.papermc.paper.advancements.triggers.conditions.predicates.values; ++ ++import com.google.gson.JsonDeserializationContext; ++import com.google.gson.JsonDeserializer; ++import com.google.gson.JsonElement; ++import com.google.gson.JsonObject; ++import com.google.gson.JsonParseException; ++import com.google.gson.JsonPrimitive; ++import com.google.gson.JsonSerializationContext; ++import com.google.gson.JsonSerializer; ++import net.minecraft.server.ChatDeserializer; ++ ++import java.lang.reflect.Type; ++ ++public class ValueRangeAdapter implements JsonDeserializer, JsonSerializer { ++ ++ private static final String MIN = "min"; ++ private static final String MAX = "max"; ++ private static final String VALUE = "value"; ++ ++ @Override ++ public ValueRange deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ++ if (ChatDeserializer.isNumber(json)) { ++ return new ValueRange(ChatDeserializer.asFloat(json, VALUE)); ++ } else { ++ JsonObject jsonObject = ChatDeserializer.asJsonObject(json, VALUE); ++ float min = ChatDeserializer.getFloat(jsonObject, MIN); ++ float max = ChatDeserializer.getFloat(jsonObject, MAX); ++ return new ValueRange(min, max); ++ } ++ } ++ ++ @Override ++ public JsonElement serialize(ValueRange src, Type typeOfSrc, JsonSerializationContext context) { ++ if (src.getMax() == src.getMin()) { ++ return new JsonPrimitive(src.getMax()); ++ } else { ++ JsonObject jsonObject = new JsonObject(); ++ jsonObject.addProperty(MIN, src.getMin()); ++ jsonObject.addProperty(MAX, src.getMax()); ++ return jsonObject; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/tag/CraftEntityTag.java b/src/main/java/io/papermc/paper/tag/CraftEntityTag.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a6f1bbd78401cdc61e3742e0530105defe8e49f0 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/tag/CraftEntityTag.java +@@ -0,0 +1,31 @@ ++package io.papermc.paper.tag; ++ ++import net.minecraft.server.EntityTypes; ++import net.minecraft.server.IRegistry; ++import net.minecraft.server.MinecraftKey; ++import net.minecraft.server.Tags; ++import org.bukkit.craftbukkit.tag.CraftTag; ++import org.bukkit.craftbukkit.util.CraftMagicNumbers; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++import org.bukkit.entity.EntityType; ++ ++import java.util.Collections; ++import java.util.Set; ++import java.util.stream.Collectors; ++ ++public class CraftEntityTag extends CraftTag, EntityType> { ++ ++ public CraftEntityTag(Tags> registry, MinecraftKey tag) { ++ super(registry, tag); ++ } ++ ++ @Override ++ public boolean isTagged(EntityType item) { ++ return getHandle().isTagged(CraftMagicNumbers.getEntityTypes(item)); ++ } ++ ++ @Override ++ public Set getValues() { ++ return Collections.unmodifiableSet(getHandle().getTagged().stream().map(CraftMagicNumbers::getEntityType).collect(Collectors.toSet())); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/util/PaperChatDeserializer.java b/src/main/java/io/papermc/paper/util/PaperChatDeserializer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..bc6009daa321d79c5ed22a90ce4234ddc5f5ac59 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/util/PaperChatDeserializer.java +@@ -0,0 +1,32 @@ ++package io.papermc.paper.util; ++ ++import com.google.gson.JsonArray; ++import com.google.gson.JsonObject; ++import net.minecraft.server.ChatDeserializer; ++ ++public class PaperChatDeserializer { ++ ++ public static boolean isMissingOrNull(JsonObject jsonObject, String key) { ++ return !jsonObject.has(key) || jsonObject.get(key).isJsonNull(); ++ } ++ ++ public static String getStringOrDefault(JsonObject jsonObject, String key, String def) { ++ return isMissingOrNull(jsonObject, key) ? def : ChatDeserializer.getString(jsonObject, key); ++ } ++ ++ public static Boolean getBooleanOrDefault(JsonObject jsonObject, String key, Boolean def) { ++ return isMissingOrNull(jsonObject, key) ? def : (Boolean) ChatDeserializer.getBoolean(jsonObject, key); ++ } ++ ++ public static Integer getIntOrDefault(JsonObject jsonObject, String key, Integer def) { ++ return isMissingOrNull(jsonObject, key) ? def : (Integer) ChatDeserializer.getInt(jsonObject, key); ++ } ++ ++ public static JsonObject getJsonObjectOrDefault(JsonObject jsonObject, String key, JsonObject def) { ++ return isMissingOrNull(jsonObject, key) ? def : ChatDeserializer.getJsonObject(jsonObject, key); ++ } ++ ++ public static JsonArray getJsonArrayOrDefault(JsonObject jsonObject, String key, JsonArray def) { ++ return isMissingOrNull(jsonObject, key) ? def : ChatDeserializer.getJsonArray(jsonObject, key); ++ } ++} +diff --git a/src/main/java/net/minecraft/server/Advancement.java b/src/main/java/net/minecraft/server/Advancement.java +index c405047c00d354bbc1449fd2f917b73f980ef1a5..22a3bd24f39b2b52bd141bcd4aefb7c878cc0a84 100644 +--- a/src/main/java/net/minecraft/server/Advancement.java ++++ b/src/main/java/net/minecraft/server/Advancement.java +@@ -26,7 +26,7 @@ public class Advancement { + private final String[][] requirements; + private final Set children = Sets.newLinkedHashSet(); + private final IChatBaseComponent chatComponent; +- public final org.bukkit.advancement.Advancement bukkit = new org.bukkit.craftbukkit.advancement.CraftAdvancement(this); // CraftBukkit ++ public final org.bukkit.advancement.Advancement bukkit; // CraftBukkit // Paper - moved to end of ctor + + public Advancement(MinecraftKey minecraftkey, @Nullable Advancement advancement, @Nullable AdvancementDisplay advancementdisplay, AdvancementRewards advancementrewards, Map map, String[][] astring) { + this.key = minecraftkey; +@@ -52,12 +52,15 @@ public class Advancement { + this.chatComponent = ChatComponentUtils.a((IChatBaseComponent) ichatmutablecomponent1).a(enumchatformat); + } + ++ bukkit = new org.bukkit.craftbukkit.advancement.CraftAdvancement(this, org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(minecraftkey)); // Paper - moved to end of ctor + } + ++ public Advancement.SerializedAdvancement getSerializedAdvancement() { return a(); } // Paper - OBFHELPER + public Advancement.SerializedAdvancement a() { + return new Advancement.SerializedAdvancement(this.parent == null ? null : this.parent.getName(), this.display, this.rewards, this.criteria, this.requirements); + } + ++ public Advancement getParent() { return b(); } // Paper - OBFHELPER + @Nullable + public Advancement b() { + return this.parent; +@@ -76,6 +79,7 @@ public class Advancement { + return "SimpleAdvancement{id=" + this.getName() + ", parent=" + (this.parent == null ? "null" : this.parent.getName()) + ", display=" + this.display + ", rewards=" + this.rewards + ", criteria=" + this.criteria + ", requirements=" + Arrays.deepToString(this.requirements) + '}'; + } + ++ public Iterable getChildren() { return this.children; } // Paper - OBFHELPER + public Iterable e() { + return this.children; + } +@@ -230,6 +234,7 @@ public class Advancement { + return advancement; + } + ++ public JsonObject toJson() { return b(); } // Paper - OBFHELPER + public JsonObject b() { + if (this.f == null) { + this.f = this.g.createRequirements(this.e.keySet()); +diff --git a/src/main/java/net/minecraft/server/AdvancementDisplay.java b/src/main/java/net/minecraft/server/AdvancementDisplay.java +index b0d4b7a67679a35fa8f88c241193c0f3814f1e7b..c17fc3e0c3b83da578a4ad51e9e3f3a253d3682f 100644 +--- a/src/main/java/net/minecraft/server/AdvancementDisplay.java ++++ b/src/main/java/net/minecraft/server/AdvancementDisplay.java +@@ -74,6 +74,7 @@ public class AdvancementDisplay { + } + } + ++ public static ItemStack deserializeItemStack(JsonObject jsonObject) { return b(jsonObject); } // Paper - OBFHELPER + private static ItemStack b(JsonObject jsonobject) { + if (!jsonobject.has("item")) { + throw new JsonSyntaxException("Unsupported icon type, currently only items are supported (add 'item' key)"); +diff --git a/src/main/java/net/minecraft/server/ChatDeserializer.java b/src/main/java/net/minecraft/server/ChatDeserializer.java +index 094a217b00393f648f85946168b13b5837ef90df..678450bae8d9c15ff28f1e252ed23dc34438f24c 100644 +--- a/src/main/java/net/minecraft/server/ChatDeserializer.java ++++ b/src/main/java/net/minecraft/server/ChatDeserializer.java +@@ -24,6 +24,7 @@ public class ChatDeserializer { + return !f(jsonobject, s) ? false : jsonobject.getAsJsonPrimitive(s).isString(); + } + ++ public static boolean isNumber(JsonElement jsonElement) { return b(jsonElement); } // Paper - OBFHELPER + public static boolean b(JsonElement jsonelement) { + return !jsonelement.isJsonPrimitive() ? false : jsonelement.getAsJsonPrimitive().isNumber(); + } +@@ -40,6 +41,7 @@ public class ChatDeserializer { + return jsonobject == null ? false : jsonobject.get(s) != null; + } + ++ public static String getStringRaw(JsonElement jsonElement, String key) { return a(jsonElement, key); } // Paper - OBFHELPER + public static String a(JsonElement jsonelement, String s) { + if (jsonelement.isJsonPrimitive()) { + return jsonelement.getAsString(); +@@ -48,6 +50,7 @@ public class ChatDeserializer { + } + } + ++ public static String getString(JsonObject jsonObject, String key) { return h(jsonObject, key); } // Paper - OBFHELPER + public static String h(JsonObject jsonobject, String s) { + if (jsonobject.has(s)) { + return a(jsonobject.get(s), s); +@@ -72,6 +75,7 @@ public class ChatDeserializer { + } + } + ++ public static Item getItem(JsonObject jsonObject, String key) { return i(jsonObject, key); } // Paper - OBFHELPER + public static Item i(JsonObject jsonobject, String s) { + if (jsonobject.has(s)) { + return b(jsonobject.get(s), s); +@@ -80,6 +84,7 @@ public class ChatDeserializer { + } + } + ++ public static boolean asBoolean(JsonElement jsonElement, String name) { return c(jsonElement, name); } // Paper - OBFHELPER + public static boolean c(JsonElement jsonelement, String s) { + if (jsonelement.isJsonPrimitive()) { + return jsonelement.getAsBoolean(); +@@ -88,6 +93,7 @@ public class ChatDeserializer { + } + } + ++ public static boolean getBoolean(JsonObject jsonObject, String key) { return j(jsonObject, key); } // Paper - OBFHELPER + public static boolean j(JsonObject jsonobject, String s) { + if (jsonobject.has(s)) { + return c(jsonobject.get(s), s); +@@ -100,6 +106,7 @@ public class ChatDeserializer { + return jsonobject.has(s) ? c(jsonobject.get(s), s) : flag; + } + ++ public static float asFloat(JsonElement jsonElement, String key) { return e(jsonElement, key); } // Paper - OBFHELPER + public static float e(JsonElement jsonelement, String s) { + if (jsonelement.isJsonPrimitive() && jsonelement.getAsJsonPrimitive().isNumber()) { + return jsonelement.getAsFloat(); +@@ -108,6 +115,7 @@ public class ChatDeserializer { + } + } + ++ public static float getFloat(JsonObject jsonObject, String key) { return l(jsonObject, key); } // Paper - OBFHELPER + public static float l(JsonObject jsonobject, String s) { + if (jsonobject.has(s)) { + return e(jsonobject.get(s), s); +@@ -128,6 +136,7 @@ public class ChatDeserializer { + } + } + ++ public static long getLong(JsonObject jsonObject, String key) { return m(jsonObject, key); } // Paper - OBFHELPER + public static long m(JsonObject jsonobject, String s) { + if (jsonobject.has(s)) { + return f(jsonobject.get(s), s); +@@ -140,6 +149,7 @@ public class ChatDeserializer { + return jsonobject.has(s) ? f(jsonobject.get(s), s) : i; + } + ++ public static int asInt(JsonElement jsonElement, String key) { return g(jsonElement, key); } // Paper - OBFHELPER + public static int g(JsonElement jsonelement, String s) { + if (jsonelement.isJsonPrimitive() && jsonelement.getAsJsonPrimitive().isNumber()) { + return jsonelement.getAsInt(); +@@ -148,6 +158,7 @@ public class ChatDeserializer { + } + } + ++ public static int getInt(JsonObject jsonObject, String key) { return n(jsonObject, key); } // Paper - OBFHELPER + public static int n(JsonObject jsonobject, String s) { + if (jsonobject.has(s)) { + return g(jsonobject.get(s), s); +@@ -172,6 +183,7 @@ public class ChatDeserializer { + return jsonobject.has(s) ? h(jsonobject.get(s), s) : b0; + } + ++ public static JsonObject asJsonObject(JsonElement jsonElement, String name) { return m(jsonElement, name); } // Paper - OBFHELPER + public static JsonObject m(JsonElement jsonelement, String s) { + if (jsonelement.isJsonObject()) { + return jsonelement.getAsJsonObject(); +@@ -180,6 +192,7 @@ public class ChatDeserializer { + } + } + ++ public static JsonObject getJsonObject(JsonObject jsonObject, String key) { return t(jsonObject, key); } // Paper - OBFHELPER + public static JsonObject t(JsonObject jsonobject, String s) { + if (jsonobject.has(s)) { + return m(jsonobject.get(s), s); +@@ -192,6 +205,7 @@ public class ChatDeserializer { + return jsonobject.has(s) ? m(jsonobject.get(s), s) : jsonobject1; + } + ++ public static JsonArray asJsonArray(JsonElement jsonElement, String name) { return n(jsonElement, name); } // Paper - OBFHELPER + public static JsonArray n(JsonElement jsonelement, String s) { + if (jsonelement.isJsonArray()) { + return jsonelement.getAsJsonArray(); +@@ -200,6 +214,7 @@ public class ChatDeserializer { + } + } + ++ public static JsonArray getJsonArray(JsonObject jsonObject, String key) { return u(jsonObject, key); } // Paper - OBFHELPER + public static JsonArray u(JsonObject jsonobject, String s) { + if (jsonobject.has(s)) { + return n(jsonobject.get(s), s); +@@ -213,6 +228,7 @@ public class ChatDeserializer { + return jsonobject.has(s) ? n(jsonobject.get(s), s) : jsonarray; + } + ++ public static T asDeserializedType(@Nullable JsonElement jsonElement, String name, JsonDeserializationContext context, Class type) { return a(jsonElement, name, context, type); } // Paper - OBFHELPER + public static T a(@Nullable JsonElement jsonelement, String s, JsonDeserializationContext jsondeserializationcontext, Class oclass) { + if (jsonelement != null) { + return jsondeserializationcontext.deserialize(jsonelement, oclass); +@@ -221,6 +237,7 @@ public class ChatDeserializer { + } + } + ++ public static T getDeserializedType(JsonObject jsonObject, String key, JsonDeserializationContext context, Class type) { return a(jsonObject, key, context, type); } // Paper - OBFHELPER + public static T a(JsonObject jsonobject, String s, JsonDeserializationContext jsondeserializationcontext, Class oclass) { + if (jsonobject.has(s)) { + return a(jsonobject.get(s), s, jsondeserializationcontext, oclass); +diff --git a/src/main/java/net/minecraft/server/CriterionConditionPlayer.java b/src/main/java/net/minecraft/server/CriterionConditionPlayer.java +index e0f8e36085ef47a7b26cbe0f47dd7de7f4f39a08..996772a54f62585bccc640fda1b8a6f0c476028c 100644 +--- a/src/main/java/net/minecraft/server/CriterionConditionPlayer.java ++++ b/src/main/java/net/minecraft/server/CriterionConditionPlayer.java +@@ -80,7 +80,7 @@ public class CriterionConditionPlayer { + ObjectIterator objectiterator = this.e.object2BooleanEntrySet().iterator(); + + while (objectiterator.hasNext()) { +- it.unimi.dsi.fastutil.objects.Object2BooleanMap.Entry it_unimi_dsi_fastutil_objects_object2booleanmap_entry = (it.unimi.dsi.fastutil.objects.Object2BooleanMap.Entry) objectiterator.next(); ++ Object2BooleanMap.Entry it_unimi_dsi_fastutil_objects_object2booleanmap_entry = (Object2BooleanMap.Entry) objectiterator.next(); // Paper - decompile fix + + if (recipebookserver.hasDiscoveredRecipe((MinecraftKey) it_unimi_dsi_fastutil_objects_object2booleanmap_entry.getKey()) != it_unimi_dsi_fastutil_objects_object2booleanmap_entry.getBooleanValue()) { + return false; +@@ -167,6 +167,7 @@ public class CriterionConditionPlayer { + } + } + ++ public static Statistic getStat(StatisticWrapper statisticWrapper, MinecraftKey minecraftKey) { return a(statisticWrapper, minecraftKey); } // Paper - OBFHELPER + private static Statistic a(StatisticWrapper statisticwrapper, MinecraftKey minecraftkey) { + IRegistry iregistry = statisticwrapper.getRegistry(); + T t0 = iregistry.get(minecraftkey); +@@ -178,6 +179,7 @@ public class CriterionConditionPlayer { + } + } + ++ public static MinecraftKey getKey(Statistic statistic) { return a(statistic); } // Paper - OBFHELPER + private static MinecraftKey a(Statistic statistic) { + return statistic.getWrapper().getRegistry().getKey(statistic.b()); + } +@@ -211,16 +213,18 @@ public class CriterionConditionPlayer { + + if (!this.e.isEmpty()) { + jsonobject1 = new JsonObject(); ++ JsonObject finalJsonobject = jsonobject1; // Paper - decompile fix + this.e.forEach((minecraftkey, obool) -> { +- jsonobject1.addProperty(minecraftkey.toString(), obool); ++ finalJsonobject.addProperty(minecraftkey.toString(), obool); // Paper - decompile fix + }); + jsonobject.add("recipes", jsonobject1); + } + + if (!this.f.isEmpty()) { + jsonobject1 = new JsonObject(); ++ JsonObject finalJsonobject1 = jsonobject1; // Paper - decompile fix + this.f.forEach((minecraftkey, criterionconditionplayer_c) -> { +- jsonobject1.add(minecraftkey.toString(), criterionconditionplayer_c.a()); ++ finalJsonobject1.add(minecraftkey.toString(), criterionconditionplayer_c.a()); // Paper - decompile fix + }); + jsonobject.add("advancements", jsonobject1); + } +@@ -269,7 +273,7 @@ public class CriterionConditionPlayer { + public boolean test(AdvancementProgress advancementprogress) { + ObjectIterator objectiterator = this.a.object2BooleanEntrySet().iterator(); + +- it.unimi.dsi.fastutil.objects.Object2BooleanMap.Entry it_unimi_dsi_fastutil_objects_object2booleanmap_entry; ++ Object2BooleanMap.Entry it_unimi_dsi_fastutil_objects_object2booleanmap_entry; // Paper - decompile fix + CriterionProgress criterionprogress; + + do { +@@ -277,7 +281,7 @@ public class CriterionConditionPlayer { + return true; + } + +- it_unimi_dsi_fastutil_objects_object2booleanmap_entry = (it.unimi.dsi.fastutil.objects.Object2BooleanMap.Entry) objectiterator.next(); ++ it_unimi_dsi_fastutil_objects_object2booleanmap_entry = (Object2BooleanMap.Entry) objectiterator.next(); // Paper - decompile fix + criterionprogress = advancementprogress.getCriterionProgress((String) it_unimi_dsi_fastutil_objects_object2booleanmap_entry.getKey()); + } while (criterionprogress != null && criterionprogress.a() == it_unimi_dsi_fastutil_objects_object2booleanmap_entry.getBooleanValue()); + +diff --git a/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancement.java b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancement.java +index a5aadf2850f273e258f84b6c7bc9ca3649fb884d..a9a1cdf462972c0a6049422cfd97dce09423fc43 100644 +--- a/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancement.java ++++ b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancement.java +@@ -8,10 +8,18 @@ import org.bukkit.craftbukkit.util.CraftNamespacedKey; + + public class CraftAdvancement implements org.bukkit.advancement.Advancement { + +- private final Advancement handle; ++ private Advancement handle; // Papoer + +- public CraftAdvancement(Advancement handle) { ++ public CraftAdvancement(Advancement handle, NamespacedKey key) { // Paper + this.handle = handle; ++ // Paper start ++ this.key = key; ++ CraftSerializedAdvancement serializedAdvancement = io.papermc.paper.advancements.CraftAdvancementsManager.getGson().fromJson(handle.getSerializedAdvancement().toJson(), CraftSerializedAdvancement.class); ++ this.advancementDisplay = serializedAdvancement.advancementDisplay; ++ this.advancementRewards = serializedAdvancement.advancementRewards; ++ this.triggerMap = serializedAdvancement.triggerMap; ++ this.requirements = serializedAdvancement.requirements; ++ // Paper end + } + + public Advancement getHandle() { +@@ -20,11 +28,132 @@ public class CraftAdvancement implements org.bukkit.advancement.Advancement { + + @Override + public NamespacedKey getKey() { +- return CraftNamespacedKey.fromMinecraft(handle.getName()); ++ return key; // Paper + } + + @Override + public Collection getCriteria() { + return Collections.unmodifiableCollection(handle.getCriteria().keySet()); + } ++ // Paper start ++ private final NamespacedKey key; ++ private org.bukkit.advancement.Advancement parent; ++ private io.papermc.paper.advancements.AdvancementDisplay advancementDisplay; ++ private final io.papermc.paper.advancements.AdvancementRewards advancementRewards; ++ private final java.util.Map triggerMap; ++ private final String[][] requirements; ++ ++ /*public CraftAdvancement(NamespacedKey key) { ++ this.key = key; ++ this.advancementDisplay = new io.papermc.paper.advancements.AdvancementDisplay(); ++ this.advancementRewards = new io.papermc.paper.advancements.AdvancementRewards(); ++ this.triggerMap = new java.util.HashMap<>(); ++ }*/ ++ ++ @Override ++ public org.bukkit.advancement.Advancement getParent() { ++ return parent; ++ } ++ ++ @Override ++ public void setParent(org.bukkit.advancement.Advancement parent) { ++ this.parent = parent; ++ } ++ ++ @Override ++ public io.papermc.paper.advancements.AdvancementDisplay getAdvancementDisplay() { ++ return advancementDisplay; ++ } ++ ++ @Override ++ public io.papermc.paper.advancements.AdvancementRewards getAdvancementRewards() { ++ return advancementRewards; ++ } ++ ++ @Override ++ public java.util.Map getTriggers() { ++ return triggerMap; ++ } ++ ++ @Override ++ public String[][] getRequirements() { ++ return new String[0][]; ++ } ++ ++ public static class CraftSerializedAdvancement { ++ private final io.papermc.paper.advancements.AdvancementDisplay advancementDisplay; ++ private final io.papermc.paper.advancements.AdvancementRewards advancementRewards; ++ private final java.util.Map triggerMap; ++ private final String[][] requirements; ++ ++ public CraftSerializedAdvancement(io.papermc.paper.advancements.AdvancementDisplay advancementDisplay, io.papermc.paper.advancements.AdvancementRewards advancementRewards, java.util.Map triggerMap, String[][] requirements) { ++ this.advancementDisplay = advancementDisplay; ++ this.advancementRewards = advancementRewards; ++ this.triggerMap = triggerMap; ++ this.requirements = requirements; ++ } ++ } ++ ++ public static class AdvancementSerialization implements com.google.gson.JsonDeserializer { ++ ++ private static final String DISPLAY = "display"; ++ private static final String PARENT = "parent"; ++ private static final String CRITERIA = "criteria"; ++ private static final String REQUIREMENTS = "requirements"; ++ private static final String REWARDS = "rewards"; ++ ++ private static final String CONDITIONS = "conditions"; ++ ++ @Override ++ public CraftSerializedAdvancement deserialize(com.google.gson.JsonElement json, java.lang.reflect.Type typeOfT, com.google.gson.JsonDeserializationContext context) throws com.google.gson.JsonParseException { ++ com.google.gson.JsonObject jsonObject = json.getAsJsonObject(); ++ io.papermc.paper.advancements.AdvancementDisplay advancementDisplay = context.deserialize(jsonObject.get(DISPLAY), io.papermc.paper.advancements.AdvancementDisplay.class); ++ io.papermc.paper.advancements.AdvancementRewards advancementRewards = context.deserialize(jsonObject.get(REWARDS), io.papermc.paper.advancements.AdvancementRewards.class); ++ ++ java.util.Map triggerMap = new java.util.HashMap<>(); ++ com.google.gson.JsonObject critieraObj = jsonObject.getAsJsonObject(CRITERIA); ++ critieraObj.entrySet().forEach(entry -> { ++ com.google.gson.JsonObject triggerObj = net.minecraft.server.ChatDeserializer.asJsonObject(entry.getValue(), "trigger"); ++ NamespacedKey triggerKey = io.papermc.paper.advancements.AdvancementTriggers.getTrigerKey(triggerObj); ++ if (!io.papermc.paper.advancements.AdvancementTriggers.TRIGGER_MAP.containsKey(triggerKey)) { ++ throw new com.google.gson.JsonParseException("Did not recognize trigger '" + triggerKey + "'"); ++ } ++ io.papermc.paper.advancements.triggers.Trigger trigger; ++ if (!triggerObj.has(CONDITIONS)) { ++ if (triggerKey.equals(io.papermc.paper.advancements.triggers.ImpossibleTrigger.KEY)) { ++ trigger = new io.papermc.paper.advancements.triggers.ImpossibleTrigger(); ++ } else if (triggerKey.equals(io.papermc.paper.advancements.triggers.TickTrigger.KEY)) { ++ trigger = new io.papermc.paper.advancements.triggers.TickTrigger(); ++ } else { ++ throw new com.google.gson.JsonParseException("Could not find conditions for '" + triggerObj + "'"); ++ } ++ } else { ++ trigger = context.deserialize(net.minecraft.server.ChatDeserializer.getJsonObject(triggerObj, CONDITIONS), io.papermc.paper.advancements.AdvancementTriggers.TRIGGER_MAP.get(triggerKey).getTriggerClass()); ++ } ++ triggerMap.put(entry.getKey(), trigger); ++ }); ++ ++ com.google.gson.JsonArray ands = io.papermc.paper.util.PaperChatDeserializer.getJsonArrayOrDefault(jsonObject, REQUIREMENTS, new com.google.gson.JsonArray()); ++ String[][] requirements = new String[ands.size()][]; ++ for (int i = 0; i < ands.size(); i++) { ++ com.google.gson.JsonArray ors = net.minecraft.server.ChatDeserializer.asJsonArray(ands.get(i), REQUIREMENTS + "[" + i + "]"); ++ requirements[i] = new String[ors.size()]; ++ for (int j = 0; j < ors.size(); j++) { ++ requirements[i][j] = net.minecraft.server.ChatDeserializer.getStringRaw(ors.get(j), REQUIREMENTS + "[" + i + "][" + j + "]"); ++ } ++ } ++ if (requirements.length == 0) { ++ requirements = new String[triggerMap.size()][]; ++ ++ int i = 0; ++ for (String s : triggerMap.keySet()) { ++ requirements[i] = new String[] { s }; ++ i++; ++ } ++ } ++ ++ return new CraftSerializedAdvancement(advancementDisplay, advancementRewards, triggerMap, requirements); ++ } ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java +index 082b0fdf908f6728b940fd9f3fd5e0aecfa1af15..4c47f4f3df00af0b39f3e433c656ba793aac66d6 100644 +--- a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java ++++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java +@@ -102,4 +102,10 @@ public class CraftPotionEffectType extends PotionEffectType { + public Color getColor() { + return Color.fromRGB(handle.getColor()); + } ++ // Paper start ++ @Override ++ public org.bukkit.NamespacedKey getKey() { ++ return org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(net.minecraft.server.IRegistry.MOB_EFFECT.getKey(this.handle)); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index 0f7f1503d07bdff7ce7644dfe21e444adb52c7db..2795f21e196d982d225e4378954b6cbb0a079680 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -91,6 +91,8 @@ public final class CraftMagicNumbers implements UnsafeValues { + private static final Map MATERIAL_ITEM = new HashMap<>(); + private static final Map MATERIAL_BLOCK = new HashMap<>(); + private static final Map MATERIAL_FLUID = new HashMap<>(); ++ private static final Map> ENTITY_TYPE_ENTITY_TYPES = new HashMap<>(); // Paper ++ private static final Map, org.bukkit.entity.EntityType> ENTITY_TYPES_ENTITY_TYPE = new HashMap<>(); // Paper + + static { + for (Block block : IRegistry.BLOCK) { +@@ -121,8 +123,23 @@ public final class CraftMagicNumbers implements UnsafeValues { + MATERIAL_FLUID.put(material, fluid); + }); + } ++ // Paper start ++ for (org.bukkit.entity.EntityType type : org.bukkit.entity.EntityType.values()) { ++ if (type == org.bukkit.entity.EntityType.UNKNOWN) continue; ++ ENTITY_TYPE_ENTITY_TYPES.put(type, IRegistry.ENTITY_TYPE.get(CraftNamespacedKey.toMinecraft(type.getKey()))); ++ ENTITY_TYPES_ENTITY_TYPE.put(IRegistry.ENTITY_TYPE.get(CraftNamespacedKey.toMinecraft(type.getKey())), type); ++ } ++ } ++ ++ public static net.minecraft.server.EntityTypes getEntityTypes(org.bukkit.entity.EntityType type) { ++ return ENTITY_TYPE_ENTITY_TYPES.get(type); + } + ++ public static org.bukkit.entity.EntityType getEntityType(net.minecraft.server.EntityTypes entityTypes) { ++ return ENTITY_TYPES_ENTITY_TYPE.get(entityTypes); ++ } ++ // Paper end ++ + public static Material getMaterial(Block block) { + return BLOCK_MATERIAL.get(block); + }