Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1.21] Add an Attribute formatting API for better control of attribute tooltips #1551

Merged
merged 27 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
90c20b0
Initial IFormattableAttribute implementation
Shadows-of-Fire Sep 18, 2024
610bee9
Finish API-ifying the implementation
Shadows-of-Fire Sep 19, 2024
c1be879
Fix sentiment on nametag distance
Shadows-of-Fire Sep 19, 2024
f5e58c2
Make potion tooltips use new extensions
Shadows-of-Fire Sep 19, 2024
0e265f9
Switch to TooltipFlag key modifier methods
Shadows-of-Fire Sep 19, 2024
8990ed5
Move group name logic to applyModifierTooltips
Shadows-of-Fire Sep 21, 2024
82321aa
Flattern TooltipUtil into AttributeUtil
Shadows-of-Fire Sep 21, 2024
2c95e34
update event sidedness docs
Shadows-of-Fire Sep 21, 2024
e9e5871
Add the ability to skip entire groups to GatherSkipped
Shadows-of-Fire Sep 21, 2024
1911a78
Remove unnecessary ItemStack patch comment
Shadows-of-Fire Sep 22, 2024
49ae124
Clean up BooleanAttribute logic
Shadows-of-Fire Sep 22, 2024
484361d
Override KBRes and MS in Attributes.java
Shadows-of-Fire Sep 22, 2024
c0fba7a
Condense IAttributeExtension#toComponent
Shadows-of-Fire Sep 22, 2024
508fbae
Use Locale.ROOT, simplify toValueComponent
Shadows-of-Fire Sep 22, 2024
814a094
Clean up toBaseComponent
Shadows-of-Fire Sep 22, 2024
30da192
Rename key neoforge.adv.base to neoforge.attribute.debug.base
Shadows-of-Fire Sep 22, 2024
1f6af2b
Lazy init skip sets in GatherSkipped
Shadows-of-Fire Sep 22, 2024
d003411
Remove unnecessary calls in the comparator
Shadows-of-Fire Sep 22, 2024
ecdb13e
Remove unneeded class specifier in AttributeUtil methods
Shadows-of-Fire Sep 22, 2024
35687bc
Move potion logic down a few lines
Shadows-of-Fire Sep 22, 2024
65e1f20
Use Holder::getKey for comparison
Shadows-of-Fire Sep 22, 2024
2b78a62
Remove resource suppression
Shadows-of-Fire Sep 22, 2024
7185337
Avoid capturing lambda
Shadows-of-Fire Sep 22, 2024
e9e355c
list() -> listHeader()
Shadows-of-Fire Sep 22, 2024
8021829
Vastly simplify tooltip merging logic
Shadows-of-Fire Sep 22, 2024
8ac0fce
Remove staged MC-271840 support
Shadows-of-Fire Sep 23, 2024
ff9981d
Better lazy-init of skip sets in GatherSkipped
Shadows-of-Fire Sep 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
--- a/net/minecraft/world/entity/ai/attributes/Attribute.java
+++ b/net/minecraft/world/entity/ai/attributes/Attribute.java
@@ -9,7 +_,7 @@
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;

