Display trinket slots in the spellbook

This commit is contained in:
Sollace 2023-08-16 15:58:44 +01:00
parent 5f8dfe14e9
commit 1ed6ef7a17
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
10 changed files with 200 additions and 8 deletions

View file

@ -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<SpellbookScreenHandler> 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);

View file

@ -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<SlotType> canShowSlots;
private Predicate<SlotType> 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<Identifier, Identifier> 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;
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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<Identifier, Identifier> 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();
}
}

View file

@ -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<Identifier, Identifier> 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 <T> Optional<T> readImage(Identifier id, Function<NativeImage, T> 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;
});
}
}

View file

@ -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<Slot> 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();
}
}

View file

@ -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<SlotGroup> getGroup(LivingEntity entity, Identifier slotId) {
return TrinketsApi.getTrinketComponent(entity)
.stream()
.map(component -> component.getGroups().get(slotId.getNamespace()))
.findFirst();
}
@Override
public Optional<Slot> 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) {