Expand on spell crafting

This commit is contained in:
Sollace 2021-11-13 00:05:42 +02:00
parent 7949ccff2e
commit 338491d052
8 changed files with 298 additions and 42 deletions

View file

@ -0,0 +1,71 @@
package com.minelittlepony.unicopia.ability.magic.spell.crafting;
import java.util.Optional;
import java.util.function.Predicate;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.item.GemstoneItem;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.recipe.Ingredient;
import net.minecraft.util.Identifier;
import net.minecraft.util.JsonHelper;
public class IngredientWithSpell implements Predicate<ItemStack> {
private Optional<Ingredient> stack = Optional.empty();
private Optional<SpellType<?>> spell = Optional.empty();
private IngredientWithSpell() {}
@Override
public boolean test(ItemStack t) {
boolean stackMatch = stack.map(m -> m.test(t)).orElse(true);
boolean spellMatch = spell.map(m -> GemstoneItem.getSpellKey(t).equals(m)).orElse(true);
return stackMatch && spellMatch;
}
public void write(PacketByteBuf buf) {
stack.ifPresentOrElse(i -> {
buf.writeBoolean(true);
i.write(buf);
}, () -> buf.writeBoolean(false));
spell.ifPresentOrElse(i -> {
buf.writeBoolean(true);
buf.writeIdentifier(i.getId());
}, () -> buf.writeBoolean(false));
}
public static IngredientWithSpell fromPacket(PacketByteBuf buf) {
IngredientWithSpell ingredient = new IngredientWithSpell();
if (buf.readBoolean()) {
ingredient.stack = Optional.ofNullable(Ingredient.fromPacket(buf));
}
if (buf.readBoolean()) {
ingredient.spell = Optional.of(SpellType.getKey(buf.readIdentifier()));
}
return ingredient;
}
public static IngredientWithSpell fromJson(JsonObject json) {
IngredientWithSpell ingredient = new IngredientWithSpell();
if (json.has("item") || json.has("spell")) {
if (json.has("item")) {
ingredient.stack = Optional.ofNullable(Ingredient.fromJson(JsonHelper.getObject(json, "item")));
}
if (json.has("spell")) {
ingredient.spell = Optional.ofNullable(Identifier.tryParse(JsonHelper.getString(json, "spell"))).map(SpellType::getKey);
}
} else {
ingredient.stack = Optional.ofNullable(Ingredient.fromJson(json));
}
return ingredient;
}
}

View file

@ -0,0 +1,67 @@
package com.minelittlepony.unicopia.ability.magic.spell.crafting;
import java.util.Optional;
import java.util.function.Predicate;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.JsonHelper;
public class TraitIngredient implements Predicate<SpellTraits> {
private Optional<SpellTraits> min = Optional.empty();
private Optional<SpellTraits> max = Optional.empty();
private TraitIngredient() {}
@Override
public boolean test(SpellTraits t) {
boolean minMatch = min.map(m -> t.includes(m)).orElse(true);
boolean maxMatch = max.map(m -> m.includes(t)).orElse(true);
return minMatch && maxMatch;
}
public void write(PacketByteBuf buf) {
min.ifPresentOrElse(m -> {
buf.writeBoolean(true);
m.write(buf);
}, () -> buf.writeBoolean(false));
max.ifPresentOrElse(m -> {
buf.writeBoolean(true);
m.write(buf);
}, () -> buf.writeBoolean(false));
}
public static TraitIngredient fromPacket(PacketByteBuf buf) {
TraitIngredient ingredient = new TraitIngredient();
if (buf.readBoolean()) {
ingredient.min = SpellTraits.fromPacket(buf);
}
if (buf.readBoolean()) {
ingredient.max = SpellTraits.fromPacket(buf);
}
return ingredient;
}
public static TraitIngredient fromJson(JsonObject json) {
TraitIngredient ingredient = new TraitIngredient();
if (json.has("min") || json.has("max")) {
if (json.has("min")) {
ingredient.min = SpellTraits.fromJson(JsonHelper.getObject(json, "min"));
}
if (json.has("max")) {
ingredient.max = SpellTraits.fromJson(JsonHelper.getObject(json, "max"));
}
} else {
ingredient.min = SpellTraits.fromJson(json);
}
return ingredient;
}
}

