Skip to content

Commit 7ddc4e0

Browse files
committed
Feature/item rendering properties (#68)
* Add itemIcon with possibility for overriding of rendering properties
1 parent 34b2cca commit 7ddc4e0

File tree

7 files changed

+200
-5
lines changed

7 files changed

+200
-5
lines changed

src/main/java/com/ldtteam/blockui/Loader.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import net.minecraft.server.packs.resources.ResourceManager;
88
import net.minecraft.server.packs.resources.SimplePreparableReloadListener;
99
import net.minecraft.util.profiling.ProfilerFiller;
10+
import net.neoforged.fml.loading.FMLEnvironment;
1011
import org.w3c.dom.Document;
1112
import org.xml.sax.SAXException;
1213

@@ -43,7 +44,7 @@ private Loader()
4344
register("image", Image::new);
4445
register("imagerepeat", ImageRepeatable::new);
4546
register("box", Box::new);
46-
register("itemicon", ItemIconWithBlockState::new);
47+
register("itemicon", Loader::itemIcon);
4748
register("entityicon", EntityIcon::new);
4849
register("switch", SwitchView::new);
4950
register("dropdown", DropDownList::new);
@@ -53,6 +54,23 @@ private Loader()
5354
register("checkbox", CheckBox::new);
5455
}
5556

57+
private static ItemIcon itemIcon(final PaneParams paneParams)
58+
{
59+
if (paneParams.hasAttribute(ItemIconWithBlockState.PARAM_NBT))
60+
{
61+
if (!FMLEnvironment.production && paneParams.hasAttribute(ItemIconWithProperties.PARAM_PROPERTIES))
62+
{
63+
throw new IllegalStateException("Must be one of '%s' or '%s'".formatted(ItemIconWithBlockState.PARAM_NBT, ItemIconWithProperties.PARAM_PROPERTIES));
64+
}
65+
return new ItemIconWithBlockState(paneParams);
66+
}
67+
if (paneParams.hasAttribute(ItemIconWithProperties.PARAM_PROPERTIES))
68+
{
69+
return new ItemIconWithProperties(paneParams);
70+
}
71+
return new ItemIcon(paneParams);
72+
}
73+
5674
/**
5775
* registers an element definition class so it can be used in
5876
* gui definition files

src/main/java/com/ldtteam/blockui/controls/ItemIcon.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,15 @@ public void setItem(final ItemStack itemStack)
8787
{
8888
clearDataAndScheduleTooltipUpdate();
8989
this.itemStack = itemStack;
90+
onItemUpdate();
91+
}
92+
93+
/**
94+
* Called when itemStack was changed
95+
*/
96+
protected void onItemUpdate()
97+
{
98+
9099
}
91100

