diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookScreen.java index 3aa17195..9949f602 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/spellbook/SpellbookScreen.java @@ -16,6 +16,8 @@ import com.minelittlepony.unicopia.container.*; import com.minelittlepony.unicopia.container.inventory.*; import com.minelittlepony.unicopia.network.Channel; import com.minelittlepony.unicopia.network.MsgSpellbookStateChanged; +import com.minelittlepony.unicopia.trinkets.TrinketSlotBackSprites; +import com.minelittlepony.unicopia.trinkets.TrinketsDelegate; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; @@ -203,6 +205,9 @@ public class SpellbookScreen extends HandledScreen imple RenderSystem.enableBlend(); } } + if (slot.isEnabled() && slot instanceof TrinketsDelegate.SlotWithForeground fg && slot.getStack().isEmpty()) { + context.drawTexture(TrinketSlotBackSprites.getBackSprite(fg.getForegroundIdentifier()), slot.x, slot.y, 0, 0, 16, 16, 16, 16); + } } RenderSystem.disableBlend(); RenderSystem.setShaderColor(1, 1, 1, 1); diff --git a/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java b/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java index 5c8d81f4..3d261daf 100644 --- a/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java +++ b/src/main/java/com/minelittlepony/unicopia/container/SpellbookScreenHandler.java @@ -9,6 +9,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.crafting.SpellbookRecipe; import com.minelittlepony.unicopia.container.inventory.*; import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.URecipes; +import com.minelittlepony.unicopia.trinkets.TrinketsDelegate; import com.mojang.datafixers.util.Pair; import net.minecraft.enchantment.EnchantmentHelper; @@ -52,7 +53,7 @@ public class SpellbookScreenHandler extends ScreenHandler { private final ScreenHandlerContext context; - public Predicate canShowSlots; + private Predicate canShowSlots; private final SpellbookState state; @@ -126,6 +127,11 @@ public class SpellbookScreenHandler extends ScreenHandler { }); } + TrinketsDelegate.getInstance().createSlot(this, inv.player, TrinketsDelegate.FACE, 0, 340 + 20, 60).ifPresent(this::addSlot); + TrinketsDelegate.getInstance().createSlot(this, inv.player, TrinketsDelegate.NECKLACE, 0, 340 + 20, 60 + 20).ifPresent(this::addSlot); + TrinketsDelegate.getInstance().createSlot(this, inv.player, TrinketsDelegate.MAINHAND, 0, 350 - 20, 170).ifPresent(this::addSlot); + TrinketsDelegate.getInstance().createSlot(this, inv.player, TrinketsDelegate.OFFHAND, 0, 330 + 20, 170).ifPresent(this::addSlot); + addSlot(new InventorySlot(this, inventory, PlayerInventory.OFF_HAND_SLOT, 340, 150) { @Override public Pair getBackgroundSprite() { @@ -146,6 +152,10 @@ public class SpellbookScreenHandler extends ScreenHandler { this.canShowSlots = canShowSlots; } + public boolean canShowSlots(SlotType type) { + return canShowSlots == null || canShowSlots.test(type); + } + public int getOutputSlotId() { return outputSlot.id; } diff --git a/src/main/java/com/minelittlepony/unicopia/container/inventory/IngredientSlot.java b/src/main/java/com/minelittlepony/unicopia/container/inventory/IngredientSlot.java index 337becd0..5b6b9e48 100644 --- a/src/main/java/com/minelittlepony/unicopia/container/inventory/IngredientSlot.java +++ b/src/main/java/com/minelittlepony/unicopia/container/inventory/IngredientSlot.java @@ -33,6 +33,6 @@ public class IngredientSlot extends Slot implements SpellbookSlot { @Override public boolean isEnabled() { - return handler.canShowSlots.test(SlotType.CRAFTING) && super.isEnabled(); + return handler.canShowSlots(SlotType.CRAFTING) && super.isEnabled(); } } \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/container/inventory/InputSlot.java b/src/main/java/com/minelittlepony/unicopia/container/inventory/InputSlot.java index 6d0f9e4c..70d270c5 100644 --- a/src/main/java/com/minelittlepony/unicopia/container/inventory/InputSlot.java +++ b/src/main/java/com/minelittlepony/unicopia/container/inventory/InputSlot.java @@ -27,6 +27,6 @@ public class InputSlot extends Slot implements SpellbookSlot { @Override public boolean isEnabled() { - return handler.canShowSlots.test(SlotType.CRAFTING) && !handler.outputSlot.isEnabled(); + return handler.canShowSlots(SlotType.CRAFTING) && !handler.outputSlot.isEnabled(); } } \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/container/inventory/InventorySlot.java b/src/main/java/com/minelittlepony/unicopia/container/inventory/InventorySlot.java index 2aa68b12..3da59343 100644 --- a/src/main/java/com/minelittlepony/unicopia/container/inventory/InventorySlot.java +++ b/src/main/java/com/minelittlepony/unicopia/container/inventory/InventorySlot.java @@ -15,6 +15,6 @@ public class InventorySlot extends Slot implements SpellbookSlot { @Override public boolean isEnabled() { - return handler.canShowSlots.test(SlotType.INVENTORY); + return handler.canShowSlots(SlotType.INVENTORY); } } \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/container/inventory/OutputSlot.java b/src/main/java/com/minelittlepony/unicopia/container/inventory/OutputSlot.java index abf77fad..c28605f1 100644 --- a/src/main/java/com/minelittlepony/unicopia/container/inventory/OutputSlot.java +++ b/src/main/java/com/minelittlepony/unicopia/container/inventory/OutputSlot.java @@ -46,7 +46,7 @@ public class OutputSlot extends CraftingResultSlot implements SpellbookSlot { @Override public boolean isEnabled() { - return handler.canShowSlots.test(SlotType.CRAFTING) && hasStack(); + return handler.canShowSlots(SlotType.CRAFTING) && hasStack(); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/trinkets/SpellbookTrinketSlot.java b/src/main/java/com/minelittlepony/unicopia/trinkets/SpellbookTrinketSlot.java new file mode 100644 index 00000000..c870dbdb --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/trinkets/SpellbookTrinketSlot.java @@ -0,0 +1,94 @@ +package com.minelittlepony.unicopia.trinkets; + +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.container.SpellbookScreenHandler; +import com.minelittlepony.unicopia.container.inventory.InventorySlot; +import com.mojang.datafixers.util.Pair; + +import dev.emi.trinkets.SurvivalTrinketSlot; +import dev.emi.trinkets.api.SlotGroup; +import dev.emi.trinkets.api.TrinketInventory; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Identifier; + +class SpellbookTrinketSlot extends InventorySlot implements TrinketsDelegate.SlotWithForeground { + private final SurvivalTrinketSlot slot; + + public SpellbookTrinketSlot(SpellbookScreenHandler handler, TrinketInventory inventory, int index, int x, int y, SlotGroup group) { + super(handler, inventory, index, x, y); + this.slot = new SurvivalTrinketSlot(inventory, index, x, y, group, inventory.getSlotType(), 0, true); + } + + @Override + public void onTakeItem(PlayerEntity player, ItemStack stack) { + this.slot.onTakeItem(player, stack); + } + + @Override + public boolean canInsert(ItemStack stack) { + return this.slot.canInsert(stack); + } + + @Override + public ItemStack getStack() { + return this.slot.getStack(); + } + + @Override + public boolean hasStack() { + return this.slot.hasStack(); + } + + @Override + public void setStack(ItemStack stack) { + this.slot.setStack(stack); + } + + @Override + public void setStackNoCallbacks(ItemStack stack) { + this.slot.setStackNoCallbacks(stack); + } + + @Override + public void markDirty() { + this.slot.markDirty(); + } + + @Override + public int getMaxItemCount() { + return this.slot.getMaxItemCount(); + } + + @Override + public int getMaxItemCount(ItemStack stack) { + return this.slot.getMaxItemCount(stack); + } + + @Override + @Nullable + public Pair getBackgroundSprite() { + return null; + } + + @Override + public ItemStack takeStack(int amount) { + return this.slot.takeStack(amount); + } + + @Override + public boolean isEnabled() { + return this.slot.isEnabled(); + } + + @Override + public boolean canTakeItems(PlayerEntity playerEntity) { + return this.slot.canTakeItems(playerEntity); + } + + @Override + public Identifier getForegroundIdentifier() { + return slot.getBackgroundIdentifier(); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketSlotBackSprites.java b/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketSlotBackSprites.java new file mode 100644 index 00000000..f0cb90aa --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketSlotBackSprites.java @@ -0,0 +1,55 @@ +package com.minelittlepony.unicopia.trinkets; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +import com.minelittlepony.unicopia.Unicopia; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.texture.NativeImage; +import net.minecraft.client.texture.NativeImageBackedTexture; +import net.minecraft.util.Identifier; + +public class TrinketSlotBackSprites { + private static final Identifier BLANK_FACE = new Identifier("trinkets", "textures/gui/blank_back.png"); + + private static final Map CACHE = new HashMap<>(); + + public static Identifier getBackSprite(Identifier originalSprite) { + return CACHE.computeIfAbsent(originalSprite, TrinketSlotBackSprites::generateTransparentSprite); + } + + private static Identifier generateTransparentSprite(Identifier originalId) { + return readImage(BLANK_FACE, blank -> { + return readImage(originalId, original -> { + NativeImage generatedImage = new NativeImage(original.getWidth(), original.getHeight(), false); + final float widthScale = original.getWidth() / (float)blank.getWidth(); + final float heightScale = original.getHeight() / (float)blank.getHeight(); + + for (int x = 0; x < original.getWidth(); x++) { + for (int y = 0; y < original.getHeight(); y++) { + int blankColor = blank.getColor((int)(x * widthScale), (int)(y * heightScale)); + int originalColor = original.getColor(x, y); + + generatedImage.setColor(x, y, blankColor == originalColor ? 0 : originalColor); + } + } + + return MinecraftClient.getInstance().getTextureManager().registerDynamicTexture("trinket_slot" + originalId.getPath(), new NativeImageBackedTexture(generatedImage)); + }).orElse(originalId); + }).orElse(originalId); + } + + private static Optional readImage(Identifier id, Function consumer) { + return MinecraftClient.getInstance().getResourceManager().getResource(id).map(input -> { + try (NativeImage image = NativeImage.read(input.getInputStream())) { + return consumer.apply(image); + } catch (Exception e) { + Unicopia.LOGGER.error("Error whilst reading slot background resource " + id, e); + } + return null; + }); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegate.java b/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegate.java index 719a517f..db3adde6 100644 --- a/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegate.java +++ b/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegate.java @@ -5,7 +5,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import com.minelittlepony.unicopia.EntityConvertable; - +import com.minelittlepony.unicopia.Unicopia; +import com.minelittlepony.unicopia.container.SpellbookScreenHandler; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.LivingEntity; @@ -89,6 +90,10 @@ public interface TrinketsDelegate { } + default Optional createSlot(SpellbookScreenHandler handler, LivingEntity entity, Identifier slotId, int i, int x, int y) { + return Optional.empty(); + } + default boolean isTrinketSlot(Slot slot) { return false; } @@ -107,4 +112,10 @@ public interface TrinketsDelegate { TrinketsDelegate.getInstance().setEquippedStack(asEntity(), slot, stack); } } + + interface SlotWithForeground { + Identifier EMPTY_TEXTURE = Unicopia.id("transparent"); + + Identifier getForegroundIdentifier(); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegateImpl.java b/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegateImpl.java index 4e552210..82f74dd3 100644 --- a/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegateImpl.java +++ b/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegateImpl.java @@ -4,9 +4,9 @@ import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; +import com.minelittlepony.unicopia.container.SpellbookScreenHandler; import com.minelittlepony.unicopia.item.enchantment.UEnchantments; import com.minelittlepony.unicopia.util.InventoryUtil; - import dev.emi.trinkets.TrinketSlot; import dev.emi.trinkets.api.*; import dev.emi.trinkets.api.TrinketEnums.DropRule; @@ -24,6 +24,7 @@ import net.minecraft.world.event.GameEvent; public class TrinketsDelegateImpl implements TrinketsDelegate { public static final TrinketsDelegateImpl INSTANCE = new TrinketsDelegateImpl(); + // who tf designed this api? @Override @@ -104,9 +105,25 @@ public class TrinketsDelegateImpl implements TrinketsDelegate { .flatMap(group -> group.values().stream()); } + public Optional getGroup(LivingEntity entity, Identifier slotId) { + return TrinketsApi.getTrinketComponent(entity) + .stream() + .map(component -> component.getGroups().get(slotId.getNamespace())) + .findFirst(); + } + + @Override + public Optional createSlot(SpellbookScreenHandler handler, LivingEntity entity, Identifier slotId, int i, int x, int y) { + return getGroup(entity, slotId).flatMap(group -> { + return getInventory(entity, slotId).map(inventory -> { + return new SpellbookTrinketSlot(handler, inventory, i, x, y, group); + }); + }); + } + @Override public boolean isTrinketSlot(Slot slot) { - return slot instanceof TrinketSlot; + return slot instanceof TrinketSlot || slot instanceof SpellbookTrinketSlot; } private static Identifier getSlotId(SlotType slotType) {