Skip to content

Commit 210576d

Browse files
authored
feat(compat): porting changes from version/1.21 to main. see #11647 for details (#11700)
1 parent 673013c commit 210576d

3 files changed

Lines changed: 207 additions & 30 deletions

File tree

src/main/java/com/minecolonies/api/compatibility/Compatibility.java

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,28 @@
44
import com.minecolonies.api.compatibility.resourcefulbees.IBeehiveCompat;
55
import com.minecolonies.api.compatibility.tinkers.SlimeTreeProxy;
66
import com.minecolonies.api.compatibility.tinkers.TinkersToolProxy;
7+
import com.minecolonies.api.crafting.ItemStorage;
78
import com.minecolonies.api.equipment.registry.EquipmentTypeEntry;
89
import net.minecraft.core.BlockPos;
910
import net.minecraft.core.NonNullList;
1011
import net.minecraft.resources.ResourceKey;
1112
import net.minecraft.world.damagesource.DamageType;
1213
import net.minecraft.world.item.Item;
1314
import net.minecraft.world.item.ItemStack;
15+
import net.minecraft.world.item.Tier;
16+
import net.minecraft.world.item.Tiers;
1417
import net.minecraft.world.level.Level;
1518
import net.minecraft.world.level.LevelAccessor;
1619
import net.minecraft.world.level.block.Block;
1720
import net.minecraft.world.level.block.state.BlockState;
1821
import org.jetbrains.annotations.NotNull;
1922
import org.jetbrains.annotations.Nullable;
2023

24+
import java.util.ArrayList;
25+
import java.util.HashMap;
2126
import java.util.List;
27+
import java.util.Map;
28+
import java.util.function.Predicate;
2229

