diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/BlockEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/BlockEntity.kt index 71afc00d2..d4413c158 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/BlockEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/BlockEntity.kt @@ -13,11 +13,15 @@ package de.bixilon.minosoft.data.entities.block +import de.bixilon.minosoft.data.mappings.blocks.BlockState import de.bixilon.minosoft.protocol.network.connection.PlayConnection +import glm_.vec3.Vec3i abstract class BlockEntity( val connection: PlayConnection, ) { open fun updateNBT(nbt: Map) {} + + open fun realTick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) {} } diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/CampfireBlockEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/CampfireBlockEntity.kt index 783a99e0b..bf3cb05b5 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/CampfireBlockEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/CampfireBlockEntity.kt @@ -15,10 +15,16 @@ package de.bixilon.minosoft.data.entities.block import de.bixilon.minosoft.data.inventory.ItemStack import de.bixilon.minosoft.data.mappings.ResourceLocation +import de.bixilon.minosoft.data.mappings.blocks.BlockState +import de.bixilon.minosoft.data.mappings.blocks.properties.BlockProperties +import de.bixilon.minosoft.data.mappings.blocks.types.CampfireBlock import de.bixilon.minosoft.gui.rendering.RenderConstants +import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.util.KUtil.nullCast import de.bixilon.minosoft.util.nbt.tag.NBTUtil.listCast +import glm_.vec3.Vec3i +import kotlin.random.Random class CampfireBlockEntity(connection: PlayConnection) : BlockEntity(connection) { val items: Array = arrayOfNulls(RenderConstants.CAMPFIRE_ITEMS) @@ -38,6 +44,23 @@ class CampfireBlockEntity(connection: PlayConnection) : BlockEntity(connection) } } + + override fun realTick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) { + val particleRenderer = connection.rendering?.renderWindow?.get(ParticleRenderer) ?: return + if (blockState.properties[BlockProperties.LIT] != true) { + return + } + if (blockState.block !is CampfireBlock) { + return + } + + if (Random.nextFloat() < 0.11f) { + for (i in 0 until Random.nextInt(2) + 2) { + blockState.block.spawnSmokeParticles(connection, particleRenderer, blockState, blockPosition, false) + } + } + } + companion object : BlockEntityFactory { override val RESOURCE_LOCATION: ResourceLocation = ResourceLocation("minecraft:campfire") diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/Block.kt b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/Block.kt index f61c62d87..0588fe99e 100644 --- a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/Block.kt +++ b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/Block.kt @@ -81,7 +81,7 @@ open class Block( return true } - open fun use(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack?): BlockUsages { + open fun onUse(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack?): BlockUsages { if (blockEntityType == null) { return BlockUsages.PASS } @@ -107,6 +107,7 @@ open class Block( "NoteBlock" -> NoteBlock(resourceLocation, mappings, data) "RepeaterBlock" -> RepeaterBlock(resourceLocation, mappings, data) "ComparatorBlock" -> ComparatorBlock(resourceLocation, mappings, data) + "CampfireBlock" -> CampfireBlock(resourceLocation, mappings, data) else -> Block(resourceLocation, mappings, data) } diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/CampfireBlock.kt b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/CampfireBlock.kt new file mode 100644 index 000000000..9ffe561e5 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/CampfireBlock.kt @@ -0,0 +1,72 @@ +/* + * Minosoft + * Copyright (C) 2021 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.data.mappings.blocks.types + +import com.google.gson.JsonObject +import de.bixilon.minosoft.data.inventory.ItemStack +import de.bixilon.minosoft.data.mappings.ResourceLocation +import de.bixilon.minosoft.data.mappings.blocks.BlockState +import de.bixilon.minosoft.data.mappings.blocks.BlockUsages +import de.bixilon.minosoft.data.mappings.blocks.properties.BlockProperties +import de.bixilon.minosoft.data.mappings.items.tools.ShovelItem +import de.bixilon.minosoft.data.mappings.versions.Registries +import de.bixilon.minosoft.data.player.Hands +import de.bixilon.minosoft.gui.rendering.input.camera.RaycastHit +import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer +import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.CampfireSmokeParticle +import de.bixilon.minosoft.protocol.network.connection.PlayConnection +import glm_.vec3.Vec3 +import glm_.vec3.Vec3i +import kotlin.random.Random + +open class CampfireBlock(resourceLocation: ResourceLocation, mappings: Registries, data: JsonObject) : Block(resourceLocation, mappings, data) { + + private fun extinguish(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) { + val particleRenderer = connection.rendering?.renderWindow?.get(ParticleRenderer) ?: return + for (i in 0 until 20) { + spawnSmokeParticles(connection, particleRenderer, blockState, blockPosition, true) + } + } + + fun spawnSmokeParticles(connection: PlayConnection, particleRenderer: ParticleRenderer, blockState: BlockState, blockPosition: Vec3i, extinguished: Boolean) { + val horizontal = { 0.5f + Random.nextFloat() / 3.0f * if (Random.nextBoolean()) 1.0f else -1.0f } + val position = Vec3( + blockPosition.x + horizontal(), + blockPosition.y + Random.nextFloat() + Random.nextFloat(), + blockPosition.z + horizontal() + ) + val isSignal = blockState.properties[BlockProperties.CAMPFIRE_SIGNAL_FIRE] == true + + val data = connection.registries.particleTypeRegistry[if (isSignal) { + CampfireSmokeParticle.SignalSmokeParticleFactory + } else { + CampfireSmokeParticle.CosySmokeParticleFactory + }]!! + + particleRenderer.add(CampfireSmokeParticle(connection, particleRenderer, position, Vec3(0.0f, 0.07f, 0.0f), data.simple(), isSignal)) + + if (extinguished) { + // ToDo: Spawn smoke particles + } + } + + override fun onUse(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack?): BlockUsages { + if (itemStack?.item !is ShovelItem || blockState.properties[BlockProperties.LIT] != true) { + return super.onUse(connection, blockState, blockPosition, raycastHit, hands, itemStack) + } + connection.world.setBlockState(blockPosition, blockState.withProperties(BlockProperties.LIT to false)) + extinguish(connection, blockState, blockPosition) + return BlockUsages.SUCCESS + } +} diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/ComparatorBlock.kt b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/ComparatorBlock.kt index c090b58e5..13d288c0f 100644 --- a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/ComparatorBlock.kt +++ b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/ComparatorBlock.kt @@ -18,7 +18,7 @@ open class ComparatorBlock(resourceLocation: ResourceLocation, mappings: Registr TODO() } - override fun use(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack?): BlockUsages { + override fun onUse(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack?): BlockUsages { connection.world[blockPosition] = blockState.cycle(BlockProperties.STRUCTURE_BLOCK_MODE) return BlockUsages.SUCCESS diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/DoorBlock.kt b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/DoorBlock.kt index 5c3faca7f..c9a21f048 100644 --- a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/DoorBlock.kt +++ b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/DoorBlock.kt @@ -32,7 +32,7 @@ open class DoorBlock(resourceLocation: ResourceLocation, mappings: Registries, d TODO() } - override fun use(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack?): BlockUsages { + override fun onUse(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack?): BlockUsages { if (blockState.material.resourceLocation == DefaultMaterials.METAL) { return BlockUsages.CONSUME } diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/LeverBlock.kt b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/LeverBlock.kt index 7cf148c58..38514e221 100644 --- a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/LeverBlock.kt +++ b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/LeverBlock.kt @@ -31,7 +31,7 @@ open class LeverBlock(resourceLocation: ResourceLocation, mappings: Registries, TODO() } - override fun use(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack?): BlockUsages { + override fun onUse(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack?): BlockUsages { connection.world[blockPosition] = blockState.cycle(BlockProperties.POWERED) return BlockUsages.SUCCESS diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/NoteBlock.kt b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/NoteBlock.kt index 46fb1d0f9..5c9d77ae1 100644 --- a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/NoteBlock.kt +++ b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/NoteBlock.kt @@ -26,7 +26,7 @@ import glm_.vec3.Vec3i open class NoteBlock(resourceLocation: ResourceLocation, mappings: Registries, data: JsonObject) : Block(resourceLocation, mappings, data) { - override fun use(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack?): BlockUsages { + override fun onUse(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack?): BlockUsages { return BlockUsages.SUCCESS } } diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/RepeaterBlock.kt b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/RepeaterBlock.kt index f17c76f93..a3085afec 100644 --- a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/RepeaterBlock.kt +++ b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/types/RepeaterBlock.kt @@ -18,7 +18,7 @@ open class RepeaterBlock(resourceLocation: ResourceLocation, mappings: Registrie TODO() } - override fun use(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack?): BlockUsages { + override fun onUse(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack?): BlockUsages { connection.world[blockPosition] = blockState.cycle(BlockProperties.REPEATER_DELAY) return BlockUsages.SUCCESS diff --git a/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt b/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt index 036417be0..09d30562a 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt @@ -16,8 +16,13 @@ import de.bixilon.minosoft.data.entities.block.BlockEntity import de.bixilon.minosoft.data.mappings.blocks.BlockState import de.bixilon.minosoft.data.world.biome.source.BiomeSource import de.bixilon.minosoft.data.world.light.LightAccessor +import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkSectionPosition +import de.bixilon.minosoft.gui.rendering.util.VecUtil.of import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight +import de.bixilon.minosoft.protocol.network.connection.PlayConnection +import de.bixilon.minosoft.util.KUtil.toSynchronizedMap +import glm_.vec2.Vec2i import glm_.vec3.Vec3i /** @@ -90,6 +95,18 @@ class Chunk( } } + fun realTick(connection: PlayConnection, chunkPosition: Vec2i) { + if (!isFullyLoaded) { + return + } + val sections = sections + sections ?: return + for ((height, section) in sections.toSynchronizedMap()) { + section.realTick(connection, Vec3i.of(chunkPosition, height, Vec3i.EMPTY)) + } + } + + fun getBlockEntity(inChunkPosition: Vec3i): BlockEntity? { return sections?.get(inChunkPosition.sectionHeight)?.getBlockEntity(inChunkPosition.inChunkSectionPosition) } diff --git a/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt b/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt index 93cc85bc6..e8a5ec299 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt @@ -17,6 +17,7 @@ import de.bixilon.minosoft.data.mappings.blocks.BlockState import de.bixilon.minosoft.data.world.block.entities.ArrayBlockEntityProvider import de.bixilon.minosoft.data.world.block.entities.BlockEntityProvider import de.bixilon.minosoft.data.world.block.entities.MapBlockEntityProvider +import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import glm_.vec3.Vec3i @@ -55,6 +56,12 @@ class ChunkSection( } } + fun realTick(connection: PlayConnection, chunkSectionPosition: Vec3i) { + blockEntities.forEach { entity, inChunkSectionPosition -> + entity.realTick(connection, blocks[inChunkSectionPosition.index]!!, chunkSectionPosition + inChunkSectionPosition) + } + } + companion object { val Vec3i.index: Int get() = getIndex(x, y, z) 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 9e9279ffc..d45d2a2dd 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/World.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/World.kt @@ -30,6 +30,7 @@ import de.bixilon.minosoft.modding.event.events.BlockSetEvent import de.bixilon.minosoft.modding.event.events.ChunkUnloadEvent import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.util.KUtil.synchronizedMapOf +import de.bixilon.minosoft.util.KUtil.toSynchronizedMap import glm_.vec2.Vec2i import glm_.vec3.Vec3i @@ -155,6 +156,12 @@ class World( return biomeAccessor.getBiome(blockPosition) } + fun realTick() { + for ((chunkPosition, chunk) in chunks.toSynchronizedMap()) { + chunk.realTick(connection, chunkPosition) + } + } + fun getBlocks(start: Vec3i, end: Vec3i): Map { val blocks: MutableMap = mutableMapOf() diff --git a/src/main/java/de/bixilon/minosoft/data/world/block/entities/ArrayBlockEntityProvider.kt b/src/main/java/de/bixilon/minosoft/data/world/block/entities/ArrayBlockEntityProvider.kt index 54226e567..3e2d5d9e8 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/block/entities/ArrayBlockEntityProvider.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/block/entities/ArrayBlockEntityProvider.kt @@ -15,6 +15,7 @@ package de.bixilon.minosoft.data.world.block.entities import de.bixilon.minosoft.data.entities.block.BlockEntity import de.bixilon.minosoft.data.world.ChunkSection.Companion.index +import de.bixilon.minosoft.data.world.ChunkSection.Companion.indexPosition import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import glm_.vec3.Vec3i @@ -47,4 +48,11 @@ class ArrayBlockEntityProvider( override fun clone(): ArrayBlockEntityProvider { return ArrayBlockEntityProvider(blockEntities.clone()) } + + override fun forEach(lambda: (entity: BlockEntity, inChunkSectionPosition: Vec3i) -> Unit) { + for ((index, blockEntity) in blockEntities.withIndex()) { + blockEntity ?: continue + lambda(blockEntity, index.indexPosition) + } + } } diff --git a/src/main/java/de/bixilon/minosoft/data/world/block/entities/BlockEntityProvider.kt b/src/main/java/de/bixilon/minosoft/data/world/block/entities/BlockEntityProvider.kt index dcde01b30..9751ecf30 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/block/entities/BlockEntityProvider.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/block/entities/BlockEntityProvider.kt @@ -25,6 +25,8 @@ interface BlockEntityProvider { fun clone(): BlockEntityProvider + fun forEach(lambda: (entity: BlockEntity, inChunkSectionPosition: Vec3i) -> Unit) + companion object { const val BLOCK_ENTITY_MAP_LIMIT_UP = 15 const val BLOCK_ENTITY_MAP_LIMIT_DOWN = 5 diff --git a/src/main/java/de/bixilon/minosoft/data/world/block/entities/MapBlockEntityProvider.kt b/src/main/java/de/bixilon/minosoft/data/world/block/entities/MapBlockEntityProvider.kt index 4979c6aa7..4f0a81263 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/block/entities/MapBlockEntityProvider.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/block/entities/MapBlockEntityProvider.kt @@ -15,10 +15,12 @@ package de.bixilon.minosoft.data.world.block.entities import de.bixilon.minosoft.data.entities.block.BlockEntity import de.bixilon.minosoft.data.world.ChunkSection.Companion.indexPosition +import de.bixilon.minosoft.util.KUtil.synchronizedMapOf +import de.bixilon.minosoft.util.KUtil.toSynchronizedMap import glm_.vec3.Vec3i class MapBlockEntityProvider( - var blockEntities: MutableMap = mutableMapOf(), + var blockEntities: MutableMap = synchronizedMapOf(), ) : BlockEntityProvider { override val size: Int get() = blockEntities.size @@ -47,4 +49,10 @@ class MapBlockEntityProvider( override fun clone(): MapBlockEntityProvider { return MapBlockEntityProvider(blockEntities.toMutableMap()) } + + override fun forEach(lambda: (entity: BlockEntity, inChunkSectionPosition: Vec3i) -> Unit) { + for ((position, blockEntity) in blockEntities.toSynchronizedMap()) { + lambda(blockEntity, position) + } + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/RightClickHandler.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/RightClickHandler.kt index 111ee3520..bbd958889 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/RightClickHandler.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/RightClickHandler.kt @@ -54,7 +54,7 @@ class RightClickHandler( val usage = if (renderWindow.inputHandler.camera.sneaking) { BlockUsages.PASS } else { - raycastHit.blockState.block.use(renderWindow.connection, raycastHit.blockState, raycastHit.blockPosition, raycastHit, Hands.MAIN_HAND, itemInHand) + raycastHit.blockState.block.onUse(renderWindow.connection, raycastHit.blockState, raycastHit.blockPosition, raycastHit, Hands.MAIN_HAND, itemInHand) } if (currentTime - lastInteractionSent < ProtocolDefinition.TICK_TIME) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt index 088e3e227..63297466b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt @@ -20,7 +20,6 @@ import de.bixilon.minosoft.gui.rendering.Renderer import de.bixilon.minosoft.gui.rendering.RendererBuilder import de.bixilon.minosoft.gui.rendering.modding.events.CameraMatrixChangeEvent import de.bixilon.minosoft.gui.rendering.particle.types.Particle -import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.CampfireSmokeParticle import de.bixilon.minosoft.gui.rendering.shader.Shader import de.bixilon.minosoft.gui.rendering.textures.Texture import de.bixilon.minosoft.gui.rendering.textures.TextureArray @@ -32,7 +31,6 @@ import de.bixilon.minosoft.util.KUtil.toSynchronizedSet import de.bixilon.minosoft.util.MMath import glm_.vec3.Vec3 import org.lwjgl.opengl.GL11.glDepthMask -import kotlin.random.Random class ParticleRenderer( @@ -78,7 +76,6 @@ class ParticleRenderer( particles += particle } - var lastTickTime = System.currentTimeMillis() override fun draw() { particleShader.use() @@ -86,25 +83,6 @@ class ParticleRenderer( particleMesh.unload() particleMesh = ParticleMesh() - // ToDo: Remove, this ist just for testing purposes - if (System.currentTimeMillis() - lastTickTime > ProtocolDefinition.TICK_TIME) { - val blockPosition = Vec3(0, 5, 0) - if (Random.nextFloat() < 0.11f) { - for (i in 0 until Random.nextInt(2) + 2) { - val horizontal = { 0.5f + Random.nextFloat() / 3.0f * if (Random.nextBoolean()) 1.0f else -1.0f } - val position = Vec3( - blockPosition.x + horizontal(), - blockPosition.y + Random.nextFloat() + Random.nextFloat(), - blockPosition.z + horizontal() - ) - - val data = connection.registries.particleTypeRegistry[CampfireSmokeParticle.CosySmokeParticleFactory]!! - val particle = CampfireSmokeParticle(connection, this, position, Vec3(0.0f, 0.07f, 0.0f), data.simple(), true) - add(particle) - } - } - lastTickTime = System.currentTimeMillis() - } for (particle in particles.toSynchronizedSet()) { particle.tick() diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/Particle.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/Particle.kt index 55f482f96..fa91a076e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/Particle.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/Particle.kt @@ -62,7 +62,6 @@ abstract class Particle( var spacing: Vec3 = Vec3.EMPTY set(value) { if (field == value) { - return } field = value diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt index c6f066be0..cbe25717d 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt @@ -150,33 +150,27 @@ object VecUtil { return Pair(Vec2(this[0].asFloat, BlockModelElement.BLOCK_RESOLUTION - this[1].asFloat), Vec2(this[2].asFloat, BlockModelElement.BLOCK_RESOLUTION - this[3].asFloat)) } - val Vec3i.chunkPosition: Vec2i - get() { - val chunkX = if (this.x >= 0) { - this.x / ProtocolDefinition.SECTION_WIDTH_X - } else { - ((this.x + 1) / ProtocolDefinition.SECTION_WIDTH_X) - 1 - } - val chunkY = if (this.z >= 0) { - this.z / ProtocolDefinition.SECTION_WIDTH_Z - } else { - ((this.z + 1) / ProtocolDefinition.SECTION_WIDTH_Z) - 1 - } - return Vec2i(chunkX, chunkY) + fun Int.chunkPosition(multiplier: Int): Int { + return if (this >= 0) { + this / multiplier + } else { + ((this + 1) / multiplier) - 1 } + } + + val Vec3i.chunkPosition: Vec2i + get() = Vec2i(this.x.chunkPosition(ProtocolDefinition.SECTION_WIDTH_X), this.z.chunkPosition(ProtocolDefinition.SECTION_WIDTH_Z)) + + fun Int.inChunkPosition(multiplier: Int): Int { + var coordinate: Int = this % multiplier + if (coordinate < 0) { + coordinate += multiplier + } + return coordinate + } val Vec3i.inChunkPosition: Vec3i - get() { - var x: Int = this.x % ProtocolDefinition.SECTION_WIDTH_X - if (x < 0) { - x += ProtocolDefinition.SECTION_WIDTH_X - } - var z: Int = this.z % ProtocolDefinition.SECTION_WIDTH_Z - if (z < 0) { - z += ProtocolDefinition.SECTION_WIDTH_Z - } - return Vec3i(x, y, z) - } + get() = Vec3i(this.x.inChunkPosition(ProtocolDefinition.SECTION_WIDTH_X), y, this.z.inChunkPosition(ProtocolDefinition.SECTION_WIDTH_Z)) val Vec3i.inChunkSectionPosition: Vec3i get() { @@ -199,20 +193,20 @@ object VecUtil { } val Vec3i.entityPosition: Vec3 - get() = Vec3(x + 0.5f, y, z + 0.5f) // ToDo + get() = Vec3(x + 0.5f, y, z + 0.5f) // ToDo: Confirm val Vec3.blockPosition: Vec3i - get() = Vec3i((x - 0.5f).toInt(), y.toInt(), (z - 0.5f).toInt()) // ToDo + get() = Vec3i((x - 0.5f).toInt(), y.toInt(), (z - 0.5f).toInt()) // ToDo: Confirm val Vec3i.center: Vec3 - get() = Vec3(x + 0.5f, y + 0.5f, z + 0.5f) // ToDo + get() = Vec3(x + 0.5f, y + 0.5f, z + 0.5f) // ToDo: Confirm fun Vec3i.Companion.of(chunkPosition: Vec2i, sectionHeight: Int, inChunkSectionPosition: Vec3i): Vec3i { return Vec3i( chunkPosition.x * ProtocolDefinition.SECTION_WIDTH_X + inChunkSectionPosition.x, sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y + inChunkSectionPosition.y, chunkPosition.y * ProtocolDefinition.SECTION_WIDTH_Z + inChunkSectionPosition.z - ) // ToDo + ) // ToDo: Confirm } infix operator fun Vec3i.plus(vec3: Vec3i?): Vec3i { diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/connection/PlayConnection.kt b/src/main/java/de/bixilon/minosoft/protocol/network/connection/PlayConnection.kt index 9cec15be2..68de6fd98 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/connection/PlayConnection.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/network/connection/PlayConnection.kt @@ -80,6 +80,7 @@ class PlayConnection( lateinit var velocityHandlerTask: TimeWorkerTask private var velocityHandlerLastExecutionTime: Long = 0L + lateinit var worldTickTask: TimeWorkerTask val collisionDetector = CollisionDetector(this) override var connectionState: ConnectionStates = ConnectionStates.DISCONNECTED @@ -137,6 +138,11 @@ class PlayConnection( } TimeWorker.addTask(velocityHandlerTask) + worldTickTask = TimeWorkerTask(ProtocolDefinition.TICK_TIME) { + world.realTick() + } + TimeWorker.addTask(worldTickTask) + registerEvent(CallbackEventInvoker.of { val additionalPrefix = when (it.position) { ChatTextPositions.SYSTEM_MESSAGE -> "[SYSTEM] " @@ -157,6 +163,9 @@ class PlayConnection( if (this::velocityHandlerTask.isInitialized) { TimeWorker.removeTask(velocityHandlerTask) } + if (this::worldTickTask.isInitialized) { + TimeWorker.removeTask(worldTickTask) + } } else -> { } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ContainerOpenS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ContainerOpenS2CP.kt index 65785ac3a..a650f0f2c 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ContainerOpenS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ContainerOpenS2CP.kt @@ -43,18 +43,18 @@ class ContainerOpenS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { } } val title: ChatComponent = buffer.readChatComponent() - val slotCount: Int = if (buffer.versionId < V_19W02A || buffer.versionId >= V_19W11A) { + val slotCount: Int = if (buffer.versionId <= V_19W11A) { // ToDo: This is completely guessed, it is not present in 1.16.5 (unchecked) buffer.readUnsignedByte() } else { // ToDo: load from pixlyzer 0 } - val hasTitle: Boolean = if (buffer.versionId > V_14W03B) { + val hasTitle: Boolean = if (buffer.versionId > V_14W03B && buffer.versionId <= V_1_16) { // also completely guessed buffer.readBoolean() } else { true } - var entityId: Int? = if (containerType.resourceLocation == DefaultInventoryTypes.HORSE || buffer.versionId < V_14W03B) { + var entityId: Int? = if (containerType.resourceLocation == DefaultInventoryTypes.HORSE || buffer.versionId < V_14W03B) { // ToDo: This was removed at some point buffer.readInt() } else { null diff --git a/src/main/java/de/bixilon/minosoft/util/task/time/TimeWorker.kt b/src/main/java/de/bixilon/minosoft/util/task/time/TimeWorker.kt index 9f0a5ea99..02d4e60a5 100644 --- a/src/main/java/de/bixilon/minosoft/util/task/time/TimeWorker.kt +++ b/src/main/java/de/bixilon/minosoft/util/task/time/TimeWorker.kt @@ -12,16 +12,25 @@ object TimeWorker { while (true) { val currentTime = System.currentTimeMillis() for (task in TASKS.toSynchronizedSet()) { - if (!task.getsExecuted && currentTime - task.lastExecution >= task.interval) { - Minosoft.THREAD_POOL.execute { + if (task.getsExecuted) { + continue + } + if (currentTime - task.lastExecution <= task.interval) { + continue + } + Minosoft.THREAD_POOL.execute { + synchronized(task.getsExecuted) { + if (task.getsExecuted) { + return@execute + } task.getsExecuted = true task.runnable.run() task.lastExecution = currentTime task.getsExecuted = false } - if (task.runOnce) { - TASKS -= task - } + } + if (task.runOnce) { + TASKS -= task } } Thread.sleep(1)