Implement crafting using traits, and trait discovery, AND show known traits in item tooltips

This commit is contained in:
Sollace 2021-11-11 20:06:28 +02:00
parent 1768420b66
commit 8aea7d326f
11 changed files with 443 additions and 32 deletions

View file

@ -0,0 +1,26 @@
package com.minelittlepony.unicopia.ability.magic.spell.crafting;
import com.minelittlepony.unicopia.container.SpellbookScreenHandler.SpellbookInventory;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.item.URecipes;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.Recipe;
import net.minecraft.recipe.RecipeType;
public interface SpellbookRecipe extends Recipe<SpellbookInventory> {
@Override
default RecipeType<?> getType() {
return URecipes.SPELLBOOK;
}
@Override
default String getGroup() {
return "unicopia:spellbook";
}
@Override
default ItemStack createIcon() {
return new ItemStack(UItems.SPELLBOOK);
}
}

View file

@ -0,0 +1,105 @@
package com.minelittlepony.unicopia.ability.magic.spell.crafting;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.container.SpellbookScreenHandler.SpellbookInventory;
import com.minelittlepony.unicopia.item.GemstoneItem;
import com.minelittlepony.unicopia.item.URecipes;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.recipe.Ingredient;
import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.ShapedRecipe;
import net.minecraft.util.Identifier;
import net.minecraft.util.JsonHelper;
import net.minecraft.world.World;
public class TraitRequirementRecipe implements SpellbookRecipe {
private final Identifier id;
private final Ingredient requirement;
private final SpellTraits requiredTraits;
private final ItemStack output;
private TraitRequirementRecipe(Identifier id, Ingredient requirement, SpellTraits requiredTraits, ItemStack output) {
this.id = id;
this.requirement = requirement;
this.requiredTraits = requiredTraits;
this.output = output;
}
@Override
public boolean matches(SpellbookInventory inventory, World world) {
return requirement.test(inventory.getItemToModify())
&& SpellTraits.of(inventory).includes(requiredTraits);
}
@Override
public ItemStack craft(SpellbookInventory inventory) {
return SpellTraits.union(
SpellTraits.of(inventory.getItemToModify()),
SpellTraits.of(inventory),
SpellTraits.of(output)
).applyTo(output);
}
@Override
public boolean fits(int width, int height) {
return (width * height) > 0;
}
@Override
public ItemStack getOutput() {
return output;
}
@Override
public Identifier getId() {
return id;
}
@Override
public RecipeSerializer<?> getSerializer() {
return URecipes.TRAIT_REQUIREMENT;
}
public static ItemStack outputFromJson(JsonObject json) {
ItemStack stack = ShapedRecipe.outputFromJson(json);
SpellTraits.fromJson(JsonHelper.getObject(json, "traits", new JsonObject()))
.map(traits -> traits.applyTo(stack)).orElse(stack);
SpellType<?> spell = SpellType.getKey(Identifier.tryParse(JsonHelper.getString(json, "spell", "")));
if (spell != SpellType.EMPTY_KEY) {
return GemstoneItem.enchanted(stack, spell);
}
return stack;
}
public static class Serializer implements RecipeSerializer<TraitRequirementRecipe> {
@Override
public TraitRequirementRecipe read(Identifier id, JsonObject json) {
return new TraitRequirementRecipe(id,
Ingredient.fromJson(JsonHelper.getObject(json, "material")),
SpellTraits.fromJson(JsonHelper.getObject(json, "traits")).get(),
outputFromJson(JsonHelper.getObject(json, "result")));
}
@Override
public TraitRequirementRecipe read(Identifier id, PacketByteBuf buf) {
return new TraitRequirementRecipe(id,
Ingredient.fromPacket(buf),
SpellTraits.fromPacket(buf).get(),
buf.readItemStack()
);
}
@Override
public void write(PacketByteBuf buf, TraitRequirementRecipe recipe) {
recipe.requirement.write(buf);
recipe.requiredTraits.write(buf);
buf.writeItemStack(recipe.output);
}
}
}

View file

