diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ServerApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ServerApi.java index 0d1e97862..962c7b323 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ServerApi.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ServerApi.java @@ -141,7 +141,7 @@ public class ServerApi //=======================// public void serverChunkLoadEvent(IChunkWrapper chunkWrapper, ILevelWrapper level) { SharedApi.INSTANCE.applyChunkUpdate(chunkWrapper, level, false); } - public void serverChunkSaveEvent(IChunkWrapper chunkWrapper, ILevelWrapper level) { SharedApi.INSTANCE.applyChunkUpdate(chunkWrapper, level, false); } + public void serverChunkSaveEvent(IChunkWrapper chunkWrapper, ILevelWrapper level) { SharedApi.INSTANCE.applyChunkUpdate(chunkWrapper, level, true); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java index 192e60d5e..86565a6b3 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java @@ -311,6 +311,18 @@ public class SharedApi } + // having a list of the nearby chunks is needed for lighting and beacon generation + ArrayList nearbyChunkList; + if (neighbourChunkList != null) + { + nearbyChunkList = neighbourChunkList; + } + else + { + nearbyChunkList = new ArrayList<>(1); + nearbyChunkList.add(chunkWrapper); + } + // Save or populate the chunk wrapper's lighting // this is done so we don't have to worry about MC unloading the lighting data for this chunk @@ -330,24 +342,13 @@ public class SharedApi else { // generate the chunk's lighting, using neighboring chunks if present - - ArrayList nearbyChunkList; - if (neighbourChunkList != null) - { - nearbyChunkList = neighbourChunkList; - } - else - { - nearbyChunkList = new ArrayList<>(1); - nearbyChunkList.add(chunkWrapper); - } - DhLightingEngine.INSTANCE.lightChunk(chunkWrapper, nearbyChunkList, dhLevel.hasSkyLight() ? 15 : 0); } + // get this chunk's active beacons - List beaconBeamList = chunkWrapper.getAllActiveBeacons(); + List beaconBeamList = chunkWrapper.getAllActiveBeacons(nearbyChunkList); dhLevel.setBeaconBeamsForChunk(chunkWrapper.getChunkPos(), beaconBeamList); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/AdjacentChunkHolder.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/AdjacentChunkHolder.java new file mode 100644 index 000000000..a3d5603e3 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/AdjacentChunkHolder.java @@ -0,0 +1,117 @@ +package com.seibel.distanthorizons.core.generation; + +import com.seibel.distanthorizons.core.pos.DhChunkPos; +import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; +import com.seibel.distanthorizons.coreapi.util.BitShiftUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.HashSet; + +/** holds adjacent chunks without having to create new Pos objects */ +public class AdjacentChunkHolder +{ + final IChunkWrapper[] chunkArray = new IChunkWrapper[9]; + + + //==============// + // constructors // + //==============// + + public AdjacentChunkHolder(IChunkWrapper centerWrapper) { this.chunkArray[4] = centerWrapper; } + + public AdjacentChunkHolder(IChunkWrapper centerWrapper, @NotNull ArrayList nearbyChunkList) + { + this.chunkArray[4] = centerWrapper; + + DhChunkPos centerChunkPos = centerWrapper.getChunkPos(); + + // generate the list of chunk pos we need, + // currently a 3x3 grid + HashSet requestedAdjacentPositions = new HashSet<>(9); + for (int xOffset = -1; xOffset <= 1; xOffset++) + { + for (int zOffset = -1; zOffset <= 1; zOffset++) + { + DhChunkPos adjacentPos = new DhChunkPos(centerChunkPos.x + xOffset, centerChunkPos.z + zOffset); + requestedAdjacentPositions.add(adjacentPos); + } + } + + for (int chunkIndex = 0; chunkIndex < nearbyChunkList.size(); chunkIndex++) // using iterators in high traffic areas can cause GC issues due to allocating a bunch of iterators, use an indexed for-loop instead + { + IChunkWrapper chunk = nearbyChunkList.get(chunkIndex); + if (chunk != null && requestedAdjacentPositions.contains(chunk.getChunkPos())) + { + // remove the newly found position + requestedAdjacentPositions.remove(chunk.getChunkPos()); + + // add the adjacent chunk + this.add(chunk); + } + + if (requestedAdjacentPositions.isEmpty()) + { + // we found every chunk we needed, we don't need to keep iterating + break; + } + } + } + + + + //=========// + // methods // + //=========// + + public void add(IChunkWrapper centerWrapper) + { + DhChunkPos centerPos = this.chunkArray[4].getChunkPos(); + DhChunkPos offsetPos = centerWrapper.getChunkPos(); + + int offsetX = offsetPos.x - centerPos.x; + if (offsetX < -1 || offsetX > 1) + { + return; + } + + int offsetZ = offsetPos.z - centerPos.z; + if (offsetZ < -1 || offsetZ > 1) + { + return; + } + + // equivalent to 4 + offsetX + (offsetZ * 3). + this.chunkArray[4 + offsetX + offsetZ + (offsetZ << 1)] = centerWrapper; + } + + public IChunkWrapper getByBlockPos(int blockX, int blockZ) + { + int chunkX = BitShiftUtil.divideByPowerOfTwo(blockX, 4); + int chunkZ = BitShiftUtil.divideByPowerOfTwo(blockZ, 4); + IChunkWrapper centerChunk = this.chunkArray[4]; + DhChunkPos centerPos = centerChunk.getChunkPos(); + if (centerPos.x == chunkX && centerPos.z == chunkZ) + { + return centerChunk; + } + + int offsetX = chunkX - centerPos.x; + if (offsetX < -1 || offsetX > 1) + { + return null; + } + + int offsetZ = chunkZ - centerPos.z; + if (offsetZ < -1 || offsetZ > 1) + { + return null; + } + + // equivalent to 4 + offsetX + (offsetZ * 3). + return this.chunkArray[4 + offsetX + offsetZ + (offsetZ << 1)]; + } + + +} + \ No newline at end of file diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/DhLightingEngine.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/DhLightingEngine.java index 6648f62ee..34f1cec9b 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/generation/DhLightingEngine.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/DhLightingEngine.java @@ -306,64 +306,6 @@ public class DhLightingEngine } - /** holds the adjacent chunks without having to create new Pos objects */ - private static class AdjacentChunkHolder - { - final IChunkWrapper[] chunkArray = new IChunkWrapper[9]; - - - public AdjacentChunkHolder(IChunkWrapper centerWrapper) { this.chunkArray[4] = centerWrapper; } - - - public void add(IChunkWrapper centerWrapper) - { - DhChunkPos centerPos = this.chunkArray[4].getChunkPos(); - DhChunkPos offsetPos = centerWrapper.getChunkPos(); - - int offsetX = offsetPos.x - centerPos.x; - if (offsetX < -1 || offsetX > 1) - { - return; - } - - int offsetZ = offsetPos.z - centerPos.z; - if (offsetZ < -1 || offsetZ > 1) - { - return; - } - - // equivalent to 4 + offsetX + (offsetZ * 3). - this.chunkArray[4 + offsetX + offsetZ + (offsetZ << 1)] = centerWrapper; - } - - public IChunkWrapper getByBlockPos(int blockX, int blockZ) - { - int chunkX = BitShiftUtil.divideByPowerOfTwo(blockX, 4); - int chunkZ = BitShiftUtil.divideByPowerOfTwo(blockZ, 4); - IChunkWrapper centerChunk = this.chunkArray[4]; - DhChunkPos centerPos = centerChunk.getChunkPos(); - if (centerPos.x == chunkX && centerPos.z == chunkZ) - { - return centerChunk; - } - - int offsetX = chunkX - centerPos.x; - if (offsetX < -1 || offsetX > 1) - { - return null; - } - - int offsetZ = chunkZ - centerPos.z; - if (offsetZ < -1 || offsetZ > 1) - { - return null; - } - - // equivalent to 4 + offsetX + (offsetZ * 3). - return this.chunkArray[4 + offsetX + offsetZ + (offsetZ << 1)]; - } - } - /** * Holds all potential {@link LightPos} objects a lighting task may need. * This is done so existing {@link LightPos} objects can be repurposed instead of destroyed, diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/chunk/IChunkWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/chunk/IChunkWrapper.java index d31b005fc..b0670c271 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/chunk/IChunkWrapper.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/chunk/IChunkWrapper.java @@ -19,6 +19,7 @@ package com.seibel.distanthorizons.core.wrapperInterfaces.chunk; +import com.seibel.distanthorizons.core.generation.AdjacentChunkHolder; import com.seibel.distanthorizons.core.pos.DhBlockPos; import com.seibel.distanthorizons.core.pos.DhBlockPos2D; import com.seibel.distanthorizons.core.pos.DhChunkPos; @@ -31,6 +32,8 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; import java.awt.*; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; public interface IChunkWrapper extends IBindable @@ -38,6 +41,15 @@ public interface IChunkWrapper extends IBindable /** useful for debugging, but can slow down chunk operations quite a bit due to being called every time. */ boolean RUN_RELATIVE_POS_INDEX_VALIDATION = ModInfo.IS_DEV_BUILD; + /** should be all lowercase */ + List BEACON_BASE_BLOCK_NAME_LIST = Arrays.asList( + "iron_block", + "gold_block", + "diamond_block", + "emerald_block", + "netherite_block" + ); + DhChunkPos getChunkPos(); @@ -246,10 +258,12 @@ public interface IChunkWrapper extends IBindable return hash; } - default List getAllActiveBeacons() + default List getAllActiveBeacons(ArrayList neighbourChunkList) { ArrayList beaconPosList = new ArrayList<>(); + AdjacentChunkHolder adjacentChunkHolder = new AdjacentChunkHolder(this, neighbourChunkList); + // since beacons emit light we can check only the positions that are emitting light ArrayList blockPosList = this.getBlockLightPosList(); for (int i = 0; i < blockPosList.size(); i++) @@ -260,7 +274,7 @@ public interface IChunkWrapper extends IBindable IBlockStateWrapper block = this.getBlockState(relPos); if (block.getSerialString().toLowerCase().contains("minecraft:beacon")) { - if (isBeaconActive(relPos.x, relPos.y, relPos.z, this)) + if (isBeaconActive(pos, adjacentChunkHolder)) { BeaconBeamDTO beam = new BeaconBeamDTO(blockPosList.get(i), Color.WHITE); beaconPosList.add(beam); @@ -270,31 +284,43 @@ public interface IChunkWrapper extends IBindable return beaconPosList; } - static boolean isBeaconActive(int relBlockX, int y, int relBlockZ, IChunkWrapper chunkWrapper) + static boolean isBeaconActive(DhBlockPos beaconPos, AdjacentChunkHolder chunkHolder) { + DhBlockPos beaconRelPos = beaconPos.convertToChunkRelativePos(); + DhBlockPos baseRelPos = new DhBlockPos(0, beaconRelPos.y-1, 0); + for (int x = -1; x<= 1; x++) { for (int z = -1; z <= 1; z++) { - if ((relBlockX + x < 0 || relBlockX + x >= LodUtil.CHUNK_WIDTH) - || (relBlockZ + z < 0 || relBlockZ + z >= LodUtil.CHUNK_WIDTH)) - { - // if the beacon is on the border of a chunk and all other blocks are there, assume it's complete - //TODO! Check adjacent chunk, if possible - continue; - } - String blockId = chunkWrapper.getBlockState(relBlockX + x, y -1, relBlockZ + z).getSerialString(); + baseRelPos.x = beaconRelPos.x + x; + baseRelPos.z = beaconRelPos.z + z; + baseRelPos.mutateToChunkRelativePos(baseRelPos); - if (!(blockId.contains("diamond_block") - || blockId.contains("iron_block") - || blockId.contains("emerald_block") - || blockId.contains("netherite_block") - || blockId.contains("gold_block"))) - { - return false; + IChunkWrapper chunk = chunkHolder.getByBlockPos(beaconPos.x + x, beaconPos.z + z); + if (chunk != null) + { + String blockSerial = chunk.getBlockState(baseRelPos.x, baseRelPos.y, baseRelPos.z).getSerialString(); + + boolean baseBlockFound = false; + for (int i = 0; i < BEACON_BASE_BLOCK_NAME_LIST.size(); i++) + { + String baseBlockName = BEACON_BASE_BLOCK_NAME_LIST.get(i); + if (blockSerial.contains(baseBlockName)) + { + baseBlockFound = true; + break; + } + } + + if (!baseBlockFound) + { + return false; + } } } } + return true; }