diff --git a/core/src/main/java/com/seibel/lod/core/datatype/full/ChunkSizedData.java b/core/src/main/java/com/seibel/lod/core/datatype/full/ChunkSizedData.java
index 85badb245..586d9f5de 100644
--- a/core/src/main/java/com/seibel/lod/core/datatype/full/ChunkSizedData.java
+++ b/core/src/main/java/com/seibel/lod/core/datatype/full/ChunkSizedData.java
@@ -11,7 +11,7 @@ public class ChunkSizedData extends FullArrayView
public ChunkSizedData(byte dataDetail, int x, int z)
{
- super(new IdBiomeBlockStateMap(), new long[16 * 16][0], 16);
+ super(new FullDataPointIdMap(), new long[16 * 16][0], 16);
this.dataDetail = dataDetail;
this.x = x;
this.z = z;
diff --git a/core/src/main/java/com/seibel/lod/core/datatype/full/FullFormat.java b/core/src/main/java/com/seibel/lod/core/datatype/full/FullDataPoint.java
similarity index 58%
rename from core/src/main/java/com/seibel/lod/core/datatype/full/FullFormat.java
rename to core/src/main/java/com/seibel/lod/core/datatype/full/FullDataPoint.java
index 7a82c4f7d..120fb2936 100644
--- a/core/src/main/java/com/seibel/lod/core/datatype/full/FullFormat.java
+++ b/core/src/main/java/com/seibel/lod/core/datatype/full/FullDataPoint.java
@@ -1,25 +1,38 @@
package com.seibel.lod.core.datatype.full;
-// Static class for the data format:
-// ID: blockState id Y: Height(signed) DP: Depth(signed?) (Depth means the length of the block!)
-// BL: Block light SL: Sky light
-// =======Bit layout=======
-// BL BL BL BL SL SL SL SL <-- Top bits
-// YY YY YY YY YY YY YY YY
-// YY YY YY YY DP DP DP DP
-// DP DP DP DP DP DP DP DP
-// ID ID ID ID ID ID IO ID
-// ID ID ID ID ID ID IO ID
-// ID ID ID ID ID ID IO ID
-// ID ID ID ID ID ID IO ID <-- Bottom bits
+//
import com.seibel.lod.core.util.LodUtil;
import org.jetbrains.annotations.Contract;
import static com.seibel.lod.core.datatype.column.accessor.ColumnFormat.MAX_WORLD_Y_SIZE;
-public class FullFormat {
-
+/**
+ *
+ * Static class used to format the full binary Distant Horizons data format.
+ * Contains all the data we save.
+ *
+ *
+ * ID: blockState id
+ * Y: Height(signed)
+ * DP: Depth(signed?) (Depth means the length of the block!)
+ * BL: Block light
+ * SL: Sky light
+ *
+ * =======Bit layout=======
+ * BL BL BL BL SL SL SL SL <-- Top bits
+ * YY YY YY YY YY YY YY YY
+ * YY YY YY YY DP DP DP DP
+ * DP DP DP DP DP DP DP DP
+ * ID ID ID ID ID ID IO ID
+ * ID ID ID ID ID ID IO ID
+ * ID ID ID ID ID ID IO ID
+ * ID ID ID ID ID ID IO ID <-- Bottom bits
+ *
+ *
+ */
+public class FullDataPoint
+{
public static final int ID_WIDTH = 32;
public static final int DP_WIDTH = 12;
public static final int Y_WIDTH = 12;
@@ -28,18 +41,22 @@ public class FullFormat {
public static final int DP_OFFSET = ID_OFFSET + ID_WIDTH;
public static final int Y_OFFSET = DP_OFFSET + DP_WIDTH;
public static final int LIGHT_OFFSET = Y_OFFSET + Y_WIDTH;
-
-
+
+
public static final long ID_MASK = Integer.MAX_VALUE;
public static final long INVERSE_ID_MASK = ~ID_MASK;
public static final int DP_MASK = (int)Math.pow(2, DP_WIDTH) - 1;
public static final int Y_MASK = (int)Math.pow(2, Y_WIDTH) - 1;
public static final int LIGHT_MASK = (int)Math.pow(2, LIGHT_WIDTH) - 1;
-
- public static long encode(int id, int depth, int y, byte lightPair) {
+
+
+ /** creates a new datapoint with the given values */
+ public static long encode(int id, int depth, int y, byte lightPair)
+ {
LodUtil.assertTrue(y >= 0 && y < MAX_WORLD_Y_SIZE, "Trying to create datapoint with y[{}] out of range!", y);
LodUtil.assertTrue(depth > 0 && depth < MAX_WORLD_Y_SIZE, "Trying to create datapoint with depth[{}] out of range!", depth);
LodUtil.assertTrue(y+depth <= MAX_WORLD_Y_SIZE, "Trying to create datapoint with y+depth[{}] out of range!", y+depth);
+
long data = 0;
data |= id & ID_MASK;
data |= (long) (depth & DP_MASK) << DP_OFFSET;
@@ -48,31 +65,19 @@ public class FullFormat {
LodUtil.assertTrue(getId(data) == id && getDepth(data) == depth && getY(data) == y && getLight(data) == Byte.toUnsignedInt(lightPair),
"Trying to create datapoint with id[{}], depth[{}], y[{}], lightPair[{}] but got id[{}], depth[{}], y[{}], lightPair[{}]!",
id, depth, y, Byte.toUnsignedInt(lightPair), getId(data), getDepth(data), getY(data), getLight(data));
+
return data;
}
-
- public static int getId(long data) {
- return (int) (data & ID_MASK);
- }
-
- public static int getDepth(long data) {
- return (int) ((data >> DP_OFFSET) & DP_MASK);
- }
-
- public static int getY(long data) {
- return (int) ((data >> Y_OFFSET) & Y_MASK);
- }
-
- public static int getLight(long data) {
- return (int) ((data >> LIGHT_OFFSET) & LIGHT_MASK);
- }
-
- public static String toString(long data) {
- return "[ID:" + getId(data) + ",Y:" + getY(data) + ",Depth:" + getY(data) + ",Light:" + getLight(data) + "]";
- }
-
+
+ public static int getId(long data) { return (int) (data & ID_MASK); }
+ public static int getDepth(long data) { return (int) ((data >> DP_OFFSET) & DP_MASK); }
+ public static int getY(long data) { return (int) ((data >> Y_OFFSET) & Y_MASK); }
+ public static int getLight(long data) { return (int) ((data >> LIGHT_OFFSET) & LIGHT_MASK); }
+
+ public static String toString(long data) { return "[ID:" + getId(data) + ",Y:" + getY(data) + ",Depth:" + getY(data) + ",Light:" + getLight(data) + "]"; }
+
+ /** Remaps the biome/blockState ID of the given datapoint */
@Contract(pure = true)
- public static long remap(int[] mapping, long data) {
- return (data & INVERSE_ID_MASK) | mapping[(int)data];
- }
+ public static long remap(int[] newIdMapping, long data) { return (data & INVERSE_ID_MASK) | newIdMapping[(int)data]; }
+
}
diff --git a/core/src/main/java/com/seibel/lod/core/datatype/full/FullDataPointIdMap.java b/core/src/main/java/com/seibel/lod/core/datatype/full/FullDataPointIdMap.java
new file mode 100644
index 000000000..00aa84a6f
--- /dev/null
+++ b/core/src/main/java/com/seibel/lod/core/datatype/full/FullDataPointIdMap.java
@@ -0,0 +1,150 @@
+package com.seibel.lod.core.datatype.full;
+
+import com.seibel.lod.core.dependencyInjection.SingletonInjector;
+import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
+import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
+import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * WARNING: This is not THREAD-SAFE!
+ *
+ * Used to map a numerical ID to a Biome/BlockState pair.
+ *
+ * @author Leetom
+ * @version 2022-9-30
+ */
+public class FullDataPointIdMap
+{
+ final ArrayList entries = new ArrayList<>();
+ final ConcurrentHashMap idMap = new ConcurrentHashMap<>(); // FIXME: Improve performance
+
+
+
+ public IBiomeWrapper getBiomeWrapper(int id) { return entries.get(id).biome; }
+ public IBlockStateWrapper getBlockStateWrapper(int id) { return entries.get(id).blockState; }
+
+ /** Adds a new entry to the map and returns its numerical ID */
+ public int setAndGetId(IBiomeWrapper biome, IBlockStateWrapper blockState) { return setAndGetId(new Entry(biome, blockState)); }
+ private int setAndGetId(Entry biomeBlockStateEntry)
+ {
+ return idMap.computeIfAbsent(biomeBlockStateEntry, (entry) -> {
+ int id = entries.size();
+ entries.add(entry);
+ return id;
+ });
+ }
+
+
+ /**
+ * Adds each entry from the given map to this map.
+ * @return an array of each added entry's ID in this map in order
+ */
+ public int[] mergeAndReturnRemappedEntityIds(FullDataPointIdMap target)
+ {
+ ArrayList entriesToMerge = target.entries;
+
+ int[] remappedEntryIds = new int[entriesToMerge.size()];
+ for (int i = 0; i < entriesToMerge.size(); i++)
+ {
+ remappedEntryIds[i] = setAndGetId(entriesToMerge.get(i));
+ }
+ return remappedEntryIds;
+ }
+
+ /** Serializes all contained entries into the given stream, formatted in UTF */
+ void serialize(OutputStream outputStream) throws IOException
+ {
+ DataOutputStream dataStream = new DataOutputStream(outputStream); // DO NOT CLOSE! It would close all related streams
+ dataStream.writeInt(entries.size());
+ for (Entry entry : entries)
+ {
+ dataStream.writeUTF(entry.serialize());
+ }
+ }
+
+ /** Creates a new IdBiomeBlockStateMap from the given UTF formatted stream */
+ static FullDataPointIdMap deserialize(InputStream inputStream) throws IOException
+ {
+ DataInputStream dataStream = new DataInputStream(inputStream); // DO NOT CLOSE! It would close all related streams
+ int entityCount = dataStream.readInt();
+ FullDataPointIdMap newMap = new FullDataPointIdMap();
+ for (int i = 0; i < entityCount; i++)
+ {
+ newMap.entries.add(Entry.deserialize(dataStream.readUTF()));
+ }
+ return newMap;
+ }
+
+ @Override
+ public boolean equals(Object other)
+ {
+ if (other == this)
+ return true;
+// if (!(other instanceof IdBiomeBlockStateMap)) return false;
+// IdBiomeBlockStateMap otherMap = (IdBiomeBlockStateMap) other;
+// if (entries.size() != otherMap.entries.size()) return false;
+// for (int i=0; i entries = new ArrayList<>();
- final ConcurrentHashMap idMap = new ConcurrentHashMap<>(); // FIXME: Improve performance
-
- public Entry get(int id) { return entries.get(id); }
-
- public int setAndGetId(IBiomeWrapper biome, IBlockStateWrapper blockState)
- {
- return idMap.computeIfAbsent(new Entry(biome, blockState), (e) -> {
- int id = entries.size();
- entries.add(e);
- return id;
- });
- }
-
- public int setAndGetId(Entry biomeBlockStateEntry)
- {
- return idMap.computeIfAbsent(biomeBlockStateEntry, (e) -> {
- int id = entries.size();
- entries.add(e);
- return id;
- });
- }
-
- public int[] computeAndMergeMapFrom(IdBiomeBlockStateMap target)
- {
- ArrayList mergeEntry = target.entries;
- int[] mapper = new int[mergeEntry.size()];
- for (int i = 0; i < mergeEntry.size(); i++)
- {
- mapper[i] = setAndGetId(mergeEntry.get(i));
- }
- return mapper;
- }
-
- void serialize(OutputStream os) throws IOException
- {
- DataOutputStream dos = new DataOutputStream(os); // DO NOT CLOSE!
- dos.writeInt(entries.size());
- for (Entry e : entries)
- {
- dos.writeUTF(e.serialize());
- }
- }
-
- static IdBiomeBlockStateMap deserialize(InputStream is) throws IOException
- {
- DataInputStream dis = new DataInputStream(is); // DO NOT CLOSE!
- int size = dis.readInt();
- IdBiomeBlockStateMap map = new IdBiomeBlockStateMap();
- for (int i = 0; i < size; i++)
- {
- map.entries.add(Entry.deserialize(dis.readUTF()));
- }
- return map;
- }
-
- @Override
- public boolean equals(Object other)
- {
- if (other == this)
- return true;
-// if (!(other instanceof IdBiomeBlockStateMap)) return false;
-// IdBiomeBlockStateMap otherMap = (IdBiomeBlockStateMap) other;
-// if (entries.size() != otherMap.entries.size()) return false;
-// for (int i=0; i SPARSE_UNIT_DETAIL);
LodUtil.assertTrue(sectionPos.sectionDetail <= MAX_SECTION_DETAIL);
this.sectionPos = sectionPos;
@@ -213,7 +213,7 @@ public class SparseDataSource implements ILodDataSource
public static SparseDataSource loadData(DataMetaFile dataFile, InputStream dataStream, IDhLevel level) throws IOException {
LodUtil.assertTrue(dataFile.pos.sectionDetail > SPARSE_UNIT_DETAIL);
LodUtil.assertTrue(dataFile.pos.sectionDetail <= MAX_SECTION_DETAIL);
- DataInputStream dos = new DataInputStream(dataStream); // DO NOT CLOSE!
+ DataInputStream dos = new DataInputStream(dataStream); // DO NOT CLOSE! It would close all related streams
{
int dataDetail = dos.readShort();
if(dataDetail != dataFile.metaData.dataLevel)
@@ -271,7 +271,7 @@ public class SparseDataSource implements ILodDataSource
// Id mapping
end = dos.readInt();
if (end != 0xFFFFFFFF) throw new IOException("invalid data content end guard");
- IdBiomeBlockStateMap mapping = IdBiomeBlockStateMap.deserialize(dos);
+ FullDataPointIdMap mapping = FullDataPointIdMap.deserialize(dos);
end = dos.readInt();
if (end != 0xFFFFFFFF) throw new IOException("invalid id mapping end guard");
diff --git a/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/FullArrayView.java b/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/FullArrayView.java
index 75c078997..aff3ee883 100644
--- a/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/FullArrayView.java
+++ b/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/FullArrayView.java
@@ -1,7 +1,7 @@
package com.seibel.lod.core.datatype.full.accessor;
-import com.seibel.lod.core.datatype.full.FullFormat;
-import com.seibel.lod.core.datatype.full.IdBiomeBlockStateMap;
+import com.seibel.lod.core.datatype.full.FullDataPoint;
+import com.seibel.lod.core.datatype.full.FullDataPointIdMap;
import com.seibel.lod.core.util.LodUtil;
public class FullArrayView implements IFullDataView
@@ -10,9 +10,9 @@ public class FullArrayView implements IFullDataView
protected final int offset;
protected final int size;
protected final int dataSize;
- protected final IdBiomeBlockStateMap mapping;
+ protected final FullDataPointIdMap mapping;
- public FullArrayView(IdBiomeBlockStateMap mapping, long[][] dataArrays, int size)
+ public FullArrayView(FullDataPointIdMap mapping, long[][] dataArrays, int size)
{
if (dataArrays.length != size * size)
throw new IllegalArgumentException(
@@ -37,7 +37,7 @@ public class FullArrayView implements IFullDataView
}
@Override
- public IdBiomeBlockStateMap getMapping()
+ public FullDataPointIdMap getMapping()
{
return mapping;
}
@@ -66,11 +66,13 @@ public class FullArrayView implements IFullDataView
return new FullArrayView(this, size, ox, oz);
}
- /** WARNING: It will potentially share the underlying array object! */
+ /** WARNING: This will potentially share the underlying array object! */
public void shadowCopyTo(FullArrayView target)
{
if (target.size != size)
+ {
throw new IllegalArgumentException("Target view must have same size as this view");
+ }
if (target.mapping.equals(mapping))
{
for (int x = 0; x < size; x++)
@@ -81,7 +83,7 @@ public class FullArrayView implements IFullDataView
}
else
{
- int[] map = target.mapping.computeAndMergeMapFrom(mapping);
+ int[] remappedIds = target.mapping.mergeAndReturnRemappedEntityIds(mapping);
for (int x = 0; x < size; x++)
{
for (int o = 0; o < size; o++)
@@ -90,7 +92,7 @@ public class FullArrayView implements IFullDataView
long[] newData = new long[sourceData.length];
for (int i = 0; i < newData.length; i++)
{
- newData[i] = FullFormat.remap(map, sourceData[i]);
+ newData[i] = FullDataPoint.remap(remappedIds, sourceData[i]);
}
target.dataArrays[target.offset + x * target.dataSize + o] = newData;
}
diff --git a/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/IFullDataView.java b/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/IFullDataView.java
index 440c2241a..2b987db81 100644
--- a/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/IFullDataView.java
+++ b/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/IFullDataView.java
@@ -1,13 +1,13 @@
package com.seibel.lod.core.datatype.full.accessor;
-import com.seibel.lod.core.datatype.full.IdBiomeBlockStateMap;
+import com.seibel.lod.core.datatype.full.FullDataPointIdMap;
import com.seibel.lod.core.util.LodUtil;
import java.util.Iterator;
public interface IFullDataView
{
- IdBiomeBlockStateMap getMapping();
+ FullDataPointIdMap getMapping();
SingleFullArrayView get(int index);
diff --git a/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/SingleFullArrayView.java b/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/SingleFullArrayView.java
index e74d5ac2d..b019c3d2b 100644
--- a/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/SingleFullArrayView.java
+++ b/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/SingleFullArrayView.java
@@ -1,15 +1,15 @@
package com.seibel.lod.core.datatype.full.accessor;
-import com.seibel.lod.core.datatype.full.FullFormat;
-import com.seibel.lod.core.datatype.full.IdBiomeBlockStateMap;
+import com.seibel.lod.core.datatype.full.FullDataPoint;
+import com.seibel.lod.core.datatype.full.FullDataPointIdMap;
public class SingleFullArrayView implements IFullDataView
{
private final long[][] dataArrays;
private final int offset;
- private final IdBiomeBlockStateMap mapping;
+ private final FullDataPointIdMap mapping;
- public SingleFullArrayView(IdBiomeBlockStateMap mapping, long[][] dataArrays, int offset)
+ public SingleFullArrayView(FullDataPointIdMap mapping, long[][] dataArrays, int offset)
{
this.dataArrays = dataArrays;
this.offset = offset;
@@ -19,7 +19,7 @@ public class SingleFullArrayView implements IFullDataView
public boolean doesItExist() { return dataArrays[offset].length != 0; }
@Override
- public IdBiomeBlockStateMap getMapping() { return mapping; }
+ public FullDataPointIdMap getMapping() { return mapping; }
@Override
public SingleFullArrayView get(int index)
@@ -68,12 +68,12 @@ public class SingleFullArrayView implements IFullDataView
}
else
{
- int[] map = target.mapping.computeAndMergeMapFrom(mapping);
+ int[] remappedEntryIds = target.mapping.mergeAndReturnRemappedEntityIds(mapping);
long[] sourceData = dataArrays[offset];
long[] newData = new long[sourceData.length];
for (int i = 0; i < newData.length; i++)
{
- newData[i] = FullFormat.remap(map, sourceData[i]);
+ newData[i] = FullDataPoint.remap(remappedEntryIds, sourceData[i]);
}
target.dataArrays[target.offset] = newData;
}
@@ -87,12 +87,12 @@ public class SingleFullArrayView implements IFullDataView
}
else
{
- int[] map = target.mapping.computeAndMergeMapFrom(mapping);
+ int[] remappedEntryIds = target.mapping.mergeAndReturnRemappedEntityIds(mapping);
long[] sourceData = dataArrays[offset];
long[] newData = new long[sourceData.length];
for (int i = 0; i < newData.length; i++)
{
- newData[i] = FullFormat.remap(map, sourceData[i]);
+ newData[i] = FullDataPoint.remap(remappedEntryIds, sourceData[i]);
}
target.dataArrays[target.offset] = newData;
}
diff --git a/core/src/main/java/com/seibel/lod/core/datatype/transform/FullToColumnTransformer.java b/core/src/main/java/com/seibel/lod/core/datatype/transform/FullToColumnTransformer.java
index df624cc1b..83e1c4905 100644
--- a/core/src/main/java/com/seibel/lod/core/datatype/transform/FullToColumnTransformer.java
+++ b/core/src/main/java/com/seibel/lod/core/datatype/transform/FullToColumnTransformer.java
@@ -163,18 +163,17 @@ public class FullToColumnTransformer {
}
private static void iterateAndConvert(IDhClientLevel level, int blockX, int blockZ, int genMode, ColumnArrayView column, SingleFullArrayView data) {
- IdBiomeBlockStateMap mapping = data.getMapping();
+ FullDataPointIdMap mapping = data.getMapping();
boolean isVoid = true;
int offset = 0;
for (int i = 0; i < data.getSingleLength(); i++) {
long fullData = data.getSingle(i);
- int y = FullFormat.getY(fullData);
- int blockLength = FullFormat.getDepth(fullData);
- int id = FullFormat.getId(fullData);
- int light = FullFormat.getLight(fullData);
- IdBiomeBlockStateMap.Entry entry = mapping.get(id);
- IBiomeWrapper biome = entry.biome;
- IBlockStateWrapper block = entry.blockState;
+ int y = FullDataPoint.getY(fullData);
+ int blockLength = FullDataPoint.getDepth(fullData);
+ int id = FullDataPoint.getId(fullData);
+ int light = FullDataPoint.getLight(fullData);
+ IBiomeWrapper biome = mapping.getBiomeWrapper(id);
+ IBlockStateWrapper block = mapping.getBlockStateWrapper(id);
if (block.equals(AIR)) continue;
isVoid = false;
int color = level.computeBaseColor(new DhBlockPos(blockX, y + level.getMinY(), blockZ), biome, block);
diff --git a/core/src/main/java/com/seibel/lod/core/datatype/transform/LodDataBuilder.java b/core/src/main/java/com/seibel/lod/core/datatype/transform/LodDataBuilder.java
index e94d1908a..fd3b914d1 100644
--- a/core/src/main/java/com/seibel/lod/core/datatype/transform/LodDataBuilder.java
+++ b/core/src/main/java/com/seibel/lod/core/datatype/transform/LodDataBuilder.java
@@ -1,7 +1,7 @@
package com.seibel.lod.core.datatype.transform;
import com.seibel.lod.core.datatype.full.ChunkSizedData;
-import com.seibel.lod.core.datatype.full.FullFormat;
+import com.seibel.lod.core.datatype.full.FullDataPoint;
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
@@ -34,7 +34,7 @@ public class LodDataBuilder {
byte newLight = (byte) ((chunk.getBlockLight(x,y+1,z) << 4) + chunk.getSkyLight(x,y+1,z));
if (!newBiome.equals(biome) || !newBlockState.equals(blockState)) {
- longs.add(FullFormat.encode(mappedId, lastY-y, y+1 - chunk.getMinBuildHeight(), light));
+ longs.add(FullDataPoint.encode(mappedId, lastY-y, y+1 - chunk.getMinBuildHeight(), light));
biome = newBiome;
blockState = newBlockState;
mappedId = chunkData.getMapping().setAndGetId(biome, blockState);
@@ -47,7 +47,7 @@ public class LodDataBuilder {
// lastY = y;
// }
}
- longs.add(FullFormat.encode(mappedId, lastY-y, y+1 - chunk.getMinBuildHeight(), light));
+ longs.add(FullDataPoint.encode(mappedId, lastY-y, y+1 - chunk.getMinBuildHeight(), light));
chunkData.setSingleColumn(longs.toArray(new long[0]), x, z);
}