@ -90,7 +90,7 @@ public abstract class AbstractSpell implements Spell {
}
isDead = compound.getBoolean("dead");
if (compound.contains("traits")) {
traits = SpellTraits.readNbt(compound.getCompound("traits")).orElse(SpellTraits.EMPTY);
traits = SpellTraits.fromNbt(compound.getCompound("traits")).orElse(SpellTraits.EMPTY);
}
}
}

View file

@ -1,7 +1,10 @@
package com.minelittlepony.unicopia.ability.magic.spell.trait;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@ -9,11 +12,18 @@ import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.util.InventoryUtil;
import net.minecraft.block.Block;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.util.registry.Registry;
public final class SpellTraits {
@ -29,6 +39,12 @@ public final class SpellTraits {
return traits.isEmpty();
}
public boolean includes(SpellTraits other) {
return other.entries().stream().allMatch(pair -> {
return getAmount(pair.getKey()) >= pair.getValue();
});
}
public Set<Map.Entry<Trait, Float>> entries() {
return traits.entrySet();
}
@ -37,14 +53,46 @@ public final class SpellTraits {
return traits.getOrDefault(trait, 0F);
}
public void appendTooltip(List<Text> tooltip) {
if (isEmpty()) {
return;
}
tooltip.add(new LiteralText("Traits:"));
traits.forEach((trait, amount) -> {
tooltip.add(new LiteralText(trait.name().toLowerCase() + ": " + amount));
});
}
public NbtCompound toNbt() {
NbtCompound nbt = new NbtCompound();
traits.forEach((key, value) -> nbt.putFloat(key.name(), value));
return nbt;
}
public static Optional<SpellTraits> of(Collection<ItemStack> stacks) {
return fromEntries(stacks.stream().flatMap(a -> of(a).entries().stream()));
public void write(PacketByteBuf buf) {
buf.writeInt(traits.size());
traits.forEach((trait, value) -> {
buf.writeIdentifier(trait.getId());
buf.writeFloat(value);
});
}
public static SpellTraits union(SpellTraits...many) {
Map<Trait, Float> traits = new HashMap<>();
for (SpellTraits i : many) {
combine(traits, i.traits);
}
return traits.isEmpty() ? EMPTY : new SpellTraits(traits);
}
public static SpellTraits of(Inventory inventory) {
List<ItemStack> stacks = new ArrayList<>();
InventoryUtil.iterate(inventory).forEach(stacks::add);
return of(stacks);
}
public static SpellTraits of(Collection<ItemStack> stacks) {
return fromEntries(stacks.stream().flatMap(a -> of(a).entries().stream())).orElse(SpellTraits.EMPTY);
}
public static SpellTraits of(ItemStack stack) {
@ -52,7 +100,7 @@ public final class SpellTraits {
}
public static SpellTraits of(Item item) {
return TraitLoader.INSTANCE.values.getOrDefault(Registry.ITEM.getId(item), null);
return TraitLoader.INSTANCE.values.getOrDefault(Registry.ITEM.getId(item), EMPTY);
}
public static SpellTraits of(Block block) {
@ -63,13 +111,43 @@ public final class SpellTraits {
if (!(stack.hasTag() && stack.getTag().contains("spell_traits", NbtElement.COMPOUND_TYPE))) {
return Optional.empty();
}
return readNbt(stack.getTag().getCompound("spell_traits"));
return fromNbt(stack.getTag().getCompound("spell_traits"));
}
public static Optional<SpellTraits> readNbt(NbtCompound traits) {
public ItemStack applyTo(ItemStack stack) {
stack = stack.copy();
stack.getOrCreateTag().put("spell_traits", toNbt());
return stack;
}
public static Optional<SpellTraits> fromNbt(NbtCompound traits) {
return fromEntries(streamFromNbt(traits));
}
public static Optional<SpellTraits> fromJson(JsonObject traits) {
return fromEntries(streamFromJson(traits));
}
public static Optional<SpellTraits> fromPacket(PacketByteBuf buf) {
Map<Trait, Float> entries = new HashMap<>();
int count = buf.readInt();
if (count <= 0) {
return Optional.empty();
}
for (int i = 0; i < count; i++) {
Trait trait = Trait.REGISTRY.getOrDefault(buf.readIdentifier(), null);
float value = buf.readFloat();
if (trait != null) {
entries.compute(trait, (k, v) -> v == null ? value : (v + value));
}
}
if (entries.isEmpty()) {
return Optional.empty();
}
return Optional.of(new SpellTraits(entries));
}
public static Stream<Map.Entry<Trait, Float>> streamFromNbt(NbtCompound traits) {
return traits.getKeys().stream().map(key -> {
Trait trait = Trait.REGISTRY.get(key.toUpperCase());
@ -80,6 +158,16 @@ public final class SpellTraits {
});
}
public static Stream<Map.Entry<Trait, Float>> streamFromJson(JsonObject traits) {
return traits.entrySet().stream().map(entry -> {
Trait trait = Trait.REGISTRY.get(entry.getKey().toUpperCase());
if (trait == null && !entry.getValue().isJsonPrimitive() && !entry.getValue().getAsJsonPrimitive().isNumber()) {
return null;
}
return Map.entry(trait, entry.getValue().getAsJsonPrimitive().getAsFloat());
});
}
public static Optional<SpellTraits> fromEntries(Stream<Map.Entry<Trait, Float>> entries) {
var result = collect(entries);
@ -89,6 +177,12 @@ public final class SpellTraits {
return Optional.of(new SpellTraits(result));
}
static void combine(Map<Trait, Float> to, Map<Trait, Float> from) {
from.forEach((trait, value) -> {
to.compute(trait, (k, v) -> v == null ? value : (v + value));
});
}
static Map<Trait, Float> collect(Stream<Map.Entry<Trait, Float>> entries) {
return entries.filter(Objects::nonNull)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a + b, () -> new EnumMap<>(Trait.class)));

View file

@ -0,0 +1,115 @@
package com.minelittlepony.unicopia.ability.magic.spell.trait;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.util.NbtSerialisable;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtList;
import net.minecraft.nbt.NbtString;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.World;
public class TraitDiscovery implements NbtSerialisable {
private final Set<Identifier> unreadTraits = new HashSet<>();
private final Set<Identifier> traits = new HashSet<>();
private final Map<Identifier, SpellTraits> items = new HashMap<>();
private final Pony pony;
public TraitDiscovery(Pony pony) {
this.pony = pony;
}
public void clear() {
unreadTraits.clear();
items.clear();
traits.clear();
pony.setDirty();
}
public void markRead() {
unreadTraits.clear();
pony.setDirty();
}
public void unlock(Item item) {
if (item == Items.AIR) {
return;
}
SpellTraits traits = SpellTraits.of(item);
items.put(Registry.ITEM.getId(item), traits);
traits.entries().forEach(e -> {
if (this.traits.add(e.getKey().getId())) {
unreadTraits.add(e.getKey().getId());
}
});
pony.setDirty();
}
public SpellTraits getKnownTraits(Item item) {
return items.getOrDefault(Registry.ITEM.getId(item), SpellTraits.EMPTY);
}
public void appendTooltip(ItemStack stack, @Nullable World world, List<Text> tooltip) {
getKnownTraits(stack.getItem()).appendTooltip(tooltip);
}
@Override
public void toNBT(NbtCompound compound) {
NbtCompound disco = new NbtCompound();
items.forEach((key, val) -> {
disco.put(key.toString(), val.toNbt());
});
compound.put("items", disco);
NbtList a = new NbtList();
this.traits.forEach(id -> a.add(NbtString.of(id.toString())));
compound.put("traits", a);
NbtList b = new NbtList();
unreadTraits.forEach(id -> b.add(NbtString.of(id.toString())));
compound.put("unreadTraits", b);
}
@Override
public void fromNBT(NbtCompound compound) {
clear();
NbtCompound disco = compound.getCompound("items");
disco.getKeys().forEach(key -> {
Optional.ofNullable(Identifier.tryParse(key)).ifPresent(id -> {
SpellTraits.fromNbt(disco.getCompound(key)).ifPresent(val -> {
items.put(id, val);
});
});
});
compound.getList("traits", NbtElement.STRING_TYPE).forEach(el -> {
Optional.ofNullable(Identifier.tryParse(el.asString())).ifPresent(this.traits::add);
});
compound.getList("unreadTraits", NbtElement.STRING_TYPE).forEach(el -> {
Optional.ofNullable(Identifier.tryParse(el.asString())).ifPresent(this.unreadTraits::add);
});
}
public void copyFrom(TraitDiscovery old) {
clear();
unreadTraits.addAll(old.unreadTraits);
traits.addAll(old.traits);
items.putAll(old.items);
}
}

View file

@ -42,7 +42,7 @@ public class TraitLoader extends SinglePreparationResourceReloader<Map<Identifie
for (String namespace : manager.getAllNamespaces()) {
profiler.push(namespace);
try {
for (Resource resource : manager.getAllResources(new Identifier(namespace, "items/traits"))) {
for (Resource resource : manager.getAllResources(new Identifier(namespace, "traits/items.json"))) {
profiler.push(resource.getResourcePackName());
try (InputStreamReader reader = new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8)) {

View file

@ -5,7 +5,10 @@ import java.util.List;
import java.util.Optional;
import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.item.URecipes;
import com.minelittlepony.unicopia.util.InventoryUtil;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
@ -13,11 +16,12 @@ import net.minecraft.inventory.CraftingInventory;
import net.minecraft.inventory.CraftingResultInventory;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.RecipeType;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.slot.CraftingResultSlot;
import net.minecraft.screen.slot.Slot;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.Pair;
import net.minecraft.util.collection.DefaultedList;
import net.minecraft.world.World;
public class SpellbookScreenHandler extends ScreenHandler {
@ -28,7 +32,7 @@ public class SpellbookScreenHandler extends ScreenHandler {
private final int HOTBAR_START;
private final int HOTBAR_END;
private final CraftingInventory input;
private final SpellbookInventory input;
private OutputSlot gemSlot;
private final CraftingResultInventory result = new CraftingResultInventory();
@ -47,7 +51,7 @@ public class SpellbookScreenHandler extends ScreenHandler {
HOTBAR_START = GEM_SLOT_INDEX + 1;
HOTBAR_END = HOTBAR_START + 9;
input = new CraftingInventory(this, MAX_INGREDIENTS, 1);
input = new SpellbookInventory(this, MAX_INGREDIENTS, 1);
for (int i = 0; i < MAX_INGREDIENTS; i++) {
var pos = grid.get(i);
@ -72,7 +76,8 @@ public class SpellbookScreenHandler extends ScreenHandler {
public void onContentChanged(Inventory inventory) {
World world = this.inventory.player.world;
if (!world.isClient && !gemSlot.getStack().isEmpty()) {
world.getServer().getRecipeManager().getFirstMatch(RecipeType.CRAFTING, input, world)
world.getServer().getRecipeManager().getFirstMatch(URecipes.SPELLBOOK, input, world)
.filter(recipe -> result.shouldCraftRecipe(world, (ServerPlayerEntity)this.inventory.player, recipe))
.map(recipe -> recipe.craft(input))
.ifPresentOrElse(gemSlot::setCrafted, gemSlot::setUncrafted);
}
@ -202,6 +207,17 @@ public class SpellbookScreenHandler extends ScreenHandler {
public interface SpellbookSlot {}
public class SpellbookInventory extends CraftingInventory {
public SpellbookInventory(ScreenHandler handler, int width, int height) {
super(handler, width, height);
}
public ItemStack getItemToModify() {
return gemSlot.getStack();
}
}
public class InputSlot extends Slot implements SpellbookSlot {
public InputSlot(Inventory inventory, int index, int xPosition, int yPosition) {
super(inventory, index, xPosition, yPosition);
@ -217,8 +233,11 @@ public class SpellbookScreenHandler extends ScreenHandler {
private Optional<ItemStack> uncrafted = Optional.empty();
public OutputSlot(PlayerEntity player, CraftingInventory input, Inventory inventory, int index, int x, int y) {
private final SpellbookInventory input;
public OutputSlot(PlayerEntity player, SpellbookInventory input, Inventory inventory, int index, int x, int y) {
super(player, input, inventory, index, x, y);
this.input = input;
}
public void setCrafted(ItemStack crafted) {
@ -247,7 +266,34 @@ public class SpellbookScreenHandler extends ScreenHandler {
public void onTakeItem(PlayerEntity player, ItemStack stack) {
if (uncrafted.isPresent()) {
uncrafted = Optional.empty();
super.onTakeItem(player, stack);
onCrafted(stack);
Pony pony = Pony.of(player);
InventoryUtil.iterate(input).forEach(s -> {
pony.getDiscoveries().unlock(s.getItem());
});
DefaultedList<ItemStack> defaultedList = player.world.getRecipeManager().getRemainingStacks(URecipes.SPELLBOOK, input, player.world);
for (int i = 0; i < defaultedList.size(); ++i) {
ItemStack itemStack = input.getStack(i);
ItemStack itemStack2 = defaultedList.get(i);
if (!itemStack.isEmpty()) {
input.removeStack(i, 1);
itemStack = input.getStack(i);
}
if (!itemStack2.isEmpty()) {
if (itemStack.isEmpty()) {
input.setStack(i, itemStack2);
} else if (ItemStack.areItemsEqualIgnoreDamage(itemStack, itemStack2) && ItemStack.areTagsEqual(itemStack, itemStack2)) {
itemStack2.increment(itemStack.getCount());
input.setStack(i, itemStack2);
} else if (!player.getInventory().insertStack(itemStack2)) {
player.dropItem(itemStack2, false);
}
}
}
}
}
}

View file

@ -18,6 +18,7 @@ import com.minelittlepony.unicopia.ability.EarthPonyStompAbility;
import com.minelittlepony.unicopia.ability.magic.Affine;
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.ability.magic.spell.trait.TraitDiscovery;
import com.minelittlepony.unicopia.advancement.UCriteria;
import com.minelittlepony.unicopia.entity.PonyContainer;
import com.minelittlepony.unicopia.entity.Living;
@ -77,6 +78,8 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
private final PlayerCharmTracker charms = new PlayerCharmTracker(this);
private final PlayerAttributes attributes = new PlayerAttributes(this);
private final PlayerCamera camera = new PlayerCamera(this);
private final TraitDiscovery discoveries = new TraitDiscovery(this);
private final ManaContainer mana;
private final PlayerLevelStore levels;
@ -137,6 +140,10 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
UCriteria.PLAYER_CHANGE_RACE.trigger(entity);
}
public TraitDiscovery getDiscoveries() {
return discoveries;
}
public MagicReserves getMagicalReserves() {
return mana;
}
@ -469,6 +476,7 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
compound.put("powers", powers.toNBT());
compound.put("gravity", gravity.toNBT());
compound.put("charms", charms.toNBT());
compound.put("discoveries", discoveries.toNBT());
getSpellSlot().get(true).ifPresent(effect ->{
compound.put("effect", SpellType.toNBT(effect));
@ -484,6 +492,7 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
powers.fromNBT(compound.getCompound("powers"));
gravity.fromNBT(compound.getCompound("gravity"));
charms.fromNBT(compound.getCompound("charms"));
discoveries.fromNBT(compound.getCompound("discoveries"));
magicExhaustion = compound.getFloat("magicExhaustion");
@ -500,6 +509,7 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
}
oldPlayer.setSpell(null);
setSpecies(oldPlayer.getSpecies());
getDiscoveries().copyFrom(oldPlayer.getDiscoveries());
setDirty();
}

View file

@ -1,39 +1,27 @@
package com.minelittlepony.unicopia.item;
import com.google.gson.JsonArray;
import com.minelittlepony.unicopia.ability.magic.spell.crafting.SpellbookRecipe;
import com.minelittlepony.unicopia.ability.magic.spell.crafting.TraitRequirementRecipe;
import net.fabricmc.fabric.api.loot.v1.FabricLootSupplier;
import net.fabricmc.fabric.api.loot.v1.event.LootTableLoadingCallback;
import net.minecraft.loot.LootTable;
import net.minecraft.recipe.Ingredient;
import net.minecraft.recipe.Recipe;
import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.RecipeType;
import net.minecraft.recipe.ShapelessRecipe;
import net.minecraft.recipe.SpecialRecipeSerializer;
import net.minecraft.util.Identifier;
import net.minecraft.util.collection.DefaultedList;
import net.minecraft.util.registry.Registry;
public interface URecipes {
RecipeType<SpellbookRecipe> SPELLBOOK = RecipeType.register("unicopia:spellbook");
RecipeSerializer<ShapelessRecipe> ZAP_APPLE_SERIALIZER = register("crafting_zap_apple", new ZapAppleRecipe.Serializer());
RecipeSerializer<GlowingRecipe> GLOWING_SERIALIZER = register("crafting_glowing", new SpecialRecipeSerializer<>(GlowingRecipe::new));
RecipeSerializer<JarInsertRecipe> JAR_INSERT_SERIALIZER = register("jar_insert", new SpecialRecipeSerializer<>(JarInsertRecipe::new));
static <T extends Recipe<?>> RecipeType<T> register(final String id) {
return Registry.register(Registry.RECIPE_TYPE, new Identifier("unicopia", id), new RecipeType<T>() {
@Override
public String toString() {
return id;
}
});
}
static <S extends RecipeSerializer<T>, T extends Recipe<?>> S register(String id, S serializer) {
return Registry.register(Registry.RECIPE_SERIALIZER, new Identifier("unicopia", id), serializer);
}
RecipeSerializer<ShapelessRecipe> ZAP_APPLE_SERIALIZER = RecipeSerializer.register("unicopia:crafting_zap_apple", new ZapAppleRecipe.Serializer());
RecipeSerializer<GlowingRecipe> GLOWING_SERIALIZER = RecipeSerializer.register("unicopia:crafting_glowing", new SpecialRecipeSerializer<>(GlowingRecipe::new));
RecipeSerializer<JarInsertRecipe> JAR_INSERT_SERIALIZER = RecipeSerializer.register("unicopia:jar_insert", new SpecialRecipeSerializer<>(JarInsertRecipe::new));
RecipeSerializer<TraitRequirementRecipe> TRAIT_REQUIREMENT = RecipeSerializer.register("unicopia:spellbook/crafting", new TraitRequirementRecipe.Serializer());
static DefaultedList<Ingredient> getIngredients(JsonArray json) {
DefaultedList<Ingredient> defaultedList = DefaultedList.of();

View file

@ -7,6 +7,8 @@ import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.toxin.ToxicHolder;
import net.minecraft.client.MinecraftClient;
@ -21,5 +23,8 @@ abstract class MixinItem implements ToxicHolder {
@Inject(method = "appendTooltip", at = @At("RETURN"))
private void onAppendTooltip(ItemStack stack, @Nullable World world, List<Text> tooltip, TooltipContext context, CallbackInfo into) {
getToxic().ifPresent(t -> t.getAilmentFor(MinecraftClient.getInstance().player).appendTooltip(tooltip, context));
if (MinecraftClient.getInstance().player != null) {
Pony.of(MinecraftClient.getInstance().player).getDiscoveries().appendTooltip(stack, world, tooltip);
}
}
}

View file

@ -0,0 +1,22 @@
package com.minelittlepony.unicopia.util;
import com.google.common.collect.AbstractIterator;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
public interface InventoryUtil {
static Iterable<ItemStack> iterate(Inventory inventory) {
return () -> new AbstractIterator<>() {
private int slot = 0;
@Override
protected ItemStack computeNext() {
if (slot >= inventory.size()) {
return endOfData();
}
return inventory.getStack(slot++);
}
};
}
}