diff --git a/src/main/java/com/minelittlepony/unicopia/client/UnicopiaClient.java b/src/main/java/com/minelittlepony/unicopia/client/UnicopiaClient.java index 63ff54e7..f1e29bce 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/UnicopiaClient.java +++ b/src/main/java/com/minelittlepony/unicopia/client/UnicopiaClient.java @@ -11,11 +11,14 @@ import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.client.gui.LanSettingsScreen; import com.minelittlepony.unicopia.client.gui.UHud; import com.minelittlepony.unicopia.client.minelittlepony.MineLPConnector; +import com.minelittlepony.unicopia.container.SpellbookScreen; +import com.minelittlepony.unicopia.container.UScreenHandlers; import com.minelittlepony.unicopia.entity.player.PlayerCamera; import com.minelittlepony.unicopia.entity.player.Pony; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback; +import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.OpenToLanScreen; import net.minecraft.client.gui.screen.Screen; @@ -59,6 +62,8 @@ public class UnicopiaClient implements ClientModInitializer { KeyBindingsHandler.bootstrap(); URenderers.bootstrap(); + ScreenRegistry.register(UScreenHandlers.SPELL_BOOK, SpellbookScreen::new); + ClientTickEvents.END_CLIENT_TICK.register(this::onTick); ScreenInitCallback.EVENT.register(this::onScreenInit); ItemTooltipCallback.EVENT.register(new ModifierTooltipRenderer()); diff --git a/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreen.java b/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreen.java new file mode 100644 index 00000000..7b47f5f2 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreen.java @@ -0,0 +1,62 @@ +package com.minelittlepony.unicopia.container; + +import com.minelittlepony.unicopia.container.SpellbookScreenHandler.SpellbookSlot; +import com.mojang.blaze3d.systems.RenderSystem; + +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.screen.slot.Slot; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +public class SpellbookScreen extends HandledScreen { + public static final Identifier TEXTURE = new Identifier("unicopia", "textures/gui/container/book.png"); + + public SpellbookScreen(SpellbookScreenHandler handler, PlayerInventory inventory, Text title) { + super(handler, inventory, title); + backgroundWidth = 405; + backgroundHeight = 219; + } + + @Override + public void init() { + super.init(); + } + + @Override + public void render(MatrixStack matrices, int mouseX, int mouseY, float partialTicks) { + super.render(matrices, mouseX, mouseY, partialTicks); + drawMouseoverTooltip(matrices, mouseX, mouseY); + } + + @Override + protected void drawBackground(MatrixStack matrices, float delta, int mouseX, int mouseY) { + renderBackground(matrices, 0); + RenderSystem.setShaderColor(1, 1, 1, 1); + + int left = (width - backgroundWidth) / 2; + int top = (height - backgroundHeight) / 2; + + RenderSystem.setShaderTexture(0, TEXTURE); + + drawTexture(matrices, left, top, 0, 0, backgroundWidth, backgroundHeight, 512, 256); + + matrices.push(); + matrices.translate(this.x, this.y, 0); + + RenderSystem.enableBlend(); + for (Slot slot : handler.slots) { + if (slot.isEnabled() && slot instanceof SpellbookSlot) { + drawTexture(matrices, slot.x - 1, slot.y - 1, 74, 223, 18, 18, 512, 256); + } + } + RenderSystem.disableBlend(); + + RenderSystem.enableBlend(); + drawTexture(matrices, 56, 50, 407, 2, 100, 101, 512, 256); + RenderSystem.disableBlend(); + + matrices.pop(); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java b/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java index 0755dd96..c6ff323b 100644 --- a/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java +++ b/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java @@ -1,19 +1,196 @@ package com.minelittlepony.unicopia.container; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + import com.minelittlepony.unicopia.EquinePredicates; +import com.minelittlepony.unicopia.item.UItems; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; +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.util.Pair; +import net.minecraft.world.World; -public class SpellBookScreenHandler extends ScreenHandler { +public class SpellbookScreenHandler extends ScreenHandler { - protected SpellBookScreenHandler(int syncId, PlayerInventory inv) { + private final int MAX_INGREDIENTS; + + private final int GEM_SLOT_INDEX; + private final int HOTBAR_START; + private final int HOTBAR_END; + + private final CraftingInventory input; + + private OutputSlot gemSlot; + private final CraftingResultInventory result = new CraftingResultInventory(); + + private final PlayerInventory inventory; + + protected SpellbookScreenHandler(int syncId, PlayerInventory inv) { super(UScreenHandlers.SPELL_BOOK, syncId); + inventory = inv; + + List> grid = new ArrayList<>(); + List> gemPos = new ArrayList<>(); + createGrid(grid, gemPos); + + GEM_SLOT_INDEX = MAX_INGREDIENTS = grid.size(); + HOTBAR_START = GEM_SLOT_INDEX + 1; + HOTBAR_END = HOTBAR_START + 9; + + input = new CraftingInventory(this, MAX_INGREDIENTS, 1); + + for (int i = 0; i < MAX_INGREDIENTS; i++) { + var pos = grid.get(i); + addSlot(new InputSlot(input, i, pos.getLeft(), pos.getRight())); + } + + addSlot(gemSlot = new OutputSlot(inventory.player, input, result, 0, gemPos.get(0).getLeft(), gemPos.get(0).getRight())); + + for (int i = 0; i < 9; ++i) { + addSlot(new Slot(inventory, i, 121 + i * 18, 195)); + } + + onContentChanged(input); } @Override public boolean canUse(PlayerEntity player) { return EquinePredicates.IS_CASTER.test(player); } + + @Override + public void onContentChanged(Inventory inventory) { + World world = this.inventory.player.world; + if (!world.isClient) { + world.getServer().getRecipeManager().getFirstMatch(RecipeType.CRAFTING, input, world) + .map(recipe -> recipe.craft(input)) + .ifPresentOrElse(gemSlot::setCrafted, gemSlot::setUncrafted); + } + } + + @Override + public ItemStack transferSlot(PlayerEntity player, int index) { + Slot sourceSlot = slots.get(index); + + if (sourceSlot == null || !sourceSlot.hasStack()) { + return ItemStack.EMPTY; + } + + ItemStack transferredStack = sourceSlot.getStack(); + ItemStack stack = transferredStack.copy(); + + if (index >= HOTBAR_START) { + if (!gemSlot.hasStack() && gemSlot.canInsert(stack)) { + if (!insertItem(transferredStack, GEM_SLOT_INDEX, GEM_SLOT_INDEX + 1, false)) { + return ItemStack.EMPTY; + } + } + + if (!insertItem(transferredStack, 0, GEM_SLOT_INDEX, false)) { + return ItemStack.EMPTY; + } + } else { + if (!insertItem(transferredStack, HOTBAR_START, HOTBAR_END, false)) { + return ItemStack.EMPTY; + } + + sourceSlot.onQuickTransfer(transferredStack, stack); + onContentChanged(input); + } + + if (transferredStack.getCount() == stack.getCount()) { + return ItemStack.EMPTY; + } + + sourceSlot.onTakeItem(player, transferredStack); + + return stack; + } + + @Override + public void close(PlayerEntity playerEntity) { + gemSlot.setUncrafted(); + super.close(playerEntity); + dropInventory(playerEntity, input); + dropInventory(playerEntity, result); + } + + private static void createGrid(List> grid, List> gemPos) { + int cols = 4; + int spacing = 23; + + int top = 34; + int left = 65; + + for (int row = 0; row < 7; row++) { + for (int i = 0; i < cols; i++) { + (row == 3 && i == 3 ? gemPos : grid).add(new Pair<>(left + (i * spacing), top)); + } + top += spacing * 0.9; + left -= (spacing / 2) * (row > 2 ? -1 : 1); + cols += row > 2 ? -1 : 1; + } + } + + public interface SpellbookSlot {} + + public class InputSlot extends Slot implements SpellbookSlot { + public InputSlot(Inventory inventory, int index, int xPosition, int yPosition) { + super(inventory, index, xPosition, yPosition); + } + + @Override + public int getMaxItemCount() { + return 1; + } + } + + public static class OutputSlot extends CraftingResultSlot implements SpellbookSlot { + + private Optional uncrafted = Optional.empty(); + + public OutputSlot(PlayerEntity player, CraftingInventory input, Inventory inventory, int index, int x, int y) { + super(player, input, inventory, index, x, y); + } + + public void setCrafted(ItemStack crafted) { + uncrafted = uncrafted.or(() -> Optional.of(getStack())); + setStack(crafted); + } + + public void setUncrafted() { + uncrafted = uncrafted.filter(stack -> { + setStack(stack); + return false; + }); + } + + @Override + public boolean canInsert(ItemStack stack) { + return stack.getItem() == UItems.GEMSTONE; + } + + @Override + public int getMaxItemCount() { + return 1; + } + + @Override + public void onTakeItem(PlayerEntity player, ItemStack stack) { + if (uncrafted.isPresent()) { + uncrafted = Optional.empty(); + super.onTakeItem(player, stack); + } + } + } } diff --git a/src/main/java/com/minelittlepony/unicopia/container/UScreenHandlers.java b/src/main/java/com/minelittlepony/unicopia/container/UScreenHandlers.java index 07c14e59..719f7548 100644 --- a/src/main/java/com/minelittlepony/unicopia/container/UScreenHandlers.java +++ b/src/main/java/com/minelittlepony/unicopia/container/UScreenHandlers.java @@ -7,7 +7,7 @@ import net.minecraft.screen.ScreenHandlerType; import net.minecraft.util.Identifier; public interface UScreenHandlers { - ScreenHandlerType SPELL_BOOK = register("spell_book", SpellBookScreenHandler::new); + ScreenHandlerType SPELL_BOOK = register("spell_book", SpellbookScreenHandler::new); static ScreenHandlerType register(String name, SimpleClientHandlerFactory factory) { return ScreenHandlerRegistry.registerSimple(new Identifier("unicopia", name), factory); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/SpellbookEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/SpellbookEntity.java index 15dd4954..b92664a8 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/SpellbookEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/SpellbookEntity.java @@ -150,8 +150,6 @@ public class SpellbookEntity extends MobEntity { }); if (!world.isClient) { - System.out.println(activeTicks); - if (activeTicks > 0 && --activeTicks <= 0) { setBored(true); } @@ -193,13 +191,14 @@ public class SpellbookEntity extends MobEntity { setBored(false); setAwake(!isOpen()); setLocked(TriState.of(isAwake())); + player.playSound(SoundEvents.ITEM_BOOK_PAGE_TURN, 2, 1); return ActionResult.SUCCESS; } if (isOpen() && EquinePredicates.PLAYER_UNICORN.test(player)) { setBored(false); player.openHandledScreen(new SimpleNamedScreenHandlerFactory((syncId, inv, ply) -> UScreenHandlers.SPELL_BOOK.create(syncId, inv), getDisplayName())); - player.playSound(SoundEvents.BLOCK_FURNACE_FIRE_CRACKLE, 2, 1); + player.playSound(SoundEvents.ITEM_BOOK_PAGE_TURN, 2, 1); return ActionResult.SUCCESS; }