浏览代码

Javadoc all the things and do some general cleanup

malte0811 4 年之前
父节点
当前提交
dc4bf356f3
共有 21 个文件被更改,包括 205 次插入48 次删除
  1. 9 2
      README.md
  2. 0 5
      common/src/main/java/malte0811/ferritecore/ModMain.java
  3. 11 7
      common/src/main/java/malte0811/ferritecore/classloading/FastImmutableMapDefiner.java
  4. 5 1
      common/src/main/java/malte0811/ferritecore/fastmap/BinaryFastMapKey.java
  5. 4 1
      common/src/main/java/malte0811/ferritecore/fastmap/CompactFastMapKey.java
  6. 35 4
      common/src/main/java/malte0811/ferritecore/fastmap/FastMap.java
  7. 24 0
      common/src/main/java/malte0811/ferritecore/fastmap/FastMapKey.java
  8. 40 6
      common/src/main/java/malte0811/ferritecore/fastmap/PropertyIndexer.java
  9. 9 0
      common/src/main/java/malte0811/ferritecore/impl/BlockStateCacheImpl.java
  10. 3 8
      common/src/main/java/malte0811/ferritecore/impl/Deduplicator.java
  11. 6 1
      common/src/main/java/malte0811/ferritecore/impl/PropertyValueConditionImpl.java
  12. 5 0
      common/src/main/java/malte0811/ferritecore/impl/StateHolderImpl.java
  13. 1 0
      common/src/main/java/malte0811/ferritecore/mixin/config/FerriteConfig.java
  14. 5 0
      common/src/main/java/malte0811/ferritecore/util/Constants.java
  15. 6 0
      common/src/main/java/malte0811/ferritecore/util/LastAccessedCache.java
  16. 29 3
      common/src/main/java/malte0811/ferritecore/util/PredicateHelper.java
  17. 5 4
      common/src/test/java/malte0811/ferritecore/fastmap/FastMapTest.java
  18. 2 2
      fabric/src/main/java/malte0811/ferritecore/mixin/config/ConfigFileHandler.java
  19. 2 1
      forge/src/main/java/malte0811/ferritecore/ModClientForge.java
  20. 2 1
      forge/src/main/java/malte0811/ferritecore/ModMainForge.java
  21. 2 2
      forge/src/main/java/malte0811/ferritecore/mixin/config/ConfigFileHandler.java

+ 9 - 2
README.md

@@ -1,8 +1,15 @@
 A coremod to save a few of these:  
