Add new advancements

This commit is contained in:
Sollace 2023-09-09 18:46:41 +01:00
parent 1a3655d244
commit 77e662bb85
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
12 changed files with 319 additions and 38 deletions

View file

@ -1,13 +1,8 @@
package com.minelittlepony.unicopia.advancement; package com.minelittlepony.unicopia.advancement;
import java.util.HashSet;
import java.util.Set;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
@ -32,19 +27,10 @@ public class CustomEventCriterion extends AbstractCriterion<CustomEventCriterion
@Override @Override
protected Conditions conditionsFromJson(JsonObject json, LootContextPredicate playerPredicate, AdvancementEntityPredicateDeserializer deserializer) { protected Conditions conditionsFromJson(JsonObject json, LootContextPredicate playerPredicate, AdvancementEntityPredicateDeserializer deserializer) {
Set<Race> races = new HashSet<>();
if (json.has("race")) {
json.get("race").getAsJsonArray().forEach(el -> {
races.add(Race.fromName(el.getAsString(), Race.EARTH));
});
}
return new Conditions( return new Conditions(
playerPredicate, playerPredicate,
JsonHelper.getString(json, "event"), JsonHelper.getString(json, "event"),
races, RacePredicate.fromJson(json.get("race")),
json.has("flying") ? json.get("flying").getAsBoolean() : null, json.has("flying") ? json.get("flying").getAsBoolean() : null,
JsonHelper.getInt(json, "repeats", 0) JsonHelper.getInt(json, "repeats", 0)
); );
@ -67,13 +53,13 @@ public class CustomEventCriterion extends AbstractCriterion<CustomEventCriterion
public static class Conditions extends AbstractCriterionConditions { public static class Conditions extends AbstractCriterionConditions {
private final String event; private final String event;
private final Set<Race> races; private final RacePredicate races;
private final Boolean flying; private final Boolean flying;
private final int repeatCount; private final int repeatCount;
public Conditions(LootContextPredicate playerPredicate, String event, Set<Race> races, Boolean flying, int repeatCount) { public Conditions(LootContextPredicate playerPredicate, String event, RacePredicate races, Boolean flying, int repeatCount) {
super(ID, playerPredicate); super(ID, playerPredicate);
this.event = event; this.event = event;
this.races = races; this.races = races;
@ -83,7 +69,7 @@ public class CustomEventCriterion extends AbstractCriterion<CustomEventCriterion
public boolean test(String event, int count, ServerPlayerEntity player) { public boolean test(String event, int count, ServerPlayerEntity player) {
return this.event.equalsIgnoreCase(event) return this.event.equalsIgnoreCase(event)
&& (races.isEmpty() || races.contains(Pony.of(player).getSpecies())) && races.test(player)
&& (flying == null || flying == Pony.of(player).getPhysics().isFlying()) && (flying == null || flying == Pony.of(player).getPhysics().isFlying())
&& (repeatCount <= 0 || (count > 0 && count % repeatCount == 0)); && (repeatCount <= 0 || (count > 0 && count % repeatCount == 0));
} }
@ -92,11 +78,7 @@ public class CustomEventCriterion extends AbstractCriterion<CustomEventCriterion
public JsonObject toJson(AdvancementEntityPredicateSerializer serializer) { public JsonObject toJson(AdvancementEntityPredicateSerializer serializer) {
JsonObject json = super.toJson(serializer); JsonObject json = super.toJson(serializer);
json.addProperty("event", event); json.addProperty("event", event);
if (!races.isEmpty()) { json.add("race", races.toJson());
JsonArray arr = new JsonArray();
races.forEach(r -> arr.add(Race.REGISTRY.getId(r).toString()));
json.add("race", arr);
}
if (flying != null) { if (flying != null) {
json.addProperty("flying", flying); json.addProperty("flying", flying);
} }

View file

@ -0,0 +1,73 @@
package com.minelittlepony.unicopia.advancement;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.jetbrains.annotations.Nullable;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.JsonHelper;
public record RacePredicate(Set<Race> include, Set<Race> exclude) implements Predicate<ServerPlayerEntity> {
public static final RacePredicate EMPTY = new RacePredicate(Set.of(), Set.of());
public static RacePredicate fromJson(JsonElement json) {
if (json == null || json.isJsonNull()) {
return EMPTY;
}
if (json.isJsonArray()) {
return of(getRaces(json.getAsJsonArray()), Set.of());
}
JsonObject root = JsonHelper.asObject(json, "race");
return of(getRaces(root, "include"), getRaces(root, "exclude"));
}
private static RacePredicate of(Set<Race> include, Set<Race> exclude) {
if (include.isEmpty() && exclude.isEmpty()) {
return EMPTY;
}
return new RacePredicate(include, exclude);
}
private static @Nullable Set<Race> getRaces(JsonObject json, String field) {
return json.has(field) ? getRaces(JsonHelper.getArray(json, field)) : Set.of();
}
private static Set<Race> getRaces(JsonArray array) {
return array.asList()
.stream()
.map(el -> Race.fromName(el.getAsString(), Race.EARTH))
.distinct()
.collect(Collectors.toSet());
}
@Override
public boolean test(ServerPlayerEntity player) {
Race race = Pony.of(player).getSpecies();
return (include.isEmpty() || include.contains(race)) && !(!exclude.isEmpty() && exclude.contains(race));
}
public JsonObject toJson() {
JsonObject json = new JsonObject();
if (!include.isEmpty()) {
JsonArray arr = new JsonArray();
include.forEach(r -> arr.add(Race.REGISTRY.getId(r).toString()));
json.add("include", arr);
}
if (!exclude.isEmpty()) {
JsonArray arr = new JsonArray();
exclude.forEach(r -> arr.add(Race.REGISTRY.getId(r).toString()));
json.add("exclude", arr);
}
return json;
}
}

View file

@ -0,0 +1,109 @@
package com.minelittlepony.unicopia.advancement;
import java.util.Optional;
import java.util.function.BiConsumer;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.fabricmc.fabric.api.util.TriState;
import net.minecraft.advancement.criterion.AbstractCriterion;
import net.minecraft.advancement.criterion.AbstractCriterionConditions;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.predicate.entity.AdvancementEntityPredicateDeserializer;
import net.minecraft.predicate.entity.AdvancementEntityPredicateSerializer;
import net.minecraft.predicate.entity.LootContextPredicate;
import net.minecraft.predicate.item.ItemPredicate;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier;
import net.minecraft.util.JsonHelper;
import net.minecraft.util.TypeFilter;
public class SendViaDragonBreathScrollCriterion extends AbstractCriterion<SendViaDragonBreathScrollCriterion.Conditions> {
private static final Identifier ID = Unicopia.id("send_dragon_breath");
@Override
public Identifier getId() {
return ID;
}
@Override
protected Conditions conditionsFromJson(JsonObject json, LootContextPredicate playerPredicate, AdvancementEntityPredicateDeserializer deserializer) {
return new Conditions(playerPredicate,
ItemPredicate.fromJson(json.get("item")),
JsonHelper.getBoolean(json, "is_receiving_end", false),
json.has("recipient_name") ? Optional.of(JsonHelper.getString(json, "recipient_name")) : Optional.empty(),
json.has("recipient_present") ? TriState.of(JsonHelper.getBoolean(json, "recipient_present")) : TriState.DEFAULT,
json.has("counter") ? Optional.of(JsonHelper.getString(json, "counter")) : Optional.empty(),
RacePredicate.fromJson(json.get("race"))
);
}
public void triggerSent(PlayerEntity player, ItemStack payload, String recipient, BiConsumer<String, Integer> counterCallback) {
if (player instanceof ServerPlayerEntity spe) {
trigger(spe, c -> {
if (c.test(spe, payload, recipient, false)) {
c.counter.ifPresent(counter -> {
counterCallback.accept(counter, Pony.of(spe).getAdvancementProgress().compute(counter, (key, i) -> i == null ? 1 : i + 1));
});
return true;
}
return false;
});
}
}
public void triggerReceived(LivingEntity recipient, ItemStack payload) {
if (recipient instanceof ServerPlayerEntity spe) {
trigger(spe, c -> c.test(spe, payload, recipient.getDisplayName().getString(), true));
}
}
public static class Conditions extends AbstractCriterionConditions {
private final ItemPredicate item;
private final boolean isReceivingEnd;
private final Optional<String> recipientName;
private final TriState recipientPresent;
private final Optional<String> counter;
private final RacePredicate races;
public Conditions(LootContextPredicate playerPredicate, ItemPredicate item, boolean isReceivingEnd, Optional<String> recipient, TriState recipientPresent, Optional<String> counter, RacePredicate races) {
super(ID, playerPredicate);
this.item = item;
this.isReceivingEnd = isReceivingEnd;
this.recipientName = recipient;
this.recipientPresent = recipientPresent;
this.counter = counter;
this.races = races;
}
public boolean test(ServerPlayerEntity player, ItemStack payload, String recipient, boolean receiving) {
return isReceivingEnd == receiving
&& races.test(player)
&& item.test(payload)
&& recipientName.map(expectedRecipientname -> recipient.equalsIgnoreCase(expectedRecipientname)).orElse(true)
&& (recipientPresent == TriState.DEFAULT || isRecipientAbsent(player.getServerWorld(), recipient) != recipientPresent.get());
}
private boolean isRecipientAbsent(ServerWorld world, String recipient) {
return world.getEntitiesByType(TypeFilter.instanceOf(LivingEntity.class), e -> e.hasCustomName() && e.getCustomName().getString().equalsIgnoreCase(recipient)).isEmpty();
}
@Override
public JsonObject toJson(AdvancementEntityPredicateSerializer serializer) {
JsonObject json = super.toJson(serializer);
json.add("item", item.toJson());
json.add("race", races.toJson());
recipientName.ifPresent(recipient -> json.addProperty("recipient_name", recipient));
if (recipientPresent != TriState.DEFAULT) {
json.addProperty("recipient_present", recipientPresent.getBoxed());
}
counter.ifPresent(counter -> json.addProperty("counter", counter));
return json;
}
}
}

View file

@ -5,6 +5,7 @@ import net.minecraft.advancement.criterion.Criteria;
public interface UCriteria { public interface UCriteria {
CustomEventCriterion CUSTOM_EVENT = Criteria.register(new CustomEventCriterion()); CustomEventCriterion CUSTOM_EVENT = Criteria.register(new CustomEventCriterion());
RaceChangeCriterion PLAYER_CHANGE_RACE = Criteria.register(new RaceChangeCriterion()); RaceChangeCriterion PLAYER_CHANGE_RACE = Criteria.register(new RaceChangeCriterion());
SendViaDragonBreathScrollCriterion SEND_DRAGON_BREATH = Criteria.register(new SendViaDragonBreathScrollCriterion());
CustomEventCriterion.Trigger LOOK_INTO_SUN = CUSTOM_EVENT.createTrigger("look_into_sun"); CustomEventCriterion.Trigger LOOK_INTO_SUN = CUSTOM_EVENT.createTrigger("look_into_sun");
CustomEventCriterion.Trigger WEAR_SHADES = CUSTOM_EVENT.createTrigger("wear_shades"); CustomEventCriterion.Trigger WEAR_SHADES = CUSTOM_EVENT.createTrigger("wear_shades");
@ -16,8 +17,6 @@ public interface UCriteria {
CustomEventCriterion.Trigger SPOOK_MOB = CUSTOM_EVENT.createTrigger("spook_mob"); CustomEventCriterion.Trigger SPOOK_MOB = CUSTOM_EVENT.createTrigger("spook_mob");
CustomEventCriterion.Trigger SHED_FEATHER = CUSTOM_EVENT.createTrigger("shed_feather"); CustomEventCriterion.Trigger SHED_FEATHER = CUSTOM_EVENT.createTrigger("shed_feather");
CustomEventCriterion.Trigger THROW_MUFFIN = CUSTOM_EVENT.createTrigger("throw_muffin"); CustomEventCriterion.Trigger THROW_MUFFIN = CUSTOM_EVENT.createTrigger("throw_muffin");
CustomEventCriterion.Trigger SEND_OATS = CUSTOM_EVENT.createTrigger("send_oats");
CustomEventCriterion.Trigger RECEIVE_OATS = CUSTOM_EVENT.createTrigger("receive_oats");
CustomEventCriterion.Trigger BREAK_WINDOW = CUSTOM_EVENT.createTrigger("break_window"); CustomEventCriterion.Trigger BREAK_WINDOW = CUSTOM_EVENT.createTrigger("break_window");
CustomEventCriterion.Trigger KILL_PHANTOM_WHILE_FLYING = CUSTOM_EVENT.createTrigger("kill_phantom_while_flying"); CustomEventCriterion.Trigger KILL_PHANTOM_WHILE_FLYING = CUSTOM_EVENT.createTrigger("kill_phantom_while_flying");
CustomEventCriterion.Trigger USE_CONSUMPTION = CUSTOM_EVENT.createTrigger("use_consumption"); CustomEventCriterion.Trigger USE_CONSUMPTION = CUSTOM_EVENT.createTrigger("use_consumption");

View file

@ -447,10 +447,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
itemEntity.setPosition(randomPos); itemEntity.setPosition(randomPos);
itemEntity.getWorld().spawnEntity(itemEntity); itemEntity.getWorld().spawnEntity(itemEntity);
entity.getWorld().playSoundFromEntity(null, entity, USounds.ITEM_DRAGON_BREATH_ARRIVE, entity.getSoundCategory(), 1, 1); entity.getWorld().playSoundFromEntity(null, entity, USounds.ITEM_DRAGON_BREATH_ARRIVE, entity.getSoundCategory(), 1, 1);
UCriteria.SEND_DRAGON_BREATH.triggerReceived(entity, payload.copy());
if (item == UItems.OATS && entity instanceof PlayerEntity player) {
UCriteria.RECEIVE_OATS.trigger(player);
}
} }
} }
}); });

View file

@ -5,10 +5,12 @@ import java.util.UUID;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.advancement.UCriteria; import com.minelittlepony.unicopia.advancement.UCriteria;
import com.minelittlepony.unicopia.server.world.DragonBreathStore; import com.minelittlepony.unicopia.server.world.DragonBreathStore;
import com.minelittlepony.unicopia.server.world.UnicopiaWorldProperties;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult; import net.minecraft.util.TypedActionResult;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -30,10 +32,15 @@ public class DragonBreathScrollItem extends Item {
stack.split(1); stack.split(1);
if (!world.isClient) { if (!world.isClient) {
if (payload.getItem() == UItems.OATS) { String recipient = stack.getName().getString();
UCriteria.SEND_OATS.trigger(player); UCriteria.SEND_DRAGON_BREATH.triggerSent(player, payload, recipient, (counterName, count) -> {
} if (count == 1 && "dings_on_celestias_head".equals(counterName)) {
DragonBreathStore.get(world).put(stack.getName().getString(), payload.split(1)); UnicopiaWorldProperties properties = UnicopiaWorldProperties.forWorld((ServerWorld)world);
properties.setTangentalSkyAngle(properties.getTangentalSkyAngle() + 15);
player.playSound(USounds.Vanilla.BLOCK_ANVIL_HIT, 0.3F, 1);
}
});
DragonBreathStore.get(world).put(recipient, payload.split(1));
} }
player.playSound(USounds.ITEM_DRAGON_BREATH_SCROLL_USE, 1, 1); player.playSound(USounds.ITEM_DRAGON_BREATH_SCROLL_USE, 1, 1);
return TypedActionResult.consume(stack); return TypedActionResult.consume(stack);

View file

@ -892,6 +892,11 @@
"advancements.unicopia.extra_spooky.title": "Extra Spooky", "advancements.unicopia.extra_spooky.title": "Extra Spooky",
"advancements.unicopia.extra_spooky.description": "Spook a mob so hard it drops a brick", "advancements.unicopia.extra_spooky.description": "Spook a mob so hard it drops a brick",
"advancements.unicopia.sweet_sweet_revenge.title": "Sweet Sweet Revenge",
"advancements.unicopia.sweet_sweet_revenge.description": "Get Celestia back for burning your eyes",
"advancements.unicopia.blasphemy.title": "Blasphemy!",
"advancements.unicopia.blasphemy.description": "Ding Celestia on the noggin. Oops!",
"advancements.unicopia.earth_route.title": "Path of the Pony", "advancements.unicopia.earth_route.title": "Path of the Pony",
"advancements.unicopia.earth_route.description": "Join the Apple Clan", "advancements.unicopia.earth_route.description": "Join the Apple Clan",
"advancements.unicopia.sticks_and_stones.title": "Sticks and Stones", "advancements.unicopia.sticks_and_stones.title": "Sticks and Stones",

View file

@ -0,0 +1,30 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"unicopia:pineapple_crown"
]
},
"criteria": {
"has_ingredients": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{ "items": [ "unicopia:pineapple" ] }
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "unicopia:pineapple_crown"
}
}
},
"requirements": [
[
"has_ingredients",
"has_the_recipe"
]
]
}