View file

@ -9,7 +9,6 @@ import com.minelittlepony.unicopia.item.URecipes;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketByteBuf;
import net.minecraft.recipe.Ingredient;
import net.minecraft.recipe.RecipeSerializer; import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.ShapedRecipe; import net.minecraft.recipe.ShapedRecipe;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
@ -17,13 +16,12 @@ import net.minecraft.util.JsonHelper;
import net.minecraft.world.World; import net.minecraft.world.World;
public class TraitRequirementRecipe implements SpellbookRecipe { public class TraitRequirementRecipe implements SpellbookRecipe {
private final Identifier id; private final Identifier id;
private final Ingredient requirement; private final IngredientWithSpell requirement;
private final SpellTraits requiredTraits; private final TraitIngredient requiredTraits;
private final ItemStack output; private final ItemStack output;
private TraitRequirementRecipe(Identifier id, Ingredient requirement, SpellTraits requiredTraits, ItemStack output) { private TraitRequirementRecipe(Identifier id, IngredientWithSpell requirement, TraitIngredient requiredTraits, ItemStack output) {
this.id = id; this.id = id;
this.requirement = requirement; this.requirement = requirement;
this.requiredTraits = requiredTraits; this.requiredTraits = requiredTraits;
@ -33,14 +31,18 @@ public class TraitRequirementRecipe implements SpellbookRecipe {
@Override @Override
public boolean matches(SpellbookInventory inventory, World world) { public boolean matches(SpellbookInventory inventory, World world) {
return requirement.test(inventory.getItemToModify()) return requirement.test(inventory.getItemToModify())
&& SpellTraits.of(inventory).includes(requiredTraits); && requiredTraits.test(SpellTraits.union(
SpellTraits.of(inventory.getItemToModify()),
inventory.getTraits(),
SpellTraits.of(output)
));
} }
@Override @Override
public ItemStack craft(SpellbookInventory inventory) { public ItemStack craft(SpellbookInventory inventory) {
return SpellTraits.union( return SpellTraits.union(
SpellTraits.of(inventory.getItemToModify()), SpellTraits.of(inventory.getItemToModify()),
SpellTraits.of(inventory), inventory.getTraits(),
SpellTraits.of(output) SpellTraits.of(output)
).applyTo(output); ).applyTo(output);
} }
@ -81,16 +83,16 @@ public class TraitRequirementRecipe implements SpellbookRecipe {
@Override @Override
public TraitRequirementRecipe read(Identifier id, JsonObject json) { public TraitRequirementRecipe read(Identifier id, JsonObject json) {
return new TraitRequirementRecipe(id, return new TraitRequirementRecipe(id,
Ingredient.fromJson(JsonHelper.getObject(json, "material")), IngredientWithSpell.fromJson(JsonHelper.getObject(json, "material")),
SpellTraits.fromJson(JsonHelper.getObject(json, "traits")).get(), TraitIngredient.fromJson(JsonHelper.getObject(json, "traits")),
outputFromJson(JsonHelper.getObject(json, "result"))); outputFromJson(JsonHelper.getObject(json, "result")));
} }
@Override @Override
public TraitRequirementRecipe read(Identifier id, PacketByteBuf buf) { public TraitRequirementRecipe read(Identifier id, PacketByteBuf buf) {
return new TraitRequirementRecipe(id, return new TraitRequirementRecipe(id,
Ingredient.fromPacket(buf), IngredientWithSpell.fromPacket(buf),
SpellTraits.fromPacket(buf).get(), TraitIngredient.fromPacket(buf),
buf.readItemStack() buf.readItemStack()
); );
} }

View file

@ -4,11 +4,14 @@ 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.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -26,7 +29,7 @@ import net.minecraft.text.LiteralText;
import net.minecraft.text.Text; 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 implements Iterable<Map.Entry<Trait, Float>> {
public static final SpellTraits EMPTY = new SpellTraits(Map.of()); public static final SpellTraits EMPTY = new SpellTraits(Map.of());
private final Map<Trait, Float> traits; private final Map<Trait, Float> traits;
@ -35,20 +38,47 @@ public final class SpellTraits {
this.traits = traits; this.traits = traits;
} }
SpellTraits(SpellTraits from) {
this(new EnumMap<>(from.traits));
}
public SpellTraits multiply(float factor) {
return factor == 0 ? EMPTY : map(v -> v * factor);
}
public SpellTraits map(Function<Float, Float> function) {
if (isEmpty()) {
return this;
}
Map<Trait, Float> newMap = new EnumMap<>(traits);
newMap.entrySet().forEach(entry -> entry.setValue(function.apply(entry.getValue())));
return fromEntries(newMap.entrySet().stream()).orElse(EMPTY);
}
public boolean isEmpty() { public boolean isEmpty() {
return traits.isEmpty(); return traits.isEmpty();
} }
public boolean includes(SpellTraits other) { public boolean includes(SpellTraits other) {
return other.entries().stream().allMatch(pair -> { return other.stream().allMatch(pair -> {
return getAmount(pair.getKey()) >= pair.getValue(); return getAmount(pair.getKey()) >= pair.getValue();
}); });
} }
@Override
public Iterator<Entry<Trait, Float>> iterator() {
return entries().iterator();
}
public Set<Map.Entry<Trait, Float>> entries() { public Set<Map.Entry<Trait, Float>> entries() {
return traits.entrySet(); return traits.entrySet();
} }
public Stream<Map.Entry<Trait, Float>> stream() {
return entries().stream();
}
public float getAmount(Trait trait) { public float getAmount(Trait trait) {
return traits.getOrDefault(trait, 0F); return traits.getOrDefault(trait, 0F);
} }
@ -179,12 +209,15 @@ public final class SpellTraits {
static void combine(Map<Trait, Float> to, Map<Trait, Float> from) { static void combine(Map<Trait, Float> to, Map<Trait, Float> from) {
from.forEach((trait, value) -> { from.forEach((trait, value) -> {
if (value != 0) {
to.compute(trait, (k, v) -> v == null ? value : (v + 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)
.filter(e -> e.getValue() != 0)
.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)));
} }
} }

View file

@ -49,6 +49,7 @@ public class SpellbookScreen extends HandledScreen<SpellbookScreenHandler> {
for (Slot slot : handler.slots) { for (Slot slot : handler.slots) {
if (slot.isEnabled() && slot instanceof SpellbookSlot) { if (slot.isEnabled() && slot instanceof SpellbookSlot) {
drawTexture(matrices, slot.x - 1, slot.y - 1, 74, 223, 18, 18, 512, 256); drawTexture(matrices, slot.x - 1, slot.y - 1, 74, 223, 18, 18, 512, 256);
// drawStringWithShadow(matrices, this.textRenderer, ((SpellbookSlot)slot).getRing() + "", slot.x, slot.y, 0x000000FF);
} }
} }
RenderSystem.disableBlend(); RenderSystem.disableBlend();

View file

@ -5,6 +5,7 @@ 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.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.entity.player.Pony; 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.item.URecipes;
@ -18,14 +19,13 @@ import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket; import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket;
import net.minecraft.screen.ScreenHandler; import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.ScreenHandlerContext;
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.server.network.ServerPlayerEntity;
import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents; import net.minecraft.sound.SoundEvents;
import net.minecraft.util.Pair;
import net.minecraft.util.collection.DefaultedList; import net.minecraft.util.collection.DefaultedList;
import net.minecraft.world.World;
public class SpellbookScreenHandler extends ScreenHandler { public class SpellbookScreenHandler extends ScreenHandler {
@ -42,12 +42,19 @@ public class SpellbookScreenHandler extends ScreenHandler {
private final PlayerInventory inventory; private final PlayerInventory inventory;
private final ScreenHandlerContext context;
protected SpellbookScreenHandler(int syncId, PlayerInventory inv) { protected SpellbookScreenHandler(int syncId, PlayerInventory inv) {
this(syncId, inv, ScreenHandlerContext.EMPTY);
}
public SpellbookScreenHandler(int syncId, PlayerInventory inv, ScreenHandlerContext context) {
super(UScreenHandlers.SPELL_BOOK, syncId); super(UScreenHandlers.SPELL_BOOK, syncId);
inventory = inv; inventory = inv;
this.context = context;
List<Pair<Integer, Integer>> grid = new ArrayList<>(); List<int[]> grid = new ArrayList<>();
List<Pair<Integer, Integer>> gemPos = new ArrayList<>(); List<int[]> gemPos = new ArrayList<>();
createGrid(grid, gemPos); createGrid(grid, gemPos);
GEM_SLOT_INDEX = MAX_INGREDIENTS = grid.size(); GEM_SLOT_INDEX = MAX_INGREDIENTS = grid.size();
@ -58,10 +65,10 @@ public class SpellbookScreenHandler extends ScreenHandler {
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);
addSlot(new InputSlot(input, i, pos.getLeft(), pos.getRight())); addSlot(new InputSlot(input, i, pos));
} }
addSlot(gemSlot = new OutputSlot(inventory.player, input, result, 0, gemPos.get(0).getLeft(), gemPos.get(0).getRight())); addSlot(gemSlot = new OutputSlot(inventory.player, input, result, 0, gemPos.get(0)));
for (int i = 0; i < 9; ++i) { for (int i = 0; i < 9; ++i) {
addSlot(new Slot(inventory, i, 121 + i * 18, 195)); addSlot(new Slot(inventory, i, 121 + i * 18, 195));
@ -77,16 +84,16 @@ public class SpellbookScreenHandler extends ScreenHandler {
@Override @Override
public void onContentChanged(Inventory inventory) { public void onContentChanged(Inventory inventory) {
World world = this.inventory.player.world; context.run((world, pos) -> {
if (!world.isClient && !gemSlot.getStack().isEmpty()) { if (!world.isClient && !gemSlot.getStack().isEmpty()) {
world.getServer().getRecipeManager().getFirstMatch(URecipes.SPELLBOOK, input, world) world.getServer().getRecipeManager().getFirstMatch(URecipes.SPELLBOOK, input, world)
.filter(recipe -> result.shouldCraftRecipe(world, (ServerPlayerEntity)this.inventory.player, recipe)) .filter(recipe -> result.shouldCraftRecipe(world, (ServerPlayerEntity)this.inventory.player, recipe))
.map(recipe -> { .map(recipe -> recipe.craft(input))
this.inventory.player.playSound(SoundEvents.BLOCK_END_PORTAL_FRAME_FILL, SoundCategory.MASTER, 1, 0.3F);
return recipe.craft(input);
})
.ifPresentOrElse(gemSlot::setCrafted, gemSlot::setUncrafted); .ifPresentOrElse(gemSlot::setCrafted, gemSlot::setUncrafted);
((ServerPlayerEntity)this.inventory.player).networkHandler.sendPacket(new ScreenHandlerSlotUpdateS2CPacket(syncId, GEM_SLOT_INDEX, gemSlot.getStack()));
} }
});
} }
@Override @Override
@ -190,11 +197,18 @@ public class SpellbookScreenHandler extends ScreenHandler {
public void close(PlayerEntity playerEntity) { public void close(PlayerEntity playerEntity) {
gemSlot.setUncrafted(); gemSlot.setUncrafted();
super.close(playerEntity); super.close(playerEntity);
context.run((world, pos) -> {
dropInventory(playerEntity, input); dropInventory(playerEntity, input);
dropInventory(playerEntity, result); dropInventory(playerEntity, result);
});
} }
private static void createGrid(List<Pair<Integer, Integer>> grid, List<Pair<Integer, Integer>> gemPos) { /**
* Creates a hexagonal crafting grid.
* @param grid Output for normal slot positions.
* @param gemPos Output for the gem slot position.
*/
private static void createGrid(List<int[]> grid, List<int[]> gemPos) {
int cols = 4; int cols = 4;
int spacing = 23; int spacing = 23;
@ -203,7 +217,25 @@ public class SpellbookScreenHandler extends ScreenHandler {
for (int row = 0; row < 7; row++) { for (int row = 0; row < 7; row++) {
for (int i = 0; i < cols; i++) { for (int i = 0; i < cols; i++) {
(row == 3 && i == 3 ? gemPos : grid).add(new Pair<>(left + (i * spacing), top));
int ring = 3;
if (row == 0 || row == 6) {
ring = 1;
} else if ((row == 1 || row == 5) && i > 0 && i < cols - 1) {
ring = 2;
} else {
if (i == 0 || i == cols - 1) {
ring = 1;
} else if (i == 1 || i == cols - 2) {
ring = 2;
}
}
(row == 3 && i == 3 ? gemPos : grid).add(new int[] {
left + (i * spacing),
top,
row == 3 && i == 3 ? 4 : ring
});
} }
top += spacing * 0.9; top += spacing * 0.9;
left -= (spacing / 2) * (row > 2 ? -1 : 1); left -= (spacing / 2) * (row > 2 ? -1 : 1);
@ -211,7 +243,9 @@ public class SpellbookScreenHandler extends ScreenHandler {
} }
} }
public interface SpellbookSlot {} public interface SpellbookSlot {
int getRing();
}
public class SpellbookInventory extends CraftingInventory { public class SpellbookInventory extends CraftingInventory {
@ -220,38 +254,74 @@ public class SpellbookScreenHandler extends ScreenHandler {
} }
public ItemStack getItemToModify() { public ItemStack getItemToModify() {
return gemSlot.getStack(); return gemSlot.uncrafted.orElse(gemSlot.getStack());
}
public int getRing(int slot) {
Slot s = slots.get(slot);
return s instanceof SpellbookSlot ? ((SpellbookSlot)s).getRing() : 0;
}
public SpellTraits getTraits() {
return SpellTraits.union(InventoryUtil.slots(this)
.map(slot -> SpellTraits.of(getStack(slot)).multiply(getRingFactor(getRing(slot))))
.toArray(SpellTraits[]::new)
);
}
public static float getRingFactor(int ring) {
switch (ring) {
case 1: return 1;
case 2: return 0.6F;
case 3: return 0.3F;
default: return 0;
}
} }
} }
public class InputSlot extends Slot implements SpellbookSlot { public class InputSlot extends Slot implements SpellbookSlot {
public InputSlot(Inventory inventory, int index, int xPosition, int yPosition) { private final int ring;
super(inventory, index, xPosition, yPosition);
public InputSlot(Inventory inventory, int index, int[] params) {
super(inventory, index, params[0], params[1]);
ring = params[2];
} }
@Override @Override
public int getMaxItemCount() { public int getMaxItemCount() {
return 1; return 1;
} }
@Override
public int getRing() {
return ring;
}
} }
public static class OutputSlot extends CraftingResultSlot implements SpellbookSlot { public static class OutputSlot extends CraftingResultSlot implements SpellbookSlot {
private Optional<ItemStack> uncrafted = Optional.empty(); private Optional<ItemStack> uncrafted = Optional.empty();
private final PlayerEntity player;
private final SpellbookInventory input; private final SpellbookInventory input;
public OutputSlot(PlayerEntity player, SpellbookInventory input, Inventory inventory, int index, int x, int y) { private final int ring;
super(player, input, inventory, index, x, y);
public OutputSlot(PlayerEntity player, SpellbookInventory input, Inventory inventory, int index, int[] params) {
super(player, input, inventory, index, params[0], params[1]);
this.player = player;
this.input = input; this.input = input;
this.ring = params[2];
} }
public void setCrafted(ItemStack crafted) { public void setCrafted(ItemStack crafted) {
uncrafted = uncrafted.or(() -> Optional.of(getStack())); uncrafted = uncrafted.or(() -> Optional.of(getStack()));
setStack(crafted); setStack(crafted);
player.playSound(SoundEvents.BLOCK_END_PORTAL_FRAME_FILL, SoundCategory.MASTER, 1, 0.3F);
} }
public void setUncrafted() { public void setUncrafted() {
player.playSound(SoundEvents.BLOCK_END_PORTAL_FRAME_FILL, SoundCategory.MASTER, 0.2F, 0.2F);
uncrafted = uncrafted.filter(stack -> { uncrafted = uncrafted.filter(stack -> {
setStack(stack); setStack(stack);
return false; return false;
@ -268,6 +338,11 @@ public class SpellbookScreenHandler extends ScreenHandler {
return 1; return 1;
} }
@Override
public int getRing() {
return ring;
}
@Override @Override
public void onTakeItem(PlayerEntity player, ItemStack stack) { public void onTakeItem(PlayerEntity player, ItemStack stack) {
if (uncrafted.isPresent()) { if (uncrafted.isPresent()) {

View file

@ -3,7 +3,7 @@ package com.minelittlepony.unicopia.entity;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.container.UScreenHandlers; import com.minelittlepony.unicopia.container.SpellbookScreenHandler;
import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.UItems;
import net.fabricmc.fabric.api.util.TriState; import net.fabricmc.fabric.api.util.TriState;
@ -18,6 +18,7 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.screen.ScreenHandlerContext;
import net.minecraft.screen.SimpleNamedScreenHandlerFactory; import net.minecraft.screen.SimpleNamedScreenHandlerFactory;
import net.minecraft.sound.BlockSoundGroup; import net.minecraft.sound.BlockSoundGroup;
import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundCategory;
@ -197,7 +198,7 @@ public class SpellbookEntity extends MobEntity {
if (isOpen() && EquinePredicates.PLAYER_UNICORN.test(player)) { if (isOpen() && EquinePredicates.PLAYER_UNICORN.test(player)) {
setBored(false); setBored(false);
player.openHandledScreen(new SimpleNamedScreenHandlerFactory((syncId, inv, ply) -> UScreenHandlers.SPELL_BOOK.create(syncId, inv), getDisplayName())); player.openHandledScreen(new SimpleNamedScreenHandlerFactory((syncId, inv, ply) -> new SpellbookScreenHandler(syncId, inv, ScreenHandlerContext.create(world, getBlockPos())), getDisplayName()));
player.playSound(SoundEvents.ITEM_BOOK_PAGE_TURN, 2, 1); player.playSound(SoundEvents.ITEM_BOOK_PAGE_TURN, 2, 1);
return ActionResult.SUCCESS; return ActionResult.SUCCESS;
} }

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.util; package com.minelittlepony.unicopia.util;
import java.util.stream.Stream;
import com.google.common.collect.AbstractIterator; import com.google.common.collect.AbstractIterator;
import net.minecraft.inventory.Inventory; import net.minecraft.inventory.Inventory;
@ -19,4 +21,8 @@ public interface InventoryUtil {
} }
}; };
} }
static Stream<Integer> slots(Inventory inventory) {
return Stream.iterate(0, i -> i < inventory.size(), i -> i + 1);
}
} }