-<img src="https://upload.wikimedia.org/wikipedia/commons/d/da/KL_CoreMemory.jpg" width="400"/>  
+<img src="https://upload.wikimedia.org/wikipedia/commons/d/da/KL_CoreMemory.jpg" width="400"/>
 
 or rather their modern equivalent: RAM.
 
 (Image: Konstantin Lanzet, CC BY-SA 3.0 <http://creativecommons.org/licenses/by-sa/3.0/>, via Wikimedia Commons)
 
-I am working on getting at least some of the changes made by this mod into Forge, features will be removed here if and when they are added to Forge. For a description of the improvements implemented by this mod see [here](summary.md).
+I am working on getting at least some of the changes made by this mod into Forge, features will be removed here if and
+when they are added to Forge. For a description of the improvements implemented by this mod see [here](summary.md).
+
+### Mappings
+
+This mod currently uses MCP names for everything, in case someone involved in MCP mapping wants to look at it. There are
+a few commits using official names, so be careful when looking at the commit history if you are concerned about "mapping
+taint".

+ 0 - 5
common/src/main/java/malte0811/ferritecore/ModMain.java

@@ -1,5 +0,0 @@
-package malte0811.ferritecore;
-
-public class ModMain {
-    public static final String MODID = "ferritecore";
-}

+ 11 - 7
common/src/main/java/malte0811/ferritecore/classloading/FastImmutableMapDefiner.java

@@ -17,6 +17,10 @@ import java.util.Map;
 import java.util.function.BiFunction;
 import java.util.function.ToIntFunction;
 
+/**
+ * Helper to define classes in the com.google.common.collect package without issues due to jar signing and classloaders
+ * (the second one only seems to be an issue on Fabric, but the first one is a problem on both)
+ */
 public class FastImmutableMapDefiner {
     private static final Logger LOGGER = LogManager.getLogger("FerriteCore - class definer");
     private static final LazyValue<Definer> DEFINE_CLASS = new LazyValue<>(() -> {
@@ -24,9 +28,7 @@ public class FastImmutableMapDefiner {
             // Try to create a Java 9+ style class definer
             // These are all public methods, but just don't exist in Java 8
             Method makePrivateLookup = MethodHandles.class.getMethod(
-                    "privateLookupIn",
-                    Class.class,
-                    MethodHandles.Lookup.class
+                    "privateLookupIn", Class.class, MethodHandles.Lookup.class
             );
             Object privateLookup = makePrivateLookup.invoke(null, ImmutableMap.class, MethodHandles.lookup());
             Method defineClass = MethodHandles.Lookup.class.getMethod("defineClass", byte[].class);
@@ -48,6 +50,11 @@ public class FastImmutableMapDefiner {
             }
         }
     });
+    /**
+     * Creates a MethodHandle for the constructor of {@link com.google.common.collect.FerriteCoreImmutableMap} which
+     * takes one argument, which has to be an instance FastMapStateHolder. The Lazy also sets up the callbacks used by
+     * the map to get data out of the StateHolder
+     */
     private static final LazyValue<MethodHandle> MAKE_IMMUTABLE_FAST_MAP = new LazyValue<>(() -> {
         try {
             define("com.google.common.collect.FerriteCoreIterator");
@@ -69,9 +76,7 @@ public class FastImmutableMapDefiner {
                     }
             );
             MethodHandles.Lookup lookup = MethodHandles.lookup();
-            return lookup.findConstructor(map, MethodType.methodType(
-                    void.class, Object.class
-            ));
+            return lookup.findConstructor(map, MethodType.methodType(void.class, Object.class));
         } catch (Exception x) {
             throw new RuntimeException(x);
         }
@@ -88,7 +93,6 @@ public class FastImmutableMapDefiner {
     }
 
     private static Class<?> define(String name) throws Exception {
-        ClassLoader loaderToUse = ImmutableMap.class.getClassLoader();
         InputStream byteInput = FastImmutableMapDefiner.class.getResourceAsStream(
                 '/' + name.replace('.', '/') + ".class"
         );

+ 5 - 1
common/src/main/java/malte0811/ferritecore/fastmap/BinaryFastMapKey.java

@@ -4,6 +4,10 @@ import com.google.common.base.Preconditions;
 import net.minecraft.state.Property;
 import net.minecraft.util.math.MathHelper;
 
+/**
+ * A bitmask-based implementation of a FastMapKey. This reduces the density of data in the value matrix, but allows
+ * accessing values with only some bitwise operations, which are much faster than integer division
+ */
 public class BinaryFastMapKey<T extends Comparable<T>> extends FastMapKey<T> {
     private final byte firstBitInValue;
     private final byte firstBitAfterValue;
@@ -16,7 +20,7 @@ public class BinaryFastMapKey<T extends Comparable<T>> extends FastMapKey<T> {
         Preconditions.checkState(addedFactor < 2 * numValues());
         final int setBitInBaseFactor = MathHelper.log2(mapFactor);
         final int setBitInAddedFactor = MathHelper.log2(addedFactor);
-        Preconditions.checkState(setBitInBaseFactor + setBitInAddedFactor <= 32);
+        Preconditions.checkState(setBitInBaseFactor + setBitInAddedFactor <= 31);
         firstBitInValue = (byte) setBitInBaseFactor;
         firstBitAfterValue = (byte) (setBitInBaseFactor + setBitInAddedFactor);
     }

+ 4 - 1
common/src/main/java/malte0811/ferritecore/fastmap/CompactFastMapKey.java

@@ -2,6 +2,9 @@ package malte0811.ferritecore.fastmap;
 
 import net.minecraft.state.Property;
 
+/**
+ * A "compact" implementation of a FastMapKey, i.e. one which completely fills the value matrix
+ */
 public class CompactFastMapKey<T extends Comparable<T>> extends FastMapKey<T> {
     private final int mapFactor;
 
@@ -22,7 +25,7 @@ public class CompactFastMapKey<T extends Comparable<T>> extends FastMapKey<T> {
         final int upperFactor = mapFactor * numValues();
         final int upperData = mapIndex - mapIndex % upperFactor;
         int internalIndex = getInternalIndex(newValue);
-        if (internalIndex < 0) {
+        if (internalIndex < 0 || internalIndex >= numValues()) {
             return -1;
         } else {
             return lowerData + mapFactor * internalIndex + upperData;

+ 35 - 4
common/src/main/java/malte0811/ferritecore/fastmap/FastMap.java

@@ -7,6 +7,9 @@ import net.minecraft.state.Property;
 import javax.annotation.Nullable;
 import java.util.*;
 
+/**
+ * Maps a Property->Value assignment to a value, while allowing fast access to "neighbor" states
+ */
 public class FastMap<Value> {
     private final List<FastMapKey<?>> keys;
     private final List<Value> valueMatrix;
@@ -45,20 +48,31 @@ public class FastMap<Value> {
         this.valueMatrix = Collections.unmodifiableList(valuesList);
     }
 
+    /**
+     * Computes the value for a neighbor state
+     *
+     * @param oldIndex The original state index
+     * @param prop     The property to be replaced
+     * @param value    The new value of this property
+     * @return The value corresponding to the specified neighbor, or null if value is not a valid value for prop
+     */
     @Nullable
     public <T extends Comparable<T>>
-    Value with(int last, Property<T> prop, T value) {
+    Value with(int oldIndex, Property<T> prop, T value) {
         final FastMapKey<T> keyToChange = getKeyFor(prop);
         if (keyToChange == null) {
             return null;
         }
-        int newIndex = keyToChange.replaceIn(last, value);
+        int newIndex = keyToChange.replaceIn(oldIndex, value);
         if (newIndex < 0) {
             return null;
         }
         return valueMatrix.get(newIndex);
     }
 
+    /**
+     * @return The map index corresponding to the given property-value assignment
+     */
     public int getIndexOf(Map<Property<?>, Comparable<?>> state) {
         int id = 0;
         for (FastMapKey<?> k : keys) {
@@ -67,6 +81,13 @@ public class FastMap<Value> {
         return id;
     }
 
+    /**
+     * Returns the value assigned to a property at a given map index
+     *
+     * @param stateIndex The map index for the assignment to check
+     * @param property   The property to retrieve
+     * @return The value of the property or null if the state if not present
+     */
     @Nullable
     public <T extends Comparable<T>>
     T getValue(int stateIndex, Property<T> property) {
@@ -77,15 +98,25 @@ public class FastMap<Value> {
         return propId.getValue(stateIndex);
     }
 
+    /**
+     * Returns the given property and its value in the given state
+     *
+     * @param propertyIndex The index of the property to retrieve
+     * @param stateIndex    The index of the state to use for the value
+     */
     public Map.Entry<Property<?>, Comparable<?>> getEntry(int propertyIndex, int stateIndex) {
         return new AbstractMap.SimpleImmutableEntry<>(
                 getKey(propertyIndex).getProperty(), getKey(propertyIndex).getValue(stateIndex)
         );
     }
 
+    /**
+     * Same as {@link FastMap#with(int, Property, Comparable)}, but usable when the type of the value to set is not
+     * correctly typed
+     */
     public <T extends Comparable<T>>
-    Value withUnsafe(int globalTableIndex, Property<T> rowKey, Object columnKey) {
-        return with(globalTableIndex, rowKey, (T) columnKey);
+    Value withUnsafe(int globalTableIndex, Property<T> property, Object newValue) {
+        return with(globalTableIndex, property, (T) newValue);
     }
 
     public int numProperties() {

+ 24 - 0
common/src/main/java/malte0811/ferritecore/fastmap/FastMapKey.java

@@ -2,19 +2,43 @@ package malte0811.ferritecore.fastmap;
 
 import net.minecraft.state.Property;
 
+/**
+ * Defines the indexing strategy for a single property in a FastMap
+ */
 public abstract class FastMapKey<T extends Comparable<T>> {
+    /**
+     * Maps values of the property to indices in [0, numValues()) and vice versa
+     */
     private final PropertyIndexer<T> indexer;
 
     protected FastMapKey(Property<T> property) {
         this.indexer = PropertyIndexer.makeIndexer(property);
     }
 
+    /**
+     * @param mapIndex An index in the FastMap's value matrix
+     * @return The value of this property in that index
+     */
     abstract T getValue(int mapIndex);
 
+    /**
+     * @param mapIndex The original index in the FastMap's value matrix
+     * @param newValue The value to assign to this property
+     * @return The index in the value matrix corresponding to the input state with only the value of this property
+     * replaced by <code>newValue</code>
+     */
     abstract int replaceIn(int mapIndex, T newValue);
 
+    /**
+     * @param value A possible value of this property
+     * @return An integer such that the sum over the returned values for all properties is the state corresponding to
+     * the arguments
+     */
     abstract int toPartialMapIndex(Comparable<?> value);
 
+    /**
+     * @return An integer such that adding multiples of this value does not change the result of getValue
+     */
     abstract int getFactorToNext();
 
     protected final int numValues() {

+ 40 - 6
common/src/main/java/malte0811/ferritecore/fastmap/PropertyIndexer.java

@@ -12,8 +12,13 @@ import net.minecraft.state.properties.BlockStateProperties;
 import net.minecraft.util.Direction;
 import net.minecraft.util.IStringSerializable;
 
+import javax.annotation.Nullable;
 import java.util.*;
 
+/**
+ * Provides a way of converting between values of a property and indices in [0, #values). Most properties are covered
+ * by one of the (faster) specific implementations, all other properties use the {@link GenericIndexer}
+ */
 public abstract class PropertyIndexer<T extends Comparable<T>> {
     private static final Map<Property<?>, PropertyIndexer<?>> KNOWN_INDEXERS = new Object2ObjectOpenHashMap<>();
 
@@ -56,10 +61,14 @@ public abstract class PropertyIndexer<T extends Comparable<T>> {
         return numValues;
     }
 
+    @Nullable
     public abstract T byIndex(int index);
 
     public abstract int toIndex(T value);
 
+    /**
+     * Checks if this indexer is valid, i.e. iterates over the correct set of values in the correct order
+     */
     protected boolean isValid() {
         Collection<T> allowed = getProperty().getAllowedValues();
         int index = 0;
@@ -79,8 +88,16 @@ public abstract class PropertyIndexer<T extends Comparable<T>> {
         }
 
         @Override
+        @Nullable
         public Boolean byIndex(int index) {
-            return index == 1 ? Boolean.FALSE : Boolean.TRUE;
+            switch (index) {
+                case 0:
+                    return Boolean.TRUE;
+                case 1:
+                    return Boolean.FALSE;
+                default:
+                    return null;
+            }
         }
 
         @Override
@@ -98,8 +115,13 @@ public abstract class PropertyIndexer<T extends Comparable<T>> {
         }
 
         @Override
+        @Nullable
         public Integer byIndex(int index) {
-            return index + min;
+            if (index >= 0 && index < numValues()) {
+                return index + min;
+            } else {
+                return null;
+            }
         }
 
         @Override
@@ -124,8 +146,14 @@ public abstract class PropertyIndexer<T extends Comparable<T>> {
         }
 
         @Override
+        @Nullable
         public E byIndex(int index) {
-            return enumValues[index + ordinalOffset];
+            final int arrayIndex = index + ordinalOffset;
+            if (arrayIndex < enumValues.length) {
+                return enumValues[arrayIndex];
+            } else {
+                return null;
+            }
         }
 
         @Override
@@ -158,8 +186,13 @@ public abstract class PropertyIndexer<T extends Comparable<T>> {
         }
 
         @Override
+        @Nullable
         public Direction byIndex(int index) {
-            return ORDER[index];
+            if (index >= 0 && index < ORDER.length) {
+                return ORDER[index];
+            } else {
+                return null;
+            }
         }
 
         @Override
@@ -178,7 +211,7 @@ public abstract class PropertyIndexer<T extends Comparable<T>> {
                 case DOWN:
                     return 5;
             }
-            throw new IllegalArgumentException("Invalid direction: "+value);
+            return -1;
         }
     }
 
@@ -197,13 +230,14 @@ public abstract class PropertyIndexer<T extends Comparable<T>> {
         }
 
         @Override
+        @Nullable
         public T byIndex(int index) {
             return values.get(index);
         }
 
         @Override
         public int toIndex(T value) {
-            return toValueIndex.get(value);
+            return toValueIndex.getOrDefault(value, -1);
         }
     }
 }

+ 9 - 0
common/src/main/java/malte0811/ferritecore/impl/BlockStateCacheImpl.java

@@ -43,6 +43,11 @@ public class BlockStateCacheImpl {
         projectCalls = 0;
     }
 
+    /**
+     * Returns an interned/deduplicated version of the voxel shape returned by
+     * {@link AbstractBlock#getCollisionShape(BlockState, IBlockReader, BlockPos, ISelectionContext)}
+     * and replaces the internals of the original returned shape (see {@link BlockStateCacheImpl#replaceInternals(VoxelShapeArray, VoxelShapeArray)})
+     */
     public static VoxelShape redirectGetCollisionShape(
             AbstractBlock block, BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context
     ) {
@@ -57,6 +62,10 @@ public class BlockStateCacheImpl {
         return resultArray;
     }
 
+    /**
+     * Returns the interned/deduplicated "face shape" of the given shape, and replaces the internals of the original
+     * shape if necessary/appropriate
+     */
     public static VoxelShape redirectFaceShape(VoxelShape shape, Direction face) {
         ++projectCalls;
         Pair<VoxelShape, VoxelShape[]> sides = CACHE_PROJECT.get(shape);

+ 3 - 8
common/src/main/java/malte0811/ferritecore/impl/Deduplicator.java

@@ -4,6 +4,7 @@ import com.mojang.datafixers.util.Unit;
 import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap;
 import malte0811.ferritecore.hash.LambdaBasedHash;
 import malte0811.ferritecore.mixin.dedupbakedquad.BakedQuadAccess;
+import malte0811.ferritecore.util.PredicateHelper;
 import net.minecraft.block.BlockState;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.renderer.model.BakedQuad;
@@ -41,17 +42,11 @@ public class Deduplicator {
     }
 
     public static Predicate<BlockState> or(List<Predicate<BlockState>> list) {
-        return OR_PREDICATE_CACHE.computeIfAbsent(
-                list,
-                listInt -> state -> listInt.stream().anyMatch((predicate) -> predicate.test(state))
-        );
+        return OR_PREDICATE_CACHE.computeIfAbsent(list, PredicateHelper::or);
     }
 
     public static Predicate<BlockState> and(List<Predicate<BlockState>> list) {
-        return AND_PREDICATE_CACHE.computeIfAbsent(
-                list,
-                listInt -> state -> listInt.stream().allMatch((predicate) -> predicate.test(state))
-        );
+        return AND_PREDICATE_CACHE.computeIfAbsent(list, PredicateHelper::and);
     }
 
     public static void deduplicate(BakedQuad bq) {

+ 6 - 1
common/src/main/java/malte0811/ferritecore/impl/PropertyValueConditionImpl.java

@@ -18,6 +18,10 @@ import java.util.stream.Collectors;
 public class PropertyValueConditionImpl {
     private static final Map<Pair<Property<?>, Comparable<?>>, Predicate<BlockState>> STATE_HAS_PROPERTY_CACHE = new ConcurrentHashMap<>();
 
+    /**
+     * A copy of {@link net.minecraft.client.renderer.model.multipart.PropertyValueCondition#getPredicate(StateContainer)}
+     * since targeting the correct line is near impossible
+     */
     public static Predicate<BlockState> getPredicate(
             StateContainer<Block, BlockState> stateContainer, String key, String value, Splitter splitter
     ) {
@@ -49,7 +53,8 @@ public class PropertyValueConditionImpl {
                             .collect(Collectors.toList());
                     // This line is the only functional change, but targeting it with anything but Overwrite appears to
                     // be impossible
-                    isMatchedState = Deduplicator.or(PredicateHelper.canonize(subPredicates));
+                    PredicateHelper.canonize(subPredicates);
+                    isMatchedState = Deduplicator.or(subPredicates);
                 }
 
                 return invert ? isMatchedState.negate() : isMatchedState;

+ 5 - 0
common/src/main/java/malte0811/ferritecore/impl/StateHolderImpl.java

@@ -12,6 +12,11 @@ public class StateHolderImpl {
     public static final ThreadLocal<Map<Map<Property<?>, Comparable<?>>, ?>> LAST_STATE_MAP = new ThreadLocal<>();
     public static final ThreadLocal<FastMap<?>> LAST_FAST_STATE_MAP = new ThreadLocal<>();
 
+    /**
+     * Set up the {@link FastMap} used by the given {@link FastMapStateHolder} to handle neighbors and property lookups.
+     * This is called in a loop for each {@link net.minecraft.state.StateContainer}, so all state holders of a given
+     * container will use the same {@link FastMap} instance.
+     */
     public static <S>
     void populateNeighbors(Map<Map<Property<?>, Comparable<?>>, S> states, FastMapStateHolder<S> holder) {
         if (holder.getStateMap() != null) {

+ 1 - 0
common/src/main/java/malte0811/ferritecore/mixin/config/FerriteConfig.java

@@ -73,6 +73,7 @@ public class FerriteConfig {
 
         private void finish() {
             try {
+                // This runs too early for arch's ExpectPlatform, so reflection it is
                 Class<?> handler = Class.forName("malte0811.ferritecore.mixin.config.ConfigFileHandler");
                 Method finish = handler.getMethod("finish", List.class);
                 finish.invoke(null, options);

+ 5 - 0
common/src/main/java/malte0811/ferritecore/util/Constants.java

@@ -0,0 +1,5 @@
+package malte0811.ferritecore.util;
+
+public class Constants {
+    public static final String MODID = "ferritecore";
+}

+ 6 - 0
common/src/main/java/malte0811/ferritecore/util/LastAccessedCache.java

@@ -6,6 +6,12 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap;
 
 import java.util.function.Function;
 
+/**
+ * A cache which checks if the last accessed value is being accessed again before checking the main map
+ *
+ * @param <K> Key type
+ * @param <V> Value type
+ */
 public class LastAccessedCache<K, V> {
     private final Object2ObjectOpenCustomHashMap<K, V> mainMap;
     private final Function<K, V> createValue;

+ 29 - 3
common/src/main/java/malte0811/ferritecore/util/PredicateHelper.java

@@ -18,14 +18,40 @@ public class PredicateHelper {
         for (ICondition cond : conditions) {
             list.add(cond.getPredicate(stateContainer));
         }
-        return canonize(list);
+        canonize(list);
+        return list;
     }
 
-    public static <T> List<Predicate<T>> canonize(List<Predicate<T>> input) {
+    /**
+     * Sorts the given list by hashcode. This means that passing in different permutations of the same predicates will
+     * usually result in the same list (ignoring hash collisions).
+     */
+    public static <T> void canonize(List<Predicate<T>> input) {
         input.sort(Comparator.comparingInt(Predicate::hashCode));
         if (input instanceof ArrayList) {
             ((ArrayList<Predicate<T>>) input).trimToSize();
         }
-        return input;
+    }
+
+    public static <T> Predicate<T> and(List<Predicate<T>> list) {
+        return state -> {
+            for (Predicate<T> predicate : list) {
+                if (!predicate.test(state)) {
+                    return false;
+                }
+            }
+            return true;
+        };
+    }
+
+    public static <T> Predicate<T> or(List<Predicate<T>> list) {
+        return state -> {
+            for (Predicate<T> predicate : list) {
+                if (predicate.test(state)) {
+                    return true;
+                }
+            }
+            return false;
+        };
     }
 }

+ 5 - 4
common/src/test/java/malte0811/ferritecore/fastmap/FastMapTest.java

@@ -61,20 +61,21 @@ public class FastMapTest {
 
     @Test
     public void testOversizedBinaryKey() {
-        new BinaryFastMapKey<>(IntegerProperty.create("", 1, 4), 1 << 30);
+        new BinaryFastMapKey<>(IntegerProperty.create("", 1, 4), 1 << 29);
         Assertions.assertThrows(
                 IllegalStateException.class,
-                () -> new BinaryFastMapKey<>(IntegerProperty.create("", 1, 4), 1 << 31)
+                () -> new BinaryFastMapKey<>(IntegerProperty.create("", 1, 4), 1 << 30)
         );
     }
 
     @Test
     public void testBinaryKey32Bits() {
         int factor = 1;
-        for (int i = 0; i < 32; ++i) {
+        for (int i = 0; i < 31; ++i) {
             BinaryFastMapKey<Boolean> k = new BinaryFastMapKey<>(BOOL, factor);
-            Assertions.assertEquals(true, k.getValue(factor >>> 2));
+            Assertions.assertEquals(true, k.getValue(factor / 2));
             Assertions.assertEquals(false, k.getValue(factor));
+            Assertions.assertTrue(factor > 0);
             Assertions.assertEquals(true, k.getValue(factor << 2));
             factor *= k.getFactorToNext();
         }

+ 2 - 2
fabric/src/main/java/malte0811/ferritecore/mixin/config/ConfigFileHandler.java

@@ -2,7 +2,7 @@ package malte0811.ferritecore.mixin.config;
 
 import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
 import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap;
-import malte0811.ferritecore.ModMain;
+import malte0811.ferritecore.util.Constants;
 
 import java.io.IOException;
 import java.nio.file.Files;
@@ -15,7 +15,7 @@ import java.util.Properties;
 public class ConfigFileHandler {
     // Called reflectively from FerriteConfig
     public static void finish(List<FerriteConfig.Option> options) throws IOException {
-        Path config = Paths.get("config", ModMain.MODID + ".mixin.properties");
+        Path config = Paths.get("config", Constants.MODID + ".mixin.properties");
         if (!Files.exists(config))
             Files.createFile(config);
         Properties propsInFile = new Properties();

+ 2 - 1
forge/src/main/java/malte0811/ferritecore/ModClientForge.java

@@ -1,12 +1,13 @@
 package malte0811.ferritecore;
 
 import malte0811.ferritecore.impl.Deduplicator;
+import malte0811.ferritecore.util.Constants;
 import net.minecraftforge.api.distmarker.Dist;
 import net.minecraftforge.client.event.ParticleFactoryRegisterEvent;
 import net.minecraftforge.eventbus.api.SubscribeEvent;
 import net.minecraftforge.fml.common.Mod;
 
-@Mod.EventBusSubscriber(value = Dist.CLIENT, modid = ModMain.MODID, bus = Mod.EventBusSubscriber.Bus.MOD)
+@Mod.EventBusSubscriber(value = Dist.CLIENT, modid = Constants.MODID, bus = Mod.EventBusSubscriber.Bus.MOD)
 public class ModClientForge {
     @SubscribeEvent
     public static void registerReloadListener(ParticleFactoryRegisterEvent ev) {

+ 2 - 1
forge/src/main/java/malte0811/ferritecore/ModMainForge.java

@@ -1,12 +1,13 @@
 package malte0811.ferritecore;
 
 import malte0811.ferritecore.impl.BlockStateCacheImpl;
+import malte0811.ferritecore.util.Constants;
 import net.minecraftforge.event.TagsUpdatedEvent;
 import net.minecraftforge.eventbus.api.SubscribeEvent;
 import net.minecraftforge.fml.common.Mod;
 import net.minecraftforge.fml.event.lifecycle.FMLModIdMappingEvent;
 
-@Mod(ModMain.MODID)
+@Mod(Constants.MODID)
 @Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.FORGE)
 public class ModMainForge {
     // Caches are populated in two places: a) In ITagCollectionSupplier#updateTags (which triggers this event)

+ 2 - 2
forge/src/main/java/malte0811/ferritecore/mixin/config/ConfigFileHandler.java

@@ -2,8 +2,8 @@ package malte0811.ferritecore.mixin.config;
 
 import com.electronwill.nightconfig.core.ConfigSpec;
 import com.electronwill.nightconfig.core.file.CommentedFileConfig;
-import malte0811.ferritecore.ModMain;
 import malte0811.ferritecore.mixin.config.FerriteConfig.Option;
+import malte0811.ferritecore.util.Constants;
 
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -16,7 +16,7 @@ public class ConfigFileHandler {
         for (Option o : options) {
             spec.define(o.getName(), o.getDefaultValue());
         }
-        CommentedFileConfig configData = read(Paths.get("config", ModMain.MODID+"-mixin.toml"));
+        CommentedFileConfig configData = read(Paths.get("config", Constants.MODID + "-mixin.toml"));
         for (Option o : options) {
             configData.setComment(o.getName(), o.getComment());
         }