92101
/**
@@ -135,6 +144,7 @@ public void setItemFromBlockState(final BlockStateRenderingData blockStateExtens
135144
{
136145
blockStateExtension.blockEntity().saveToItem(itemStack);
137146
}
147+
onItemUpdate();
138148
}
139149

140150
/**
@@ -146,11 +156,16 @@ public void clearDataAndScheduleTooltipUpdate()
146156
tooltipUpdateScheduled = true;
147157
}
148158

149-
public boolean isDataEmpty()
159+
protected boolean isItemEmpty()
150160
{
151161
return itemStack == null || itemStack.isEmpty();
152162
}
153163

164+
public boolean isDataEmpty()
165+
{
166+
return isItemEmpty();
167+
}
168+
154169
protected void updateTooltipIfNeeded()
155170
{
156171
if (tooltipUpdateScheduled)
@@ -189,7 +204,7 @@ public void drawSelf(final BOGuiGraphics target, final double mx, final double m
189204
@Override
190205
public void onUpdate()
191206
{
192-
if (onHover == null && itemStack != null && !itemStack.isEmpty())
207+
if (onHover == null && !isItemEmpty())
193208
{
194209
new AutomaticTooltipBuilder().hoverPane(this).build().setTextOld(getModifiedItemStackTooltip());
195210
}

src/main/java/com/ldtteam/blockui/controls/ItemIconWithBlockState.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232

3333
public class ItemIconWithBlockState extends ItemIcon
3434
{
35+
public static final String PARAM_NBT = "nbt";
36+
3537
/**
3638
* BlockState + BlockEntity ModelData override
3739
*/
@@ -73,7 +75,7 @@ public ItemIconWithBlockState(final PaneParams params)
7375
final ItemStack newItemStack = itemStack;
7476
if (newItemStack != null)
7577
{
76-
final String nbt = params.getString("nbt");
78+
final String nbt = params.getString(PARAM_NBT);
7779
if (nbt != null)
7880
{
7981
try
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package com.ldtteam.blockui.controls;
2+
3+
import com.ldtteam.blockui.BOGuiGraphics;
4+
import com.ldtteam.blockui.PaneParams;
5+
import com.mojang.brigadier.exceptions.CommandSyntaxException;
6+
import net.minecraft.client.renderer.item.ItemProperties;
7+
import net.minecraft.client.renderer.item.ItemPropertyFunction;
8+
import net.minecraft.core.registries.BuiltInRegistries;
9+
import net.minecraft.nbt.CompoundTag;
10+
import net.minecraft.nbt.Tag;
11+
import net.minecraft.nbt.TagParser;
12+
import net.minecraft.resources.ResourceLocation;
13+
import net.minecraft.world.item.Item;
14+
import java.util.Collections;
15+
import java.util.HashMap;
16+
import java.util.Map;
17+
import java.util.Objects;
18+
19+
/**
20+
* Useful for overriding things like clock/compass textures. In xml defined through {@value #PARAM_PROPERTIES} key using nbt:
21+
* {<item registry key>:{<property name>:<float value>, ...}, ...}.
22+
* <p>
23+
* Special keys: {@value #NBT_CURRENT_ITEM} - refers to xml item (resolved during parsing not dynamic),
24+
* {@value #NBT_GENERIC_KEY} - generic properties
25+
*
26+
* @see ItemProperties
27+
*/
28+
@SuppressWarnings("deprecation")
29+
public class ItemIconWithProperties extends ItemIcon
30+
{
31+
private static final String NBT_GENERIC_KEY = "_generic";
32+
private static final String NBT_CURRENT_ITEM = "_item";
33+
34+
public static final String PARAM_PROPERTIES = "properties";
35+
36+
protected final Map<ResourceLocation, ItemPropertyFunction> genericPropertyOverrides = new HashMap<>();
37+
protected final Map<Item, Map<ResourceLocation, ItemPropertyFunction>> itemPropertyOverrides = new HashMap<>();
38+
private Map<ResourceLocation, ItemPropertyFunction> currentItemOverrides = Collections.emptyMap();
39+
40+
public ItemIconWithProperties()
41+
{
42+
super();
43+
}
44+
45+
public ItemIconWithProperties(final PaneParams paneParams)
46+
{
47+
super(paneParams);
48+
49+
final String data = paneParams.getString(PARAM_PROPERTIES);
50+
if (data != null && itemStack != null)
51+
{
52+
final CompoundTag tag;
53+
try
54+
{
55+
tag = TagParser.parseTag(data);
56+
}
57+
catch (CommandSyntaxException e)
58+
{
59+
throw new RuntimeException(data, null);
60+
}
61+
tag.getAllKeys().forEach(itemKey -> {
62+
if (tag.contains(itemKey, Tag.TAG_COMPOUND))
63+
{
64+
final CompoundTag child = tag.getCompound(itemKey);
65+
final var itemOverrides = NBT_GENERIC_KEY.equals(itemKey) ? genericPropertyOverrides :
66+
itemPropertyOverrides.computeIfAbsent(NBT_CURRENT_ITEM.equals(itemKey) ? itemStack.getItem() :
67+
BuiltInRegistries.ITEM.get(new ResourceLocation(itemKey)), i -> new HashMap<>());
68+
69+
child.getAllKeys().forEach(key -> {
70+
if (child.contains(key, Tag.TAG_ANY_NUMERIC))
71+
{
72+
final float value = child.getFloat(key); // intentionally ouf of lambda
73+
itemOverrides.put(new ResourceLocation(key), (itemStack, level, entity, seee) -> value);
74+
}
75+
});
76+
}
77+
});
78+
79+
onItemUpdate();
80+
}
81+
}
82+
83+
/**
84+
* Short call for adding itemProperty to current item
85+
*/
86+
public void addPropertyForCurrentItem(final ResourceLocation propertyKey, final ItemPropertyFunction property)
87+
{
88+
itemPropertyOverrides
89+
.computeIfAbsent(Objects.requireNonNull(itemStack, "Call #setItem before this method").getItem(), item -> new HashMap<>())
90+
.put(propertyKey, property);
91+
}
92+
93+
/**
94+
* @return modifiable all item-based overrides
95+
*/
96+
public Map<Item, Map<ResourceLocation, ItemPropertyFunction>> getItemPropertyOverrides()
97+
{
98+
return itemPropertyOverrides;
99+
}
100+
101+
/**
102+
* @return modifiable generic overrides
103+
*/
104+
public Map<ResourceLocation, ItemPropertyFunction> getGenericPropertyOverrides()
105+
{
106+
return genericPropertyOverrides;
107+
}
108+
109+
@Override
110+
public void drawSelf(final BOGuiGraphics target, final double mx, final double my)
111+
{
112+
if (isDataEmpty())
113+
{
114+
return;
115+
}
116+
if (currentItemOverrides.isEmpty() && genericPropertyOverrides.isEmpty())
117+
{
118+
super.drawSelf(target, mx, my);
119+
return;
120+
}
121+
final Item item = itemStack.getItem();
122+
123+
// generic
124+
final Map<ResourceLocation, ItemPropertyFunction> oldGenericVals =
125+
genericPropertyOverrides.isEmpty() ? Collections.emptyMap() : new HashMap<>();
126+
genericPropertyOverrides.forEach((key, val) -> {
127+
oldGenericVals.put(key, ItemProperties.getProperty(item, key));
128+
ItemProperties.registerGeneric(key, val);
129+
});
130+
131+
// item
132+
final Map<ResourceLocation, ItemPropertyFunction> oldItemVals =
133+
currentItemOverrides.isEmpty() ? Collections.emptyMap() : new HashMap<>();
134+
currentItemOverrides.forEach((key, val) -> {
135+
oldItemVals.put(key, ItemProperties.getProperty(item, key));
136+
ItemProperties.register(item, key, val);
137+
});
138+
139+
super.drawSelf(target, mx, my);
140+
141+
oldItemVals.forEach((key, val) -> ItemProperties.register(item, key, val));
142+
oldGenericVals.forEach((key, val) -> ItemProperties.registerGeneric(key, val));
143+
}
144+
145+
@Override
146+
protected void onItemUpdate()
147+
{
148+
super.onItemUpdate();
149+
if (itemPropertyOverrides != null) // ctor race condition
150+
{
151+
currentItemOverrides = itemPropertyOverrides.getOrDefault(itemStack.getItem(), Collections.emptyMap());
152+
}
153+
}
154+
}

src/main/java/com/ldtteam/blockui/controls/Tooltip.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ public void drawSelfLast(final BOGuiGraphics target, final double mx, final doub
156156
if (absoluteY > maxAbsoluteMy)
157157
{
158158
// but we don't flip here but just move upwards
159-
y -= (absoluteY - maxAbsoluteMy) / 2;
159+
y -= (absoluteY - maxAbsoluteMy) / renderScale;
160160
}
161161

162162
// modified INLINE: vanilla Screen#renderTooltip(MatrixStack, List<? extends IReorderingProcessor>, int, int, FontRenderer)

src/main/resources/assets/blockui/gui/block_ui.xsd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,14 @@
210210
<xs:extension base="paneType">
211211
<xs:attribute name="item" type="xs:string"/>
212212
<xs:attribute name="nbt" type="xs:string"/>
213+
<xs:attribute name="properties" type="xs:string"/>
213214
<xs:attribute name="renderItemDecorations" type="xs:boolean" default="true"/>
214215
<xs:attribute name="alwaysAddBlockStateTooltip" type="xs:boolean" default="false"/>
215216
</xs:extension>
216217
</xs:complexContent>
218+
<!-- TODO:
219+
<xs:assert test="(@nbt and not(@properties)) or (not(@nbt) and @properties)"/>
220+
-->
217221
</xs:complexType>
218222

219223
<!-- <entityicon> -->

src/main/resources/assets/blockui/gui/test.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,7 @@
4848
<itemicon item="minecraft:oak_stairs" nbt="{BlockStateTag:{waterlogged:'true',facing:'south'}}" size="64 64" pos="440 50"/>
4949
<itemicon item="minecraft:oak_stairs" nbt="{BlockStateTag:{facing:'east'}}" size="64 64" pos="510 50"/>
5050
<itemicon item="minecraft:oak_stairs" size="64 64" pos="580 50"/>
51+
<itemicon item="minecraft:clock" properties="{_item:{time:0.5}}" size="32 32" pos="650 50"/>
52+
<itemicon item="minecraft:clock" size="32 32" pos="700 50"/>
5153
</zoomdragview>
5254
</window>

0 commit comments

Comments
 (0)