-public class Attribute {
+public class Attribute implements net.neoforged.neoforge.common.extensions.IAttributeExtension {
public static final Codec<Holder<Attribute>> CODEC = BuiltInRegistries.ATTRIBUTE.holderByNameCodec();
public static final StreamCodec<RegistryFriendlyByteBuf, Holder<Attribute>> STREAM_CODEC = ByteBufCodecs.holderRegistry(Registries.ATTRIBUTE);
private final double defaultValue;
@@ -50,6 +_,21 @@

public ChatFormatting getStyle(boolean p_347715_) {
return this.sentiment.getStyle(p_347715_);
+ }
+
+ // Neo: Patch in the default implementation of IAttributeExtension#getMergedStyle since we need access to Attribute#sentiment
+
+ protected static final net.minecraft.network.chat.TextColor MERGED_RED = net.minecraft.network.chat.TextColor.fromRgb(0xF93131);
+ protected static final net.minecraft.network.chat.TextColor MERGED_BLUE = net.minecraft.network.chat.TextColor.fromRgb(0x7A7AF9);
+ protected static final net.minecraft.network.chat.TextColor MERGED_GRAY = net.minecraft.network.chat.TextColor.fromRgb(0xCCCCCC);
pupnewfster marked this conversation as resolved.
Show resolved Hide resolved
+
+ @Override
+ public net.minecraft.network.chat.TextColor getMergedStyle(boolean isPositive) {
+ return switch (this.sentiment) {
+ case POSITIVE -> isPositive ? MERGED_BLUE : MERGED_RED;
+ case NEGATIVE -> isPositive ? MERGED_RED : MERGED_BLUE;
+ case NEUTRAL -> MERGED_GRAY;
+ };
}

public static enum Sentiment {
17 changes: 16 additions & 1 deletion patches/net/minecraft/world/item/ItemStack.java.patch
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,18 @@
if (this.has(DataComponents.CUSTOM_NAME)) {
mutablecomponent.withStyle(ChatFormatting.ITALIC);
}
@@ -784,12 +_,14 @@
@@ -752,7 +_,9 @@
this.addToTooltip(DataComponents.ENCHANTMENTS, p_339637_, consumer, p_41653_);
this.addToTooltip(DataComponents.DYED_COLOR, p_339637_, consumer, p_41653_);
this.addToTooltip(DataComponents.LORE, p_339637_, consumer, p_41653_);
- this.addAttributeTooltips(consumer, p_41652_);
+ // Neo: Replace attribute tooltips with custom handling
+ net.neoforged.neoforge.client.util.TooltipUtil.addAttributeTooltips(this, consumer,
+ net.neoforged.neoforge.client.util.TooltipUtil.AttributeTooltipContext.of(p_41652_, p_339637_, p_41653_));
this.addToTooltip(DataComponents.UNBREAKABLE, p_339637_, consumer, p_41653_);
AdventureModePredicate adventuremodepredicate = this.get(DataComponents.CAN_BREAK);
if (adventuremodepredicate != null && adventuremodepredicate.showInTooltip()) {
@@ -784,12 +_,18 @@
list.add(DISABLED_ITEM_TOOLTIP);
}

Expand All @@ -157,6 +168,10 @@
}
}

+ /**
+ * @deprecated Neo: Use {@link net.neoforged.neoforge.client.util.TooltipUtil#addAttributeTooltips}
+ */
+ @Deprecated
private void addAttributeTooltips(Consumer<Component> p_330796_, @Nullable Player p_330530_) {
ItemAttributeModifiers itemattributemodifiers = this.getOrDefault(DataComponents.ATTRIBUTE_MODIFIERS, ItemAttributeModifiers.EMPTY);
+ // Neo: We don't need to call IItemStackExtension#getAttributeModifiers here, since it will be done in forEachModifier.
Shadows-of-Fire marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
13 changes: 13 additions & 0 deletions patches/net/minecraft/world/item/alchemy/PotionContents.java.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--- a/net/minecraft/world/item/alchemy/PotionContents.java
+++ b/net/minecraft/world/item/alchemy/PotionContents.java
@@ -169,6 +_,10 @@
p_331296_.accept(NO_EFFECT);
}

+ // Neo: Override handling of potion attribute tooltips to support IAttributeExtension
Shadows-of-Fire marked this conversation as resolved.
Show resolved Hide resolved
+ net.neoforged.neoforge.client.util.TooltipUtil.addPotionTooltip(list, p_331296_);
+ if (true) return;
+
if (!list.isEmpty()) {
p_331296_.accept(CommonComponents.EMPTY);
p_331296_.accept(Component.translatable("potion.whenDrank").withStyle(ChatFormatting.DARK_PURPLE));
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (c) NeoForged and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/

package net.neoforged.neoforge.client.event;

import java.util.function.Consumer;
import net.minecraft.core.component.DataComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.ItemAttributeModifiers;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.Event;
import net.neoforged.neoforge.client.util.TooltipUtil;
import net.neoforged.neoforge.client.util.TooltipUtil.AttributeTooltipContext;

/**
* This event is fired after attribute tooltip lines have been added to an item stack's tooltip in {@link TooltipUtil#addAttributeTooltips}.
* <p>
* It can be used to add additional tooltip lines adjacent to the attribute lines without having to manually locate the inject point.
* <p>
* This event is only fired on the {@linkplain Dist#CLIENT physical client}.
*/
public class AddAttributeTooltipsEvent extends Event {
protected final ItemStack stack;
protected final Consumer<Component> tooltip;
protected final AttributeTooltipContext ctx;

public AddAttributeTooltipsEvent(ItemStack stack, Consumer<Component> tooltip, AttributeTooltipContext ctx) {
this.stack = stack;
this.tooltip = tooltip;
this.ctx = ctx;
}

/**
* The current tooltip context.
*/
public AttributeTooltipContext getContext() {
return this.ctx;
}

/**
* The {@link ItemStack} with the tooltip.
*/
public ItemStack getStack() {
return this.stack;
}

/**
* Adds one or more {@link Component}s to the tooltip.
*/
public void addTooltipLines(Component... comps) {
for (Component comp : comps) {
this.tooltip.accept(comp);
}
}

/**
* Checks if the attribute tooltips should be shown on the current item stack.
* <p>
* This event is fired even if the component would prevent the normal tooltip lines from showing.
*/
public boolean shouldShow() {
return this.stack.getOrDefault(DataComponents.ATTRIBUTE_MODIFIERS, ItemAttributeModifiers.EMPTY).showInTooltip();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (c) NeoForged and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/

package net.neoforged.neoforge.client.event;

import java.util.Set;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.Event;
import net.neoforged.neoforge.client.util.TooltipUtil.AttributeTooltipContext;

/**
* This event is used to collect the IDs of attribute modifiers that will not be displayed in item tooltips.
* <p>
* It allows hiding some (or all) of the modifiers, potentially for displaying them in an alternative way (or for hiding information from the player).
* <p>
* This event is only fired on the {@linkplain Dist#CLIENT physical client}.
*/
public class GatherSkippedAttributeTooltipsEvent extends Event {
protected final ItemStack stack;
protected final Set<ResourceLocation> skips;
protected final AttributeTooltipContext ctx;
protected boolean skipAll = false;

public GatherSkippedAttributeTooltipsEvent(ItemStack stack, Set<ResourceLocation> skips, AttributeTooltipContext ctx) {
this.stack = stack;
this.skips = skips;
this.ctx = ctx;
}

/**
* The current tooltip context.
*/
public AttributeTooltipContext getContext() {
return this.ctx;
}

/**
* The {@link ItemStack} with the tooltip.
*/
public ItemStack getStack() {
return this.stack;
}

/**
* Marks the id of a specific attribute modifier as skipped, causing it to not be displayed in the tooltip.
*/
public void skipId(ResourceLocation id) {
this.skips.add(id);
}

/**
* Checks if a given id is skipped or not. If all modifiers are skipped, this method always returns true.
*/
public boolean isSkipped(ResourceLocation id) {
return this.skipAll || this.skips.contains(id);
}

/**
* Sets if the event should skip displaying all attribute modifiers.
*/
public void setSkipAll(boolean skip) {
this.skipAll = skip;
}

/**
* Checks if the event will cause all attribute modifiers to be skipped.
*/
public boolean isSkippingAll() {
return this.skipAll;
}
}
Loading