block entity ticking, campfire block game logic

This commit is contained in:
Bixilon 2021-05-28 17:32:51 +02:00 committed by Lukas
parent 1f791378ec
commit 820cf347f7
22 changed files with 205 additions and 67 deletions

View File

@ -13,11 +13,15 @@
package de.bixilon.minosoft.data.entities.block package de.bixilon.minosoft.data.entities.block
import de.bixilon.minosoft.data.mappings.blocks.BlockState
import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import glm_.vec3.Vec3i
abstract class BlockEntity( abstract class BlockEntity(
val connection: PlayConnection, val connection: PlayConnection,
) { ) {
open fun updateNBT(nbt: Map<String, Any>) {} open fun updateNBT(nbt: Map<String, Any>) {}
open fun realTick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) {}
} }

View File

@ -15,10 +15,16 @@ package de.bixilon.minosoft.data.entities.block
import de.bixilon.minosoft.data.inventory.ItemStack import de.bixilon.minosoft.data.inventory.ItemStack
import de.bixilon.minosoft.data.mappings.ResourceLocation 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.RenderConstants
import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer
import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.util.KUtil.nullCast import de.bixilon.minosoft.util.KUtil.nullCast
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.listCast import de.bixilon.minosoft.util.nbt.tag.NBTUtil.listCast
import glm_.vec3.Vec3i
import kotlin.random.Random
class CampfireBlockEntity(connection: PlayConnection) : BlockEntity(connection) { class CampfireBlockEntity(connection: PlayConnection) : BlockEntity(connection) {
val items: Array<ItemStack?> = arrayOfNulls(RenderConstants.CAMPFIRE_ITEMS) val items: Array<ItemStack?> = 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<CampfireBlockEntity> { companion object : BlockEntityFactory<CampfireBlockEntity> {
override val RESOURCE_LOCATION: ResourceLocation = ResourceLocation("minecraft:campfire") override val RESOURCE_LOCATION: ResourceLocation = ResourceLocation("minecraft:campfire")

View File

@ -81,7 +81,7 @@ open class Block(
return true 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) { if (blockEntityType == null) {
return BlockUsages.PASS return BlockUsages.PASS
} }
@ -107,6 +107,7 @@ open class Block(
"NoteBlock" -> NoteBlock(resourceLocation, mappings, data) "NoteBlock" -> NoteBlock(resourceLocation, mappings, data)
"RepeaterBlock" -> RepeaterBlock(resourceLocation, mappings, data) "RepeaterBlock" -> RepeaterBlock(resourceLocation, mappings, data)
"ComparatorBlock" -> ComparatorBlock(resourceLocation, mappings, data) "ComparatorBlock" -> ComparatorBlock(resourceLocation, mappings, data)
"CampfireBlock" -> CampfireBlock(resourceLocation, mappings, data)
else -> Block(resourceLocation, mappings, data) else -> Block(resourceLocation, mappings, data)
} }

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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
}
}

View File

@ -18,7 +18,7 @@ open class ComparatorBlock(resourceLocation: ResourceLocation, mappings: Registr
TODO() 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) connection.world[blockPosition] = blockState.cycle(BlockProperties.STRUCTURE_BLOCK_MODE)
return BlockUsages.SUCCESS return BlockUsages.SUCCESS

View File

@ -32,7 +32,7 @@ open class DoorBlock(resourceLocation: ResourceLocation, mappings: Registries, d
TODO() 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) { if (blockState.material.resourceLocation == DefaultMaterials.METAL) {
return BlockUsages.CONSUME return BlockUsages.CONSUME
} }

View File

@ -31,7 +31,7 @@ open class LeverBlock(resourceLocation: ResourceLocation, mappings: Registries,
TODO() 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) connection.world[blockPosition] = blockState.cycle(BlockProperties.POWERED)
return BlockUsages.SUCCESS return BlockUsages.SUCCESS

View File

@ -26,7 +26,7 @@ import glm_.vec3.Vec3i
open class NoteBlock(resourceLocation: ResourceLocation, mappings: Registries, data: JsonObject) : Block(resourceLocation, mappings, data) { 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 return BlockUsages.SUCCESS
} }
} }