2330
/**
2431
* This class is to store the methods that call the methods to check for miscellaneous compatibility problems.
@@ -31,6 +38,131 @@ private Compatibility()
3138
throw new IllegalAccessError("Utility class");
3239
}
3340

41+
private record TierEntry(@NotNull Tier tier, int level) {}
42+
43+
private static final Map<ItemStorage, TierEntry> itemTierRegistry = new HashMap<>();
44+
private static final List<Predicate<ItemStack>> customWeaponRecognizers = new ArrayList<>();
45+
46+
// Ordered by level 0–5. Level 5 maps to Netherite (the highest vanilla Tier).
47+
private static final Tiers[] LEVEL_TO_TIER = {
48+
Tiers.WOOD, Tiers.STONE, Tiers.IRON, Tiers.DIAMOND, Tiers.NETHERITE, Tiers.NETHERITE
49+
};
50+
51+
private static Tiers tierForLevel(final int level)
52+
{
53+
return LEVEL_TO_TIER[Math.min(Math.max(level, 0), LEVEL_TO_TIER.length - 1)];
54+
}
55+
56+
/**
57+
* Register an item with an explicit Tier object and pre-computed level.
58+
* Always overwrites any existing entry — intended for mod compat hooks.
59+
*
60+
* @param item the item to register.
61+
* @param tier the Tier object to associate.
62+
* @param level the equipment level integer.
63+
*/
64+
public static void registerItemTier(@NotNull final Item item, @NotNull final Tier tier, final int level)
65+
{
66+
itemTierRegistry.put(new ItemStorage(new ItemStack(item), true, true), new TierEntry(tier, level));
67+
}
68+
69+
/**
70+
* Register an item by level only.
71+
* The closest matching vanilla {@link Tiers} instance is stored so that
72+
* {@link #getItemTier} never returns null for a registered item.
73+
* Always overwrites any existing entry — intended for mod compat hooks.
74+
*
75+
* @param item the item to register.
76+
* @param level the equipment level integer.
77+
*/
78+
public static void registerItemTier(@NotNull final Item item, final int level)
79+
{
80+
itemTierRegistry.put(new ItemStorage(new ItemStack(item), true, true), new TierEntry(tierForLevel(level), level));
81+
}
82+
83+
/**
84+
* Register an item with an explicit Tier and level only if not already registered.
85+
* Used by auto-population so explicit mod registrations are never overwritten.
86+
*
87+
* @param item the item to register.
88+
* @param tier the Tier object to associate.
89+
* @param level the equipment level integer.
90+
*/
91+
public static void registerItemTierIfAbsent(@NotNull final Item item, @NotNull final Tier tier, final int level)
92+
{
93+
itemTierRegistry.putIfAbsent(new ItemStorage(new ItemStack(item), true, true), new TierEntry(tier, level));
94+
}
95+
96+
/**
97+
* Register an item by level only if not already registered.
98+
* The closest matching vanilla {@link Tiers} instance is stored.
99+
* Used by auto-population so explicit mod registrations are never overwritten.
100+
*
101+
* @param item the item to register.
102+
* @param level the equipment level integer.
103+
*/
104+
public static void registerItemTierIfAbsent(@NotNull final Item item, final int level)
105+
{
106+
itemTierRegistry.putIfAbsent(new ItemStorage(new ItemStack(item), true, true), new TierEntry(tierForLevel(level), level));
107+
}
108+
109+
/**
110+
* Return the Tier associated with this stack.
111+
* Returns {@code null} only when the item has not been registered.
112+
* Items registered without a real Tier (armor, bow, etc.) return the closest
113+
* matching vanilla {@link Tiers} instance.
114+
*
115+
* @param stack the item stack.
116+
* @return the registered Tier, or null if not registered.
117+
*/
118+
@Nullable
119+
public static Tier getItemTier(final ItemStack stack)
120+
{
121+
final TierEntry entry = itemTierRegistry.get(new ItemStorage(stack, true));
122+
return entry != null ? entry.tier() : null;
123+
}
124+
125+
/**
126+
* Return the pre-computed equipment level for this stack, or -1 if not registered.
127+
*
128+
* @param stack the item stack.
129+
* @return the equipment level, or -1.
130+
*/
131+
public static int getItemLevel(final ItemStack stack)
132+
{
133+
final TierEntry entry = itemTierRegistry.get(new ItemStorage(stack, true));
134+
return entry != null ? entry.level() : -1;
135+
}
136+
137+
/**
138+
* Register a custom weapon recognizer. The predicate should return true if the stack
139+
* is a weapon that should be treated as a sword by colonists (e.g. maces, javelins).
140+
*
141+
* @param recognizer the predicate to register.
142+
*/
143+
public static void registerWeaponRecognizer(final Predicate<ItemStack> recognizer)
144+
{
145+
customWeaponRecognizers.add(recognizer);
146+
}
147+
148+
/**
149+
* Query all registered weapon recognizers.
150+
*
151+
* @param stack the item stack.
152+
* @return true if any recognizer claims the stack as a weapon.
153+
*/
154+
public static boolean isCustomWeapon(final ItemStack stack)
155+
{
156+
for (final Predicate<ItemStack> recognizer : customWeaponRecognizers)
157+
{
158+
if (recognizer.test(stack))
159+
{
160+
return true;
161+
}
162+
}
163+
return false;
164+
}
165+
34166
public static IJeiProxy jeiProxy = new IJeiProxy() {};
35167
public static IBeehiveCompat beeHiveCompat = new IBeehiveCompat() {};
36168
public static SlimeTreeProxy tinkersSlimeCompat = new SlimeTreeProxy();

src/main/java/com/minecolonies/api/equipment/ModEquipmentTypes.java

Lines changed: 74 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.minecolonies.api.util.ItemStackUtils;
88
import com.minecolonies.api.util.constant.Constants;
99
import com.minecolonies.api.util.constant.translation.ToolTranslationConstants;
10+
import net.minecraft.core.registries.BuiltInRegistries;
1011
import net.minecraft.network.chat.Component;
1112
import net.minecraft.resources.ResourceLocation;
1213
import net.minecraft.world.entity.EquipmentSlot;
@@ -86,73 +87,64 @@ public class ModEquipmentTypes
8687

