66import net .minecraft .block .Block ;
77import net .minecraft .block .SoundType ;
88import net .minecraft .block .material .Material ;
9- import net .minecraft .block .properties .PropertyEnum ;
9+ import net .minecraft .block .properties .PropertyHelper ;
1010import net .minecraft .block .state .BlockStateContainer ;
1111import net .minecraft .block .state .IBlockState ;
1212import net .minecraft .client .resources .I18n ;
2323import net .minecraftforge .fml .relauncher .Side ;
2424import net .minecraftforge .fml .relauncher .SideOnly ;
2525
26+ import com .google .common .base .Optional ;
27+ import it .unimi .dsi .fastutil .ints .Int2ObjectArrayMap ;
28+ import it .unimi .dsi .fastutil .ints .Int2ObjectMap ;
29+ import it .unimi .dsi .fastutil .objects .Object2IntArrayMap ;
30+ import it .unimi .dsi .fastutil .objects .Object2IntMap ;
2631import org .jetbrains .annotations .NotNull ;
2732import org .jetbrains .annotations .Nullable ;
2833
34+ import java .lang .reflect .Array ;
2935import java .lang .reflect .ParameterizedType ;
3036import java .lang .reflect .Type ;
37+ import java .util .Arrays ;
38+ import java .util .Collection ;
3139import java .util .Collections ;
3240import java .util .List ;
3341
34- public class VariantBlock <T extends Enum < T > & IStringSerializable > extends Block {
42+ public abstract class VariantBlock <T extends IStringSerializable & Comparable < T > > extends Block {
3543
36- protected PropertyEnum <T > VARIANT ;
44+ protected PropertyIntMap <T > VARIANT ;
3745 protected T [] VALUES ;
3846
3947 public VariantBlock (@ NotNull Material materialIn ) {
4048 super (materialIn );
41- if (VALUES .length > 0 && VALUES [0 ] instanceof IStateHarvestLevel ) {
49+ updateHarvestLevels ();
50+ setCreativeTab (GTCreativeTabs .TAB_GREGTECH );
51+ setDefaultState (this .blockState .getBaseState ().withProperty (VARIANT , 0 ));
52+ }
53+
54+ protected void updateHarvestLevels () {
55+ if (VALUES .length > 0 && VALUES [0 ] instanceof IStateHarvestLevel stateHarvestLevel ) {
4256 for (T t : VALUES ) {
43- IStateHarvestLevel stateHarvestLevel = (IStateHarvestLevel ) t ;
4457 IBlockState state = getState (t );
45- setHarvestLevel (stateHarvestLevel .getHarvestTool (state ), stateHarvestLevel . getHarvestLevel ( state ),
46- state );
58+ setHarvestLevel (stateHarvestLevel .getHarvestTool (state ),
59+ stateHarvestLevel . getHarvestLevel ( state ), state );
4760 }
4861 }
49- setCreativeTab (GTCreativeTabs .TAB_GREGTECH );
50- setDefaultState (this .blockState .getBaseState ().withProperty (VARIANT , VALUES [0 ]));
5162 }
5263
5364 @ Override
@@ -58,11 +69,11 @@ public void getSubBlocks(@NotNull CreativeTabs tab, @NotNull NonNullList<ItemSta
5869 }
5970
6071 public IBlockState getState (T variant ) {
61- return getDefaultState ().withProperty (VARIANT , variant );
72+ return getDefaultState ().withProperty (VARIANT , VARIANT . getIndexOf ( variant ) );
6273 }
6374
6475 public T getState (IBlockState blockState ) {
65- return blockState .getValue (VARIANT );
76+ return VARIANT . getValue ( blockState .getValue (VARIANT ) );
6677 }
6778
6879 public T getState (ItemStack stack ) {
@@ -74,18 +85,34 @@ public ItemStack getItemVariant(T variant) {
7485 }
7586
7687 public ItemStack getItemVariant (T variant , int amount ) {
77- return new ItemStack (this , amount , variant . ordinal ( ));
88+ return new ItemStack (this , amount , VARIANT . getIndexOf ( variant ));
7889 }
7990
8091 @ NotNull
8192 @ Override
8293 protected BlockStateContainer createBlockState () {
83- Class <T > enumClass = getActualTypeParameter (getClass (), VariantBlock .class );
84- this .VARIANT = PropertyEnum .create ("variant" , enumClass );
85- this .VALUES = enumClass .getEnumConstants ();
94+ this .VARIANT = new PropertyIntMap <>("variant" , computeVariants ());
95+ this .VALUES = VARIANT .getValues ();
8696 return new BlockStateContainer (this , VARIANT );
8797 }
8898
99+ @ NotNull
100+ protected Collection <T > computeVariants () {
101+ Class <T > enumClass = null ;
102+ for (Class <?> innerClazz : getClass ().getClasses ()) {
103+ var enums = innerClazz .getEnumConstants ();
104+ if (enums != null && enums [0 ] instanceof IStringSerializable ) {
105+ // noinspection unchecked
106+ enumClass = (Class <T >) innerClazz ;
107+ break ;
108+ }
109+ }
110+ if (enumClass == null ) {
111+ enumClass = getActualTypeParameter (getClass (), VariantBlock .class );;
112+ }
113+ return Arrays .asList (enumClass .getEnumConstants ());
114+ }
115+
89116 @ Override
90117 @ SideOnly (Side .CLIENT )
91118 public void addInformation (@ NotNull ItemStack stack , @ Nullable World player , @ NotNull List <String > tooltip ,
@@ -109,12 +136,12 @@ public int damageDropped(@NotNull IBlockState state) {
109136 @ Override
110137 @ SuppressWarnings ("deprecation" )
111138 public IBlockState getStateFromMeta (int meta ) {
112- return getDefaultState ().withProperty (VARIANT , VALUES [ meta % VALUES .length ] );
139+ return getDefaultState ().withProperty (VARIANT , meta % VALUES .length );
113140 }
114141
115142 @ Override
116143 public int getMetaFromState (IBlockState state ) {
117- return state .getValue (VARIANT ). ordinal () ;
144+ return state .getValue (VARIANT );
118145 }
119146
120147 @ NotNull
@@ -141,13 +168,87 @@ public boolean canCreatureSpawn(@NotNull IBlockState state, @NotNull IBlockAcces
141168 protected static <T , R > Class <T > getActualTypeParameter (Class <? extends R > thisClass , Class <R > declaringClass ) {
142169 Type type = thisClass .getGenericSuperclass ();
143170
144- while (!(type instanceof ParameterizedType ) || (( ParameterizedType ) type ) .getRawType () != declaringClass ) {
171+ while (!(type instanceof ParameterizedType pType ) || pType .getRawType () != declaringClass ) {
145172 if (type instanceof ParameterizedType ) {
146173 type = ((Class <?>) ((ParameterizedType ) type ).getRawType ()).getGenericSuperclass ();
147174 } else {
148175 type = ((Class <?>) type ).getGenericSuperclass ();
149176 }
150177 }
151- return (Class <T >) ((ParameterizedType ) type ).getActualTypeArguments ()[0 ];
178+ var arg = pType .getActualTypeArguments ()[0 ];
179+ if (!(arg instanceof Class <?>)) {
180+ throw new ClassCastException (String .format ("cannot cast %s to a class!" , arg ));
181+ }
182+ return (Class <T >) pType .getActualTypeArguments ()[0 ];
183+ }
184+
185+ protected static class PropertyIntMap <O extends Comparable <O > & IStringSerializable >
186+ extends PropertyHelper <Integer > {
187+
188+ private final Int2ObjectMap <O > intMap ;
189+ private final Object2IntMap <O > reverse ;
190+ private final O [] allowedObjects ;
191+
192+ @ SuppressWarnings ("unchecked" )
193+ protected PropertyIntMap (String name , Collection <O > values ) {
194+ super (name , Integer .class );
195+ if (values .isEmpty ()) throw new IllegalArgumentException ("values are empty!" );
196+ if (values .size () > 16 ) throw new IllegalArgumentException ("values cannot be greater than 16!" );
197+
198+ this .intMap = new Int2ObjectArrayMap <>(values .size ());
199+ this .reverse = new Object2IntArrayMap <>(values .size ());
200+
201+ O first = values .iterator ().next ();
202+ this .allowedObjects = (O []) Array .newInstance (first .getClass (), values .size ());
203+
204+ for (O value : values ) {
205+ int size = this .intMap .size ();
206+ this .allowedObjects [size ] = value ;
207+ this .intMap .put (size , value );
208+ this .reverse .put (value , size );
209+ }
210+ }
211+
212+ @ Override
213+ public @ NotNull Collection <Integer > getAllowedValues () {
214+ return this .intMap .keySet ();
215+ }
216+
217+ public @ NotNull O [] getValues () {
218+ return this .allowedObjects ;
219+ }
220+
221+ @ Override
222+ @ Deprecated
223+ public @ NotNull String getName (@ NotNull Integer value ) {
224+ return getNameByInt (value );
225+ }
226+
227+ public @ NotNull String getNameByInt (int value ) {
228+ return getValue (value ).getName ();
229+ }
230+
231+ @ Override
232+ public @ NotNull Optional <Integer > parseValue (@ NotNull String value ) {
233+ for (O object : reverse .keySet ()) {
234+ if (object .getName ().equals (value )) {
235+ return Optional .of (getIndexOf (object ));
236+ }
237+ }
238+ return Optional .absent ();
239+ }
240+
241+ @ Override
242+ public int hashCode () {
243+ return 31 * super .hashCode () + this .allowedObjects .hashCode ();
244+ }
245+
246+ public int getIndexOf (O value ) {
247+ return this .reverse .getInt (value );
248+ }
249+
250+ public O getValue (int index ) {
251+ return this .intMap .get (index );
252+ }
152253 }
153254}
0 commit comments