diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/file/ConfigFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/config/file/ConfigFileHandler.java
index e4f0b2512..4b46f0a07 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/config/file/ConfigFileHandler.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/config/file/ConfigFileHandler.java
@@ -240,7 +240,7 @@ public class ConfigFileHandler
else if (entry.getTrueValue() == null)
{
// TODO when can this happen?
- throw new IllegalArgumentException("Entry [" + entry.getNameAndCategory() + "] is null, this may be a problem with [" + ModInfo.NAME + "]. Please contact the authors.");
+ throw new IllegalArgumentException("BlockBiomeWrapperPair [" + entry.getNameAndCategory() + "] is null, this may be a problem with [" + ModInfo.NAME + "]. Please contact the authors.");
}
workConfig.set(entry.getNameAndCategory(), ConfigTypeConverters.attemptToConvertToString(entry.getType(), entry.getTrueValue()));
@@ -287,13 +287,13 @@ public class ConfigFileHandler
if (entry.getTrueValue() == null)
{
- LOGGER.warn("Entry [" + entry.getNameAndCategory() + "] returned as null from the config. Using default value.");
+ LOGGER.warn("BlockBiomeWrapperPair [" + entry.getNameAndCategory() + "] returned as null from the config. Using default value.");
entry.setWithoutFiringEvents(entry.getDefaultValue());
}
}
catch (Exception e)
{
- LOGGER.warn("Entry [" + entry.getNameAndCategory() + "] had an invalid value when loading the config. Using default value.");
+ LOGGER.warn("BlockBiomeWrapperPair [" + entry.getNameAndCategory() + "] had an invalid value when loading the config. Using default value.");
entry.setWithoutFiringEvents(entry.getDefaultValue());
}
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/BlockBiomeWrapperPair.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/BlockBiomeWrapperPair.java
new file mode 100644
index 000000000..3ec642291
--- /dev/null
+++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/BlockBiomeWrapperPair.java
@@ -0,0 +1,151 @@
+package com.seibel.distanthorizons.core.dataObjects;
+
+import com.seibel.distanthorizons.core.dataObjects.fullData.FullDataPointIdMap;
+import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
+import com.seibel.distanthorizons.core.util.objects.DataCorruptedException;
+import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
+import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
+import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
+import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A pooled compound key between the biome and blockState.
+ * These objects are pooled since we will need this compound key
+ * many times.
+ *
+ * @see FullDataPointIdMap
+ * @see IBlockStateWrapper
+ * @see IBiomeWrapper
+ */
+public class BlockBiomeWrapperPair
+{
+ private static final IWrapperFactory WRAPPER_FACTORY = SingletonInjector.INSTANCE.get(IWrapperFactory.class);
+
+ /** two levels are present so we don't need to use a key object */
+ private static final ConcurrentHashMap> CACHED_PAIR_BY_BIOME_BY_BLOCK = new ConcurrentHashMap<>();
+
+ public final IBiomeWrapper biome;
+ public final IBlockStateWrapper blockState;
+
+ private int hashCode = 0;
+ private boolean hashGenerated = false;
+ private String serialString = null;
+
+
+
+ //=============//
+ // constructor //
+ //=============//
+
+ public static BlockBiomeWrapperPair get(IBlockStateWrapper blockState, IBiomeWrapper biome)
+ {
+ // check for existing entry
+ ConcurrentHashMap pairByBiomeWrapper = CACHED_PAIR_BY_BIOME_BY_BLOCK.get(blockState);
+ if (pairByBiomeWrapper != null)
+ {
+ BlockBiomeWrapperPair pair = pairByBiomeWrapper.get(biome);
+ if (pair != null)
+ {
+ return pair;
+ }
+ }
+
+ // Lazily create the inner map and new BlockBiomeWrapperPair
+ return CACHED_PAIR_BY_BIOME_BY_BLOCK
+ .computeIfAbsent(blockState, newBlockState -> new ConcurrentHashMap<>())
+ .computeIfAbsent(biome, newBiome -> new BlockBiomeWrapperPair(biome, blockState));
+ }
+ private BlockBiomeWrapperPair(IBiomeWrapper biome, IBlockStateWrapper blockState)
+ {
+ this.biome = biome;
+ this.blockState = blockState;
+ }
+
+
+
+ //===========//
+ // overrides //
+ //===========//
+
+ /**
+ * Reminder: this hash code won't always be unique, collisions can occur;
+ * because of that this hash shouldn't be the only unique identifier for this object.
+ */
+ @Override
+ public int hashCode()
+ {
+ // cache the hash code to improve speed
+ if (!this.hashGenerated)
+ {
+ this.hashCode = generateHashCode(this);
+ this.hashGenerated = true;
+ }
+
+ return this.hashCode;
+ }
+ private static int generateHashCode(BlockBiomeWrapperPair pair) { return generateHashCode(pair.biome, pair.blockState); }
+ private static int generateHashCode(IBiomeWrapper biome, IBlockStateWrapper blockState)
+ {
+ final int prime = 31;
+
+ int result = 1;
+ // the biome and blockstate hashcode should be already calculated by the time
+ // we get here, so this operation should be very fast
+ result = prime * result + (biome == null ? 0 : biome.hashCode());
+ result = prime * result + (blockState == null ? 0 : blockState.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object otherObj)
+ {
+ if (otherObj == this)
+ {
+ return true;
+ }
+
+ if (!(otherObj instanceof BlockBiomeWrapperPair))
+ {
+ return false;
+ }
+
+ BlockBiomeWrapperPair other = (BlockBiomeWrapperPair) otherObj;
+ return other.biome.getSerialString().equals(this.biome.getSerialString())
+ && other.blockState.getSerialString().equals(this.blockState.getSerialString());
+ }
+
+ @Override
+ public String toString() { return this.serialize(); }
+
+
+
+ //=================//
+ // (de)serializing //
+ //=================//
+
+ public String serialize()
+ {
+ if (this.serialString == null)
+ {
+ this.serialString = this.biome.getSerialString() + FullDataPointIdMap.BLOCK_STATE_SEPARATOR_STRING + this.blockState.getSerialString();
+ }
+
+ return this.serialString;
+ }
+
+ public static BlockBiomeWrapperPair deserialize(String str, ILevelWrapper levelWrapper) throws DataCorruptedException
+ {
+ int separatorIndex = str.indexOf(FullDataPointIdMap.BLOCK_STATE_SEPARATOR_STRING);
+ if (separatorIndex == -1)
+ {
+ throw new DataCorruptedException("Failed to deserialize BiomeBlockStateEntry ["+str+"], unable to find separator.");
+ }
+
+ IBiomeWrapper biome = WRAPPER_FACTORY.deserializeBiomeWrapperOrGetDefault(str.substring(0, separatorIndex), levelWrapper);
+ IBlockStateWrapper blockState = WRAPPER_FACTORY.deserializeBlockStateWrapperOrGetDefault(str.substring(separatorIndex+FullDataPointIdMap.BLOCK_STATE_SEPARATOR_STRING.length()), levelWrapper);
+ return BlockBiomeWrapperPair.get(blockState, biome);
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataPointIdMap.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataPointIdMap.java
index b9034ded9..de96c6c97 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataPointIdMap.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataPointIdMap.java
@@ -19,7 +19,7 @@
package com.seibel.distanthorizons.core.dataObjects.fullData;
-import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
+import com.seibel.distanthorizons.core.dataObjects.BlockBiomeWrapperPair;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.util.LodUtil;
@@ -28,9 +28,7 @@ import com.seibel.distanthorizons.core.util.objects.dataStreams.DhDataInputStrea
import com.seibel.distanthorizons.core.util.objects.dataStreams.DhDataOutputStream;
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
-import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
-import org.apache.logging.log4j.LogManager;
import com.seibel.distanthorizons.core.logging.DhLogger;
import java.io.*;
@@ -60,15 +58,15 @@ public class FullDataPointIdMap
*/
private static final boolean RUN_SERIALIZATION_DUPLICATE_VALIDATION = false;
/** Distant Horizons - Block State Wrapper */
- private static final String BLOCK_STATE_SEPARATOR_STRING = "_DH-BSW_";
+ public static final String BLOCK_STATE_SEPARATOR_STRING = "_DH-BSW_";
/** should only be used for debugging */
private long pos;
- /** The index should be the same as the Entry's ID */
- private final ArrayList entryList = new ArrayList<>();
- private final ConcurrentHashMap idMap = new ConcurrentHashMap<>();
+ /** The index should be the same as the BlockBiomeWrapperPair's ID */
+ private final ArrayList blockBiomePairList = new ArrayList<>();
+ private final ConcurrentHashMap idMap = new ConcurrentHashMap<>();
private int cachedHashCode = 0;
@@ -90,28 +88,28 @@ public class FullDataPointIdMap
public IBiomeWrapper getBiomeWrapper(int id) throws IndexOutOfBoundsException { return this.getEntry(id).biome; }
/** @see FullDataPointIdMap#getEntry(int) */
public IBlockStateWrapper getBlockStateWrapper(int id) throws IndexOutOfBoundsException { return this.getEntry(id).blockState; }
- /** @throws IndexOutOfBoundsException if the given ID isn't in the {@link FullDataPointIdMap#entryList} */
- private Entry getEntry(int id) throws IndexOutOfBoundsException
+ /** @throws IndexOutOfBoundsException if the given ID isn't in the {@link FullDataPointIdMap#blockBiomePairList} */
+ private BlockBiomeWrapperPair getEntry(int id) throws IndexOutOfBoundsException
{
- Entry entry;
+ BlockBiomeWrapperPair pair;
try
{
- entry = this.entryList.get(id);
+ pair = this.blockBiomePairList.get(id);
}
catch (IndexOutOfBoundsException e)
{
- throw new IndexOutOfBoundsException("FullData ID Map out of sync for pos: "+DhSectionPos.toString(this.pos)+". ID: ["+id+"] greater than the number of known ID's: ["+this.entryList.size()+"].");
+ throw new IndexOutOfBoundsException("FullData ID Map out of sync for pos: "+DhSectionPos.toString(this.pos)+". ID: ["+id+"] greater than the number of known ID's: ["+this.blockBiomePairList.size()+"].");
}
- return entry;
+ return pair;
}
/** @return -1 if the list is empty */
- public int getMaxValidId() { return this.entryList.size() - 1; }
- public int size() { return this.entryList.size(); }
+ public int getMaxValidId() { return this.blockBiomePairList.size() - 1; }
+ public int size() { return this.blockBiomePairList.size(); }
- public boolean isEmpty() { return this.entryList.isEmpty(); }
+ public boolean isEmpty() { return this.blockBiomePairList.isEmpty(); }
public long getPos() { return this.pos; }
@@ -125,11 +123,11 @@ public class FullDataPointIdMap
* If an entry with the given values already exists nothing will
* be added but the existing item's ID will still be returned.
*/
- public int addIfNotPresentAndGetId(IBiomeWrapper biome, IBlockStateWrapper blockState) { return this.addIfNotPresentAndGetId(Entry.getEntry(biome, blockState)); }
- private int addIfNotPresentAndGetId(Entry biomeBlockStateEntry)
+ public int addIfNotPresentAndGetId(IBiomeWrapper biome, IBlockStateWrapper blockState) { return this.addIfNotPresentAndGetId(BlockBiomeWrapperPair.get(blockState, biome)); }
+ private int addIfNotPresentAndGetId(BlockBiomeWrapperPair pair)
{
// try getting the existing ID
- Integer nullableId = this.idMap.get(biomeBlockStateEntry);
+ Integer nullableId = this.idMap.get(pair);
if (nullableId != null)
{
return nullableId;
@@ -137,7 +135,7 @@ public class FullDataPointIdMap
// create the new ID
- return this.idMap.compute(biomeBlockStateEntry, (Entry newBiomeBlockStateEntry, Integer currentId) ->
+ return this.idMap.compute(pair, (BlockBiomeWrapperPair newPair, Integer currentId) ->
{
if (currentId != null)
{
@@ -146,8 +144,8 @@ public class FullDataPointIdMap
// Add the new ID
- currentId = this.entryList.size();
- this.entryList.add(biomeBlockStateEntry);
+ currentId = this.blockBiomePairList.size();
+ this.blockBiomePairList.add(newPair);
// invalidate the cached hash code
this.cachedHashCode = 0;
@@ -157,7 +155,7 @@ public class FullDataPointIdMap
}
/**
- * Adds every {@link Entry} from inputMap into this map.
+ * Adds every {@link BlockBiomeWrapperPair} from inputMap into this map.
* Allows duplicate entries.
*
* Allowing duplicate entries should be done if a datasource is just being read in and
@@ -167,19 +165,19 @@ public class FullDataPointIdMap
*/
public void addAll(FullDataPointIdMap inputMap)
{
- ArrayList entriesToMerge = inputMap.entryList;
- for (int i = 0; i < entriesToMerge.size(); i++)
+ ArrayList pairsToMerge = inputMap.blockBiomePairList;
+ for (int i = 0; i < pairsToMerge.size(); i++)
{
- Entry entity = entriesToMerge.get(i);
- this.add(entity);
+ BlockBiomeWrapperPair pair = pairsToMerge.get(i);
+ this.add(pair);
}
}
- /** allows for adding duplicate {@link Entry} */
- private void add(Entry biomeBlockStateEntry)
+ /** allows for adding duplicate {@link BlockBiomeWrapperPair} */
+ private void add(BlockBiomeWrapperPair pair)
{
- int id = this.entryList.size();
- this.entryList.add(biomeBlockStateEntry);
- this.idMap.put(biomeBlockStateEntry, id);
+ int id = this.blockBiomePairList.size();
+ this.blockBiomePairList.add(pair);
+ this.idMap.put(pair, id);
// invalidate the cached hash code
this.cachedHashCode = 0;
@@ -196,23 +194,23 @@ public class FullDataPointIdMap
*/
public int[] mergeAndReturnRemappedEntityIds(FullDataPointIdMap inputMap)
{
- ArrayList entriesToMerge = inputMap.entryList;
- int[] remappedEntryIds = new int[entriesToMerge.size()];
+ ArrayList entriesToMerge = inputMap.blockBiomePairList;
+ int[] remappedPairIds = new int[entriesToMerge.size()];
for (int i = 0; i < entriesToMerge.size(); i++)
{
- Entry entity = entriesToMerge.get(i);
+ BlockBiomeWrapperPair entity = entriesToMerge.get(i);
int id = this.addIfNotPresentAndGetId(entity);
- remappedEntryIds[i] = id;
+ remappedPairIds[i] = id;
}
- return remappedEntryIds;
+ return remappedPairIds;
}
/** Should only be used if this map is going to be reused, otherwise bad things will happen. */
public void clear(long pos)
{
this.pos = pos;
- this.entryList.clear();
+ this.blockBiomePairList.clear();
this.idMap.clear();
this.cachedHashCode = 0;
}
@@ -226,27 +224,27 @@ public class FullDataPointIdMap
/** Serializes all contained entries into the given stream, formatted in UTF */
public void serialize(DhDataOutputStream outputStream) throws IOException
{
- outputStream.writeInt(this.entryList.size());
+ outputStream.writeInt(this.blockBiomePairList.size());
// only used when debugging
- HashMap dataPointEntryBySerialization = new HashMap<>();
+ HashMap dataPointEntryBySerialization = new HashMap<>();
- for (Entry entry : this.entryList)
+ for (BlockBiomeWrapperPair pair : this.blockBiomePairList)
{
- String entryString = entry.serialize();
+ String entryString = pair.serialize();
outputStream.writeUTF(entryString);
if (RUN_SERIALIZATION_DUPLICATE_VALIDATION)
{
if (dataPointEntryBySerialization.containsKey(entryString))
{
- LOGGER.error("Duplicate serialized entry found with serial: " + entryString);
+ LOGGER.error("Duplicate serialized pair found with serial: " + entryString);
}
- if (dataPointEntryBySerialization.containsValue(entry))
+ if (dataPointEntryBySerialization.containsValue(pair))
{
- LOGGER.error("Duplicate serialized entry found with value: " + entry.serialize());
+ LOGGER.error("Duplicate serialized pair found with value: " + pair.serialize());
}
- dataPointEntryBySerialization.put(entryString, entry);
+ dataPointEntryBySerialization.put(entryString, pair);
}
}
}
@@ -262,7 +260,7 @@ public class FullDataPointIdMap
// only used when debugging
- HashMap dataPointEntryBySerialization = new HashMap<>();
+ HashMap dataPointEntryBySerialization = new HashMap<>();
FullDataPointIdMap newMap = new FullDataPointIdMap(pos);
for (int i = 0; i < entityCount; i++)
@@ -275,8 +273,8 @@ public class FullDataPointIdMap
String entryString = inputStream.readUTF();
- Entry newEntry = Entry.deserialize(entryString, levelWrapper);
- newMap.entryList.add(newEntry);
+ BlockBiomeWrapperPair newPair = BlockBiomeWrapperPair.deserialize(entryString, levelWrapper);
+ newMap.blockBiomePairList.add(newPair);
if (RUN_SERIALIZATION_DUPLICATE_VALIDATION)
{
@@ -284,11 +282,11 @@ public class FullDataPointIdMap
{
LOGGER.error("Duplicate deserialized entry found with serial: " + entryString);
}
- if (dataPointEntryBySerialization.containsValue(newEntry))
+ if (dataPointEntryBySerialization.containsValue(newPair))
{
- LOGGER.error("Duplicate deserialized entry found with value: " + newEntry.serialize());
+ LOGGER.error("Duplicate deserialized entry found with value: " + newPair.serialize());
}
- dataPointEntryBySerialization.put(entryString, newEntry);
+ dataPointEntryBySerialization.put(entryString, newPair);
}
}
@@ -334,149 +332,13 @@ public class FullDataPointIdMap
private void generateHashCode()
{
int result = DhSectionPos.hashCode(this.pos);
- for (int i = 0; i < this.entryList.size(); i++)
+ for (int i = 0; i < this.blockBiomePairList.size(); i++)
{
- result = 31 * result + this.entryList.hashCode();
+ result = 31 * result + this.blockBiomePairList.hashCode();
}
this.cachedHashCode = result;
}
- //==============//
- // helper class //
- //==============//
-
- private static final class Entry
- {
- private static final IWrapperFactory WRAPPER_FACTORY = SingletonInjector.INSTANCE.get(IWrapperFactory.class);
-
- /** two levels are present so we don't need to use a key object */
- private static final ConcurrentHashMap> ENTRY_BY_BLOCKSTATE_BY_BIOMEWRAPPER = new ConcurrentHashMap<>();
-
- public final IBiomeWrapper biome;
- public final IBlockStateWrapper blockState;
-
- private int hashCode = 0;
- private boolean hashGenerated = false;
- private String serialString = null;
-
-
-
- //=============//
- // constructor //
- //=============//
-
- public static Entry getEntry(IBiomeWrapper biome, IBlockStateWrapper blockState)
- {
- // check for existing entry
- ConcurrentHashMap entryByBlockState = ENTRY_BY_BLOCKSTATE_BY_BIOMEWRAPPER.get(biome);
- if (entryByBlockState != null)
- {
- Entry entry = entryByBlockState.get(blockState);
- if (entry != null)
- {
- return entry;
- }
- }
-
- // Lazily create the inner map and new Entry
- return ENTRY_BY_BLOCKSTATE_BY_BIOMEWRAPPER
- .computeIfAbsent(biome, newBiome -> new ConcurrentHashMap<>())
- .computeIfAbsent(blockState, newBlockState -> new Entry(biome, blockState));
- }
- private Entry(IBiomeWrapper biome, IBlockStateWrapper blockState)
- {
- this.biome = biome;
- this.blockState = blockState;
- }
-
-
-
- //===========//
- // overrides //
- //===========//
-
- /**
- * Reminder: this hash code won't always be unique, collisions can occur;
- * because of that this hash shouldn't be the only unique identifier for this object.
- */
- @Override
- public int hashCode()
- {
- // cache the hash code to improve speed
- if (!this.hashGenerated)
- {
- this.hashCode = generateHashCode(this);
- this.hashGenerated = true;
- }
-
- return this.hashCode;
- }
- private static int generateHashCode(Entry entry) { return generateHashCode(entry.biome, entry.blockState); }
- private static int generateHashCode(IBiomeWrapper biome, IBlockStateWrapper blockState)
- {
- final int prime = 31;
-
- int result = 1;
- // the biome and blockstate hashcode should be already calculated by the time
- // we get here, so this operation should be very fast
- result = prime * result + (biome == null ? 0 : biome.hashCode());
- result = prime * result + (blockState == null ? 0 : blockState.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object otherObj)
- {
- if (otherObj == this)
- {
- return true;
- }
-
- if (!(otherObj instanceof Entry))
- {
- return false;
- }
-
- Entry other = (Entry) otherObj;
- return other.biome.getSerialString().equals(this.biome.getSerialString())
- && other.blockState.getSerialString().equals(this.blockState.getSerialString());
- }
-
- @Override
- public String toString() { return this.serialize(); }
-
-
-
- //=================//
- // (de)serializing //
- //=================//
-
- public String serialize()
- {
- if (this.serialString == null)
- {
- this.serialString = this.biome.getSerialString() + BLOCK_STATE_SEPARATOR_STRING + this.blockState.getSerialString();
- }
-
- return this.serialString;
- }
-
- public static Entry deserialize(String str, ILevelWrapper levelWrapper) throws DataCorruptedException
- {
- int separatorIndex = str.indexOf(BLOCK_STATE_SEPARATOR_STRING);
- if (separatorIndex == -1)
- {
- throw new DataCorruptedException("Failed to deserialize BiomeBlockStateEntry ["+str+"], unable to find separator.");
- }
-
- IBiomeWrapper biome = WRAPPER_FACTORY.deserializeBiomeWrapperOrGetDefault(str.substring(0, separatorIndex), levelWrapper);
- IBlockStateWrapper blockState = WRAPPER_FACTORY.deserializeBlockStateWrapperOrGetDefault(str.substring(separatorIndex+BLOCK_STATE_SEPARATOR_STRING.length()), levelWrapper);
- return Entry.getEntry(biome, blockState);
- }
-
- }
-
-
}