8788
sword = register("sword",
8889
builder -> builder.setDisplayName(Component.translatable(ToolTranslationConstants.TOOL_TYPE_SWORD))
89-
.setIsEquipment((itemStack, equipmentType) -> canPerformDefaultActions(itemStack, ToolActions.DEFAULT_SWORD_ACTIONS) || Compatibility.isTinkersWeapon(
90-
itemStack))
91-
.setEquipmentLevel((itemStack, equipmentType) -> {
92-
if (Compatibility.isTinkersWeapon(itemStack))
93-
{
94-
return Compatibility.getToolLevel(itemStack);
95-
}
96-
else if (itemStack.getItem() instanceof final TieredItem tieredItem)
97-
{
98-
return tieredItem.getTier().getLevel();
99-
}
100-
return -1;
101-
})
90+
.setIsEquipment((itemStack, equipmentType) -> canPerformDefaultActions(itemStack, ToolActions.DEFAULT_SWORD_ACTIONS)
91+
|| Compatibility.isTinkersWeapon(itemStack)
92+
|| Compatibility.isCustomWeapon(itemStack))
93+
.setEquipmentLevel(ModEquipmentTypes::vanillaToolLevel)
10294
.build());
10395

10496
bow = register("bow",
10597
builder -> builder.setDisplayName(Component.translatable(ToolTranslationConstants.TOOL_TYPE_BOW))
10698
.setIsEquipment((itemStack, equipmentType) -> itemStack.getItem() instanceof BowItem)
107-
.setEquipmentLevel((itemStack, equipmentType) -> durabilityBasedLevel(itemStack, Items.BOW.getMaxDamage()))
99+
.setEquipmentLevel((itemStack, equipmentType) -> Compatibility.getItemLevel(itemStack))
108100
.build());
109101

110102
fishing_rod = register("rod",
111103
builder -> builder.setDisplayName(Component.translatable(ToolTranslationConstants.TOOL_TYPE_FISHING_ROD))
112104
.setIsEquipment((itemStack, equipmentType) -> canPerformDefaultActions(itemStack, ToolActions.DEFAULT_FISHING_ROD_ACTIONS))
113-
.setEquipmentLevel((itemStack, equipmentType) -> durabilityBasedLevel(itemStack, Items.FISHING_ROD.getMaxDamage()))
105+
.setEquipmentLevel((itemStack, equipmentType) -> Compatibility.getItemLevel(itemStack))
114106
.build());
115107

116108
shears = register("shears",
117109
builder -> builder.setDisplayName(Component.translatable(ToolTranslationConstants.TOOL_TYPE_SHEARS))
118110
.setIsEquipment((itemStack, equipmentType) -> canPerformDefaultActions(itemStack, ToolActions.DEFAULT_SHEARS_ACTIONS))
119-
.setEquipmentLevel((itemStack, equipmentType) -> durabilityBasedLevel(itemStack, Items.SHEARS.getMaxDamage()))
111+
.setEquipmentLevel((itemStack, equipmentType) -> Compatibility.getItemLevel(itemStack))
120112
.build());
121113

122114
shield = register("shield",
123115
builder -> builder.setDisplayName(Component.translatable(ToolTranslationConstants.TOOL_TYPE_SHIELD))
124116
.setIsEquipment((itemStack, equipmentType) -> canPerformDefaultActions(itemStack, ToolActions.DEFAULT_SHIELD_ACTIONS))
125-
.setEquipmentLevel((itemStack, equipmentType) -> durabilityBasedLevel(itemStack, Items.SHIELD.getMaxDamage()))
117+
.setEquipmentLevel((itemStack, equipmentType) -> Compatibility.getItemLevel(itemStack))
126118
.build());
127119

128120
helmet = register("helmet",
129121
builder -> builder.setDisplayName(Component.translatable(ToolTranslationConstants.TOOL_TYPE_HELMET))
130122
.setIsEquipment((itemStack, equipmentType) -> itemStack.getItem() instanceof ArmorItem armor && EquipmentSlot.HEAD.equals(armor.getEquipmentSlot()))
131-
.setEquipmentLevel((itemStack, equipmentType) -> ItemStackUtils.getArmorLevel(itemStack))
123+
.setEquipmentLevel((itemStack, equipmentType) -> Compatibility.getItemLevel(itemStack))
132124
.build());
133125