View file

@ -0,0 +1,37 @@
{
"parent": "unicopia:unicopia/bat/praise_the_sun",
"display": {
"icon": {
"item": "minecraft:anvil"
},
"title": {
"translate": "advancements.unicopia.sweet_sweet_revenge.title"
},
"description": {
"translate": "advancements.unicopia.sweet_sweet_revenge.description"
},
"frame": "task",
"show_toast": true,
"announce_to_chat": true,
"hidden": true
},
"criteria": {
"ding_sun": {
"trigger": "unicopia:send_dragon_breath",
"conditions": {
"item": {
"tag": "unicopia:is_delivered_aggressively"
},
"recipient_name": "princess celestia",
"recipient_present": false,
"counter": "dings_on_celestias_head",
"race": {
"include": [ "unicopia:bat" ]
}
}
}
},
"requirements": [
[ "ding_sun" ]
]
}

View file

@ -0,0 +1,37 @@
{
"parent": "unicopia:unicopia/earth/earth_route",
"display": {
"icon": {
"item": "minecraft:anvil"
},
"title": {
"translate": "advancements.unicopia.blasphemy.title"
},
"description": {
"translate": "advancements.unicopia.blasphemy.description"
},
"frame": "task",
"show_toast": true,
"announce_to_chat": true,
"hidden": true
},
"criteria": {
"ding_sun": {
"trigger": "unicopia:send_dragon_breath",
"conditions": {
"item": {
"tag": "unicopia:is_delivered_aggressively"
},
"recipient_name": "princess celestia",
"recipient_present": false,
"counter": "dings_on_celestias_head",
"race": {
"exclude": [ "unicopia:bat" ]
}
}
}
},
"requirements": [
[ "ding_sun" ]
]
}

View file

@ -1,5 +1,5 @@
{ {
"parent": "unicopia:unicopia/root/earth/earth_route", "parent": "unicopia:unicopia/earth/earth_route",
"display": { "display": {
"icon": { "icon": {
"item": "unicopia:pinecone" "item": "unicopia:pinecone"

View file

@ -17,15 +17,20 @@
}, },
"criteria": { "criteria": {
"send_oats": { "send_oats": {
"trigger": "unicopia:custom", "trigger": "unicopia:send_dragon_breath",
"conditions": { "conditions": {
"event": "send_oats" "item": {
"items": [ "unicopia:oats", "unicopia:imported_oats" ]
}
} }
}, },
"receive_oats": { "receive_oats": {
"trigger": "unicopia:custom", "trigger": "unicopia:send_dragon_breath",
"conditions": { "conditions": {
"event": "receive_oats" "item": {
"items": [ "unicopia:oats", "unicopia:imported_oats" ]
},
"is_receiving_end": true
} }
} }
}, },