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
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<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.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<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> {
override val RESOURCE_LOCATION: ResourceLocation = ResourceLocation("minecraft:campfire")

View File

@ -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)
}

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()
}
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

View File

@ -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
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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

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.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)
}

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.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)

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.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<Vec3i, BlockState> {
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.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)
}
}
}

View File

@ -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

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.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<Vec3i, BlockEntity> = mutableMapOf(),
var blockEntities: MutableMap<Vec3i, BlockEntity> = 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)
}
}
}

View File

@ -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) {

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.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()

View File

@ -62,7 +62,6 @@ abstract class Particle(
var spacing: Vec3 = Vec3.EMPTY
set(value) {
if (field == value) {
return
}
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))
}
fun Int.chunkPosition(multiplier: Int): Int {
return if (this >= 0) {
this / multiplier
} else {
((this + 1) / multiplier) - 1
}
}
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
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
}
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)
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 {

View File

@ -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<ChatMessageReceiveEvent> {
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 -> {
}

View File

@ -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

View File

@ -12,18 +12,27 @@ object TimeWorker {
while (true) {
val currentTime = System.currentTimeMillis()
for (task in TASKS.toSynchronizedSet()) {
if (!task.getsExecuted && currentTime - task.lastExecution >= task.interval) {
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
}
}
}
Thread.sleep(1)
}
}, "TimeWorkerThread").start()