mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-12 16:14:24 +01:00
Implement crafting using traits, and trait discovery, AND show known traits in item tooltips
This commit is contained in:
parent
1768420b66
commit
8aea7d326f
11 changed files with 443 additions and 32 deletions
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -90,7 +90,7 @@ public abstract class AbstractSpell implements Spell {
|
||||||
}
|
}
|
||||||
isDead = compound.getBoolean("dead");
|
isDead = compound.getBoolean("dead");
|
||||||
if (compound.contains("traits")) {
|
if (compound.contains("traits")) {
|
||||||
traits = SpellTraits.readNbt(compound.getCompound("traits")).orElse(SpellTraits.EMPTY);
|
traits = SpellTraits.fromNbt(compound.getCompound("traits")).orElse(SpellTraits.EMPTY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package com.minelittlepony.unicopia.ability.magic.spell.trait;
|
package com.minelittlepony.unicopia.ability.magic.spell.trait;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -9,11 +12,18 @@ import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.minelittlepony.unicopia.util.InventoryUtil;
|
||||||
|
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.inventory.Inventory;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.nbt.NbtCompound;
|
import net.minecraft.nbt.NbtCompound;
|
||||||
import net.minecraft.nbt.NbtElement;
|
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;
|
import net.minecraft.util.registry.Registry;
|
||||||
|
|
||||||
public final class SpellTraits {
|
public final class SpellTraits {
|
||||||
|
@ -29,6 +39,12 @@ public final class SpellTraits {
|
||||||
return traits.isEmpty();
|
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() {
|
public Set<Map.Entry<Trait, Float>> entries() {
|
||||||
return traits.entrySet();
|
return traits.entrySet();
|
||||||
}
|
}
|
||||||
|
@ -37,14 +53,46 @@ public final class SpellTraits {
|
||||||
return traits.getOrDefault(trait, 0F);
|
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() {
|
public NbtCompound toNbt() {
|
||||||
NbtCompound nbt = new NbtCompound();
|
NbtCompound nbt = new NbtCompound();
|
||||||
traits.forEach((key, value) -> nbt.putFloat(key.name(), value));
|
traits.forEach((key, value) -> nbt.putFloat(key.name(), value));
|
||||||
return nbt;
|
return nbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<SpellTraits> of(Collection<ItemStack> stacks) {
|
public void write(PacketByteBuf buf) {
|
||||||
return fromEntries(stacks.stream().flatMap(a -> of(a).entries().stream()));
|
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) {
|
public static SpellTraits of(ItemStack stack) {
|
||||||
|
@ -52,7 +100,7 @@ public final class SpellTraits {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SpellTraits of(Item item) {
|
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) {
|
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))) {
|
if (!(stack.hasTag() && stack.getTag().contains("spell_traits", NbtElement.COMPOUND_TYPE))) {
|
||||||
return Optional.empty();
|
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));
|
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) {
|
public static Stream<Map.Entry<Trait, Float>> streamFromNbt(NbtCompound traits) {
|
||||||
return traits.getKeys().stream().map(key -> {
|
return traits.getKeys().stream().map(key -> {
|
||||||
Trait trait = Trait.REGISTRY.get(key.toUpperCase());
|
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) {
|
public static Optional<SpellTraits> fromEntries(Stream<Map.Entry<Trait, Float>> entries) {
|
||||||
var result = collect(entries);
|
var result = collect(entries);
|
||||||
|
|
||||||
|
@ -89,6 +177,12 @@ public final class SpellTraits {
|
||||||
return Optional.of(new SpellTraits(result));
|
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) {
|
static Map<Trait, Float> collect(Stream<Map.Entry<Trait, Float>> entries) {
|
||||||
return entries.filter(Objects::nonNull)
|
return entries.filter(Objects::nonNull)
|
||||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a + b, () -> new EnumMap<>(Trait.class)));
|
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a + b, () -> new EnumMap<>(Trait.class)));
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,7 +42,7 @@ public class TraitLoader extends SinglePreparationResourceReloader<Map<Identifie
|
||||||
for (String namespace : manager.getAllNamespaces()) {
|
for (String namespace : manager.getAllNamespaces()) {
|
||||||
profiler.push(namespace);
|
profiler.push(namespace);
|
||||||
try {
|
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());
|
profiler.push(resource.getResourcePackName());
|
||||||
|
|
||||||
try (InputStreamReader reader = new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8)) {
|
try (InputStreamReader reader = new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8)) {
|
||||||
|
|
|
@ -5,7 +5,10 @@ import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.EquinePredicates;
|
import com.minelittlepony.unicopia.EquinePredicates;
|
||||||
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
import com.minelittlepony.unicopia.item.UItems;
|
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.PlayerEntity;
|
||||||
import net.minecraft.entity.player.PlayerInventory;
|
import net.minecraft.entity.player.PlayerInventory;
|
||||||
|
@ -13,11 +16,12 @@ import net.minecraft.inventory.CraftingInventory;
|
||||||
import net.minecraft.inventory.CraftingResultInventory;
|
import net.minecraft.inventory.CraftingResultInventory;
|
||||||
import net.minecraft.inventory.Inventory;
|
import net.minecraft.inventory.Inventory;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.recipe.RecipeType;
|
|
||||||
import net.minecraft.screen.ScreenHandler;
|
import net.minecraft.screen.ScreenHandler;
|
||||||
import net.minecraft.screen.slot.CraftingResultSlot;
|
import net.minecraft.screen.slot.CraftingResultSlot;
|
||||||
import net.minecraft.screen.slot.Slot;
|
import net.minecraft.screen.slot.Slot;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.util.Pair;
|
import net.minecraft.util.Pair;
|
||||||
|
import net.minecraft.util.collection.DefaultedList;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
public class SpellbookScreenHandler extends ScreenHandler {
|
public class SpellbookScreenHandler extends ScreenHandler {
|
||||||
|
@ -28,7 +32,7 @@ public class SpellbookScreenHandler extends ScreenHandler {
|
||||||
private final int HOTBAR_START;
|
private final int HOTBAR_START;
|
||||||
private final int HOTBAR_END;
|
private final int HOTBAR_END;
|
||||||
|
|
||||||
private final CraftingInventory input;
|
private final SpellbookInventory input;
|
||||||
|
|
||||||
private OutputSlot gemSlot;
|
private OutputSlot gemSlot;
|
||||||
private final CraftingResultInventory result = new CraftingResultInventory();
|
private final CraftingResultInventory result = new CraftingResultInventory();
|
||||||
|
@ -47,7 +51,7 @@ public class SpellbookScreenHandler extends ScreenHandler {
|
||||||
HOTBAR_START = GEM_SLOT_INDEX + 1;
|
HOTBAR_START = GEM_SLOT_INDEX + 1;
|
||||||
HOTBAR_END = HOTBAR_START + 9;
|
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++) {
|
for (int i = 0; i < MAX_INGREDIENTS; i++) {
|
||||||
var pos = grid.get(i);
|
var pos = grid.get(i);
|
||||||
|
@ -72,7 +76,8 @@ public class SpellbookScreenHandler extends ScreenHandler {
|
||||||
public void onContentChanged(Inventory inventory) {
|
public void onContentChanged(Inventory inventory) {
|
||||||
World world = this.inventory.player.world;
|
World world = this.inventory.player.world;
|
||||||
if (!world.isClient && !gemSlot.getStack().isEmpty()) {
|
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))
|
.map(recipe -> recipe.craft(input))
|
||||||
.ifPresentOrElse(gemSlot::setCrafted, gemSlot::setUncrafted);
|
.ifPresentOrElse(gemSlot::setCrafted, gemSlot::setUncrafted);
|
||||||
}
|
}
|
||||||
|
@ -202,6 +207,17 @@ public class SpellbookScreenHandler extends ScreenHandler {
|
||||||
|
|
||||||
public interface SpellbookSlot {}
|
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 class InputSlot extends Slot implements SpellbookSlot {
|
||||||
public InputSlot(Inventory inventory, int index, int xPosition, int yPosition) {
|
public InputSlot(Inventory inventory, int index, int xPosition, int yPosition) {
|
||||||
super(inventory, index, xPosition, yPosition);
|
super(inventory, index, xPosition, yPosition);
|
||||||
|
@ -217,8 +233,11 @@ public class SpellbookScreenHandler extends ScreenHandler {
|
||||||
|
|
||||||
private Optional<ItemStack> uncrafted = Optional.empty();
|
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);
|
super(player, input, inventory, index, x, y);
|
||||||
|
this.input = input;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCrafted(ItemStack crafted) {
|
public void setCrafted(ItemStack crafted) {
|
||||||
|
@ -247,7 +266,34 @@ public class SpellbookScreenHandler extends ScreenHandler {
|
||||||
public void onTakeItem(PlayerEntity player, ItemStack stack) {
|
public void onTakeItem(PlayerEntity player, ItemStack stack) {
|
||||||
if (uncrafted.isPresent()) {
|
if (uncrafted.isPresent()) {
|
||||||
uncrafted = Optional.empty();
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import com.minelittlepony.unicopia.ability.EarthPonyStompAbility;
|
||||||
import com.minelittlepony.unicopia.ability.magic.Affine;
|
import com.minelittlepony.unicopia.ability.magic.Affine;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
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.advancement.UCriteria;
|
||||||
import com.minelittlepony.unicopia.entity.PonyContainer;
|
import com.minelittlepony.unicopia.entity.PonyContainer;
|
||||||
import com.minelittlepony.unicopia.entity.Living;
|
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 PlayerCharmTracker charms = new PlayerCharmTracker(this);
|
||||||
private final PlayerAttributes attributes = new PlayerAttributes(this);
|
private final PlayerAttributes attributes = new PlayerAttributes(this);
|
||||||
private final PlayerCamera camera = new PlayerCamera(this);
|
private final PlayerCamera camera = new PlayerCamera(this);
|
||||||
|
private final TraitDiscovery discoveries = new TraitDiscovery(this);
|
||||||
|
|
||||||
private final ManaContainer mana;
|
private final ManaContainer mana;
|
||||||
private final PlayerLevelStore levels;
|
private final PlayerLevelStore levels;
|
||||||
|
|
||||||
|
@ -137,6 +140,10 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
|
||||||
UCriteria.PLAYER_CHANGE_RACE.trigger(entity);
|
UCriteria.PLAYER_CHANGE_RACE.trigger(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TraitDiscovery getDiscoveries() {
|
||||||
|
return discoveries;
|
||||||
|
}
|
||||||
|
|
||||||
public MagicReserves getMagicalReserves() {
|
public MagicReserves getMagicalReserves() {
|
||||||
return mana;
|
return mana;
|
||||||
}
|
}
|
||||||
|
@ -469,6 +476,7 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
|
||||||
compound.put("powers", powers.toNBT());
|
compound.put("powers", powers.toNBT());
|
||||||
compound.put("gravity", gravity.toNBT());
|
compound.put("gravity", gravity.toNBT());
|
||||||
compound.put("charms", charms.toNBT());
|
compound.put("charms", charms.toNBT());
|
||||||
|
compound.put("discoveries", discoveries.toNBT());
|
||||||
|
|
||||||
getSpellSlot().get(true).ifPresent(effect ->{
|
getSpellSlot().get(true).ifPresent(effect ->{
|
||||||
compound.put("effect", SpellType.toNBT(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"));
|
powers.fromNBT(compound.getCompound("powers"));
|
||||||
gravity.fromNBT(compound.getCompound("gravity"));
|
gravity.fromNBT(compound.getCompound("gravity"));
|
||||||
charms.fromNBT(compound.getCompound("charms"));
|
charms.fromNBT(compound.getCompound("charms"));
|
||||||
|
discoveries.fromNBT(compound.getCompound("discoveries"));
|
||||||
|
|
||||||
magicExhaustion = compound.getFloat("magicExhaustion");
|
magicExhaustion = compound.getFloat("magicExhaustion");
|
||||||
|
|
||||||
|
@ -500,6 +509,7 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
|
||||||
}
|
}
|
||||||
oldPlayer.setSpell(null);
|
oldPlayer.setSpell(null);
|
||||||
setSpecies(oldPlayer.getSpecies());
|
setSpecies(oldPlayer.getSpecies());
|
||||||
|
getDiscoveries().copyFrom(oldPlayer.getDiscoveries());
|
||||||
setDirty();
|
setDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,39 +1,27 @@
|
||||||
package com.minelittlepony.unicopia.item;
|
package com.minelittlepony.unicopia.item;
|
||||||
|
|
||||||
import com.google.gson.JsonArray;
|
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.FabricLootSupplier;
|
||||||
import net.fabricmc.fabric.api.loot.v1.event.LootTableLoadingCallback;
|
import net.fabricmc.fabric.api.loot.v1.event.LootTableLoadingCallback;
|
||||||
import net.minecraft.loot.LootTable;
|
import net.minecraft.loot.LootTable;
|
||||||
import net.minecraft.recipe.Ingredient;
|
import net.minecraft.recipe.Ingredient;
|
||||||
import net.minecraft.recipe.Recipe;
|
|
||||||
import net.minecraft.recipe.RecipeSerializer;
|
import net.minecraft.recipe.RecipeSerializer;
|
||||||
import net.minecraft.recipe.RecipeType;
|
import net.minecraft.recipe.RecipeType;
|
||||||
import net.minecraft.recipe.ShapelessRecipe;
|
import net.minecraft.recipe.ShapelessRecipe;
|
||||||
import net.minecraft.recipe.SpecialRecipeSerializer;
|
import net.minecraft.recipe.SpecialRecipeSerializer;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
import net.minecraft.util.collection.DefaultedList;
|
import net.minecraft.util.collection.DefaultedList;
|
||||||
import net.minecraft.util.registry.Registry;
|
|
||||||
|
|
||||||
public interface URecipes {
|
public interface URecipes {
|
||||||
|
RecipeType<SpellbookRecipe> SPELLBOOK = RecipeType.register("unicopia:spellbook");
|
||||||
|
|
||||||
RecipeSerializer<ShapelessRecipe> ZAP_APPLE_SERIALIZER = register("crafting_zap_apple", new ZapAppleRecipe.Serializer());
|
RecipeSerializer<ShapelessRecipe> ZAP_APPLE_SERIALIZER = RecipeSerializer.register("unicopia:crafting_zap_apple", new ZapAppleRecipe.Serializer());
|
||||||
RecipeSerializer<GlowingRecipe> GLOWING_SERIALIZER = register("crafting_glowing", new SpecialRecipeSerializer<>(GlowingRecipe::new));
|
RecipeSerializer<GlowingRecipe> GLOWING_SERIALIZER = RecipeSerializer.register("unicopia:crafting_glowing", new SpecialRecipeSerializer<>(GlowingRecipe::new));
|
||||||
RecipeSerializer<JarInsertRecipe> JAR_INSERT_SERIALIZER = register("jar_insert", new SpecialRecipeSerializer<>(JarInsertRecipe::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 <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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static DefaultedList<Ingredient> getIngredients(JsonArray json) {
|
static DefaultedList<Ingredient> getIngredients(JsonArray json) {
|
||||||
DefaultedList<Ingredient> defaultedList = DefaultedList.of();
|
DefaultedList<Ingredient> defaultedList = DefaultedList.of();
|
||||||
|
|
|
@ -7,6 +7,8 @@ import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
import com.minelittlepony.unicopia.item.toxin.ToxicHolder;
|
import com.minelittlepony.unicopia.item.toxin.ToxicHolder;
|
||||||
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
@ -21,5 +23,8 @@ abstract class MixinItem implements ToxicHolder {
|
||||||
@Inject(method = "appendTooltip", at = @At("RETURN"))
|
@Inject(method = "appendTooltip", at = @At("RETURN"))
|
||||||
private void onAppendTooltip(ItemStack stack, @Nullable World world, List<Text> tooltip, TooltipContext context, CallbackInfo into) {
|
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));
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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++);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue