@@ -664,6 +664,7 @@ public enum ClientIntent {
664
664
private static Class <?> CHAT_FORMATTING_CLASS = null ;
665
665
private static Class <?> CLIENT_INTENT_CLASS = null ;
666
666
667
+ private static boolean INITIALIZING = false ;
667
668
private static boolean INITIALIZED = false ;
668
669
private static Map <Class <?>, EquivalentConverter <?>> FROM_NATIVE = new HashMap <>();
669
670
private static Map <Class <?>, EquivalentConverter <?>> FROM_WRAPPER = new HashMap <>();
@@ -676,119 +677,129 @@ private static void initialize() {
676
677
if (INITIALIZED )
677
678
return ;
678
679
679
- INITIALIZED = true ;
680
+ synchronized (EnumWrappers .class ) {
681
+ // Recheck initialization status inside the lock
682
+ if (INITIALIZING || INITIALIZED )
683
+ return ;
680
684
681
- PROTOCOL_CLASS = MinecraftReflection .getEnumProtocolClass ();
682
- CLIENT_COMMAND_CLASS = getEnum (PacketType .Play .Client .CLIENT_COMMAND .getPacketClass (), 0 );
685
+ // Prevent circular calls to initialize during initialization
686
+ // (certain methods below indirectly call initialize again)
687
+ INITIALIZING = true ;
683
688
684
- if (MinecraftVersion .CONFIG_PHASE_PROTOCOL_UPDATE .atOrAbove ()) {
685
- CHAT_VISIBILITY_CLASS = MinecraftReflection .getMinecraftClass ("world.entity.player.EnumChatVisibility" , "world.entity.player.ChatVisibility" , "world.entity.player.ChatVisiblity" ); // Some versions have a typo
686
- } else {
687
- CHAT_VISIBILITY_CLASS = getEnum (PacketType .Play .Client .SETTINGS .getPacketClass (), 0 );
688
- }
689
+ PROTOCOL_CLASS = MinecraftReflection .getEnumProtocolClass ();
690
+ CLIENT_COMMAND_CLASS = getEnum (PacketType .Play .Client .CLIENT_COMMAND .getPacketClass (), 0 );
689
691
690
- try {
691
- DIFFICULTY_CLASS = getEnum ( PacketType . Play . Server . SERVER_DIFFICULTY . getPacketClass (), 0 );
692
- } catch ( Exception ex ) {
693
- DIFFICULTY_CLASS = getEnum (PacketType .Play .Server . LOGIN .getPacketClass (), 1 );
694
- }
692
+ if ( MinecraftVersion . CONFIG_PHASE_PROTOCOL_UPDATE . atOrAbove ()) {
693
+ CHAT_VISIBILITY_CLASS = MinecraftReflection . getMinecraftClass ( "world.entity.player.EnumChatVisibility" , "world.entity.player.ChatVisibility" , "world.entity.player.ChatVisiblity" ); // Some versions have a typo
694
+ } else {
695
+ CHAT_VISIBILITY_CLASS = getEnum (PacketType .Play .Client . SETTINGS .getPacketClass (), 0 );
696
+ }
695
697
696
- if ( MinecraftVersion . CONFIG_PHASE_PROTOCOL_UPDATE . atOrAbove ()) {
697
- GAMEMODE_CLASS = getEnum (MinecraftReflection . getPlayerInfoDataClass (), 0 );
698
- } else {
699
- GAMEMODE_CLASS = getEnum (PacketType .Play .Server .LOGIN .getPacketClass (), 0 );
700
- }
698
+ try {
699
+ DIFFICULTY_CLASS = getEnum (PacketType . Play . Server . SERVER_DIFFICULTY . getPacketClass (), 0 );
700
+ } catch ( Exception ex ) {
701
+ DIFFICULTY_CLASS = getEnum (PacketType .Play .Server .LOGIN .getPacketClass (), 1 );
702
+ }
701
703
702
- RESOURCE_PACK_STATUS_CLASS = getEnum (PacketType .Play .Client .RESOURCE_PACK_STATUS .getPacketClass (), 0 );
703
- TITLE_ACTION_CLASS = getEnum (PacketType .Play .Server .TITLE .getPacketClass (), 0 );
704
- WORLD_BORDER_ACTION_CLASS = getEnum (PacketType .Play .Server .WORLD_BORDER .getPacketClass (), 0 );
705
- COMBAT_EVENT_TYPE_CLASS = getEnum (PacketType .Play .Server .COMBAT_EVENT .getPacketClass (), 0 );
706
- PLAYER_DIG_TYPE_CLASS = getEnum (PacketType .Play .Client .BLOCK_DIG .getPacketClass (), 1 );
707
- PLAYER_ACTION_CLASS = getEnum (PacketType .Play .Client .ENTITY_ACTION .getPacketClass (), 0 );
708
- SCOREBOARD_ACTION_CLASS = getEnum (PacketType .Play .Server .SCOREBOARD_SCORE .getPacketClass (), 0 );
709
- PARTICLE_CLASS = getEnum (PacketType .Play .Server .WORLD_PARTICLES .getPacketClass (), 0 );
710
-
711
- PLAYER_INFO_ACTION_CLASS = getEnum (PacketType .Play .Server .PLAYER_INFO .getPacketClass (), 0 );
712
- if (PLAYER_INFO_ACTION_CLASS == null ) {
713
- // todo: we can also use getField(0).getGenericType().getTypeParameters()[0]; but this should hold for now
714
- PLAYER_INFO_ACTION_CLASS = PacketType .Play .Server .PLAYER_INFO .getPacketClass ().getClasses ()[1 ];
715
- }
704
+ if (MinecraftVersion .CONFIG_PHASE_PROTOCOL_UPDATE .atOrAbove ()) {
705
+ GAMEMODE_CLASS = getEnum (MinecraftReflection .getPlayerInfoDataClass (), 0 );
706
+ } else {
707
+ GAMEMODE_CLASS = getEnum (PacketType .Play .Server .LOGIN .getPacketClass (), 0 );
708
+ }
716
709
717
- try {
718
- SOUND_CATEGORY_CLASS = MinecraftReflection .getMinecraftClass ("sounds.SoundCategory" );
719
- } catch (Exception ex ) {
720
- SOUND_CATEGORY_CLASS = getEnum (PacketType .Play .Server .NAMED_SOUND_EFFECT .getPacketClass (), 0 );
721
- }
710
+ RESOURCE_PACK_STATUS_CLASS = getEnum (PacketType .Play .Client .RESOURCE_PACK_STATUS .getPacketClass (), 0 );
711
+ TITLE_ACTION_CLASS = getEnum (PacketType .Play .Server .TITLE .getPacketClass (), 0 );
712
+ WORLD_BORDER_ACTION_CLASS = getEnum (PacketType .Play .Server .WORLD_BORDER .getPacketClass (), 0 );
713
+ COMBAT_EVENT_TYPE_CLASS = getEnum (PacketType .Play .Server .COMBAT_EVENT .getPacketClass (), 0 );
714
+ PLAYER_DIG_TYPE_CLASS = getEnum (PacketType .Play .Client .BLOCK_DIG .getPacketClass (), 1 );
715
+ PLAYER_ACTION_CLASS = getEnum (PacketType .Play .Client .ENTITY_ACTION .getPacketClass (), 0 );
716
+ SCOREBOARD_ACTION_CLASS = getEnum (PacketType .Play .Server .SCOREBOARD_SCORE .getPacketClass (), 0 );
717
+ PARTICLE_CLASS = getEnum (PacketType .Play .Server .WORLD_PARTICLES .getPacketClass (), 0 );
718
+
719
+ PLAYER_INFO_ACTION_CLASS = getEnum (PacketType .Play .Server .PLAYER_INFO .getPacketClass (), 0 );
720
+ if (PLAYER_INFO_ACTION_CLASS == null ) {
721
+ // todo: we can also use getField(0).getGenericType().getTypeParameters()[0]; but this should hold for now
722
+ PLAYER_INFO_ACTION_CLASS = PacketType .Play .Server .PLAYER_INFO .getPacketClass ().getClasses ()[1 ];
723
+ }
722
724
723
- try {
724
- // TODO enum names are more stable than their packet associations
725
- ITEM_SLOT_CLASS = MinecraftReflection .getMinecraftClass ("world.entity.EnumItemSlot" , "world.entity.EquipmentSlot" , "EnumItemSlot" );
726
- } catch (Exception ex ) {
727
- ITEM_SLOT_CLASS = getEnum (PacketType .Play .Server .ENTITY_EQUIPMENT .getPacketClass (), 0 );
728
- }
725
+ try {
726
+ SOUND_CATEGORY_CLASS = MinecraftReflection .getMinecraftClass ("sounds.SoundCategory" );
727
+ } catch (Exception ex ) {
728
+ SOUND_CATEGORY_CLASS = getEnum (PacketType .Play .Server .NAMED_SOUND_EFFECT .getPacketClass (), 0 );
729
+ }
729
730
730
- // In 1.17 the hand and use action class is no longer a field in the packet
731
- if (MinecraftVersion .CAVES_CLIFFS_1 .atOrAbove ()) {
732
- HAND_CLASS = MinecraftReflection .getMinecraftClass ("world.EnumHand" , "world.InteractionHand" );
731
+ try {
732
+ // TODO enum names are more stable than their packet associations
733
+ ITEM_SLOT_CLASS = MinecraftReflection .getMinecraftClass ("world.entity.EnumItemSlot" , "world.entity.EquipmentSlot" , "EnumItemSlot" );
734
+ } catch (Exception ex ) {
735
+ ITEM_SLOT_CLASS = getEnum (PacketType .Play .Server .ENTITY_EQUIPMENT .getPacketClass (), 0 );
736
+ }
733
737
734
- FuzzyReflection fuzzy = FuzzyReflection .fromClass (MinecraftReflection .getEnumEntityUseActionClass (), true );
735
- Method getType = fuzzy .getMethod (FuzzyMethodContract .newBuilder ()
736
- .parameterCount (0 )
737
- .returnTypeMatches (FuzzyMatchers .except (Void .class ))
738
- .build ());
738
+ // In 1.17 the hand and use action class is no longer a field in the packet
739
+ if (MinecraftVersion .CAVES_CLIFFS_1 .atOrAbove ()) {
740
+ HAND_CLASS = MinecraftReflection .getMinecraftClass ("world.EnumHand" , "world.InteractionHand" );
739
741
740
- ENTITY_USE_ACTION_CLASS = getType . getReturnType ( );
741
- } else {
742
- HAND_CLASS = getEnum ( PacketType . Play . Client . USE_ENTITY . getPacketClass (), 1 );
743
- ENTITY_USE_ACTION_CLASS = getEnum ( PacketType . Play . Client . USE_ENTITY . getPacketClass (), 0 );
744
- }
742
+ FuzzyReflection fuzzy = FuzzyReflection . fromClass ( MinecraftReflection . getEnumEntityUseActionClass (), true );
743
+ Method getType = fuzzy . getMethod ( FuzzyMethodContract . newBuilder ()
744
+ . parameterCount ( 0 )
745
+ . returnTypeMatches ( FuzzyMatchers . except ( Void . class ))
746
+ . build ());
745
747
746
- // 1.19 removed the entity spawn packet and moved the direction into a seperated class
747
- if (MinecraftVersion .WILD_UPDATE .atOrAbove ()) {
748
- DIRECTION_CLASS = MinecraftReflection .getMinecraftClass ("core.EnumDirection" , "core.Direction" );
749
- } else {
750
- DIRECTION_CLASS = getEnum (PacketType .Play .Server .SPAWN_ENTITY_PAINTING .getPacketClass (), 0 );
751
- }
748
+ ENTITY_USE_ACTION_CLASS = getType .getReturnType ();
749
+ } else {
750
+ HAND_CLASS = getEnum (PacketType .Play .Client .USE_ENTITY .getPacketClass (), 1 );
751
+ ENTITY_USE_ACTION_CLASS = getEnum (PacketType .Play .Client .USE_ENTITY .getPacketClass (), 0 );
752
+ }
753
+
754
+ // 1.19 removed the entity spawn packet and moved the direction into a seperated class
755
+ if (MinecraftVersion .WILD_UPDATE .atOrAbove ()) {
756
+ DIRECTION_CLASS = MinecraftReflection .getMinecraftClass ("core.EnumDirection" , "core.Direction" );
757
+ } else {
758
+ DIRECTION_CLASS = getEnum (PacketType .Play .Server .SPAWN_ENTITY_PAINTING .getPacketClass (), 0 );
759
+ }
760
+
761
+ CHAT_TYPE_CLASS = getEnum (PacketType .Play .Server .CHAT .getPacketClass (), 0 );
762
+ ENTITY_POSE_CLASS = MinecraftReflection .getNullableNMS ("world.entity.EntityPose" , "world.entity.Pose" , "EntityPose" );
763
+ DISPLAY_SLOT_CLASS = MinecraftReflection .getNullableNMS ("world.scores.DisplaySlot" );
764
+
765
+ RENDER_TYPE_CLASS = MinecraftReflection .getNullableNMS (
766
+ "world.scores.criteria.ObjectiveCriteria$RenderType" ,
767
+ "world.scores.criteria.IScoreboardCriteria$EnumScoreboardHealthDisplay" ,
768
+ "IScoreboardCriteria$EnumScoreboardHealthDisplay" );
769
+ CHAT_FORMATTING_CLASS = MinecraftReflection .getNullableNMS ("ChatFormatting" , "EnumChatFormat" );
770
+
771
+ CLIENT_INTENT_CLASS = getEnum (PacketType .Handshake .Client .SET_PROTOCOL .getPacketClass (), 0 );
772
+
773
+ associate (PROTOCOL_CLASS , Protocol .class , getProtocolConverter ());
774
+ associate (CLIENT_COMMAND_CLASS , ClientCommand .class , getClientCommandConverter ());
775
+ associate (CHAT_VISIBILITY_CLASS , ChatVisibility .class , getChatVisibilityConverter ());
776
+ associate (DIFFICULTY_CLASS , Difficulty .class , getDifficultyConverter ());
777
+ associate (GAMEMODE_CLASS , NativeGameMode .class , getGameModeConverter ());
778
+ associate (RESOURCE_PACK_STATUS_CLASS , ResourcePackStatus .class , getResourcePackStatusConverter ());
779
+ associate (PLAYER_INFO_ACTION_CLASS , PlayerInfoAction .class , getPlayerInfoActionConverter ());
780
+ associate (TITLE_ACTION_CLASS , TitleAction .class , getTitleActionConverter ());
781
+ associate (WORLD_BORDER_ACTION_CLASS , WorldBorderAction .class , getWorldBorderActionConverter ());
782
+ associate (COMBAT_EVENT_TYPE_CLASS , CombatEventType .class , getCombatEventTypeConverter ());
783
+ associate (PLAYER_DIG_TYPE_CLASS , PlayerDigType .class , getPlayerDiggingActionConverter ());
784
+ associate (PLAYER_ACTION_CLASS , PlayerAction .class , getEntityActionConverter ());
785
+ associate (SCOREBOARD_ACTION_CLASS , ScoreboardAction .class , getUpdateScoreActionConverter ());
786
+ associate (PARTICLE_CLASS , Particle .class , getParticleConverter ());
787
+ associate (SOUND_CATEGORY_CLASS , SoundCategory .class , getSoundCategoryConverter ());
788
+ associate (ITEM_SLOT_CLASS , ItemSlot .class , getItemSlotConverter ());
789
+ associate (DIRECTION_CLASS , Direction .class , getDirectionConverter ());
790
+ associate (CHAT_TYPE_CLASS , ChatType .class , getChatTypeConverter ());
791
+ associate (HAND_CLASS , Hand .class , getHandConverter ());
792
+ associate (ENTITY_USE_ACTION_CLASS , EntityUseAction .class , getEntityUseActionConverter ());
793
+ associate (DISPLAY_SLOT_CLASS , DisplaySlot .class , getDisplaySlotConverter ());
794
+ associate (RENDER_TYPE_CLASS , RenderType .class , getRenderTypeConverter ());
795
+ associate (CHAT_FORMATTING_CLASS , ChatFormatting .class , getChatFormattingConverter ());
796
+ associate (CLIENT_INTENT_CLASS , ClientIntent .class , getClientIntentConverter ());
797
+
798
+ if (ENTITY_POSE_CLASS != null ) {
799
+ associate (ENTITY_POSE_CLASS , EntityPose .class , getEntityPoseConverter ());
800
+ }
752
801
753
- CHAT_TYPE_CLASS = getEnum (PacketType .Play .Server .CHAT .getPacketClass (), 0 );
754
- ENTITY_POSE_CLASS = MinecraftReflection .getNullableNMS ("world.entity.EntityPose" , "world.entity.Pose" , "EntityPose" );
755
- DISPLAY_SLOT_CLASS = MinecraftReflection .getNullableNMS ("world.scores.DisplaySlot" );
756
-
757
- RENDER_TYPE_CLASS = MinecraftReflection .getNullableNMS (
758
- "world.scores.criteria.ObjectiveCriteria$RenderType" ,
759
- "world.scores.criteria.IScoreboardCriteria$EnumScoreboardHealthDisplay" ,
760
- "IScoreboardCriteria$EnumScoreboardHealthDisplay" );
761
- CHAT_FORMATTING_CLASS = MinecraftReflection .getNullableNMS ("ChatFormatting" , "EnumChatFormat" );
762
-
763
- CLIENT_INTENT_CLASS = getEnum (PacketType .Handshake .Client .SET_PROTOCOL .getPacketClass (), 0 );
764
-
765
- associate (PROTOCOL_CLASS , Protocol .class , getProtocolConverter ());
766
- associate (CLIENT_COMMAND_CLASS , ClientCommand .class , getClientCommandConverter ());
767
- associate (CHAT_VISIBILITY_CLASS , ChatVisibility .class , getChatVisibilityConverter ());
768
- associate (DIFFICULTY_CLASS , Difficulty .class , getDifficultyConverter ());
769
- associate (GAMEMODE_CLASS , NativeGameMode .class , getGameModeConverter ());
770
- associate (RESOURCE_PACK_STATUS_CLASS , ResourcePackStatus .class , getResourcePackStatusConverter ());
771
- associate (PLAYER_INFO_ACTION_CLASS , PlayerInfoAction .class , getPlayerInfoActionConverter ());
772
- associate (TITLE_ACTION_CLASS , TitleAction .class , getTitleActionConverter ());
773
- associate (WORLD_BORDER_ACTION_CLASS , WorldBorderAction .class , getWorldBorderActionConverter ());
774
- associate (COMBAT_EVENT_TYPE_CLASS , CombatEventType .class , getCombatEventTypeConverter ());
775
- associate (PLAYER_DIG_TYPE_CLASS , PlayerDigType .class , getPlayerDiggingActionConverter ());
776
- associate (PLAYER_ACTION_CLASS , PlayerAction .class , getEntityActionConverter ());
777
- associate (SCOREBOARD_ACTION_CLASS , ScoreboardAction .class , getUpdateScoreActionConverter ());
778
- associate (PARTICLE_CLASS , Particle .class , getParticleConverter ());
779
- associate (SOUND_CATEGORY_CLASS , SoundCategory .class , getSoundCategoryConverter ());
780
- associate (ITEM_SLOT_CLASS , ItemSlot .class , getItemSlotConverter ());
781
- associate (DIRECTION_CLASS , Direction .class , getDirectionConverter ());
782
- associate (CHAT_TYPE_CLASS , ChatType .class , getChatTypeConverter ());
783
- associate (HAND_CLASS , Hand .class , getHandConverter ());
784
- associate (ENTITY_USE_ACTION_CLASS , EntityUseAction .class , getEntityUseActionConverter ());
785
- associate (DISPLAY_SLOT_CLASS , DisplaySlot .class , getDisplaySlotConverter ());
786
- associate (RENDER_TYPE_CLASS , RenderType .class , getRenderTypeConverter ());
787
- associate (CHAT_FORMATTING_CLASS , ChatFormatting .class , getChatFormattingConverter ());
788
- associate (CLIENT_INTENT_CLASS , ClientIntent .class , getClientIntentConverter ());
789
-
790
- if (ENTITY_POSE_CLASS != null ) {
791
- associate (ENTITY_POSE_CLASS , EntityPose .class , getEntityPoseConverter ());
802
+ INITIALIZED = true ;
792
803
}
793
804
}
794
805
0 commit comments