diff --git a/src/main/java/de/bixilon/minosoft/data/world/World.kt b/src/main/java/de/bixilon/minosoft/data/world/World.kt index 46eefed3b..e1f01f051 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/World.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/World.kt @@ -22,16 +22,15 @@ import de.bixilon.minosoft.data.world.biome.accessor.NullBiomeAccessor import de.bixilon.minosoft.data.world.light.WorldLightAccessor import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkPosition +import de.bixilon.minosoft.util.KUtil.synchronizedMapOf import glm_.vec2.Vec2i import glm_.vec3.Vec3i -import java.util.* -import java.util.concurrent.ConcurrentHashMap /** * Collection of chunks and more */ class World : BiomeAccessor { - val chunks: MutableMap = Collections.synchronizedMap(ConcurrentHashMap()) + val chunks: MutableMap = synchronizedMapOf() val entities = WorldEntities() var isHardcore = false var isRaining = false @@ -47,16 +46,14 @@ class World : BiomeAccessor { return chunks[chunkLocation]?.getBlockState(blockPosition.inChunkPosition) } + @Synchronized fun getChunk(chunkPosition: Vec2i): Chunk? { return chunks[chunkPosition] } + @Synchronized fun getOrCreateChunk(chunkPosition: Vec2i): Chunk { - return chunks[chunkPosition] ?: run { - val chunk = Chunk() - chunks[chunkPosition] = chunk - chunk - } + return chunks.getOrPut(chunkPosition) { Chunk() } } fun setBlock(blockPosition: Vec3i, blockState: BlockState?) { diff --git a/src/main/java/de/bixilon/minosoft/data/world/WorldEntities.kt b/src/main/java/de/bixilon/minosoft/data/world/WorldEntities.kt index 4a87f40d5..1775f72d3 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/WorldEntities.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/WorldEntities.kt @@ -14,14 +14,14 @@ package de.bixilon.minosoft.data.world import de.bixilon.minosoft.data.entities.entities.Entity +import de.bixilon.minosoft.util.KUtil.synchronizedMapOf import java.util.* -import java.util.concurrent.ConcurrentHashMap class WorldEntities : Iterable { - private val idEntityMap: MutableMap = ConcurrentHashMap() - private val entityIdMap: MutableMap = ConcurrentHashMap() - private val entityUUIDMap: MutableMap = ConcurrentHashMap() - private val uuidEntityMap: MutableMap = ConcurrentHashMap() + private val idEntityMap: MutableMap = synchronizedMapOf() + private val entityIdMap: MutableMap = synchronizedMapOf() + private val entityUUIDMap: MutableMap = synchronizedMapOf() + private val uuidEntityMap: MutableMap = synchronizedMapOf() fun add(entityId: Int?, entityUUID: UUID?, entity: Entity) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt index e484024a3..ca595160b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt @@ -37,6 +37,9 @@ import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.protocol.packets.s2c.play.PositionAndRotationS2CP import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.util.CountUpAndDownLatch +import de.bixilon.minosoft.util.KUtil.synchronizedListOf +import de.bixilon.minosoft.util.KUtil.synchronizedMapOf +import de.bixilon.minosoft.util.KUtil.synchronizedSetOf import de.bixilon.minosoft.util.Stopwatch import de.bixilon.minosoft.util.logging.Log import de.bixilon.minosoft.util.logging.LogMessageType @@ -48,7 +51,6 @@ import org.lwjgl.opengl.GL import org.lwjgl.opengl.GL11.* import org.lwjgl.system.MemoryStack import org.lwjgl.system.MemoryUtil -import java.util.concurrent.ConcurrentLinkedQueue class RenderWindow( val connection: PlayConnection, @@ -73,16 +75,16 @@ class RenderWindow( private val screenshotTaker = ScreenshotTaker(this) val tintColorCalculator = TintColorCalculator(connection.world) val font = Font() - val textures = TextureArray(mutableListOf()) + val textures = TextureArray(synchronizedListOf()) - val rendererMap: MutableMap = mutableMapOf() + val rendererMap: MutableMap = synchronizedMapOf() - val renderQueue = ConcurrentLinkedQueue() + val renderQueue: MutableList = synchronizedListOf() lateinit var WHITE_TEXTURE: TextureLike - val screenResizeCallbacks: MutableSet = mutableSetOf(inputHandler.camera) + val screenResizeCallbacks: MutableSet = synchronizedSetOf(inputHandler.camera) var tickCount = 0L var lastTickTimer = System.currentTimeMillis() @@ -331,12 +333,13 @@ class RenderWindow( // handle opengl context tasks, but limit it per frame var actionsDone = 0 + val renderQueue = renderQueue.toList() for (renderQueueElement in renderQueue) { if (actionsDone == RenderConstants.MAXIMUM_CALLS_PER_FRAME) { break } renderQueueElement.run() - renderQueue.remove(renderQueueElement) + this.renderQueue.remove(renderQueueElement) actionsDone++ } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt index 7964e4d41..1fc0f6f47 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt @@ -40,13 +40,13 @@ import de.bixilon.minosoft.modding.event.events.* import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.util.KUtil.nullCast +import de.bixilon.minosoft.util.KUtil.synchronizedMapOf +import de.bixilon.minosoft.util.KUtil.synchronizedSetOf import de.bixilon.minosoft.util.MMath import de.bixilon.minosoft.util.logging.Log import glm_.vec2.Vec2i import glm_.vec3.Vec3i import org.lwjgl.opengl.GL11.glDepthMask -import java.util.* -import java.util.concurrent.ConcurrentHashMap class WorldRenderer( private val connection: PlayConnection, @@ -56,9 +56,9 @@ class WorldRenderer( private val waterBlock = connection.mapping.blockRegistry.get(ResourceLocation("minecraft:water"))?.nullCast() override lateinit var shader: Shader - val allChunkSections: MutableMap> = Collections.synchronizedMap(ConcurrentHashMap()) - val visibleChunks: MutableMap> = Collections.synchronizedMap(ConcurrentHashMap()) - val queuedChunks: MutableSet = Collections.synchronizedSet(mutableSetOf()) + val allChunkSections: MutableMap> = synchronizedMapOf() + val visibleChunks: MutableMap> = synchronizedMapOf() + val queuedChunks: MutableSet = synchronizedSetOf() private var allBlocks: Collection? = null @@ -145,7 +145,7 @@ class WorldRenderer( }) connection.registerEvent(CallbackEventInvoker.of { - val sectionHeights: MutableSet = mutableSetOf() + val sectionHeights: MutableSet = synchronizedSetOf() for ((key) in it.blocks) { sectionHeights.add(key.sectionHeight) } @@ -201,7 +201,7 @@ class WorldRenderer( private fun resolveBlockTextureIds(blocks: Collection): List { val textures: MutableList = mutableListOf() - val textureMap: MutableMap = ConcurrentHashMap() + val textureMap: MutableMap = synchronizedMapOf() for (block in blocks) { for (model in block.renderers) { @@ -242,14 +242,14 @@ class WorldRenderer( } } queuedChunks.remove(chunkPosition) - allChunkSections[chunkPosition] = Collections.synchronizedMap(ConcurrentHashMap()) + allChunkSections[chunkPosition] = synchronizedMapOf() - var currentChunks: MutableMap = Collections.synchronizedMap(ConcurrentHashMap()) + var currentChunks: MutableMap = synchronizedMapOf() var currentIndex = 0 for ((sectionHeight, section) in chunk.sections!!) { if (getSectionIndex(sectionHeight) != currentIndex) { prepareChunkSections(chunkPosition, currentChunks) - currentChunks = Collections.synchronizedMap(ConcurrentHashMap()) + currentChunks = synchronizedMapOf() currentIndex = getSectionIndex(sectionHeight) } currentChunks[sectionHeight] = section @@ -300,7 +300,7 @@ class WorldRenderer( renderWindow.renderQueue.add { - val sectionMap = allChunkSections.getOrPut(chunkPosition, { ConcurrentHashMap() }) + val sectionMap = allChunkSections.getOrPut(chunkPosition) { synchronizedMapOf() } sectionMap[index]?.let { it.opaqueSectionArrayMesh.unload() @@ -329,7 +329,7 @@ class WorldRenderer( sectionMap[index] = meshCollection if (renderWindow.inputHandler.camera.frustum.containsChunk(chunkPosition, lowestBlockHeight, highestBlockHeight)) { - visibleChunks.getOrPut(chunkPosition, { ConcurrentHashMap() })[index] = meshCollection + visibleChunks.getOrPut(chunkPosition) { synchronizedMapOf() }[index] = meshCollection } else { visibleChunks[chunkPosition]?.remove(index) } @@ -338,7 +338,7 @@ class WorldRenderer( } fun prepareChunkSection(chunkPosition: Vec2i, sectionHeight: Int) { - val sections: MutableMap = Collections.synchronizedMap(ConcurrentHashMap()) + val sections: MutableMap = synchronizedMapOf() val chunk = world.getChunk(chunkPosition)!! val lowestSectionHeight = getSectionIndex(sectionHeight) * RenderConstants.CHUNK_SECTIONS_PER_MESH for (i in lowestSectionHeight until lowestSectionHeight + RenderConstants.CHUNK_SECTIONS_PER_MESH) { @@ -381,7 +381,8 @@ class WorldRenderer( } private fun prepareWorld(world: World) { - for ((chunkLocation, chunk) in world.chunks) { + val chunkMap = world.chunks.toMap() + for ((chunkLocation, chunk) in chunkMap) { prepareChunk(chunkLocation, chunk) } } @@ -393,8 +394,13 @@ class WorldRenderer( override fun onFrustumChange() { visibleChunks.clear() - for ((chunkLocation, indexMap) in allChunkSections) { - val visibleIndexMap: MutableMap = Collections.synchronizedMap(ConcurrentHashMap()) + val allChunkSections: Map> + synchronized(this.allChunkSections) { + allChunkSections = this.allChunkSections.toMap() + } + for ((chunkLocation, rawIndexMap) in allChunkSections) { + val visibleIndexMap: MutableMap = synchronizedMapOf() + val indexMap = rawIndexMap.toMap() for ((index, mesh) in indexMap) { if (renderWindow.inputHandler.camera.frustum.containsChunk(chunkLocation, mesh.lowestBlockHeight, mesh.highestBlockHeight)) { visibleIndexMap[index] = mesh diff --git a/src/main/java/de/bixilon/minosoft/util/KUtil.kt b/src/main/java/de/bixilon/minosoft/util/KUtil.kt index 141ddd49a..f49ffa82e 100644 --- a/src/main/java/de/bixilon/minosoft/util/KUtil.kt +++ b/src/main/java/de/bixilon/minosoft/util/KUtil.kt @@ -16,6 +16,7 @@ package de.bixilon.minosoft.util import de.bixilon.minosoft.data.mappings.ResourceLocation import de.bixilon.minosoft.util.enum.AliasableEnum import java.util.* +import kotlin.Pair object KUtil { @@ -53,4 +54,16 @@ object KUtil { fun String.asResourceLocation(): ResourceLocation { return ResourceLocation(this) } + + fun synchronizedMapOf(vararg pairs: Pair): MutableMap { + return Collections.synchronizedMap(mutableMapOf(*pairs)) + } + + fun synchronizedSetOf(vararg values: V): MutableSet { + return Collections.synchronizedSet(mutableSetOf(*values)) + } + + fun synchronizedListOf(vararg values: V): MutableList { + return Collections.synchronizedList(mutableListOf(*values)) + } } diff --git a/src/main/java/de/bixilon/minosoft/util/chunk/ChunkUtil.kt b/src/main/java/de/bixilon/minosoft/util/chunk/ChunkUtil.kt index 9ce07b682..71305360f 100644 --- a/src/main/java/de/bixilon/minosoft/util/chunk/ChunkUtil.kt +++ b/src/main/java/de/bixilon/minosoft/util/chunk/ChunkUtil.kt @@ -24,8 +24,8 @@ import de.bixilon.minosoft.data.world.palette.Palette.Companion.choosePalette import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.protocol.protocol.ProtocolVersions.* +import de.bixilon.minosoft.util.KUtil.synchronizedMapOf import java.util.* -import java.util.concurrent.ConcurrentHashMap object ChunkUtil { @@ -59,7 +59,7 @@ object ChunkUtil { // parse data var arrayPosition = 0 - val sectionMap: MutableMap = Collections.synchronizedMap(ConcurrentHashMap()) + val sectionMap: MutableMap = synchronizedMapOf() for ((sectionIndex, sectionHeight) in (dimension.lowestSection until dimension.highestSection).withIndex()) { if (!sectionBitMask[sectionIndex]) { continue @@ -125,7 +125,7 @@ object ChunkUtil { } var arrayPos = 0 - val sectionMap: MutableMap = Collections.synchronizedMap(ConcurrentHashMap()) + val sectionMap: MutableMap = synchronizedMapOf() for ((sectionIndex, sectionHeight) in (dimension.lowestSection until dimension.highestSection).withIndex()) { // max sections per chunks in chunk column if (!sectionBitMask[sectionIndex]) { continue @@ -144,7 +144,7 @@ object ChunkUtil { fun readPaletteChunk(buffer: PlayInByteBuffer, dimension: Dimension, sectionBitMask: BitSet, isFullChunk: Boolean, containsSkyLight: Boolean = false): ChunkData { val chunkData = ChunkData() - val sectionMap: MutableMap = Collections.synchronizedMap(ConcurrentHashMap()) + val sectionMap: MutableMap = synchronizedMapOf() for ((sectionIndex, sectionHeight) in (dimension.lowestSection until sectionBitMask.length()).withIndex()) { // max sections per chunks in chunk column if (!sectionBitMask[sectionIndex]) {