View File

@ -18,7 +18,7 @@ open class RepeaterBlock(resourceLocation: ResourceLocation, mappings: Registrie
TODO() 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) connection.world[blockPosition] = blockState.cycle(BlockProperties.REPEATER_DELAY)
return BlockUsages.SUCCESS return BlockUsages.SUCCESS

View File

@ -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.mappings.blocks.BlockState
import de.bixilon.minosoft.data.world.biome.source.BiomeSource import de.bixilon.minosoft.data.world.biome.source.BiomeSource
import de.bixilon.minosoft.data.world.light.LightAccessor 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.inChunkSectionPosition
import de.bixilon.minosoft.gui.rendering.util.VecUtil.of
import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight 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 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? { fun getBlockEntity(inChunkPosition: Vec3i): BlockEntity? {
return sections?.get(inChunkPosition.sectionHeight)?.getBlockEntity(inChunkPosition.inChunkSectionPosition) return sections?.get(inChunkPosition.sectionHeight)?.getBlockEntity(inChunkPosition.inChunkSectionPosition)
} }

View File

@ -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.ArrayBlockEntityProvider
import de.bixilon.minosoft.data.world.block.entities.BlockEntityProvider import de.bixilon.minosoft.data.world.block.entities.BlockEntityProvider
import de.bixilon.minosoft.data.world.block.entities.MapBlockEntityProvider 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 de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import glm_.vec3.Vec3i 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 { companion object {
val Vec3i.index: Int val Vec3i.index: Int
get() = getIndex(x, y, z) get() = getIndex(x, y, z)

View File

@ -30,6 +30,7 @@ import de.bixilon.minosoft.modding.event.events.BlockSetEvent
import de.bixilon.minosoft.modding.event.events.ChunkUnloadEvent import de.bixilon.minosoft.modding.event.events.ChunkUnloadEvent
import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
import glm_.vec2.Vec2i import glm_.vec2.Vec2i
import glm_.vec3.Vec3i import glm_.vec3.Vec3i
@ -155,6 +156,12 @@ class World(
return biomeAccessor.getBiome(blockPosition) return biomeAccessor.getBiome(blockPosition)
} }
fun realTick() {
for ((chunkPosition, chunk) in chunks.toSynchronizedMap()) {
chunk.realTick(connection, chunkPosition)
}
}
fun getBlocks(start: Vec3i, end: Vec3i): Map<Vec3i, BlockState> { fun getBlocks(start: Vec3i, end: Vec3i): Map<Vec3i, BlockState> {
val blocks: MutableMap<Vec3i, BlockState> = mutableMapOf() val blocks: MutableMap<Vec3i, BlockState> = mutableMapOf()

View File

@ -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.entities.block.BlockEntity
import de.bixilon.minosoft.data.world.ChunkSection.Companion.index 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 de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import glm_.vec3.Vec3i import glm_.vec3.Vec3i
@ -47,4 +48,11 @@ class ArrayBlockEntityProvider(
override fun clone(): ArrayBlockEntityProvider { override fun clone(): ArrayBlockEntityProvider {
return ArrayBlockEntityProvider(blockEntities.clone()) 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)
}
}
} }

View File

@ -25,6 +25,8 @@ interface BlockEntityProvider {
fun clone(): BlockEntityProvider fun clone(): BlockEntityProvider
fun forEach(lambda: (entity: BlockEntity, inChunkSectionPosition: Vec3i) -> Unit)
companion object { companion object {
const val BLOCK_ENTITY_MAP_LIMIT_UP = 15 const val BLOCK_ENTITY_MAP_LIMIT_UP = 15
const val BLOCK_ENTITY_MAP_LIMIT_DOWN = 5 const val BLOCK_ENTITY_MAP_LIMIT_DOWN = 5

View File

@ -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.entities.block.BlockEntity
import de.bixilon.minosoft.data.world.ChunkSection.Companion.indexPosition 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 import glm_.vec3.Vec3i
class MapBlockEntityProvider( class MapBlockEntityProvider(
var blockEntities: MutableMap<Vec3i, BlockEntity> = mutableMapOf(), var blockEntities: MutableMap<Vec3i, BlockEntity> = synchronizedMapOf(),
) : BlockEntityProvider { ) : BlockEntityProvider {
override val size: Int override val size: Int
get() = blockEntities.size get() = blockEntities.size
@ -47,4 +49,10 @@ class MapBlockEntityProvider(
override fun clone(): MapBlockEntityProvider { override fun clone(): MapBlockEntityProvider {
return MapBlockEntityProvider(blockEntities.toMutableMap()) return MapBlockEntityProvider(blockEntities.toMutableMap())
} }
override fun forEach(lambda: (entity: BlockEntity, inChunkSectionPosition: Vec3i) -> Unit) {
for ((position, blockEntity) in blockEntities.toSynchronizedMap()) {
lambda(blockEntity, position)
}
}
} }

View File

@ -54,7 +54,7 @@ class RightClickHandler(
val usage = if (renderWindow.inputHandler.camera.sneaking) { val usage = if (renderWindow.inputHandler.camera.sneaking) {
BlockUsages.PASS BlockUsages.PASS
} else { } 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) { if (currentTime - lastInteractionSent < ProtocolDefinition.TICK_TIME) {

View File

@ -20,7 +20,6 @@ import de.bixilon.minosoft.gui.rendering.Renderer
import de.bixilon.minosoft.gui.rendering.RendererBuilder import de.bixilon.minosoft.gui.rendering.RendererBuilder
import de.bixilon.minosoft.gui.rendering.modding.events.CameraMatrixChangeEvent 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.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.shader.Shader
import de.bixilon.minosoft.gui.rendering.textures.Texture import de.bixilon.minosoft.gui.rendering.textures.Texture
import de.bixilon.minosoft.gui.rendering.textures.TextureArray 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 de.bixilon.minosoft.util.MMath
import glm_.vec3.Vec3 import glm_.vec3.Vec3
import org.lwjgl.opengl.GL11.glDepthMask import org.lwjgl.opengl.GL11.glDepthMask
import kotlin.random.Random
class ParticleRenderer( class ParticleRenderer(
@ -78,7 +76,6 @@ class ParticleRenderer(
particles += particle particles += particle
} }
var lastTickTime = System.currentTimeMillis()
override fun draw() { override fun draw() {
particleShader.use() particleShader.use()
@ -86,25 +83,6 @@ class ParticleRenderer(
particleMesh.unload() particleMesh.unload()
particleMesh = ParticleMesh() 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()) { for (particle in particles.toSynchronizedSet()) {
particle.tick() particle.tick()

View File

@ -62,7 +62,6 @@ abstract class Particle(
var spacing: Vec3 = Vec3.EMPTY var spacing: Vec3 = Vec3.EMPTY
set(value) { set(value) {
if (field == value) { if (field == value) {
return
} }
field = value field = value

View File

@ -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)) 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 fun Int.chunkPosition(multiplier: Int): Int {
get() { return if (this >= 0) {
val chunkX = if (this.x >= 0) { this / multiplier
this.x / ProtocolDefinition.SECTION_WIDTH_X } else {
} else { ((this + 1) / multiplier) - 1
((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)
} }
}
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 val Vec3i.inChunkPosition: Vec3i
get() { get() = Vec3i(this.x.inChunkPosition(ProtocolDefinition.SECTION_WIDTH_X), y, this.z.inChunkPosition(ProtocolDefinition.SECTION_WIDTH_Z))
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)
}
val Vec3i.inChunkSectionPosition: Vec3i val Vec3i.inChunkSectionPosition: Vec3i
get() { get() {
@ -199,20 +193,20 @@ object VecUtil {
} }
val Vec3i.entityPosition: Vec3 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 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 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 { fun Vec3i.Companion.of(chunkPosition: Vec2i, sectionHeight: Int, inChunkSectionPosition: Vec3i): Vec3i {
return Vec3i( return Vec3i(
chunkPosition.x * ProtocolDefinition.SECTION_WIDTH_X + inChunkSectionPosition.x, chunkPosition.x * ProtocolDefinition.SECTION_WIDTH_X + inChunkSectionPosition.x,
sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y + inChunkSectionPosition.y, sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y + inChunkSectionPosition.y,
chunkPosition.y * ProtocolDefinition.SECTION_WIDTH_Z + inChunkSectionPosition.z chunkPosition.y * ProtocolDefinition.SECTION_WIDTH_Z + inChunkSectionPosition.z
) // ToDo ) // ToDo: Confirm
} }
infix operator fun Vec3i.plus(vec3: Vec3i?): Vec3i { infix operator fun Vec3i.plus(vec3: Vec3i?): Vec3i {

View File

@ -80,6 +80,7 @@ class PlayConnection(
lateinit var velocityHandlerTask: TimeWorkerTask lateinit var velocityHandlerTask: TimeWorkerTask
private var velocityHandlerLastExecutionTime: Long = 0L private var velocityHandlerLastExecutionTime: Long = 0L
lateinit var worldTickTask: TimeWorkerTask
val collisionDetector = CollisionDetector(this) val collisionDetector = CollisionDetector(this)
override var connectionState: ConnectionStates = ConnectionStates.DISCONNECTED override var connectionState: ConnectionStates = ConnectionStates.DISCONNECTED
@ -137,6 +138,11 @@ class PlayConnection(
} }
TimeWorker.addTask(velocityHandlerTask) TimeWorker.addTask(velocityHandlerTask)
worldTickTask = TimeWorkerTask(ProtocolDefinition.TICK_TIME) {
world.realTick()
}
TimeWorker.addTask(worldTickTask)
registerEvent(CallbackEventInvoker.of<ChatMessageReceiveEvent> { registerEvent(CallbackEventInvoker.of<ChatMessageReceiveEvent> {
val additionalPrefix = when (it.position) { val additionalPrefix = when (it.position) {
ChatTextPositions.SYSTEM_MESSAGE -> "[SYSTEM] " ChatTextPositions.SYSTEM_MESSAGE -> "[SYSTEM] "
@ -157,6 +163,9 @@ class PlayConnection(
if (this::velocityHandlerTask.isInitialized) { if (this::velocityHandlerTask.isInitialized) {
TimeWorker.removeTask(velocityHandlerTask) TimeWorker.removeTask(velocityHandlerTask)
} }
if (this::worldTickTask.isInitialized) {
TimeWorker.removeTask(worldTickTask)
}
} }
else -> { else -> {
} }

View File

@ -43,18 +43,18 @@ class ContainerOpenS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
} }
} }
val title: ChatComponent = buffer.readChatComponent() 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() buffer.readUnsignedByte()
} else { } else {
// ToDo: load from pixlyzer // ToDo: load from pixlyzer
0 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() buffer.readBoolean()
} else { } else {
true 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() buffer.readInt()
} else { } else {
null null

View File

@ -12,16 +12,25 @@ object TimeWorker {
while (true) { while (true) {
val currentTime = System.currentTimeMillis() val currentTime = System.currentTimeMillis()
for (task in TASKS.toSynchronizedSet()) { for (task in TASKS.toSynchronizedSet()) {
if (!task.getsExecuted && currentTime - task.lastExecution >= task.interval) { if (task.getsExecuted) {
Minosoft.THREAD_POOL.execute { continue
}
if (currentTime - task.lastExecution <= task.interval) {
continue
}
Minosoft.THREAD_POOL.execute {
synchronized(task.getsExecuted) {
if (task.getsExecuted) {
return@execute
}
task.getsExecuted = true task.getsExecuted = true
task.runnable.run() task.runnable.run()
task.lastExecution = currentTime task.lastExecution = currentTime
task.getsExecuted = false task.getsExecuted = false
} }
if (task.runOnce) { }
TASKS -= task if (task.runOnce) {
} TASKS -= task
} }
} }
Thread.sleep(1) Thread.sleep(1)