134126
leggings = register("leggings",
135127
builder -> builder.setDisplayName(Component.translatable(ToolTranslationConstants.TOOL_TYPE_LEGGINGS))
136128
.setIsEquipment((itemStack, equipmentType) -> itemStack.getItem() instanceof ArmorItem armor && EquipmentSlot.LEGS.equals(armor.getEquipmentSlot()))
137-
.setEquipmentLevel((itemStack, equipmentType) -> ItemStackUtils.getArmorLevel(itemStack))
129+
.setEquipmentLevel((itemStack, equipmentType) -> Compatibility.getItemLevel(itemStack))
138130
.build());
139131

140132
chestplate = register("chestplate",
141133
builder -> builder.setDisplayName(Component.translatable(ToolTranslationConstants.TOOL_TYPE_CHEST_PLATE))
142134
.setIsEquipment((itemStack, equipmentType) -> itemStack.getItem() instanceof ArmorItem armor && EquipmentSlot.CHEST.equals(armor.getEquipmentSlot()))
143-
.setEquipmentLevel((itemStack, equipmentType) -> ItemStackUtils.getArmorLevel(itemStack))
135+
.setEquipmentLevel((itemStack, equipmentType) -> Compatibility.getItemLevel(itemStack))
144136
.build());
145137

146138
boots = register("boots",
147139
builder -> builder.setDisplayName(Component.translatable(ToolTranslationConstants.TOOL_TYPE_BOOTS))
148140
.setIsEquipment((itemStack, equipmentType) -> itemStack.getItem() instanceof ArmorItem armor && EquipmentSlot.FEET.equals(armor.getEquipmentSlot()))
149-
.setEquipmentLevel((itemStack, equipmentType) ->ItemStackUtils.getArmorLevel(itemStack))
141+
.setEquipmentLevel((itemStack, equipmentType) -> Compatibility.getItemLevel(itemStack))
150142
.build());
151143

152144
flint_and_steel = register("flintandsteel",
153145
builder -> builder.setDisplayName(Component.translatable(ToolTranslationConstants.TOOL_TYPE_LIGHTER))
154146
.setIsEquipment((itemStack, equipmentType) -> itemStack.getItem() instanceof FlintAndSteelItem)
155-
.setEquipmentLevel((itemStack, equipmentType) -> durabilityBasedLevel(itemStack, Items.FLINT_AND_STEEL.getMaxDamage()))
147+
.setEquipmentLevel((itemStack, equipmentType) -> Compatibility.getItemLevel(itemStack))
156148
.build());
157149

158150
lead = register("lead",
@@ -164,9 +156,8 @@ else if (itemStack.getItem() instanceof final TieredItem tieredItem)
164156
spear = register("spear",
165157
builder -> builder.setDisplayName(Component.translatable(ToolTranslationConstants.TOOL_TYPE_SPEAR))
166158
.setIsEquipment((itemStack, equipmentType) -> itemStack.is(ModItems.spear))
167-
.setEquipmentLevel((itemStack, equipmentType) -> durabilityBasedLevel(itemStack, ModItems.spear.getMaxDamage()))
159+
.setEquipmentLevel((itemStack, equipmentType) -> Compatibility.getItemLevel(itemStack))
168160
.build());
169-
170161
}
171162

172163
/**
@@ -203,15 +194,11 @@ private static RegistryObject<EquipmentTypeEntry> register(final String id, fina
203194
*/
204195
public static int vanillaToolLevel(final ItemStack itemStack, final EquipmentTypeEntry equipmentType)
205196
{
206-
if (Compatibility.isTinkersTool(itemStack, equipmentType))
197+
if (Compatibility.isTinkersTool(itemStack, equipmentType) || Compatibility.isTinkersWeapon(itemStack))
207198
{
208199
return Compatibility.getToolLevel(itemStack);
209200
}
210-
else if (itemStack.getItem() instanceof final TieredItem tieredItem) // most tools
211-
{
212-
return tieredItem.getTier().getLevel();
213-
}
214-
return -1;
201+
return Compatibility.getItemLevel(itemStack);
215202
}
216203

