Reimplement diet stuff

This commit is contained in:
Sollace 2024-10-01 19:05:43 +01:00
parent 1601c14d95
commit 0f1c2069e7
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
28 changed files with 285 additions and 353 deletions

View file

@ -28,7 +28,7 @@ public record SpellDuplicatingRecipe (IngredientWithSpell material) implements S
public void buildCraftingTree(CraftingTreeBuilder builder) { public void buildCraftingTree(CraftingTreeBuilder builder) {
ItemStack[] spells = SpellType.REGISTRY.stream() ItemStack[] spells = SpellType.REGISTRY.stream()
.filter(SpellType::isObtainable) .filter(SpellType::isObtainable)
.map(UItems.GEMSTONE::getDefaultStack) .map(i -> EnchantableItem.enchant(UItems.GEMSTONE.getDefaultStack(), i))
.toArray(ItemStack[]::new); .toArray(ItemStack[]::new);
builder.input(UItems.BOTCHED_GEM.getDefaultStack()); builder.input(UItems.BOTCHED_GEM.getDefaultStack());
builder.input(spells); builder.input(spells);

View file

@ -47,7 +47,7 @@ public class SpellShapedCraftingRecipe extends ShapedRecipe {
return inventory.getStacks().stream() return inventory.getStacks().stream()
.filter(stack -> stack.getItem() instanceof EnchantableItem) .filter(stack -> stack.getItem() instanceof EnchantableItem)
.filter(EnchantableItem::isEnchanted) .filter(EnchantableItem::isEnchanted)
.map(stack -> ((EnchantableItem)stack.getItem()).getSpellEffect(stack)) .map(stack -> EnchantableItem.getSpellEffect(stack))
.findFirst() .findFirst()
.map(spell -> spell.traits().applyTo(EnchantableItem.enchant(super.craft(inventory, registries), spell.type()))) .map(spell -> spell.traits().applyTo(EnchantableItem.enchant(super.craft(inventory, registries), spell.type())))
.orElseGet(() -> super.craft(inventory, registries)); .orElseGet(() -> super.craft(inventory, registries));

View file

@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -15,7 +16,10 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.client.TextHelper; import com.minelittlepony.unicopia.client.TextHelper;
import com.minelittlepony.unicopia.entity.effect.EffectUtils; import com.minelittlepony.unicopia.entity.effect.EffectUtils;
import net.minecraft.item.Item.TooltipContext;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.tooltip.TooltipAppender;
import net.minecraft.item.tooltip.TooltipType;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.RegistryWrapper.WrapperLookup; import net.minecraft.registry.RegistryWrapper.WrapperLookup;
import net.minecraft.text.MutableText; import net.minecraft.text.MutableText;
@ -27,7 +31,7 @@ public record CustomisedSpellType<T extends Spell> (
SpellType<T> type, SpellType<T> type,
SpellTraits traits, SpellTraits traits,
Supplier<SpellTraits> traitsDifferenceSupplier Supplier<SpellTraits> traitsDifferenceSupplier
) implements SpellPredicate<T> { ) implements SpellPredicate<T>, TooltipAppender {
public boolean isEmpty() { public boolean isEmpty() {
return type.isEmpty(); return type.isEmpty();
@ -86,25 +90,25 @@ public record CustomisedSpellType<T extends Spell> (
return traits.applyTo(type.getDefualtStack()); return traits.applyTo(type.getDefualtStack());
} }
public void appendTooltip(List<Text> lines) { @Override
public void appendTooltip(TooltipContext context, Consumer<Text> tooltip, TooltipType type) {
MutableText lore = Text.translatable(type().getTranslationKey() + ".lore").formatted(type().getAffinity().getColor()); MutableText lore = Text.translatable(type().getTranslationKey() + ".lore").formatted(type().getAffinity().getColor());
if (!InteractionManager.getInstance().getClientSpecies().canCast()) { if (!InteractionManager.getInstance().getClientSpecies().canCast()) {
lore = lore.formatted(Formatting.OBFUSCATED); lore = lore.formatted(Formatting.OBFUSCATED);
} }
lines.addAll(TextHelper.wrap(lore, 180).toList()); TextHelper.wrap(lore, 180).forEach(tooltip);
float corruption = ((int)traits().getCorruption() * 10) + type().getAffinity().getCorruption(); float corruption = ((int)traits().getCorruption() * 10) + type().getAffinity().getCorruption();
List<Text> modifiers = new ArrayList<>(); List<Text> modifiers = new ArrayList<>();
type.getTooltip().appendTooltip(this, modifiers); type().getTooltip().appendTooltip(this, modifiers);
if (corruption != 0) { if (corruption != 0) {
modifiers.add(EffectUtils.formatModifierChange("affinity.unicopia.corruption", corruption, true)); modifiers.add(EffectUtils.formatModifierChange("affinity.unicopia.corruption", corruption, true));
} }
if (!modifiers.isEmpty()) { if (!modifiers.isEmpty()) {
lines.add(Text.empty()); tooltip.accept(Text.empty());
lines.add(Text.translatable("affinity.unicopia.when_cast").formatted(Formatting.GRAY)); tooltip.accept(Text.translatable("affinity.unicopia.when_cast").formatted(Formatting.GRAY));
lines.addAll(modifiers); modifiers.forEach(tooltip);
} }
} }
public TypedActionResult<CustomisedSpellType<?>> toAction() { public TypedActionResult<CustomisedSpellType<?>> toAction() {

View file

@ -18,6 +18,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.ThrowableSpell;
import com.minelittlepony.unicopia.ability.magic.spell.TimeControlAbilitySpell; import com.minelittlepony.unicopia.ability.magic.spell.TimeControlAbilitySpell;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.item.EnchantableItem;
import com.minelittlepony.unicopia.item.GemstoneItem; import com.minelittlepony.unicopia.item.GemstoneItem;
import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.util.RegistryUtils; import com.minelittlepony.unicopia.util.RegistryUtils;
@ -117,7 +118,7 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
this.traits = traits; this.traits = traits;
this.stackable = stackable; this.stackable = stackable;
traited = new CustomisedSpellType<>(this, traits, SpellTraits::empty); traited = new CustomisedSpellType<>(this, traits, SpellTraits::empty);
defaultStack = UItems.GEMSTONE.getDefaultStack(this); defaultStack = EnchantableItem.enchant(UItems.GEMSTONE.getDefaultStack(), this);
} }
public boolean isObtainable() { public boolean isObtainable() {

View file

@ -9,8 +9,6 @@ import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.advancement.UCriteria; import com.minelittlepony.unicopia.advancement.UCriteria;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.network.Channel; import com.minelittlepony.unicopia.network.Channel;
@ -33,7 +31,6 @@ import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.registry.Registries; import net.minecraft.registry.Registries;
import net.minecraft.registry.RegistryWrapper.WrapperLookup; import net.minecraft.registry.RegistryWrapper.WrapperLookup;
import net.minecraft.world.World;
public class TraitDiscovery implements NbtSerialisable, Copyable<TraitDiscovery> { public class TraitDiscovery implements NbtSerialisable, Copyable<TraitDiscovery> {
private final Set<Trait> unreadTraits = new HashSet<>(); private final Set<Trait> unreadTraits = new HashSet<>();
@ -114,7 +111,7 @@ public class TraitDiscovery implements NbtSerialisable, Copyable<TraitDiscovery>
} }
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
public void appendTooltip(ItemStack stack, @Nullable World world, List<Text> tooltip) { public void appendTooltip(ItemStack stack, List<Text> tooltip) {
SpellTraits.getEmbeddedTraits(stack) SpellTraits.getEmbeddedTraits(stack)
.orElseGet(() -> getKnownTraits(stack.getItem())) .orElseGet(() -> getKnownTraits(stack.getItem()))
.appendTooltip(tooltip); .appendTooltip(tooltip);

View file

@ -1,146 +1,52 @@
package com.minelittlepony.unicopia.client; package com.minelittlepony.unicopia.client;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.diet.PonyDiets;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback; import com.minelittlepony.unicopia.item.EnchantableItem;
import net.minecraft.client.MinecraftClient; import com.minelittlepony.unicopia.item.GlowableItem;
import com.minelittlepony.unicopia.item.component.UDataComponentTypes;
import net.minecraft.component.ComponentType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.tooltip.TooltipAppender;
import net.minecraft.item.tooltip.TooltipType; import net.minecraft.item.tooltip.TooltipType;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
public class ModifierTooltipRenderer implements ItemTooltipCallback { public class ModifierTooltipRenderer {
public static final ModifierTooltipRenderer INSTANCE = new ModifierTooltipRenderer();
@Override public void getTooltip(ItemStack stack, Item.TooltipContext context, @Nullable PlayerEntity player, TooltipType type, List<Text> lines) {
public void getTooltip(ItemStack stack, Item.TooltipContext tooltipContext, TooltipType tooltipType, List<Text> lines) { @Nullable
Pony pony = Pony.of(player);
// TODO: Evaluate if we still need this if (pony != null) {
/*int flags = stack.hasNbt() && stack.getNbt().contains("HideFlags", 99) ? stack.getNbt().getInt("HideFlags") : 0; pony.getDiscoveries().appendTooltip(stack, lines);
if (isShowing(flags, ItemStack.TooltipSection.MODIFIERS)) {
Enchantment s;
Map<EquipmentSlot, Multimap<EntityAttribute, EntityAttributeModifier>> modifiers = new HashMap<>();
Equine.<PlayerEntity, Pony>of(MinecraftClient.getInstance().player).ifPresent(eq -> {
getEnchantments(stack).filter(p -> p.getRight() instanceof AttributedEnchantment).forEach(pair -> {
((AttributedEnchantment)pair.getRight()).getModifiers(eq, pair.getLeft(), modifiers);
});
});
modifiers.forEach((slot, modifs) -> {
List<Text> newLines = new ArrayList<>();
modifs.entries().stream()
.filter(entry -> entry.getKey().equals(EntityAttributes.GENERIC_MOVEMENT_SPEED) || UEntityAttributes.REGISTRY.contains(entry.getKey()))
.forEach(entry -> describeModifiers(entry.getKey(), entry.getValue(), null, newLines));
if (!newLines.isEmpty()) {
Text find = Text.translatable("item.modifiers." + slot.getName()).formatted(Formatting.GRAY);
int insertPosition = getInsertPosition(stack, find, flags, lines, tooltipType.isAdvanced());
if (insertPosition == -1) {
lines.add(ScreenTexts.EMPTY);
lines.add(find);
lines.addAll(newLines);
} else {
lines.addAll(insertPosition, newLines);
}
}
});
}*/
if (MinecraftClient.getInstance().player != null) {
Pony.of(MinecraftClient.getInstance().player).getDiscoveries().appendTooltip(stack, MinecraftClient.getInstance().world, lines);
}
}
/*
private int getInsertPosition(ItemStack stack, Text category, int flags, List<Text> lines, boolean advanced) {
int insertPosition = lines.indexOf(category);
if (insertPosition > -1) {
return insertPosition + 1;
} }
if (insertPosition == -1 && stack.hasNbt()) { Consumer<Text> textConsumer = lines::add;
if (isShowing(flags, ItemStack.TooltipSection.MODIFIERS) && stack.getNbt().getBoolean("Unbreakable")) {
insertPosition = checkFor(lines, Text.translatable("item.unbreakable").formatted(Formatting.BLUE));
}
if (insertPosition == -1 && isShowing(flags, ItemStack.TooltipSection.CAN_DESTROY) && stack.getNbt().contains("CanDestroy", 9)) { appendTooltip(stack, UDataComponentTypes.CHARGES, context, textConsumer, type);
insertPosition = checkFor(lines, Text.translatable("item.canBreak").formatted(Formatting.GRAY)); appendTooltip(stack, UDataComponentTypes.ISSUER, context, textConsumer, type);
} EnchantableItem.getSpellEffect(stack).appendTooltip(context, textConsumer, type);
if (GlowableItem.isGlowing(stack)) {
if (insertPosition == -1 && isShowing(flags, ItemStack.TooltipSection.CAN_PLACE) && stack.getNbt().contains("CanPlaceOn", 9)) { lines.add(Text.translatable("item.unicopia.friendship_bracelet.glowing").formatted(Formatting.ITALIC, Formatting.GRAY));
insertPosition = checkFor(lines, Text.translatable("item.canPlace").formatted(Formatting.GRAY));
}
} }
if (insertPosition == -1 && advanced) { PonyDiets.getInstance().getDiet(pony).appendTooltip(stack, pony, lines, type);
if (stack.isDamaged()) {
insertPosition = checkFor(lines, Text.translatable("item.durability", stack.getMaxDamage() - stack.getDamage(), stack.getMaxDamage()));
} else {
insertPosition = checkFor(lines, Text.literal(Registries.ITEM.getId(stack.getItem()).toString()).formatted(Formatting.DARK_GRAY));
}
}
return insertPosition;
} }
private int checkFor(List<Text> lines, Text category) { private <T extends TooltipAppender> void appendTooltip(ItemStack stack, ComponentType<T> componentType, Item.TooltipContext context, Consumer<Text> textConsumer, TooltipType type) {
return lines.indexOf(category); T tooltipAppender = stack.get(componentType);
} if (tooltipAppender != null) {
tooltipAppender.appendTooltip(context, textConsumer, type);
private void describeModifiers(RegistryEntry<EntityAttribute> attribute, EntityAttributeModifier modifier, @Nullable PlayerEntity player, List<Text> lines) {
double value = modifier.value();
boolean baseAdjusted = false;
if (player != null) {
value += player.getAttributeBaseValue(attribute);
baseAdjusted = true;
}
Operation op = modifier.operation();
double displayValue;
if (op != EntityAttributeModifier.Operation.ADD_MULTIPLIED_BASE && op != EntityAttributeModifier.Operation.ADD_MULTIPLIED_TOTAL) {
displayValue = value;
} else {
displayValue = value * 100;
}
if (baseAdjusted) {
lines.add(Text.literal(" ").append(getModifierLineBase("equals", displayValue, op, attribute, Formatting.DARK_GREEN)));
} else if (value > 0) {
lines.add(getModifierLineBase("plus", displayValue, op, attribute, attribute == UEntityAttributes.ENTITY_GRAVITY_MODIFIER ? Formatting.RED : Formatting.BLUE));
} else if (value < 0) {
lines.add(getModifierLineBase("take", -displayValue, op, attribute, attribute == UEntityAttributes.ENTITY_GRAVITY_MODIFIER ? Formatting.BLUE : Formatting.RED));
} }
} }
private Text getModifierLineBase(String root, double displayValue, Operation op, EntityAttribute attribute, Formatting color) {
return Text.translatable("attribute.modifier." + root + "." + op.getId(),
ItemStack.MODIFIER_FORMAT.format(displayValue),
Text.translatable(attribute.getTranslationKey())
).formatted(color);
}
private static boolean isShowing(int flags, ItemStack.TooltipSection section) {
return (flags & section.getFlag()) == 0;
}
private static Stream<Pair<Integer, Enchantment>> getEnchantments(ItemStack stack) {
if (!stack.isEmpty()) {
return stack.getEnchantments()
.stream()
.map(t -> (NbtCompound)t)
.map(tag -> Registries.ENCHANTMENT.getOrEmpty(Identifier.tryParse(tag.getString("id")))
.map(ench -> new Pair<>(tag.getInt("lvl"), ench)))
.filter(Optional::isPresent)
.map(Optional::get);
}
return Stream.empty();
}
*/
} }

View file

@ -27,7 +27,6 @@ import com.minelittlepony.unicopia.util.Lerp;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.OpenToLanScreen; import net.minecraft.client.gui.screen.OpenToLanScreen;
@ -145,7 +144,6 @@ public class UnicopiaClient implements ClientModInitializer {
ClientTickEvents.END_CLIENT_TICK.register(this::onTick); ClientTickEvents.END_CLIENT_TICK.register(this::onTick);
ClientTickEvents.END_WORLD_TICK.register(this::onWorldTick); ClientTickEvents.END_WORLD_TICK.register(this::onWorldTick);
ScreenInitCallback.EVENT.register(this::onScreenInit); ScreenInitCallback.EVENT.register(this::onScreenInit);
ItemTooltipCallback.EVENT.register(new ModifierTooltipRenderer());
ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(ViewportShader.INSTANCE); ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(ViewportShader.INSTANCE);
ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(SpellEffectsRenderDispatcher.INSTANCE); ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(SpellEffectsRenderDispatcher.INSTANCE);

View file

@ -19,6 +19,8 @@ import net.minecraft.client.gui.*;
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
import net.minecraft.client.sound.PositionedSoundInstance; import net.minecraft.client.sound.PositionedSoundInstance;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.Item.TooltipContext;
import net.minecraft.item.tooltip.TooltipType;
import net.minecraft.screen.ScreenTexts; import net.minecraft.screen.ScreenTexts;
import net.minecraft.text.MutableText; import net.minecraft.text.MutableText;
import net.minecraft.text.Text; import net.minecraft.text.Text;
@ -205,7 +207,7 @@ public class DismissSpellScreen extends GameGui {
tooltip.add(Text.translatable("gui.unicopia.dispell_screen.spell_type", name)); tooltip.add(Text.translatable("gui.unicopia.dispell_screen.spell_type", name));
type.traits().appendTooltip(tooltip); type.traits().appendTooltip(tooltip);
tooltip.add(ScreenTexts.EMPTY); tooltip.add(ScreenTexts.EMPTY);
type.appendTooltip(tooltip); type.appendTooltip(TooltipContext.create(client.world), tooltip::add, TooltipType.BASIC);
tooltip.add(ScreenTexts.EMPTY); tooltip.add(ScreenTexts.EMPTY);
if (spell instanceof TimedSpell timed) { if (spell instanceof TimedSpell timed) {
tooltip.add(ScreenTexts.EMPTY); tooltip.add(ScreenTexts.EMPTY);

View file

@ -32,6 +32,8 @@ import net.minecraft.client.gui.screen.recipebook.RecipeBookWidget;
import net.minecraft.client.render.GameRenderer; import net.minecraft.client.render.GameRenderer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.Item.TooltipContext;
import net.minecraft.item.tooltip.TooltipType;
import net.minecraft.screen.slot.Slot; import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
@ -209,7 +211,7 @@ public class SpellbookScreen extends HandledScreen<SpellbookScreenHandler> imple
List<Text> tooltip = new ArrayList<>(); List<Text> tooltip = new ArrayList<>();
tooltip.add(spell.type().getName()); tooltip.add(spell.type().getName());
spell.appendTooltip(tooltip); spell.appendTooltip(TooltipContext.create(client.world), tooltip::add, TooltipType.BASIC);
context.drawTooltip(textRenderer, tooltip, x, y); context.drawTooltip(textRenderer, tooltip, x, y);
context.getMatrices().pop(); context.getMatrices().pop();

View file

@ -103,11 +103,10 @@ public class Main implements EmiPlugin {
.filter(recipe -> recipe.value() instanceof SpellShapedCraftingRecipe) .filter(recipe -> recipe.value() instanceof SpellShapedCraftingRecipe)
.forEach(recipe -> { .forEach(recipe -> {
ItemStack output = recipe.value().getResult(registries); ItemStack output = recipe.value().getResult(registries);
if (output.getItem() instanceof MultiItem multiItem && output.getItem() instanceof EnchantableItem enchantable) { if (output.getItem() instanceof MultiItem multiItem) {
multiItem.getDefaultStacks().forEach(outputVariation -> { multiItem.getDefaultStacks().forEach(outputVariation -> {
var spellEffect = enchantable.getSpellEffect(outputVariation); if (EnchantableItem.isEnchanted(outputVariation)) {
if (!spellEffect.isEmpty()) { registry.addRecipe(new MagicalShapedEmiRecipe(recipe, EnchantableItem.getSpellEffect(outputVariation), outputVariation));
registry.addRecipe(new MagicalShapedEmiRecipe(recipe, spellEffect, outputVariation));
} }
}); });
} }

View file

@ -11,14 +11,12 @@ import java.util.stream.Collectors;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.ItemDuck;
import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder; import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.component.DataComponentTypes; import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.FoodComponent; import net.minecraft.component.type.FoodComponent;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.tooltip.TooltipType; import net.minecraft.item.tooltip.TooltipType;
import net.minecraft.network.RegistryByteBuf; import net.minecraft.network.RegistryByteBuf;
@ -80,7 +78,7 @@ public record DietProfile(
} }
static boolean isForaged(ItemStack stack) { static boolean isForaged(ItemStack stack) {
return ((ItemDuck)stack.getItem()).getOriginalFoodComponent().isEmpty(); return stack.getComponents().get(DataComponentTypes.FOOD) == null;
} }
@Nullable @Nullable
@ -125,10 +123,17 @@ public record DietProfile(
return Pair.of(hungerMultiplier, saturationMultiplier); return Pair.of(hungerMultiplier, saturationMultiplier);
} }
public void appendTooltip(ItemStack stack, @Nullable PlayerEntity user, List<Text> tooltip, TooltipType context) { public void appendTooltip(ItemStack stack, @Nullable Pony pony, List<Text> tooltip, TooltipType context) {
var food = stack.get(DataComponentTypes.FOOD); if (this == EMPTY) {
return;
}
tooltip.add(Text.translatable("unicopia.diet.information").formatted(Formatting.DARK_PURPLE));
findEffect(stack).orElseGet(() -> PonyDiets.getInstance().getEffects(stack)).appendTooltip(stack, tooltip, context);
var food = stack.get(DataComponentTypes.FOOD);
var ratios = getRatios(stack); var ratios = getRatios(stack);
if (food == null || isInedible(ratios)) { if (food == null || isInedible(ratios)) {
if (stack.getUseAction() != UseAction.DRINK) { if (stack.getUseAction() != UseAction.DRINK) {
tooltip.add(Text.literal(" ").append(Text.translatable("unicopia.diet.not_edible")).formatted(Formatting.DARK_GRAY)); tooltip.add(Text.literal(" ").append(Text.translatable("unicopia.diet.not_edible")).formatted(Formatting.DARK_GRAY));
@ -139,7 +144,7 @@ public record DietProfile(
float baseMultiplier = (isForaged(stack) ? foragingMultiplier() : defaultMultiplier()); float baseMultiplier = (isForaged(stack) ? foragingMultiplier() : defaultMultiplier());
if (context.isAdvanced()) { if (context.isAdvanced()) {
var nonAdjustedFood = getNonAdjustedFoodComponent(stack, user).orElse(food); var nonAdjustedFood = getNonAdjustedFoodComponent(stack, pony).orElse(food);
tooltip.add(Text.literal(" ").append(Text.translatable("unicopia.diet.base_multiplier", baseMultiplier).formatted(Formatting.DARK_GRAY))); tooltip.add(Text.literal(" ").append(Text.translatable("unicopia.diet.base_multiplier", baseMultiplier).formatted(Formatting.DARK_GRAY)));
tooltip.add(Text.literal(" ").append(Text.translatable("unicopia.diet.hunger.detailed", food.nutrition(), nonAdjustedFood.nutrition(), (int)(ratios.getFirst() * 100))).formatted(Formatting.DARK_GRAY)); tooltip.add(Text.literal(" ").append(Text.translatable("unicopia.diet.hunger.detailed", food.nutrition(), nonAdjustedFood.nutrition(), (int)(ratios.getFirst() * 100))).formatted(Formatting.DARK_GRAY));
tooltip.add(Text.literal(" ").append(Text.translatable("unicopia.diet.saturation.detailed", food.saturation(), nonAdjustedFood.saturation(), (int)(ratios.getSecond() * 100))).formatted(Formatting.DARK_GRAY)); tooltip.add(Text.literal(" ").append(Text.translatable("unicopia.diet.saturation.detailed", food.saturation(), nonAdjustedFood.saturation(), (int)(ratios.getSecond() * 100))).formatted(Formatting.DARK_GRAY));
@ -149,18 +154,20 @@ public record DietProfile(
} }
} }
private Optional<FoodComponent> getNonAdjustedFoodComponent(ItemStack stack, @Nullable PlayerEntity user) { private Optional<FoodComponent> getNonAdjustedFoodComponent(ItemStack stack, @Nullable Pony pony) {
@Nullable FoodComponent food = stack.getComponents().get(DataComponentTypes.FOOD);
Pony pony = Pony.of(user);
Optional<FoodComponent> food = ((ItemDuck)stack.getItem()).getOriginalFoodComponent();
if (food.isEmpty() && pony.getObservedSpecies().hasIronGut()) { if (food != null) {
return Optional.ofNullable(food);
}
if (pony != null && pony.getObservedSpecies().hasIronGut()) {
return findEffect(stack) return findEffect(stack)
.flatMap(Effect::foodComponent) .flatMap(Effect::foodComponent)
.or(() -> PonyDiets.getInstance().getEffects(stack).foodComponent()); .or(() -> PonyDiets.getInstance().getEffects(stack).foodComponent());
} }
return food; return Optional.empty();
} }
public record Multiplier( public record Multiplier(

View file

@ -1,13 +1,8 @@
package com.minelittlepony.unicopia.diet; package com.minelittlepony.unicopia.diet;
import java.util.List;
import org.jetbrains.annotations.Nullable;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.tooltip.TooltipType;
import net.minecraft.text.Text;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult; import net.minecraft.util.TypedActionResult;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -16,12 +11,4 @@ public interface DietView {
TypedActionResult<ItemStack> startUsing(ItemStack stack, World world, PlayerEntity user, Hand hand); TypedActionResult<ItemStack> startUsing(ItemStack stack, World world, PlayerEntity user, Hand hand);
void finishUsing(ItemStack stack, World world, LivingEntity entity); void finishUsing(ItemStack stack, World world, LivingEntity entity);
void appendTooltip(ItemStack stack, @Nullable PlayerEntity user, List<Text> tooltip, TooltipType context);
interface Holder {
default DietView getDiets(ItemStack stack) {
return PonyDiets.getInstance();
}
}
} }

View file

@ -1,7 +1,6 @@
package com.minelittlepony.unicopia.diet; package com.minelittlepony.unicopia.diet;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -9,19 +8,14 @@ import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.entity.effect.FoodPoisoningStatusEffect; import com.minelittlepony.unicopia.entity.effect.FoodPoisoningStatusEffect;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.ItemDuck;
import com.minelittlepony.unicopia.util.serialization.PacketCodecUtils; import com.minelittlepony.unicopia.util.serialization.PacketCodecUtils;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.tooltip.TooltipType;
import net.minecraft.network.RegistryByteBuf; import net.minecraft.network.RegistryByteBuf;
import net.minecraft.network.codec.PacketCodec; import net.minecraft.network.codec.PacketCodec;
import net.minecraft.network.codec.PacketCodecs; import net.minecraft.network.codec.PacketCodecs;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.TypedActionResult; import net.minecraft.util.TypedActionResult;
@ -57,11 +51,11 @@ public class PonyDiets implements DietView {
this.effects = effects; this.effects = effects;
} }
private DietProfile getDiet(Pony pony) { public DietProfile getDiet(Pony pony) {
return Optional.ofNullable(diets.get(pony.getObservedSpecies())).orElse(DietProfile.EMPTY); return Optional.ofNullable(diets.get(pony.getObservedSpecies())).orElse(DietProfile.EMPTY);
} }
Effect getEffects(ItemStack stack) { public Effect getEffects(ItemStack stack) {
return effects.values().stream().filter(effect -> effect.test(stack)).findFirst().map(Effect.class::cast).orElse(Effect.EMPTY); return effects.values().stream().filter(effect -> effect.test(stack)).findFirst().map(Effect.class::cast).orElse(Effect.EMPTY);
} }
@ -71,50 +65,11 @@ public class PonyDiets implements DietView {
@Override @Override
public TypedActionResult<ItemStack> startUsing(ItemStack stack, World world, PlayerEntity user, Hand hand) { public TypedActionResult<ItemStack> startUsing(ItemStack stack, World world, PlayerEntity user, Hand hand) {
return initEdibility(stack, user) return FoodPoisoningStatusEffect.apply(stack, user);
? FoodPoisoningStatusEffect.apply(stack, user)
: TypedActionResult.fail(stack);
} }
@Override @Override
public void finishUsing(ItemStack stack, World world, LivingEntity entity) { public void finishUsing(ItemStack stack, World world, LivingEntity entity) {
if (initEdibility(stack, entity)) { Pony.of(entity).ifPresent(pony -> getEffects(stack, pony).ailment().effects().afflict(pony.asEntity(), stack));
Pony.of(entity).ifPresent(pony -> getEffects(stack, pony).ailment().effects().afflict(pony.asEntity(), stack));
}
}
@Override
public void appendTooltip(ItemStack stack, @Nullable PlayerEntity user, List<Text> tooltip, TooltipType context) {
if (initEdibility(stack, user)) {
if (!((ItemDuck)stack.getItem()).getOriginalFoodComponent().isEmpty() || stack.contains(DataComponentTypes.FOOD)) {
Pony pony = Pony.of(user);
tooltip.add(Text.translatable("unicopia.diet.information").formatted(Formatting.DARK_PURPLE));
getEffects(stack, pony).appendTooltip(stack, tooltip, context);
getDiet(pony).appendTooltip(stack, user, tooltip, context);
}
}
}
private boolean initEdibility(ItemStack stack, LivingEntity user) {
ItemDuck item = (ItemDuck)stack.getItem();
item.resetFoodComponent();
return Pony.of(user).filter(pony -> {
DietProfile diet = getDiet(pony);
if (!stack.contains(DataComponentTypes.FOOD) && pony.getObservedSpecies().hasIronGut()) {
diet.findEffect(stack)
.flatMap(Effect::foodComponent)
.or(() -> getEffects(stack).foodComponent())
.ifPresent(item::setFoodComponent);
}
if (stack.contains(DataComponentTypes.FOOD)) {
item.setFoodComponent(diet.getAdjustedFoodComponent(stack));
}
return true;
}).isPresent();
} }
} }

View file

@ -41,7 +41,6 @@ public class AmuletItem extends WearableItem {
@Override @Override
public void appendTooltip(ItemStack stack, TooltipContext context, List<Text> list, TooltipType type) { public void appendTooltip(ItemStack stack, TooltipContext context, List<Text> list, TooltipType type) {
for (StringVisitable line : MinecraftClient.getInstance().textRenderer.getTextHandler().wrapLines( for (StringVisitable line : MinecraftClient.getInstance().textRenderer.getTextHandler().wrapLines(
Text.translatable(getTranslationKey(stack) + ".lore"), 150, Style.EMPTY)) { Text.translatable(getTranslationKey(stack) + ".lore"), 150, Style.EMPTY)) {
MutableText compiled = Text.literal("").formatted(Formatting.ITALIC, Formatting.GRAY); MutableText compiled = Text.literal("").formatted(Formatting.ITALIC, Formatting.GRAY);
@ -51,8 +50,7 @@ public class AmuletItem extends WearableItem {
}); });
list.add(compiled); list.add(compiled);
} }
super.appendTooltip(stack, context, list, type);
Charges.of(stack).appendTooltip(context, list::add, type);
} }
@Override @Override

View file

@ -1,6 +1,5 @@
package com.minelittlepony.unicopia.item; package com.minelittlepony.unicopia.item;
import java.util.List;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.entity.Creature; import com.minelittlepony.unicopia.entity.Creature;
@ -22,10 +21,8 @@ import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.tooltip.TooltipType;
import net.minecraft.particle.ParticleEffect; import net.minecraft.particle.ParticleEffect;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult; import net.minecraft.util.TypedActionResult;
@ -43,11 +40,6 @@ public class BellItem extends Item {
return UseAction.BOW; return UseAction.BOW;
} }
@Override
public void appendTooltip(ItemStack stack, TooltipContext context, List<Text> list, TooltipType type) {
Charges.of(stack).appendTooltip(context, list::add, type);
}
@Override @Override
public int getMaxUseTime(ItemStack stack, LivingEntity user) { public int getMaxUseTime(ItemStack stack, LivingEntity user) {
return 3000; return 3000;

View file

@ -19,12 +19,7 @@ import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult; import net.minecraft.util.TypedActionResult;
public interface EnchantableItem extends ItemConvertible { public interface EnchantableItem extends ItemConvertible {
static CustomisedSpellType<?> getSpellEffect(ItemStack stack) {
default ItemStack getDefaultStack(SpellType<?> spell) {
return enchant(asItem().getDefaultStack(), spell);
}
default CustomisedSpellType<?> getSpellEffect(ItemStack stack) {
return EnchantableItem.getSpellKey(stack).withTraits(SpellTraits.of(stack)); return EnchantableItem.getSpellKey(stack).withTraits(SpellTraits.of(stack));
} }

View file

@ -102,7 +102,6 @@ public class EnchantedStaffItem extends StaffItem implements EnchantableItem, Mu
SpellType<?> key = EnchantableItem.getSpellKey(stack); SpellType<?> key = EnchantableItem.getSpellKey(stack);
lines.add(Text.translatable(key.getTranslationKey()).formatted(key.getAffinity().getColor())); lines.add(Text.translatable(key.getTranslationKey()).formatted(key.getAffinity().getColor()));
} }
Charges.of(stack).appendTooltip(context, lines::add, type);
} }
@Override @Override
@ -144,7 +143,7 @@ public class EnchantedStaffItem extends StaffItem implements EnchantableItem, Mu
Pony.of(entity).ifPresent(pony -> { Pony.of(entity).ifPresent(pony -> {
pony.subtractEnergyCost(4); pony.subtractEnergyCost(4);
stack.damage(1, pony.asEntity(), EquipmentSlot.MAINHAND); stack.damage(1, pony.asEntity(), EquipmentSlot.MAINHAND);
getSpellEffect(stack).create().toThrowable().throwProjectile(pony); EnchantableItem.getSpellEffect(stack).create().toThrowable().throwProjectile(pony);
pony.setAnimation(Animation.ARMS_UP, Animation.Recipient.ANYONE, 10); pony.setAnimation(Animation.ARMS_UP, Animation.Recipient.ANYONE, 10);
}); });
} }
@ -153,7 +152,7 @@ public class EnchantedStaffItem extends StaffItem implements EnchantableItem, Mu
Pony.of(entity).ifPresent(pony -> { Pony.of(entity).ifPresent(pony -> {
pony.subtractEnergyCost(4); pony.subtractEnergyCost(4);
stack.damage(1, pony.asEntity(), EquipmentSlot.MAINHAND); stack.damage(1, pony.asEntity(), EquipmentSlot.MAINHAND);
getSpellEffect(stack).create().toThrowable().throwProjectile(pony); EnchantableItem.getSpellEffect(stack).create().toThrowable().throwProjectile(pony);
pony.setAnimation(Animation.ARMS_UP, Animation.Recipient.ANYONE, 10); pony.setAnimation(Animation.ARMS_UP, Animation.Recipient.ANYONE, 10);
}); });
} }
@ -166,7 +165,7 @@ public class EnchantedStaffItem extends StaffItem implements EnchantableItem, Mu
if (attacker.isSneaking() && Charges.discharge(stack, 1)) { if (attacker.isSneaking() && Charges.discharge(stack, 1)) {
stack.damage(50, attacker, EquipmentSlot.MAINHAND); stack.damage(50, attacker, EquipmentSlot.MAINHAND);
Caster.of(attacker).ifPresent(c -> c.subtractEnergyCost(4)); Caster.of(attacker).ifPresent(c -> c.subtractEnergyCost(4));
Caster.of(target).ifPresent(c -> getSpellEffect(stack).apply(c, CastingMethod.STAFF)); Caster.of(target).ifPresent(c -> EnchantableItem.getSpellEffect(stack).apply(c, CastingMethod.STAFF));
} }
return false; return false;
@ -193,7 +192,7 @@ public class EnchantedStaffItem extends StaffItem implements EnchantableItem, Mu
living.clearActiveItem(); living.clearActiveItem();
living.damage(entity.getDamageSources().magic(), 1); living.damage(entity.getDamageSources().magic(), 1);
if (EnchantableItem.isEnchanted(stack) && Charges.discharge(stack, 1)) { if (EnchantableItem.isEnchanted(stack) && Charges.discharge(stack, 1)) {
Caster.of(entity).ifPresent(c -> getSpellEffect(stack).apply(c, CastingMethod.STAFF)); Caster.of(entity).ifPresent(c -> EnchantableItem.getSpellEffect(stack).apply(c, CastingMethod.STAFF));
} }
} }
} }

View file

@ -1,6 +1,5 @@
package com.minelittlepony.unicopia.item; package com.minelittlepony.unicopia.item;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -15,19 +14,13 @@ import com.minelittlepony.unicopia.compat.trinkets.TrinketsDelegate;
import com.minelittlepony.unicopia.entity.AmuletSelectors; import com.minelittlepony.unicopia.entity.AmuletSelectors;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.component.Issuer; import com.minelittlepony.unicopia.item.component.Issuer;
import com.minelittlepony.unicopia.item.component.UDataComponentTypes;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.tooltip.TooltipType;
import net.minecraft.stat.Stats; import net.minecraft.stat.Stats;
import net.minecraft.text.Text;
import net.minecraft.util.*; import net.minecraft.util.*;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -69,18 +62,6 @@ public class FriendshipBraceletItem extends WearableItem {
return super.use(world, player, hand); return super.use(world, player, hand);
} }
@Override
@Environment(EnvType.CLIENT)
public void appendTooltip(ItemStack stack, TooltipContext context, List<Text> lines, TooltipType type) {
super.appendTooltip(stack, context, lines, type);
if (Issuer.isSigned(stack)) {
stack.get(UDataComponentTypes.ISSUER).appendTooltip(context, lines::add, type);
}
if (GlowableItem.isGlowing(stack)) {
lines.add(Text.translatable("item.unicopia.friendship_bracelet.glowing").formatted(Formatting.ITALIC, Formatting.GRAY));
}
}
@Override @Override
public EquipmentSlot getSlotType(ItemStack stack) { public EquipmentSlot getSlotType(ItemStack stack) {
return Issuer.isSigned(stack) ? EquipmentSlot.CHEST : super.getSlotType(stack); return Issuer.isSigned(stack) ? EquipmentSlot.CHEST : super.getSlotType(stack);

View file

@ -14,13 +14,12 @@ import com.minelittlepony.unicopia.item.group.MultiItem;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.tooltip.TooltipType;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult; import net.minecraft.util.TypedActionResult;
import net.minecraft.world.World; import net.minecraft.world.World;
public class GemstoneItem extends Item implements MultiItem, EnchantableItem { public class GemstoneItem extends Item implements MultiItem {
public GemstoneItem(Settings settings) { public GemstoneItem(Settings settings) {
super(settings); super(settings);
@ -71,15 +70,6 @@ public class GemstoneItem extends Item implements MultiItem, EnchantableItem {
return result; return result;
} }
@Override
public void appendTooltip(ItemStack stack, TooltipContext context, List<Text> lines, TooltipType type) {
super.appendTooltip(stack, context, lines, type);
if (EnchantableItem.isEnchanted(stack)) {
getSpellEffect(stack).appendTooltip(lines);
}
}
@Override @Override
public List<ItemStack> getDefaultStacks() { public List<ItemStack> getDefaultStacks() {
return SpellType.REGISTRY.stream() return SpellType.REGISTRY.stream()

View file

@ -1,24 +1,7 @@
package com.minelittlepony.unicopia.item; package com.minelittlepony.unicopia.item;
import java.util.Optional;
import com.minelittlepony.unicopia.diet.DietView;
import com.minelittlepony.unicopia.entity.ItemImpl; import com.minelittlepony.unicopia.entity.ItemImpl;
import net.minecraft.component.type.FoodComponent;
import net.minecraft.item.*; import net.minecraft.item.*;
public interface ItemDuck extends ItemConvertible, ItemImpl.TickableItem, DietView.Holder { public interface ItemDuck extends ItemConvertible, ItemImpl.TickableItem {
@Deprecated
void setFoodComponent(FoodComponent food);
// TODO: Inject into Item.Settings::getComponents and return our own implementation of ComponentMap to handle food component overrides
// ItemStack(ComponentMapImpl(UnicopiaComponentMap(ItemComponentMap()), Changes))
@Deprecated
Optional<FoodComponent> getOriginalFoodComponent();
@Deprecated
default void resetFoodComponent() {
setFoodComponent(getOriginalFoodComponent().orElse(null));
}
} }

View file

@ -0,0 +1,20 @@
package com.minelittlepony.unicopia.item;
import com.minelittlepony.unicopia.item.component.TransientComponentMap;
import net.minecraft.component.ComponentHolder;
import net.minecraft.item.ItemStack;
public interface ItemStackDuck extends ComponentHolder, TransientComponentMap.Holder {
default ItemDuck getItemDuck() {
return (ItemDuck)((ItemStack)(Object)this).getItem();
}
static ItemStackDuck of(ItemStack stack) {
return (ItemStackDuck)(Object)stack;
}
static boolean isItemStack(Object o) {
return o instanceof ItemStackDuck;
}
}

View file

@ -0,0 +1,91 @@
package com.minelittlepony.unicopia.item.component;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiFunction;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.diet.DietProfile;
import com.minelittlepony.unicopia.diet.Effect;
import com.minelittlepony.unicopia.diet.PonyDiets;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.ItemStackDuck;
import net.minecraft.component.ComponentType;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.entity.Entity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Util;
public class TransientComponentMap {
private static final BiFunction<ItemStack, ?, ?> DEFAULT = (stack, t) -> t;
public static final TransientComponentMap INITIAL = Util.make(new TransientComponentMap(), map -> {
map.set(UDataComponentTypes.DIET_PROFILE, (s, original) -> {
if (original != null) {
return original;
}
return ItemStackDuck.of(s).getTransientComponents().getCarrier()
.flatMap(Pony::of)
.map(pony -> PonyDiets.getInstance().getDiet(pony))
.orElse(DietProfile.EMPTY);
});
map.set(DataComponentTypes.FOOD, (s, originalFood) -> {
DietProfile diet = s.get(UDataComponentTypes.DIET_PROFILE);
if (diet == null) {
return originalFood;
}
if (originalFood != null) {
return diet.getAdjustedFoodComponent(s);
}
if (ItemStackDuck.of(s).getTransientComponents().getCarrier()
.flatMap(Pony::of)
.filter(pony -> pony.getObservedSpecies().hasIronGut())
.isPresent()) {
return diet.findEffect(s)
.flatMap(Effect::foodComponent)
.or(() -> PonyDiets.getInstance().getEffects(s).foodComponent())
.orElse(originalFood);
}
return originalFood;
});
});
private final Map<ComponentType<?>, BiFunction<ItemStack, ?, ?>> components = new HashMap<>();
private Optional<Entity> carrier = Optional.empty();
private TransientComponentMap() {}
public Optional<Entity> getCarrier() {
return carrier;
}
public void setCarrier(@Nullable Entity carrier) {
this.carrier = Optional.ofNullable(carrier);
}
public <T> void set(ComponentType<? extends T> type, BiFunction<ItemStack, T, T> getter) {
components.put(type, getter);
}
@SuppressWarnings("unchecked")
public <T> T get(ComponentType<? extends T> type, ItemStack stack, T upstreamValue) {
return ((BiFunction<ItemStack, T, T>)components.getOrDefault(type, DEFAULT)).apply(stack, upstreamValue);
}
public TransientComponentMap createCopy() {
TransientComponentMap copy = new TransientComponentMap();
copy.components.putAll(components);
return copy;
}
public interface Holder {
TransientComponentMap getTransientComponents();
}
}

View file

@ -6,6 +6,7 @@ import com.minelittlepony.unicopia.Unicopia;
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.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.container.SpellbookState; import com.minelittlepony.unicopia.container.SpellbookState;
import com.minelittlepony.unicopia.diet.DietProfile;
import com.minelittlepony.unicopia.entity.mob.AirBalloonEntity; import com.minelittlepony.unicopia.entity.mob.AirBalloonEntity;
import com.minelittlepony.unicopia.entity.mob.ButterflyEntity; import com.minelittlepony.unicopia.entity.mob.ButterflyEntity;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
@ -25,6 +26,7 @@ public interface UDataComponentTypes {
ComponentType<Issuer> ISSUER = register("issuer", builder -> builder.codec(Issuer.CODEC).packetCodec(Issuer.PACKET_CODEC).cache()); ComponentType<Issuer> ISSUER = register("issuer", builder -> builder.codec(Issuer.CODEC).packetCodec(Issuer.PACKET_CODEC).cache());
ComponentType<Charges> CHARGES = register("charges", builder -> builder.codec(Charges.CODEC).packetCodec(Charges.PACKET_CODEC)); ComponentType<Charges> CHARGES = register("charges", builder -> builder.codec(Charges.CODEC).packetCodec(Charges.PACKET_CODEC));
ComponentType<Appearance> APPEARANCE = register("appearance", builder -> builder.codec(Appearance.CODEC).packetCodec(Appearance.PACKET_CODEC)); ComponentType<Appearance> APPEARANCE = register("appearance", builder -> builder.codec(Appearance.CODEC).packetCodec(Appearance.PACKET_CODEC));
ComponentType<DietProfile> DIET_PROFILE = register("diet_profile", builder -> builder.codec(DietProfile.CODEC).packetCodec(DietProfile.PACKET_CODEC));
private static <T> ComponentType<T> register(String name, UnaryOperator<ComponentType.Builder<T>> builderOperator) { private static <T> ComponentType<T> register(String name, UnaryOperator<ComponentType.Builder<T>> builderOperator) {
return Registry.register(Registries.DATA_COMPONENT_TYPE, Unicopia.id(name), builderOperator.apply(ComponentType.builder()).build()); return Registry.register(Registries.DATA_COMPONENT_TYPE, Unicopia.id(name), builderOperator.apply(ComponentType.builder()).build());

View file

@ -1,10 +0,0 @@
package com.minelittlepony.unicopia.item.enchantment;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.item.ItemStack;
import net.minecraft.registry.RegistryKey;
@Deprecated
public interface CustomEnchantableItem {
boolean isAcceptableEnchant(ItemStack stack, RegistryKey<Enchantment> enchantment);
}

View file

@ -2,36 +2,19 @@ package com.minelittlepony.unicopia.mixin;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import com.google.common.base.Suppliers;
import com.minelittlepony.unicopia.entity.ItemImpl; import com.minelittlepony.unicopia.entity.ItemImpl;
import com.minelittlepony.unicopia.entity.ItemImpl.GroundTickCallback; import com.minelittlepony.unicopia.entity.ItemImpl.GroundTickCallback;
import com.minelittlepony.unicopia.item.ItemDuck; import com.minelittlepony.unicopia.item.ItemDuck;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.FoodComponent;
import net.minecraft.item.Item; import net.minecraft.item.Item;
@Mixin(Item.class) @Mixin(Item.class)
abstract class MixinItem implements ItemDuck { abstract class MixinItem implements ItemDuck {
private final List<ItemImpl.GroundTickCallback> tickCallbacks = new ArrayList<>(); private final List<ItemImpl.GroundTickCallback> tickCallbacks = new ArrayList<>();
@Deprecated
private final Supplier<Optional<FoodComponent>> originalFoodComponent = Suppliers.memoize(() -> {
return Optional.ofNullable(((Item)(Object)this).getComponents().get(DataComponentTypes.FOOD));
});
@Override @Override
public List<GroundTickCallback> getCallbacks() { public List<GroundTickCallback> getCallbacks() {
return tickCallbacks; return tickCallbacks;
} }
@Deprecated
@Override
public Optional<FoodComponent> getOriginalFoodComponent() {
return originalFoodComponent.get();
}
} }

View file

@ -1,37 +1,89 @@
package com.minelittlepony.unicopia.mixin; package com.minelittlepony.unicopia.mixin;
import java.util.List;
import java.util.function.Consumer;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
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.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.minelittlepony.unicopia.diet.DietView; import com.minelittlepony.unicopia.diet.PonyDiets;
import com.minelittlepony.unicopia.item.DamageChecker; import com.minelittlepony.unicopia.item.DamageChecker;
import com.minelittlepony.unicopia.item.ItemStackDuck;
import com.minelittlepony.unicopia.item.component.TransientComponentMap;
import net.minecraft.component.ComponentType;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.tooltip.TooltipAppender;
import net.minecraft.item.tooltip.TooltipType;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult; import net.minecraft.util.TypedActionResult;
import net.minecraft.world.World; import net.minecraft.world.World;
@Mixin(ItemStack.class) @Mixin(ItemStack.class)
abstract class MixinItemStack { abstract class MixinItemStack implements ItemStackDuck {
private final TransientComponentMap transientComponents = TransientComponentMap.INITIAL.createCopy();
@Shadow
abstract <T extends TooltipAppender> void appendTooltip(
ComponentType<T> componentType, Item.TooltipContext context, Consumer<Text> textConsumer, TooltipType type
);
@Override
public TransientComponentMap getTransientComponents() {
return transientComponents;
}
@Inject(method = "use", at = @At("HEAD"), cancellable = true) @Inject(method = "use", at = @At("HEAD"), cancellable = true)
private void onUse(World world, PlayerEntity user, Hand hand, CallbackInfoReturnable<TypedActionResult<ItemStack>> info) { private void onUse(World world, PlayerEntity user, Hand hand, CallbackInfoReturnable<TypedActionResult<ItemStack>> info) {
ItemStack self = (ItemStack)(Object)this; transientComponents.setCarrier(user);
TypedActionResult<ItemStack> result = ((DietView.Holder)self.getItem()).getDiets(self).startUsing(self, world, user, hand); TypedActionResult<ItemStack> result = PonyDiets.getInstance().startUsing((ItemStack)(Object)this, world, user, hand);
if (result.getResult() != ActionResult.PASS) { if (result.getResult() != ActionResult.PASS) {
info.setReturnValue(result); info.setReturnValue(result);
} }
} }
@Inject(method = "onStoppedUsing", at = @At("RETURN"))
public void onOnStoppedUsing(World world, LivingEntity user, int remainingUseTicks, CallbackInfo info) {
transientComponents.setCarrier(null);
}
@Inject(method = "finishUsing", at = @At("HEAD")) @Inject(method = "finishUsing", at = @At("HEAD"))
private void onFinishUsing(World world, LivingEntity user, CallbackInfoReturnable<ItemStack> info) { private void beforeFinishUsing(World world, LivingEntity user, CallbackInfoReturnable<ItemStack> info) {
ItemStack self = (ItemStack)(Object)this; transientComponents.setCarrier(user);
((DietView.Holder)self.getItem()).getDiets(self).finishUsing(self, world, user); PonyDiets.getInstance().finishUsing((ItemStack)(Object)this, world, user);
}
@Inject(method = "finishUsing", at = @At("RETURN"))
private void afterFinishUsing(World world, LivingEntity user, CallbackInfoReturnable<ItemStack> info) {
transientComponents.setCarrier(null);
}
@Inject(method = "getTooltip", at = @At("HEAD"))
public void beforeGetTooltip(Item.TooltipContext context, @Nullable PlayerEntity player, TooltipType type, CallbackInfoReturnable<List<Text>> info) {
transientComponents.setCarrier(player);
}
@Inject(method = "getTooltip", at = @At("RETURN"))
public void afterGetTooltip(Item.TooltipContext context, @Nullable PlayerEntity player, TooltipType type, CallbackInfoReturnable<List<Text>> info) {
transientComponents.setCarrier(null);
}
@Inject(method = "getTooltip",
at = @At(value = "INVOKE",
target = "net/minecraft/item/ItemStack.appendAttributeModifiersTooltip(Ljava/util/function/Consumer;Lnet/minecraft/entity/player/PlayerEntity;)V"
))
public void onGetTooltip(Item.TooltipContext context, @Nullable PlayerEntity player, TooltipType type, CallbackInfoReturnable<List<Text>> info) {
} }
@Inject(method = "takesDamageFrom", at = @At("HEAD")) @Inject(method = "takesDamageFrom", at = @At("HEAD"))
@ -41,4 +93,28 @@ abstract class MixinItemStack {
info.setReturnValue(checker.takesDamageFrom(source)); info.setReturnValue(checker.takesDamageFrom(source));
} }
} }
@Inject(method = "get", at = @At("RETURN"))
private <T> void unicopia_onGet(ComponentType<? extends T> type, CallbackInfoReturnable<T> info) {
Object o = this;
if (o instanceof ItemStack stack) {
info.setReturnValue(ItemStackDuck.of(stack).getTransientComponents().get(type, stack, info.getReturnValue()));
}
}
@Inject(method = "getOrDefault", at = @At("RETURN"))
private <T> void unicopia_onGetOrDefault(ComponentType<? extends T> type, T fallback, CallbackInfoReturnable<T> info) {
Object o = this;
if (o instanceof ItemStack stack) {
info.setReturnValue(ItemStackDuck.of(stack).getTransientComponents().get(type, stack, info.getReturnValue()));
}
}
@Inject(method = "contains", at = @At("RETURN"))
private void unicopia_onContains(ComponentType<?> type, CallbackInfoReturnable<Boolean> info) {
Object o = this;
if (o instanceof ItemStack stack && ItemStackDuck.of(stack).getTransientComponents().get(type, stack, null) != null) {
info.setReturnValue(true);
}
}
} }

View file

@ -1,25 +0,0 @@
package com.minelittlepony.unicopia.mixin.client;
import java.util.List;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.minelittlepony.unicopia.diet.DietView;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.tooltip.TooltipType;
import net.minecraft.text.Text;
@Mixin(ItemStack.class)
abstract class MixinItemStack {
@Inject(method = "getTooltip", at = @At("RETURN"))
private void onGetTooltip(Item.TooltipContext context, @Nullable PlayerEntity player, TooltipType type, CallbackInfoReturnable<List<Text>> info) {
ItemStack self = (ItemStack)(Object)this;
((DietView.Holder)self.getItem()).getDiets(self).appendTooltip(self, player, info.getReturnValue(), type);
}
}

View file

@ -94,7 +94,6 @@
"client.MixinInGameHud", "client.MixinInGameHud",
"client.MixinInGameHud$HeartType", "client.MixinInGameHud$HeartType",
"client.MixinItemModels", "client.MixinItemModels",
"client.MixinItemStack",
"client.MixinKeyboardInput", "client.MixinKeyboardInput",
"client.MixinLivingEntityRenderer", "client.MixinLivingEntityRenderer",
"client.MixinMinecraftClient", "client.MixinMinecraftClient",