diff --git a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java index 8e28bb331..ab793866c 100644 --- a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java @@ -307,7 +307,7 @@ public class LodNodeBufferBuilder int posZ; LevelPos levelPos; LodDataPoint lodData; - LodDetail detail = LodDetail.getDetailForDistance(LodConfig.CLIENT.maxDrawDetail.get(), distance, maxBlockDistance); + LodDetail detail = LodDetail.getDetailForDistance(LodConfig.CLIENT.maxDrawDetail.get(), distance, 16*128); for (int k = 0; k < detail.dataPointLengthCount * detail.dataPointLengthCount; k++) { diff --git a/src/main/java/com/seibel/lod/handlers/LodConfig.java b/src/main/java/com/seibel/lod/handlers/LodConfig.java index 322c5149e..2cfb13186 100644 --- a/src/main/java/com/seibel/lod/handlers/LodConfig.java +++ b/src/main/java/com/seibel/lod/handlers/LodConfig.java @@ -74,6 +74,10 @@ public class LodConfig /** this is multiplied by the default view distance * to determine how far out to generate/render LODs */ public ForgeConfigSpec.IntValue lodChunkRadiusMultiplier; + + public ForgeConfigSpec.IntValue lodQuality; + + public ForgeConfigSpec.IntValue lodChunkRenderDistane; public ForgeConfigSpec.DoubleValue brightnessMultiplier; @@ -146,8 +150,8 @@ public class LodConfig + " " + LodDetail.HALF.toString() + ": render 64 LODs for each Chunk. \n" + " " + LodDetail.FULL.toString() + ": render 256 LODs for each Chunk. \n") .defineEnum("lodGenerationQuality", LodDetail.DOUBLE); - - + + lodChunkRadiusMultiplier = builder .comment("\n\n" + " This is multiplied by the default view distance \n" @@ -155,7 +159,7 @@ public class LodConfig + " A value of 2 means that there is 1 render distance worth \n" + " of LODs in each cardinal direction. \n") .defineInRange("lodChunkRadiusMultiplier", 8, 2, 16); - + distanceGenerationMode = builder .comment("\n\n" + " Note: The times listed here are the amount of time it took \n" diff --git a/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java b/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java index 365bc1f1c..21b0b8cae 100644 --- a/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java +++ b/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java @@ -17,12 +17,10 @@ */ package com.seibel.lod.handlers; -import com.seibel.lod.objects.LevelContainer; -import com.seibel.lod.objects.LodDimension; -import com.seibel.lod.objects.LodRegion; -import com.seibel.lod.objects.RegionPos; +import com.seibel.lod.objects.*; import com.seibel.lod.proxy.ClientProxy; import com.seibel.lod.util.LodThreadFactory; +import com.seibel.lod.util.LodUtil; import java.io.*; import java.nio.file.Files; @@ -41,94 +39,101 @@ import java.util.concurrent.Executors; * @author James Seibel * @version 8-14-2021 */ -public class LodDimensionFileHandler -{ - /** This is what separates each piece of data */ - public static final char DATA_DELIMITER = ','; +public class LodDimensionFileHandler { + /** + * This is what separates each piece of data + */ + public static final char DATA_DELIMITER = ','; - private LodDimension loadedDimension = null; - public long regionLastWriteTime[][]; + private LodDimension loadedDimension = null; + public long regionLastWriteTime[][]; - private File dimensionDataSaveFolder; + private File dimensionDataSaveFolder; - /** lod */ - private static final String FILE_NAME_PREFIX = "lod"; - /** .txt */ - private static final String FILE_EXTENSION = ".bin"; - /** .tmp
- * Added to the end of the file path when saving to prevent - * nulling a currently existing file.
- * After the file finishes saving it will end with - * FILE_EXTENSION. */ - private static final String TMP_FILE_EXTENSION = ".tmp"; + /** + * lod + */ + private static final String FILE_NAME_PREFIX = "lod"; + /** + * .txt + */ + private static final String FILE_EXTENSION = ".bin"; + /** + * .tmp
+ * Added to the end of the file path when saving to prevent + * nulling a currently existing file.
+ * After the file finishes saving it will end with + * FILE_EXTENSION. + */ + private static final String TMP_FILE_EXTENSION = ".tmp"; - /** This is the file version currently accepted by this - * file handler, older versions (smaller numbers) will be deleted and overwritten, - * newer versions (larger numbers) will be ignored and won't be read. */ - public static final int LOD_SAVE_FILE_VERSION = 3; + /** + * This is the file version currently accepted by this + * file handler, older versions (smaller numbers) will be deleted and overwritten, + * newer versions (larger numbers) will be ignored and won't be read. + */ + public static final int LOD_SAVE_FILE_VERSION = 3; - /** This is the string written before the file version */ - private static final String LOD_FILE_VERSION_PREFIX = "lod_save_file_version"; + /** + * This is the string written before the file version + */ + private static final String LOD_FILE_VERSION_PREFIX = "lod_save_file_version"; - /** Allow saving asynchronously, but never try to save multiple regions - * at a time */ - private ExecutorService fileWritingThreadPool = Executors.newSingleThreadExecutor(new LodThreadFactory(this.getClass().getSimpleName())); + /** + * Allow saving asynchronously, but never try to save multiple regions + * at a time + */ + private ExecutorService fileWritingThreadPool = Executors.newSingleThreadExecutor(new LodThreadFactory(this.getClass().getSimpleName())); - public LodDimensionFileHandler(File newSaveFolder, LodDimension newLoadedDimension) - { - if (newSaveFolder == null) - throw new IllegalArgumentException("LodDimensionFileHandler requires a valid File location to read and write to."); + public LodDimensionFileHandler(File newSaveFolder, LodDimension newLoadedDimension) { + if (newSaveFolder == null) + throw new IllegalArgumentException("LodDimensionFileHandler requires a valid File location to read and write to."); - dimensionDataSaveFolder = newSaveFolder; + dimensionDataSaveFolder = newSaveFolder; - loadedDimension = newLoadedDimension; - // these two variable are used in sync with the LodDimension - regionLastWriteTime = new long[loadedDimension.getWidth()][loadedDimension.getWidth()]; - for(int i = 0; i < loadedDimension.getWidth(); i++) - for(int j = 0; j < loadedDimension.getWidth(); j++) - regionLastWriteTime[i][j] = -1; - } + loadedDimension = newLoadedDimension; + // these two variable are used in sync with the LodDimension + regionLastWriteTime = new long[loadedDimension.getWidth()][loadedDimension.getWidth()]; + for (int i = 0; i < loadedDimension.getWidth(); i++) + for (int j = 0; j < loadedDimension.getWidth(); j++) + regionLastWriteTime[i][j] = -1; + } + //================// + // read from file // + //================// + /** + * Return the LodRegion region at the given coordinates. + * (null if the file doesn't exist) + */ + public LodRegion loadRegionFromFile(RegionPos regionPos) { + int regionX = regionPos.x; + int regionZ = regionPos.z; - //================// - // read from file // - //================// + String fileName = getFileNameAndPathForRegion(regionX, regionZ); + if (FILE_EXTENSION == ".bin") { + try { + System.out.println(fileName); + ObjectInputStream is = new ObjectInputStream(new FileInputStream(fileName)); - - /** - * Return the LodRegion region at the given coordinates. - * (null if the file doesn't exist) - */ - public LodRegion loadRegionFromFile(RegionPos regionPos) - { - int regionX = regionPos.x; - int regionZ = regionPos.z; - - String fileName = getFileNameAndPathForRegion(regionX, regionZ); - if(FILE_EXTENSION == ".bin"){ - try { - System.out.println(fileName); - ObjectInputStream is = new ObjectInputStream(new FileInputStream(fileName)); - - - LodRegion region = (LodRegion) is.readObject(); - is.close(); - return region; - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - } - return null; + LevelContainer levelContainer = (LevelContainer) is.readObject(); + is.close(); + return new LodRegion(levelContainer, regionPos); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + return null; /* if(FILE_EXTENSION == ".txt") { File f = new File(fileName); @@ -211,71 +216,63 @@ public class LodDimensionFileHandler return null; */ - } + } + //==============// + // Save to File // + //==============// + /** + * Save all dirty regions in this LodDimension to file. + */ + public void saveDirtyRegionsToFileAsync() { + fileWritingThreadPool.execute(saveDirtyRegionsThread); + } + private Thread saveDirtyRegionsThread = new Thread(() -> + { + for (int i = 0; i < loadedDimension.getWidth(); i++) { + for (int j = 0; j < loadedDimension.getWidth(); j++) { + if (loadedDimension.isRegionDirty[i][j] && loadedDimension.regions[i][j] != null) { + saveRegionToFile(loadedDimension.regions[i][j]); + loadedDimension.isRegionDirty[i][j] = false; + } + } + } + }); + /** + * Save a specific region to disk.
+ * Note:
+ * 1. If a file already exists for a newer version + * the file won't be written.
+ * 2. This will save to the LodDimension that this + * handler is associated with. + */ + private void saveRegionToFile(LodRegion region) { + // convert to region coordinates + int x = region.regionPosX; + int z = region.regionPosZ; + // get minimum level + byte minDetailLevel = region.getMinDetailLevel(); - //==============// - // Save to File // - //==============// - - /** - * Save all dirty regions in this LodDimension to file. - */ - public void saveDirtyRegionsToFileAsync() - { - fileWritingThreadPool.execute(saveDirtyRegionsThread); - } - - private Thread saveDirtyRegionsThread = new Thread(() -> - { - for(int i = 0; i < loadedDimension.getWidth(); i++) - { - for(int j = 0; j < loadedDimension.getWidth(); j++) - { - if(loadedDimension.isRegionDirty[i][j] && loadedDimension.regions[i][j] != null) - { - saveRegionToFile(loadedDimension.regions[i][j]); - loadedDimension.isRegionDirty[i][j] = false; - } - } - } - }); - - /** - * Save a specific region to disk.
- * Note:
- * 1. If a file already exists for a newer version - * the file won't be written.
- * 2. This will save to the LodDimension that this - * handler is associated with. - */ - private void saveRegionToFile(LodRegion region) - { - // convert to region coordinates - int x = region.regionPosX; - int z = region.regionPosZ; - - - File oldFile = new File(getFileNameAndPathForRegion(x, z)); - if (!oldFile.getParentFile().exists()) - oldFile.getParentFile().mkdirs(); - if(FILE_EXTENSION == ".bin"){ - try { - ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(getFileNameAndPathForRegion(x, z))); - os.writeObject(region); - os.close(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } + File oldFile = new File(getFileNameAndPathForRegion(x, z)); + if (!oldFile.getParentFile().exists()) + oldFile.getParentFile().mkdirs(); + if (FILE_EXTENSION == ".bin") { + try { + ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(getFileNameAndPathForRegion(x, z))); + os.writeObject(region.getLevel((byte) 0)); + os.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } /* if(FILE_EXTENSION == ".txt") { try { @@ -343,41 +340,32 @@ public class LodDimensionFileHandler } } */ - } + } + //================// + // helper methods // + //================// - - - - //================// - // helper methods // - //================// - - - /** - * Return the name of the file that should contain the - * region at the given x and z.
- * Returns null if this object isn't ready to read and write.

- * - * example: "lod.0.0.txt" - */ - private String getFileNameAndPathForRegion(int regionX, int regionZ) - { - try - { - // saveFolder is something like - // ".\Super Flat\DIM-1\data" - // or - // ".\Super Flat\data" - return dimensionDataSaveFolder.getCanonicalPath() + File.separatorChar + - FILE_NAME_PREFIX + "." + regionX + "." + regionZ + FILE_EXTENSION; - } - catch(IOException e) - { - return null; - } - } + /** + * Return the name of the file that should contain the + * region at the given x and z.
+ * Returns null if this object isn't ready to read and write.

+ *

+ * example: "lod.0.0.txt" + */ + private String getFileNameAndPathForRegion(int regionX, int regionZ) { + try { + // saveFolder is something like + // ".\Super Flat\DIM-1\data" + // or + // ".\Super Flat\data" + return dimensionDataSaveFolder.getCanonicalPath() + File.separatorChar + + FILE_NAME_PREFIX + "." + regionX + "." + regionZ + FILE_EXTENSION; + } catch (IOException e) { + return null; + } + } } diff --git a/src/main/java/com/seibel/lod/objects/LodRegion.java b/src/main/java/com/seibel/lod/objects/LodRegion.java index a5162a607..99285c907 100644 --- a/src/main/java/com/seibel/lod/objects/LodRegion.java +++ b/src/main/java/com/seibel/lod/objects/LodRegion.java @@ -18,7 +18,7 @@ import java.io.Serializable; public class LodRegion implements Serializable { //x coord, - private byte minLevelOfDetail; + private byte minDetailLevel; private static final byte POSSIBLE_LOD = 10; private int numberOfPoints; @@ -41,7 +41,47 @@ public class LodRegion implements Serializable { public final int regionPosX; public final int regionPosZ; - public LodRegion(byte minimumLevelOfDetail, RegionPos regionPos) { + public LodRegion(LevelContainer levelContainer, RegionPos regionPos) { + this.regionPosX = regionPos.x; + this.regionPosZ = regionPos.z; + this.minDetailLevel = levelContainer.detailLevel; + + //Array of matrices of arrays + colors = new byte[POSSIBLE_LOD][][][]; + + //Arrays of matrices + height = new short[POSSIBLE_LOD][][]; + depth = new short[POSSIBLE_LOD][][]; + generationType = new byte[POSSIBLE_LOD][][]; + dataExistence = new boolean[POSSIBLE_LOD][][]; + + colors[minDetailLevel] = levelContainer.colors; + height[minDetailLevel] = levelContainer.height; + depth[minDetailLevel] = levelContainer.depth; + generationType[minDetailLevel] = levelContainer.generationType; + dataExistence[minDetailLevel] = levelContainer.dataExistence; + + //Initialize all the different matrices + for (byte lod = (byte) (minDetailLevel + 1); lod <= LodUtil.REGION_DETAIL_LEVEL; lod++) { + int size = (short) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - lod); + colors[lod] = new byte[size][size][3]; + height[lod] = new short[size][size]; + depth[lod] = new short[size][size]; + generationType[lod] = new byte[size][size]; + dataExistence[lod] = new boolean[size][size]; + } + int sizeDiff = (int) Math.pow(2,LodUtil.REGION_DETAIL_LEVEL - (minDetailLevel + 1)); + LevelPos levelPos; + for(int x = 0; x < sizeDiff; x++){ + for(int z = 0; z < sizeDiff; z++){ + levelPos = new LevelPos((byte) (minDetailLevel+1), x, z); + update(levelPos); + } + } + } + + public LodRegion(byte minDetailLevel, RegionPos regionPos) { + this.minDetailLevel = minDetailLevel; this.regionPosX = regionPos.x; this.regionPosZ = regionPos.z; @@ -56,7 +96,7 @@ public class LodRegion implements Serializable { //Initialize all the different matrices - for (byte lod = minimumLevelOfDetail; lod <= LodUtil.REGION_DETAIL_LEVEL; lod++) { + for (byte lod = minDetailLevel; lod <= LodUtil.REGION_DETAIL_LEVEL; lod++) { int size = (short) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - lod); colors[lod] = new byte[size][size][3]; height[lod] = new short[size][size]; @@ -143,7 +183,6 @@ public class LodRegion implements Serializable { /**TODO a method to update a whole area, to be used as a single big update*/ /** - * * @param levelPos */ private void updateArea(LevelPos levelPos) { @@ -169,7 +208,6 @@ public class LodRegion implements Serializable { } /** - * * @param levelPos */ private void update(LevelPos levelPos) { @@ -219,11 +257,15 @@ public class LodRegion implements Serializable { } } + /** + * @param levelPos + * @return + */ private boolean[][] getChildren(LevelPos levelPos) { levelPos = levelPos.regionModule(); boolean[][] children = new boolean[2][2]; int numberOfChild = 0; - if (minLevelOfDetail == levelPos.detailLevel) { + if (minDetailLevel == levelPos.detailLevel) { return children; } for (int x = 0; x <= 1; x++) { @@ -234,19 +276,31 @@ public class LodRegion implements Serializable { return children; } + /** + * @param chunkPos + * @return + */ public boolean doesDataExist(ChunkPos chunkPos) { return doesDataExist(new LevelPos(LodUtil.CHUNK_DETAIL_LEVEL, chunkPos.x, chunkPos.z)); } + /** + * @param levelPos + * @return + */ public boolean doesDataExist(LevelPos levelPos) { levelPos = levelPos.regionModule(); return dataExistence[levelPos.detailLevel][levelPos.posX][levelPos.posZ]; } + /** + * @param levelPos + * @return + */ public DistanceGenerationMode getGenerationMode(LevelPos levelPos) { levelPos = levelPos.regionModule(); DistanceGenerationMode generationMode = DistanceGenerationMode.NONE; - switch(generationType[levelPos.detailLevel][levelPos.posX][levelPos.posZ]){ + switch (generationType[levelPos.detailLevel][levelPos.posX][levelPos.posZ]) { case 0: generationMode = DistanceGenerationMode.NONE; break; @@ -273,10 +327,19 @@ public class LodRegion implements Serializable { return generationMode; } + /** + * @param levelPos + * @return + */ public boolean hasDataBeenGenerated(LevelPos levelPos) { levelPos = levelPos.regionModule(); return (generationType[levelPos.detailLevel][levelPos.posX][levelPos.posZ] != 0); } + + public byte getMinDetailLevel() { + return minDetailLevel; + } + /** * This will be used to save a level * @@ -287,19 +350,25 @@ public class LodRegion implements Serializable { return new LevelContainer(lod, colors[lod], height[lod], depth[lod], generationType[lod], dataExistence[lod]); } - public void addLevel(byte lod, LevelContainer levelContainer) { - if (lod < minLevelOfDetail - 1) { + /** + * @param levelContainer + */ + public void addLevel(LevelContainer levelContainer) { + if (levelContainer.detailLevel < minDetailLevel - 1) { throw new IllegalArgumentException("addLevel requires a level that is at least the minimum level of the region -1 "); } - if (lod == minLevelOfDetail - 1) minLevelOfDetail = lod; - colors[lod] = levelContainer.colors; - height[lod] = levelContainer.height; - depth[lod] = levelContainer.depth; - generationType[lod] = levelContainer.generationType; - dataExistence[lod] = levelContainer.dataExistence; + if (levelContainer.detailLevel == minDetailLevel - 1) minDetailLevel = levelContainer.detailLevel; + colors[levelContainer.detailLevel] = levelContainer.colors; + height[levelContainer.detailLevel] = levelContainer.height; + depth[levelContainer.detailLevel] = levelContainer.depth; + generationType[levelContainer.detailLevel] = levelContainer.generationType; + dataExistence[levelContainer.detailLevel] = levelContainer.dataExistence; } + /** + * @param lod + */ public void removeDetailLevel(byte lod) { for (byte tempLod = 0; tempLod <= lod; tempLod++) { colors[tempLod] = new byte[0][0][0]; diff --git a/src/main/java/com/seibel/lod/proxy/ClientProxy.java b/src/main/java/com/seibel/lod/proxy/ClientProxy.java index c25be2459..1b95b32dc 100644 --- a/src/main/java/com/seibel/lod/proxy/ClientProxy.java +++ b/src/main/java/com/seibel/lod/proxy/ClientProxy.java @@ -89,10 +89,10 @@ public class ClientProxy { if (mc == null || mc.player == null || !lodWorld.getIsWorldLoaded()) return; - - + + viewDistanceChangedEvent(); - + LodDimension lodDim = lodWorld.getLodDimension(mc.player.level.dimensionType()); if (lodDim == null) return; @@ -142,14 +142,14 @@ public class ClientProxy LodConfig.CLIENT.maxDrawDetail.set(LodDetail.FULL); LodConfig.CLIENT.maxGenerationDetail.set(LodDetail.FULL); - LodConfig.CLIENT.lodChunkRadiusMultiplier.set(20); + LodConfig.CLIENT.lodChunkRadiusMultiplier.set(16); LodConfig.CLIENT.fogDistance.set(FogDistance.FAR); - LodConfig.CLIENT.fogDrawOverride.set(FogDrawOverride.NEVER_DRAW_FOG); + LodConfig.CLIENT.fogDrawOverride.set(FogDrawOverride.ALWAYS_DRAW_FOG_FANCY); LodConfig.CLIENT.shadingMode.set(ShadingMode.DARKEN_SIDES); // LodConfig.CLIENT.brightnessMultiplier.set(1.0); // LodConfig.CLIENT.saturationMultiplier.set(1.0); - LodConfig.CLIENT.distanceGenerationMode.set(DistanceGenerationMode.SURFACE); + LodConfig.CLIENT.distanceGenerationMode.set(DistanceGenerationMode.FEATURES); LodConfig.CLIENT.allowUnstableFeatureGeneration.set(false); LodConfig.CLIENT.numberOfWorldGenerationThreads.set(16); @@ -237,15 +237,16 @@ public class ClientProxy //LOGGER.info("offset: " + worldRegionOffset.x + "," + worldRegionOffset.z + "\t center: " + lodDim.getCenterX() + "," + lodDim.getCenterZ()); } } - - + + /** * Re-sizes all LodDimensions if they needs to be. */ private void viewDistanceChangedEvent() { // calculate how wide the dimension(s) should be in regions - int chunksWide = (mc.options.renderDistance * 2) * LodConfig.CLIENT.lodChunkRadiusMultiplier.get(); + //int chunksWide = (mc.options.renderDistance * 2) * LodConfig.CLIENT.lodChunkRadiusMultiplier.get(); + int chunksWide = 8 * 2 * LodConfig.CLIENT.lodChunkRadiusMultiplier.get() + 1; int newWidth = (int)Math.ceil(chunksWide / (float) LodUtil.REGION_WIDTH_IN_CHUNKS); newWidth = (newWidth % 2 == 0) ? (newWidth += 1) : (newWidth += 2); // make sure we have a odd number of regions @@ -261,7 +262,7 @@ public class ClientProxy //LOGGER.info("new dimension width in regions: " + newWidth + "\t potential: " + newWidth ); } } - + //================// // public getters // diff --git a/src/main/java/com/seibel/lod/render/LodNodeRenderer.java b/src/main/java/com/seibel/lod/render/LodNodeRenderer.java index 4605d76f9..1e2b741de 100644 --- a/src/main/java/com/seibel/lod/render/LodNodeRenderer.java +++ b/src/main/java/com/seibel/lod/render/LodNodeRenderer.java @@ -213,10 +213,12 @@ public class LodNodeRenderer // determine how far the game's render distance is currently set - farPlaneBlockDistance = mc.options.renderDistance * LodUtil.CHUNK_WIDTH; + //farPlaneBlockDistance = mc.options.renderDistance * LodUtil.CHUNK_WIDTH; + farPlaneBlockDistance = 8 * LodUtil.CHUNK_WIDTH; // set how how far the LODs will go - int numbChunksWide = mc.options.renderDistance * 2 * LodConfig.CLIENT.lodChunkRadiusMultiplier.get(); + //int numbChunksWide = mc.options.renderDistance * 2 * LodConfig.CLIENT.lodChunkRadiusMultiplier.get(); + int numbChunksWide = 8 * 2 * LodConfig.CLIENT.lodChunkRadiusMultiplier.get() + 1; // determine which LODs should not be rendered close to the player HashSet chunkPosToSkip = getNearbyLodChunkPosToSkip(lodDim, player.blockPosition());