217204
/**
@@ -230,6 +217,63 @@ public static int durabilityBasedLevel(ItemStack itemStack, int vanillaItemDurab
230217
return Math.min(itemStack.getMaxDamage() / vanillaItemDurability, 5);
231218
}
232219

220+
/**
221+
* Populate the tier registry with every item currently in the game.
222+
* Called once during FMLCommonSetupEvent via MineColonies.preInit.
223+
*/
224+
@SuppressWarnings("null")
225+
public static void initRegisterEquipmentTiers()
226+
{
227+
final int bowRef = new ItemStack(Items.BOW).getMaxDamage();
228+
final int rodRef = new ItemStack(Items.FISHING_ROD).getMaxDamage();
229+
final int shearsRef = new ItemStack(Items.SHEARS).getMaxDamage();
230+
final int shieldRef = new ItemStack(Items.SHIELD).getMaxDamage();
231+
final int flintRef = new ItemStack(Items.FLINT_AND_STEEL).getMaxDamage();
232+
final int tridentRef = new ItemStack(Items.TRIDENT).getMaxDamage();
233+
234+
for (final Item item : BuiltInRegistries.ITEM)
235+
{
236+
final ItemStack dummy = new ItemStack(item);
237+
238+
if (item instanceof final TieredItem tiered)
239+
{
240+
Compatibility.registerItemTierIfAbsent(item, tiered.getTier(), (int) tiered.getTier().getAttackDamageBonus());
241+
}
242+
else if (item instanceof ArmorItem)
243+
{
244+
final int level = ItemStackUtils.getArmorLevel(dummy);
245+
if (level > 0)
246+
{
247+
Compatibility.registerItemTierIfAbsent(item, level);
248+
}
249+
}
250+
else if (item instanceof BowItem)
251+
{
252+
Compatibility.registerItemTierIfAbsent(item, durabilityBasedLevel(dummy, bowRef));
253+
}
254+
else if (canPerformDefaultActions(dummy, ToolActions.DEFAULT_FISHING_ROD_ACTIONS))
255+
{
256+
Compatibility.registerItemTierIfAbsent(item, durabilityBasedLevel(dummy, rodRef));
257+
}
258+
else if (canPerformDefaultActions(dummy, ToolActions.DEFAULT_SHEARS_ACTIONS))
259+
{
260+
Compatibility.registerItemTierIfAbsent(item, durabilityBasedLevel(dummy, shearsRef));
261+
}
262+
else if (canPerformDefaultActions(dummy, ToolActions.DEFAULT_SHIELD_ACTIONS))
263+
{
264+
Compatibility.registerItemTierIfAbsent(item, durabilityBasedLevel(dummy, shieldRef));
265+
}
266+
else if (item instanceof FlintAndSteelItem)
267+
{
268+
Compatibility.registerItemTierIfAbsent(item, durabilityBasedLevel(dummy, flintRef));
269+
}
270+
else if (item instanceof TridentItem)
271+
{
272+
Compatibility.registerItemTierIfAbsent(item, durabilityBasedLevel(dummy, tridentRef));
273+
}
274+
}
275+
}
276+
233277
/**
234278
* Determine whether an item stack can perform the default actions of a given tool.
235279
*

src/main/java/com/minecolonies/core/MineColonies.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ public static void preInit(@NotNull final FMLCommonSetupEvent event)
199199

200200
event.enqueueWork(ModLootConditions::init);
201201
event.enqueueWork(ModTags::init);
202+
event.enqueueWork(ModEquipmentTypes::initRegisterEquipmentTiers);
202203
}
203204

204205
@SubscribeEvent

0 commit comments

Comments
 (0)