minosoft meta, handle unavailable game features more gracefully, pre flattening fixes, fixes

This commit is contained in:
Bixilon 2023-03-21 20:49:29 +01:00
parent 823cd21a07
commit cf5143d9fb
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
19 changed files with 234 additions and 75 deletions

View File

@ -14,6 +14,7 @@
package de.bixilon.minosoft package de.bixilon.minosoft
import de.bixilon.kutil.latch.SimpleLatch import de.bixilon.kutil.latch.SimpleLatch
import de.bixilon.minosoft.assets.meta.MinosoftMeta
import de.bixilon.minosoft.assets.properties.version.AssetsVersionProperties import de.bixilon.minosoft.assets.properties.version.AssetsVersionProperties
import de.bixilon.minosoft.data.registries.fallback.FallbackRegistries import de.bixilon.minosoft.data.registries.fallback.FallbackRegistries
import de.bixilon.minosoft.data.registries.fallback.tags.FallbackTags import de.bixilon.minosoft.data.registries.fallback.tags.FallbackTags
@ -71,6 +72,7 @@ internal object MinosoftSIT {
fun loadDefaultRegistries() { fun loadDefaultRegistries() {
FallbackTags.load() FallbackTags.load()
FallbackRegistries.load() FallbackRegistries.load()
MinosoftMeta.load()
} }
fun loadPixlyzerData() { fun loadPixlyzerData() {

View File

@ -154,7 +154,7 @@ object VerifyIntegratedBlockRegistry {
continue continue
} }
val parsed = PixLyzerBlock.deserialize(registries, identifier, value).unsafeCast<PixLyzerBlock>() val parsed = PixLyzerBlock.deserialize(registries, identifier, value).unsafeCast<PixLyzerBlock>()
registries.block.updateStates(parsed, value, registries) registries.block.flattened(parsed, value, registries)
parsed.postInit(registries) parsed.postInit(registries)
parsed.inject(registries) parsed.inject(registries)

View File

@ -15,12 +15,14 @@ package de.bixilon.minosoft.data.registries.versions.registries
import de.bixilon.minosoft.data.entities.entities.monster.Zombie import de.bixilon.minosoft.data.entities.entities.monster.Zombie
import de.bixilon.minosoft.data.registries.blocks.MinecraftBlocks import de.bixilon.minosoft.data.registries.blocks.MinecraftBlocks
import de.bixilon.minosoft.data.registries.blocks.factory.VerifyIntegratedBlockRegistry import de.bixilon.minosoft.data.registries.identified.Namespaces.minecraft
import de.bixilon.minosoft.data.registries.item.MinecraftItems import de.bixilon.minosoft.data.registries.item.MinecraftItems
import de.bixilon.minosoft.data.registries.registries.Registries import de.bixilon.minosoft.data.registries.registries.Registries
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_1_19_3
import de.bixilon.minosoft.protocol.versions.Version import de.bixilon.minosoft.protocol.versions.Version
import de.bixilon.minosoft.protocol.versions.Versions import de.bixilon.minosoft.protocol.versions.Versions
import org.testng.Assert import org.testng.Assert.assertEquals
import org.testng.Assert.assertNotNull
import org.testng.SkipException import org.testng.SkipException
import org.testng.annotations.Test import org.testng.annotations.Test
@ -39,18 +41,24 @@ abstract class RegistryLoadingTest(val versionName: String) {
fun testItemSimple() { fun testItemSimple() {
Assert.assertNotNull(registries.item[MinecraftItems.COAL]) assertNotNull(registries.item[MinecraftItems.COAL])
} }
fun testBlockSimple() { fun testBlockSimple() {
Assert.assertNotNull(registries.block[MinecraftBlocks.DIRT]) assertNotNull(registries.block[MinecraftBlocks.DIRT])
}
fun testBlockIntegrated() {
VerifyIntegratedBlockRegistry.verify(registries, version)
} }
fun testEntitySimple() { fun testEntitySimple() {
Assert.assertNotNull(registries.entityType[Zombie]) assertNotNull(registries.entityType[Zombie])
}
fun biome() {
if (version > V_1_19_3) return // biomes are datapack only in those versions -> empty registry
assertNotNull(registries.biome[minecraft("plains")]?.identifier)
}
fun entities() {
assertEquals(registries.entityType[minecraft("player")]?.height, 1.8f)
} }
} }

View File

@ -13,11 +13,7 @@
package de.bixilon.minosoft.data.registries.versions.registries.legacy package de.bixilon.minosoft.data.registries.versions.registries.legacy
import org.testng.SkipException
import org.testng.annotations.Test import org.testng.annotations.Test
@Test(groups = ["pixlyzer"], dependsOnGroups = ["version"], priority = Int.MAX_VALUE, timeOut = 15000L) @Test(groups = ["pixlyzer"], dependsOnGroups = ["version"], priority = Int.MAX_VALUE, timeOut = 15000L)
class `1_12_2` : LegacyLoadingTest("1.12.2") { class `1_12_2` : LegacyLoadingTest("1.12.2")
override fun loadVersion() = throw SkipException("")
}

View File

@ -13,11 +13,7 @@
package de.bixilon.minosoft.data.registries.versions.registries.legacy package de.bixilon.minosoft.data.registries.versions.registries.legacy
import org.testng.SkipException
import org.testng.annotations.Test import org.testng.annotations.Test
@Test(groups = ["pixlyzer"], dependsOnGroups = ["version"], priority = Int.MAX_VALUE, timeOut = 15000L) @Test(groups = ["pixlyzer"], dependsOnGroups = ["version"], priority = Int.MAX_VALUE, timeOut = 15000L)
class `1_7_10` : LegacyLoadingTest("1.7.10") { class `1_7_10` : LegacyLoadingTest("1.7.10")
override fun loadVersion() = throw SkipException("")
}

View File

@ -13,11 +13,7 @@
package de.bixilon.minosoft.data.registries.versions.registries.legacy package de.bixilon.minosoft.data.registries.versions.registries.legacy
import org.testng.SkipException
import org.testng.annotations.Test import org.testng.annotations.Test
@Test(groups = ["pixlyzer"], dependsOnGroups = ["version"], priority = Int.MAX_VALUE, timeOut = 15000L) @Test(groups = ["pixlyzer"], dependsOnGroups = ["version"], priority = Int.MAX_VALUE, timeOut = 15000L)
class `1_8_9` : LegacyLoadingTest("1.8.9") { class `1_8_9` : LegacyLoadingTest("1.8.9")
override fun loadVersion() = throw SkipException("")
}

View File

@ -13,8 +13,51 @@
package de.bixilon.minosoft.data.registries.versions.registries.legacy package de.bixilon.minosoft.data.registries.versions.registries.legacy
import de.bixilon.minosoft.data.registries.identified.Namespaces.minecraft
import de.bixilon.minosoft.data.registries.versions.registries.RegistryLoadingTest import de.bixilon.minosoft.data.registries.versions.registries.RegistryLoadingTest
import de.bixilon.minosoft.test.ITUtil
import org.testng.Assert.assertEquals
import org.testng.Assert.assertNull
import org.testng.annotations.Test import org.testng.annotations.Test
@Test(groups = ["pixlyzer"], dependsOnGroups = ["version"], singleThreaded = false, threadPoolSize = 8, priority = Int.MAX_VALUE, timeOut = 15000L) @Test(groups = ["pixlyzer"], dependsOnGroups = ["version"], singleThreaded = false, threadPoolSize = 8, priority = Int.MAX_VALUE, timeOut = 15000L)
abstract class LegacyLoadingTest(version: String) : RegistryLoadingTest(version) abstract class LegacyLoadingTest(version: String) : RegistryLoadingTest(version) {
@Test(priority = 100000)
open fun loadRegistries() {
this._registries = ITUtil.loadPreFlatteningData(version)
}
fun dimension() {
assertEquals(registries.dimension[0].identifier, minecraft("overworld"))
assertEquals(registries.dimension[1].identifier, minecraft("the_end"))
assertEquals(registries.dimension[-1].identifier, minecraft("the_nether"))
}
fun biomeId() {
assertEquals(registries.biome[1].identifier, minecraft("plains"))
}
fun enchantmentId() {
assertEquals(registries.enchantment[16].identifier, minecraft("sharpness"))
}
fun effectId() {
assertEquals(registries.statusEffect[10].identifier, minecraft("regeneration"))
}
fun blockId() {
assertNull(registries.block.getOrNull(0))
assertEquals(registries.block[1 shl 4 or 0].identifier, minecraft("stone"))
assertEquals(registries.block[1 shl 4 or 1].identifier, minecraft("granite"))
assertEquals(registries.block[1 shl 4 or 3].identifier, minecraft("diorite"))
assertEquals(registries.block[41 shl 4 or 0].identifier, minecraft("gold_block"))
assertEquals(registries.block[166 shl 4 or 0].identifier, minecraft("barrier"))
}
fun itemId() {
assertEquals(registries.item[256].identifier, minecraft("iron_shovel"))
assertEquals(registries.item[2256].identifier, minecraft("music_disk"))
}
}

View File

@ -13,8 +13,10 @@
package de.bixilon.minosoft.data.registries.versions.registries.pixlyzer package de.bixilon.minosoft.data.registries.versions.registries.pixlyzer
import de.bixilon.minosoft.data.registries.blocks.factory.VerifyIntegratedBlockRegistry
import de.bixilon.minosoft.data.registries.versions.registries.RegistryLoadingTest import de.bixilon.minosoft.data.registries.versions.registries.RegistryLoadingTest
import de.bixilon.minosoft.test.ITUtil import de.bixilon.minosoft.test.ITUtil
import org.testng.SkipException
import org.testng.annotations.Test import org.testng.annotations.Test
@Test(groups = ["pixlyzer"], dependsOnGroups = ["version"], priority = Int.MAX_VALUE, timeOut = 15000L) @Test(groups = ["pixlyzer"], dependsOnGroups = ["version"], priority = Int.MAX_VALUE, timeOut = 15000L)
@ -22,6 +24,11 @@ abstract class PixLyzerLoadingTest(version: String) : RegistryLoadingTest(versio
@Test(priority = 100000) @Test(priority = 100000)
open fun loadRegistries() { open fun loadRegistries() {
throw SkipException("temp")
this._registries = ITUtil.loadPixlyzerData(version) this._registries = ITUtil.loadPixlyzerData(version)
} }
fun testBlockIntegrated() {
VerifyIntegratedBlockRegistry.verify(registries, version)
}
} }

