Skip to content

Commit 26a5447

Browse files
authored
fix: replace PatternType.getByIdentifier() with PatternTypeProvider (#6553)
PatternType.getByIdentifier() causes IncompatibleClassChangeError on 1.19.4 due to a mismatch between Methodref and InterfaceMethodref bytecode constants when compiled against a newer API. Introduce PatternTypeProvider with two implementations: - LegacyPatternTypeProvider: iterates PatternType.values() for 1.19.4 and older where PatternType is still an enum - ModernPatternTypeProvider: uses Registry.BANNER_PATTERN for 1.20.5+ Update MetaItemStack.addBannerMeta to resolve PatternType through the provider instead of calling the deprecated static method directly. You need to select a pull request template! If you're adding a new feature, copy and paste the following parameter at the end of the URL: ?template=new-feature.md If you're fixing a bug, copy and paste the following parameter at the end of the URL: ?template=bug-fix.md For more information about contributing to EssentialsX, see CONTRIBUTING.md: https://github.com/EssentialsX/Essentials/blob/2.x/CONTRIBUTING.md
1 parent b303bf9 commit 26a5447

5 files changed

Lines changed: 111 additions & 18 deletions

File tree

Essentials/src/main/java/com/earth2me/essentials/Essentials.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@
7979
import net.ess3.provider.providers.FlatSpawnEggProvider;
8080
import net.ess3.provider.providers.LegacyBannerDataProvider;
8181
import net.ess3.provider.providers.LegacyBiomeNameProvider;
82+
import net.ess3.provider.providers.LegacyPatternTypeProvider;
83+
import net.ess3.provider.providers.ModernPatternTypeProvider;
8284
import net.ess3.provider.providers.LegacyDamageEventProvider;
8385
import net.ess3.provider.providers.LegacyInventoryViewProvider;
8486
import net.ess3.provider.providers.LegacyItemUnbreakableProvider;
@@ -342,6 +344,9 @@ public void onEnable() {
342344
//Banner Meta Provider
343345
providerFactory.registerProvider(LegacyBannerDataProvider.class, BaseBannerDataProvider.class);
344346

347+
// Pattern Type Provider
348+
providerFactory.registerProvider(LegacyPatternTypeProvider.class, ModernPatternTypeProvider.class);
349+
345350
// Server State Provider
346351
providerFactory.registerProvider(ReflServerStateProvider.class, PaperServerStateProvider.class);
347352

Essentials/src/main/java/com/earth2me/essentials/MetaItemStack.java

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import net.ess3.api.TranslatableException;
1414
import net.ess3.provider.BannerDataProvider;
1515
import net.ess3.provider.ItemUnbreakableProvider;
16+
import net.ess3.provider.PatternTypeProvider;
1617
import net.ess3.provider.PotionMetaProvider;
1718
import org.bukkit.Color;
1819
import org.bukkit.DyeColor;
@@ -712,22 +713,15 @@ public void addBannerMeta(final CommandSource sender, final boolean allowShortNa
712713
throw new TranslatableException("invalidBanner", split[1]);
713714
}
714715

715-
PatternType patternType = null;
716-
try {
717-
//noinspection removal
718-
patternType = PatternType.getByIdentifier(split[0]);
719-
} catch (final Exception ignored) {
720-
}
716+
final PatternType patternType = ess.provider(PatternTypeProvider.class).getPatternTypeByIdentifier(split[0]);
721717

722718
final BannerMeta meta = (BannerMeta) stack.getItemMeta();
723719
if (split[0].equalsIgnoreCase("basecolor")) {
724720
final Color color = Color.fromRGB(Integer.parseInt(split[1]));
725721
ess.provider(BannerDataProvider.class).setBaseColor(stack, DyeColor.getByColor(color));
726722
} else if (patternType != null) {
727-
//noinspection removal
728-
final PatternType type = PatternType.getByIdentifier(split[0]);
729723
final DyeColor color = DyeColor.getByColor(Color.fromRGB(Integer.parseInt(split[1])));
730-
final org.bukkit.block.banner.Pattern pattern = new org.bukkit.block.banner.Pattern(color, type);
724+
final org.bukkit.block.banner.Pattern pattern = new org.bukkit.block.banner.Pattern(color, patternType);
731725
meta.addPattern(pattern);
732726
}
733727

@@ -739,12 +733,7 @@ public void addBannerMeta(final CommandSource sender, final boolean allowShortNa
739733
throw new TranslatableException("invalidBanner", split[1]);
740734
}
741735

742-
PatternType patternType = null;
743-
try {
744-
//noinspection removal
745-
patternType = PatternType.getByIdentifier(split[0]);
746-
} catch (final Exception ignored) {
747-
}
736+
final PatternType patternType = ess.provider(PatternTypeProvider.class).getPatternTypeByIdentifier(split[0]);
748737

749738
// Hacky fix for accessing Shield meta - https://github.com/drtshock/Essentials/pull/745#issuecomment-234843795
750739
final BlockStateMeta meta = (BlockStateMeta) stack.getItemMeta();
@@ -753,10 +742,8 @@ public void addBannerMeta(final CommandSource sender, final boolean allowShortNa
753742
final Color color = Color.fromRGB(Integer.parseInt(split[1]));
754743
banner.setBaseColor(DyeColor.getByColor(color));
755744
} else if (patternType != null) {
756-
//noinspection removal
757-
final PatternType type = PatternType.getByIdentifier(split[0]);
758745
final DyeColor color = DyeColor.getByColor(Color.fromRGB(Integer.parseInt(split[1])));
759-
final org.bukkit.block.banner.Pattern pattern = new org.bukkit.block.banner.Pattern(color, type);
746+
final org.bukkit.block.banner.Pattern pattern = new org.bukkit.block.banner.Pattern(color, patternType);
760747
banner.addPattern(pattern);
761748
}
762749
banner.update();
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package net.ess3.provider.providers;
2+
3+
import net.ess3.provider.PatternTypeProvider;
4+
import net.essentialsx.providers.ProviderData;
5+
import net.essentialsx.providers.ProviderTest;
6+
import org.bukkit.block.banner.PatternType;
7+
8+
/**
9+
* Legacy PatternType provider for Minecraft 1.19.4 and older.
10+
*
11+
* In these versions PatternType is an enum and getByIdentifier() is a static
12+
* method on the enum itself. Calling it via the modern API path causes an
13+
* IncompatibleClassChangeError because the compiled bytecode expects a
14+
* Methodref constant but finds an InterfaceMethodref (or vice-versa).
15+
*
16+
* This provider avoids that by iterating over PatternType.values() and
17+
* comparing identifiers manually, which works on all versions where
18+
* PatternType is still an enum.
19+
*/
20+
@ProviderData(description = "Legacy (enum-based) PatternType Provider", weight = 0)
21+
public class LegacyPatternTypeProvider implements PatternTypeProvider {
22+
23+
@Override
24+
public PatternType getPatternTypeByIdentifier(final String identifier) {
25+
if (identifier == null) {
26+
return null;
27+
}
28+
for (final PatternType type : PatternType.values()) {
29+
//noinspection removal
30+
if (type.getIdentifier().equalsIgnoreCase(identifier)) {
31+
return type;
32+
}
33+
}
34+
return null;
35+
}
36+
37+
@ProviderTest
38+
public static boolean test() {
39+
try {
40+
// PatternType is an enum in 1.19.4 and older.
41+
// In 1.20.5+ it became a Keyed interface backed by Registry,
42+
// so values() no longer exists and this will throw.
43+
PatternType.class.getMethod("values");
44+
return true;
45+
} catch (final Throwable ignored) {
46+
return false;
47+
}
48+
}
49+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package net.ess3.provider;
2+
3+
import org.bukkit.block.banner.PatternType;
4+
5+
public interface PatternTypeProvider extends Provider {
6+
/**
7+
* Returns the PatternType matching the given identifier string, or null if not found.
8+
*
9+
* @param identifier the pattern identifier (e.g. "stripe_top")
10+
* @return the matching PatternType, or null
11+
*/
12+
PatternType getPatternTypeByIdentifier(String identifier);
13+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package net.ess3.provider.providers;
2+
3+
import net.ess3.provider.PatternTypeProvider;
4+
import net.essentialsx.providers.ProviderData;
5+
import net.essentialsx.providers.ProviderTest;
6+
import org.bukkit.NamespacedKey;
7+
import org.bukkit.Registry;
8+
import org.bukkit.block.banner.PatternType;
9+
10+
/**
11+
* Modern PatternType provider for Minecraft 1.20.5+.
12+
*
13+
* In 1.20.5 PatternType was changed from an enum to a Keyed interface backed
14+
* by Registry.BANNER_PATTERN. This provider uses the Registry API to look up
15+
* pattern types by their identifier.
16+
*/
17+
@ProviderData(description = "Modern (Registry-based) PatternType Provider", weight = 1)
18+
public class ModernPatternTypeProvider implements PatternTypeProvider {
19+
20+
@Override
21+
public PatternType getPatternTypeByIdentifier(final String identifier) {
22+
if (identifier == null) {
23+
return null;
24+
}
25+
return Registry.BANNER_PATTERN.get(NamespacedKey.minecraft(identifier.toLowerCase()));
26+
}
27+
28+
@ProviderTest
29+
public static boolean test() {
30+
try {
31+
// Registry.BANNER_PATTERN was added in 1.20.5 when PatternType
32+
// was converted from an enum to a Registry-backed Keyed type.
33+
Registry.class.getField("BANNER_PATTERN");
34+
return true;
35+
} catch (final Throwable ignored) {
36+
return false;
37+
}
38+
}
39+
}

0 commit comments

Comments
 (0)