View File

@ -14,6 +14,7 @@
package de.bixilon.minosoft.test package de.bixilon.minosoft.test
import de.bixilon.kutil.latch.SimpleLatch import de.bixilon.kutil.latch.SimpleLatch
import de.bixilon.minosoft.assets.properties.version.PreFlattening
import de.bixilon.minosoft.config.profile.profiles.resources.ResourcesProfile import de.bixilon.minosoft.config.profile.profiles.resources.ResourcesProfile
import de.bixilon.minosoft.data.registries.VersionRegistry import de.bixilon.minosoft.data.registries.VersionRegistry
import de.bixilon.minosoft.data.registries.registries.PixLyzerUtil import de.bixilon.minosoft.data.registries.registries.PixLyzerUtil
@ -49,6 +50,10 @@ object ITUtil {
return registries return registries
} }
fun loadPreFlatteningData(version: Version): Registries {
return PreFlattening.loadRegistry(profile, version, CountUpAndDownLatch(0))
}
@Deprecated("Its not implemented") @Deprecated("Its not implemented")
fun todo() { fun todo() {
throw SkipException("Not yet implemented!") throw SkipException("Not yet implemented!")

View File

@ -31,6 +31,7 @@ import de.bixilon.kutil.shutdown.ShutdownManager
import de.bixilon.kutil.time.TimeUtil.nanos import de.bixilon.kutil.time.TimeUtil.nanos
import de.bixilon.kutil.unit.UnitFormatter.formatNanos import de.bixilon.kutil.unit.UnitFormatter.formatNanos
import de.bixilon.minosoft.assets.file.ResourcesAssetsUtil import de.bixilon.minosoft.assets.file.ResourcesAssetsUtil
import de.bixilon.minosoft.assets.meta.MinosoftMeta
import de.bixilon.minosoft.assets.properties.version.AssetsVersionProperties import de.bixilon.minosoft.assets.properties.version.AssetsVersionProperties
import de.bixilon.minosoft.config.profile.GlobalProfileManager import de.bixilon.minosoft.config.profile.GlobalProfileManager
import de.bixilon.minosoft.config.profile.profiles.eros.ErosProfileManager import de.bixilon.minosoft.config.profile.profiles.eros.ErosProfileManager
@ -103,7 +104,7 @@ object Minosoft {
taskWorker += WorkerTask(identifier = BootTasks.LANGUAGE_FILES, dependencies = arrayOf(BootTasks.PROFILES), executor = this::loadLanguageFiles) taskWorker += WorkerTask(identifier = BootTasks.LANGUAGE_FILES, dependencies = arrayOf(BootTasks.PROFILES), executor = this::loadLanguageFiles)
taskWorker += WorkerTask(identifier = BootTasks.ASSETS_PROPERTIES, dependencies = arrayOf(BootTasks.PROFILES), executor = AssetsVersionProperties::load) taskWorker += WorkerTask(identifier = BootTasks.ASSETS_PROPERTIES, dependencies = arrayOf(BootTasks.PROFILES), executor = AssetsVersionProperties::load)
taskWorker += WorkerTask(identifier = BootTasks.DEFAULT_REGISTRIES, dependencies = arrayOf(BootTasks.PROFILES), executor = { FallbackTags.load(); FallbackRegistries.load(); EntityEvents.load(); }) taskWorker += WorkerTask(identifier = BootTasks.DEFAULT_REGISTRIES, dependencies = arrayOf(BootTasks.PROFILES), executor = { MinosoftMeta.load(); FallbackTags.load(); FallbackRegistries.load(); EntityEvents.load() })
taskWorker += WorkerTask(identifier = BootTasks.LAN_SERVERS, dependencies = arrayOf(BootTasks.PROFILES), executor = LANServerListener::listen) taskWorker += WorkerTask(identifier = BootTasks.LAN_SERVERS, dependencies = arrayOf(BootTasks.PROFILES), executor = LANServerListener::listen)

View File

@ -0,0 +1,23 @@
/*
* Minosoft
* Copyright (C) 2020-2023 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.assets.meta
typealias MetaRoot = Map<String, MetaTypeEntry>
typealias MetaTypeEntry = List<MetaVersionEntry>
data class MetaVersionEntry(
val version: String,
val hash: String,
)

View File

@ -0,0 +1,54 @@
/*
* Minosoft
* Copyright (C) 2020-2023 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.assets.meta
import de.bixilon.kutil.cast.CastUtil.unsafeNull
import de.bixilon.kutil.json.JsonObject
import de.bixilon.minosoft.assets.util.InputStreamUtil.readJson
import de.bixilon.minosoft.assets.util.InputStreamUtil.readJsonObject
import de.bixilon.minosoft.protocol.versions.Version
import de.bixilon.minosoft.protocol.versions.Versions
import java.io.FileInputStream
object MinosoftMeta {
var root: MetaRoot = unsafeNull()
private set
fun load() {
val file = FileInputStream("/home/moritz/git/gitlab.bixilon.de/bixilon/minosoft-meta/index.json")
this.root = file.readJson<MetaRoot>()
}
private fun MetaVersionEntry.load(type: String): JsonObject {
val file = FileInputStream("/home/moritz/git/gitlab.bixilon.de/bixilon/minosoft-meta/${this.version}/$type.json")
return file.readJsonObject()
}
fun MetaTypeEntry.load(type: String, version: Version): JsonObject? {
var previous: MetaVersionEntry? = null
for (entry in this) {
if (entry.version == "_") {
previous = entry
continue
}
val entryVersion = Versions[entry.version] ?: throw IllegalArgumentException("Unknown meta version ${entry.version}")
if (entryVersion > version) break
previous = entry
}
if (previous == null) return null
return previous.load(type)
}
}

View File

@ -13,34 +13,32 @@
package de.bixilon.minosoft.assets.properties.version package de.bixilon.minosoft.assets.properties.version
import de.bixilon.kutil.collections.CollectionUtil.synchronizedMapOf
import de.bixilon.kutil.json.MutableJsonObject
import de.bixilon.kutil.latch.CountUpAndDownLatch import de.bixilon.kutil.latch.CountUpAndDownLatch
import de.bixilon.minosoft.assets.meta.MinosoftMeta
import de.bixilon.minosoft.assets.meta.MinosoftMeta.load
import de.bixilon.minosoft.config.profile.profiles.resources.ResourcesProfile import de.bixilon.minosoft.config.profile.profiles.resources.ResourcesProfile
import de.bixilon.minosoft.data.entities.entities.player.RemotePlayerEntity
import de.bixilon.minosoft.data.registries.dimension.Dimension
import de.bixilon.minosoft.data.registries.dimension.DimensionProperties
import de.bixilon.minosoft.data.registries.entities.EntityType
import de.bixilon.minosoft.data.registries.registries.Registries import de.bixilon.minosoft.data.registries.registries.Registries
import de.bixilon.minosoft.protocol.versions.Version import de.bixilon.minosoft.protocol.versions.Version
import de.bixilon.minosoft.util.KUtil.toResourceLocation
object PreFlattening { object PreFlattening {
const val VERSION = "1.12.2" const val VERSION = "1.12.2"
fun loadRegistry(profile: ResourcesProfile, version: Version, latch: CountUpAndDownLatch): Registries { fun loadRegistry(profile: ResourcesProfile, version: Version, latch: CountUpAndDownLatch): Registries {
val registries = Registries() val registries = Registries()
registries.loadEntities(version)
registries.loadDimensions() val json: MutableJsonObject = synchronizedMapOf()
// val worker = UnconditionalWorker()
for ((type, data) in MinosoftMeta.root) {
// worker += { data.load(type, version) }
json[type] = data.load(type, version) ?: continue
}
// worker.work(latch)
registries.load(version, json, latch)
return registries return registries
} }
@Deprecated("test only")
private fun Registries.loadEntities(version: Version) {
entityType[RemotePlayerEntity] = EntityType(RemotePlayerEntity.identifier, null, 1.0f, 1.0f, false, false, mutableMapOf(), RemotePlayerEntity, null)
}
@Deprecated("test only")
private fun Registries.loadDimensions() {
dimension[0] = Dimension("minecraft:overworld".toResourceLocation(), DimensionProperties())
}
} }

View File

@ -40,7 +40,23 @@ class BlockRegistry(
) : Registry<Block>(parent = parent, codec = PixLyzerBlock, flattened = flattened, metaType = MetaTypes.BLOCK) { ) : Registry<Block>(parent = parent, codec = PixLyzerBlock, flattened = flattened, metaType = MetaTypes.BLOCK) {
fun updateStates(block: Block, data: JsonObject, registries: Registries) { private fun legacy(block: Block, data: JsonObject, registries: Registries) {
val json = data["states"]
val id = data["id"]?.toInt()
val meta = data["meta"]?.toInt()
if (json == null) {
// block has only a single state
val settings = BlockStateSettings.of(registries, data)
val state = if (block is BlockStateBuilder) block.buildState(settings) else AdvancedBlockState(block, settings)
block.updateStates(setOf(state), state, emptyMap())
registries.blockState[id!! shl 4 or (meta ?: 0)] = state
return
}
println("TODO")
}
fun flattened(block: Block, data: JsonObject, registries: Registries) {
val properties: MutableMap<BlockProperties, MutableSet<Any>> = mutableMapOf() val properties: MutableMap<BlockProperties, MutableSet<Any>> = mutableMapOf()
val states: MutableSet<BlockState> = ObjectOpenHashSet() val states: MutableSet<BlockState> = ObjectOpenHashSet()
@ -69,7 +85,11 @@ class BlockRegistry(
val block = factory?.build(registries, BlockSettings.of(registries, data)) ?: this.codec!!.deserialize(registries, resourceLocation, data) ?: return null val block = factory?.build(registries, BlockSettings.of(registries, data)) ?: this.codec!!.deserialize(registries, resourceLocation, data) ?: return null
updateStates(block, data, registries) if (flattened) {
flattened(block, data, registries)
} else {
legacy(block, data, registries)
}
return block return block
} }

View File

@ -37,6 +37,7 @@ import de.bixilon.minosoft.util.KUtil.toResourceLocation
import de.bixilon.minosoft.util.logging.Log import de.bixilon.minosoft.util.logging.Log
import de.bixilon.minosoft.util.logging.LogLevels import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType import de.bixilon.minosoft.util.logging.LogMessageType
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.get
import java.lang.reflect.Modifier import java.lang.reflect.Modifier
import java.util.* import java.util.*
import kotlin.reflect.KProperty1 import kotlin.reflect.KProperty1
@ -68,11 +69,11 @@ data class EntityType(
check(registries != null) { "Registries is null!" } check(registries != null) { "Registries is null!" }
val factory = DefaultEntityFactories[resourceLocation] val factory = DefaultEntityFactories[resourceLocation]
data["meta"]?.toJsonObject()?.let { data["meta", "data"]?.toJsonObject()?.let {
val fields: MutableMap<String, EntityDataField> = mutableMapOf() val fields: MutableMap<String, EntityDataField> = mutableMapOf()
val dataClass = DefaultEntityFactories.ABSTRACT_ENTITY_DATA_CLASSES[resourceLocation]?.companionObject ?: if (factory != null) factory::class else null val dataClass = DefaultEntityFactories.ABSTRACT_ENTITY_DATA_CLASSES[resourceLocation]?.companionObject ?: if (factory != null) factory::class else null
if (dataClass == null) { if (dataClass == null) {
Log.log(LogMessageType.LOADING, LogLevels.VERBOSE) { "Can not find class for entity data ($resourceLocation)" } Log.log(LogMessageType.LOADING, LogLevels.VERBOSE) { "Can not find entity data class for $resourceLocation, fields $it" }
return@let return@let
} }
for (member in dataClass.members) { for (member in dataClass.members) {

View File

@ -13,6 +13,7 @@
package de.bixilon.minosoft.data.registries.registries.registry package de.bixilon.minosoft.data.registries.registries.registry
import de.bixilon.kutil.cast.CastUtil.unsafeCast
import de.bixilon.kutil.exception.Broken import de.bixilon.kutil.exception.Broken
import de.bixilon.kutil.json.JsonObject import de.bixilon.kutil.json.JsonObject
import de.bixilon.minosoft.data.registries.blocks.state.BlockState import de.bixilon.minosoft.data.registries.blocks.state.BlockState
@ -54,14 +55,15 @@ class BlockStateRegistry(var flattened: Boolean) : AbstractRegistry<BlockState?>
idMap[id] = state idMap[id] = state
} }
private fun _get(id: Int): BlockState? {
return idMap[id] ?: parent.unsafeCast<BlockStateRegistry?>()?._get(id)
}
fun forceGet(id: Int): BlockState? { fun forceGet(id: Int): BlockState? {
return idMap[id] ?: parent?.getOrNull(id) ?: let { val state = _get(id)
if (flattened) { if (state != null) return state
null
} else { return _get((id shr 4) shl 4) // Remove meta and try again
idMap[(id shr 4) shl 4] // Remove metadata and test again
}
}
} }
@Deprecated("Use getOrNull", ReplaceWith("getOrNull(id)")) @Deprecated("Use getOrNull", ReplaceWith("getOrNull(id)"))
@ -74,6 +76,7 @@ class BlockStateRegistry(var flattened: Boolean) : AbstractRegistry<BlockState?>
if (id == ProtocolDefinition.AIR_BLOCK_ID) { if (id == ProtocolDefinition.AIR_BLOCK_ID) {
return null return null
} }
if (!flattened && id shr 4 == ProtocolDefinition.AIR_BLOCK_ID) return null
val state = forceGet(id) ?: return null val state = forceGet(id) ?: return null
if (state.block is AirBlock) { if (state.block is AirBlock) {
return null return null

View File

@ -22,6 +22,6 @@ enum class MetaTypes(val bits: Int) {
private val metaMask = (1 shl bits) - 1 private val metaMask = (1 shl bits) - 1
fun modify(id: Int, meta: Int): Int { fun modify(id: Int, meta: Int): Int {
return (id shr bits) or (meta and metaMask) return (id shl bits) or (meta and metaMask)
} }
} }

View File

@ -26,7 +26,6 @@ import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2Util.EMPTY import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2Util.EMPTY
class HotbarAirElement(guiRenderer: GUIRenderer) : Element(guiRenderer), Pollable { class HotbarAirElement(guiRenderer: GUIRenderer) : Element(guiRenderer), Pollable {
private val water = guiRenderer.context.connection.registries.fluid[WaterFluid]!!
private val airBubble = guiRenderer.atlasManager["minecraft:air_bubble"] private val airBubble = guiRenderer.atlasManager["minecraft:air_bubble"]
private val poppingAirBubble = guiRenderer.atlasManager["minecraft:popping_air_bubble"] private val poppingAirBubble = guiRenderer.atlasManager["minecraft:popping_air_bubble"]
@ -65,7 +64,7 @@ class HotbarAirElement(guiRenderer: GUIRenderer) : Element(guiRenderer), Pollabl
var bubbles = 0 var bubbles = 0
var poppingCount = 0 var poppingCount = 0
if (submergedFluid == water || (air in 1 until FULL_AIR)) { if (submergedFluid is WaterFluid || (air in 1 until FULL_AIR)) {
bubbles = ((air - 2) / AIR_PER_BUBBLE.toFloat()).ceil // 2 ticks for the popping "animation" bubbles = ((air - 2) / AIR_PER_BUBBLE.toFloat()).ceil // 2 ticks for the popping "animation"

View File

@ -15,6 +15,7 @@ package de.bixilon.minosoft.gui.rendering.particle
import de.bixilon.kotlinglm.vec3.Vec3d import de.bixilon.kotlinglm.vec3.Vec3d
import de.bixilon.kutil.concurrent.pool.DefaultThreadPool import de.bixilon.kutil.concurrent.pool.DefaultThreadPool
import de.bixilon.minosoft.config.profile.profiles.particle.ParticleProfile
import de.bixilon.minosoft.gui.rendering.particle.types.norender.ExplosionEmitterParticle import de.bixilon.minosoft.gui.rendering.particle.types.norender.ExplosionEmitterParticle
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.explosion.ExplosionParticle import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.explosion.ExplosionParticle
import de.bixilon.minosoft.gui.rendering.util.VecUtil.times import de.bixilon.minosoft.gui.rendering.util.VecUtil.times
@ -22,30 +23,21 @@ import de.bixilon.minosoft.modding.event.events.ExplosionEvent
import de.bixilon.minosoft.modding.event.events.ParticleSpawnEvent import de.bixilon.minosoft.modding.event.events.ParticleSpawnEvent
import de.bixilon.minosoft.modding.event.listener.CallbackEventListener import de.bixilon.minosoft.modding.event.listener.CallbackEventListener
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import java.util.*
object DefaultParticleBehavior { object DefaultParticleBehavior {
fun register(connection: PlayConnection, particleRenderer: ParticleRenderer) { fun register(connection: PlayConnection, renderer: ParticleRenderer) {
val random = java.util.Random() val random = Random()
val explosionParticleType = connection.registries.particleType[ExplosionParticle]!! val profile = connection.profiles.particle
val explosionEmitterParticleType = connection.registries.particleType[ExplosionEmitterParticle]!!
val typesConfig = connection.profiles.particle.types
val invokers = listOf( val invokers = listOf(
CallbackEventListener.of<ExplosionEvent> { connection.explosion(renderer, random, profile),
if (!typesConfig.explosions) {
return@of
}
if (it.power >= 2.0f) {
particleRenderer += ExplosionEmitterParticle(connection, Vec3d(it.position), explosionEmitterParticleType.default())
} else {
particleRenderer += ExplosionParticle(connection, Vec3d(it.position), explosionParticleType.default())
}
},
CallbackEventListener.of<ParticleSpawnEvent> { CallbackEventListener.of<ParticleSpawnEvent> {
DefaultThreadPool += add@{ DefaultThreadPool += add@{
fun spawn(position: Vec3d, velocity: Vec3d) { fun spawn(position: Vec3d, velocity: Vec3d) {
val factory = it.data.type.factory ?: return val factory = it.data.type.factory ?: return
particleRenderer += factory.build(connection, position, velocity, it.data) ?: return renderer += factory.build(connection, position, velocity, it.data) ?: return
} }
// ToDo: long distance = always spawn? // ToDo: long distance = always spawn?
if (it.count == 0) { if (it.count == 0) {
@ -63,7 +55,22 @@ object DefaultParticleBehavior {
} }
}, },
) )
connection.events.register(*invokers.filterNotNull().toTypedArray())
}
connection.events.register(*invokers.toTypedArray()) private fun PlayConnection.explosion(renderer: ParticleRenderer, random: Random, profile: ParticleProfile): CallbackEventListener<*>? {
val explosion = registries.particleType[ExplosionParticle] ?: return null
val emitter = registries.particleType[ExplosionEmitterParticle] ?: return null
return CallbackEventListener.of<ExplosionEvent> {
if (!profile.types.explosions) {
return@of
}
if (it.power >= 2.0f) {
renderer += ExplosionEmitterParticle(this, Vec3d(it.position), emitter.default())
} else {
renderer += ExplosionParticle(this, Vec3d(it.position), explosion.default())
}
}
} }
} }