disable leaves culling, fix some biome bugs, fix block rotation bug, fix uv lock bugs

This commit is contained in:
Bixilon 2021-11-15 22:26:06 +01:00
parent 7344fdda6c
commit 47b620bedc
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
13 changed files with 96 additions and 104 deletions

View File

@ -16,6 +16,7 @@ package de.bixilon.minosoft.data.registries.blocks
import de.bixilon.minosoft.data.registries.blocks.types.*
import de.bixilon.minosoft.data.registries.blocks.types.button.StoneButtonBlock
import de.bixilon.minosoft.data.registries.blocks.types.button.WoodenButtonBlock
import de.bixilon.minosoft.data.registries.blocks.types.leaves.LeavesBlock
import de.bixilon.minosoft.data.registries.blocks.types.portal.NetherPortalBlock
import de.bixilon.minosoft.data.registries.blocks.types.redstone.ComparatorBlock
import de.bixilon.minosoft.data.registries.blocks.types.redstone.RepeaterBlock
@ -41,4 +42,5 @@ object DefaultBlockFactories : DefaultClassFactory<BlockFactory<*>>(
KelpBlock,
StoneButtonBlock,
WoodenButtonBlock,
LeavesBlock,
)

View File

@ -117,6 +117,8 @@ open class Block(
return blockState.outlineShape
}
open fun canCull(blockState: BlockState, other: BlockState): Boolean = true
companion object : ResourceLocationDeserializer<Block>, BlockFactory<Block> {
override fun deserialize(registries: Registries?, resourceLocation: ResourceLocation, data: Map<String, Any>): Block {
check(registries != null) { "Registries is null!" }

View File

@ -0,0 +1,37 @@
/*
* 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.registries.blocks.types.leaves
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.blocks.BlockFactory
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.registries.blocks.types.Block
import de.bixilon.minosoft.data.registries.registries.Registries
open class LeavesBlock(resourceLocation: ResourceLocation, registries: Registries, data: Map<String, Any>) : Block(resourceLocation, registries, data) {
override fun canCull(blockState: BlockState, other: BlockState): Boolean {
if (other.block is LeavesBlock) {
return false
}
return true
}
companion object : BlockFactory<LeavesBlock> {
override fun build(resourceLocation: ResourceLocation, registries: Registries, data: Map<String, Any>): LeavesBlock {
return LeavesBlock(resourceLocation, registries, data)
}
}
}

View File

@ -18,13 +18,12 @@ import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.world.ChunkSection.Companion.index
import de.bixilon.minosoft.data.world.biome.accessor.BiomeAccessor
import de.bixilon.minosoft.data.world.biome.source.BiomeSource
import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkSectionPosition
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inSectionHeight
import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight
import de.bixilon.minosoft.modding.event.EventInitiators
import de.bixilon.minosoft.modding.event.events.ChunkDataChangeEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.KUtil.unsafeCast
import glm_.vec2.Vec2i
import glm_.vec3.Vec3i
@ -59,15 +58,15 @@ class Chunk(
operator fun get(sectionHeight: Int): ChunkSection? = sections?.getOrNull(sectionHeight - lowestSection)
fun get(x: Int, y: Int, z: Int): BlockState? {
return this[y.sectionHeight]?.blocks?.get(x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z)
return this[y.sectionHeight]?.blocks?.get(x, y.inSectionHeight, z)
}
operator fun get(position: Vec3i): BlockState? = get(position.x, position.y, position.z)
fun set(x: Int, y: Int, z: Int, blockState: BlockState?, blockEntity: BlockEntity? = null) {
val section = getOrPut(y.sectionHeight)
section.blocks[x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z] = blockState
section.blockEntities[x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z] = blockEntity // ToDo
section.blocks[x, y.inSectionHeight, z] = blockState
section.blockEntities[x, y.inSectionHeight, z] = blockEntity // ToDo
}
operator fun set(position: Vec3i, blockState: BlockState?) = set(position.x, position.y, position.z, blockState)
@ -79,13 +78,13 @@ class Chunk(
}
fun getBlockEntity(x: Int, y: Int, z: Int): BlockEntity? {
return this[y.sectionHeight]?.blockEntities?.get(x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z)
return this[y.sectionHeight]?.blockEntities?.get(x, y.inSectionHeight, z)
}
fun getBlockEntity(position: Vec3i): BlockEntity? = getBlockEntity(position.x, position.y, position.z)
fun setBlockEntity(x: Int, y: Int, z: Int, blockEntity: BlockEntity?) {
getOrPut(y.sectionHeight).blockEntities[x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z] = blockEntity
getOrPut(y.sectionHeight).blockEntities[x, y.inSectionHeight, z] = blockEntity
}
fun setBlockEntity(position: Vec3i, blockEntity: BlockEntity?) = setBlockEntity(position.x, position.y, position.z, blockEntity)
@ -206,14 +205,8 @@ class Chunk(
override fun getBiome(x: Int, y: Int, z: Int): Biome? {
if (cacheBiomes) {
val sectionHeight = y.sectionHeight
val section = this[sectionHeight]
if (section == null) {
// ToDo: Faster
val chunkPosition = Vec3i(x, y, z).chunkPosition
return connection.world.cacheBiomeAccessor?.getBiome(x, y, z, chunkPosition.x, chunkPosition.y, this, null)
}
return section.biomes[x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z]
val section = this[y.sectionHeight] ?: return connection.world.cacheBiomeAccessor?.getBiome((chunkPosition.x shl 4) or x, y, (chunkPosition.y shl 4) or z, chunkPosition.x, chunkPosition.y, this, null)
return section.biomes[x, y.inSectionHeight, z]
}
return biomeSource?.getBiome(x and 0x0F, y, z and 0x0F)
}

View File

@ -23,7 +23,6 @@ import de.bixilon.minosoft.data.registries.dimension.DimensionProperties
import de.bixilon.minosoft.data.registries.sounds.SoundEvent
import de.bixilon.minosoft.data.world.biome.accessor.BiomeAccessor
import de.bixilon.minosoft.data.world.biome.accessor.NoiseBiomeAccessor
import de.bixilon.minosoft.data.world.biome.accessor.WorldBiomeAccessor
import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer
import de.bixilon.minosoft.gui.rendering.particle.types.Particle
import de.bixilon.minosoft.gui.rendering.sound.AudioPlayer
@ -67,7 +66,6 @@ class World(
var difficulty: Difficulties? = null
var difficultyLocked = false
var hashedSeed = 0L
val biomeAccessor: BiomeAccessor = WorldBiomeAccessor(this)
var time = 0L
var age = 0L
var raining = false
@ -151,11 +149,11 @@ class World(
}
override fun getBiome(blockPosition: Vec3i): Biome? {
return biomeAccessor.getBiome(blockPosition)
return this[blockPosition.chunkPosition]?.getBiome(blockPosition.inChunkPosition)
}
override fun getBiome(x: Int, y: Int, z: Int): Biome? {
return biomeAccessor.getBiome(x, y, z)
return this[Vec2i(x shr 4, z shr 4)]?.getBiome(x and 0x0F, y, z and 0x0F)
}
fun tick() {

View File

@ -1,31 +0,0 @@
/*
* 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.world.biome.accessor
import de.bixilon.minosoft.data.registries.biomes.Biome
import de.bixilon.minosoft.data.world.World
import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkPosition
import glm_.vec3.Vec3i
class WorldBiomeAccessor(val world: World) : BiomeAccessor {
override fun getBiome(x: Int, y: Int, z: Int): Biome? {
return getBiome(Vec3i(x, y, z)) // ToDo
}
override fun getBiome(blockPosition: Vec3i): Biome? {
return world[blockPosition.chunkPosition]?.getBiome(blockPosition.inChunkPosition)
}
}

View File

@ -62,9 +62,6 @@ class Camera(
var fogStart = Minosoft.config.config.game.camera.viewDistance * ProtocolDefinition.SECTION_WIDTH_X.toFloat() // ToDo
private var mouseSensitivity = Minosoft.config.config.game.controls.moseSensitivity
@Deprecated("", ReplaceWith("connection.player"))
val entity: LocalPlayerEntity
get() = connection.player
private var lastMousePosition: Vec2d = Vec2d(0.0, 0.0)
private var zoom = 0.0f
@ -288,7 +285,7 @@ class Camera(
}
private fun setSkyColor() {
renderWindow[SkyRenderer.Companion]?.let { skyRenderer ->
renderWindow[SkyRenderer]?.let { skyRenderer ->
skyRenderer.baseColor = connection.world.getBiome(connection.player.positionInfo.blockPosition)?.skyColor ?: RenderConstants.DEFAULT_SKY_COLOR

View File

@ -4,7 +4,7 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparenci
object CullUtil {
fun Array<FaceProperties>.canCull(properties: FaceProperties, sameBlock: Boolean): Boolean {
fun Array<FaceProperties>.canCull(properties: FaceProperties, blockCull: Boolean): Boolean {
val sizeStartX = properties.sizeStart.x
val sizeStartY = properties.sizeStart.y
val sizeEndX = properties.sizeEnd.x
@ -16,7 +16,7 @@ object CullUtil {
&& property.sizeEnd.x >= sizeEndX
&& property.sizeEnd.y >= sizeEndY
&& !((properties.transparency == TextureTransparencies.OPAQUE && property.transparency != TextureTransparencies.OPAQUE)
|| (properties.transparency != TextureTransparencies.OPAQUE && property.transparency == properties.transparency && !sameBlock)
|| (properties.transparency != TextureTransparencies.OPAQUE && property.transparency == properties.transparency && !blockCull)
|| (properties.transparency == TextureTransparencies.TRANSPARENT && property.transparency == TextureTransparencies.TRANSLUCENT))
) {
return true

View File

@ -53,7 +53,7 @@ class BakedBlockStateModel(
neighbourProperties = neighboursModel.getTouchingFaceProperties(random, direction.inverted)
}
for (face in faces) {
if (face.touching && neighbourProperties != null && neighbourProperties.isNotEmpty() && neighbourProperties.canCull(face, blockState == neighbour)) {
if (face.touching && neighbourProperties != null && neighbourProperties.isNotEmpty() && neighbourProperties.canCull(face, neighbour != null && blockState.block.canCull(blockState, neighbour))) {
continue
}
face.singleRender(positionArray, mesh, light, ambientLight)

View File

@ -22,22 +22,22 @@ import de.bixilon.minosoft.util.KUtil.unsafeCast
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.compoundCast
class MultipartRootModel(
private val conditions: MutableMap<MutableSet<Set<Map<BlockProperties, Any>>>, Set<UnbakedBlockStateModel>>,
private val conditions: MutableMap<MutableSet<Map<BlockProperties, Set<Any>>>, MutableSet<UnbakedBlockStateModel>>,
) : RootModel {
private fun Set<Map<BlockProperties, Any>>.matches(blockState: BlockState): Boolean {
var matches = false
private fun Map<BlockProperties, Set<Any>>.matches(blockState: BlockState): Boolean {
var matches = true
for (propertyMap in this) {
for ((property, values) in this) {
var singleMatches = false
for ((property, value) in propertyMap) {
for (value in values) {
if (blockState.properties[property] == value) {
singleMatches = true
break
}
}
if (singleMatches) {
matches = true
if (!singleMatches) {
matches = false
break
}
}
@ -45,13 +45,15 @@ class MultipartRootModel(
return matches
}
private fun MutableSet<Set<Map<BlockProperties, Any>>>.matchesAny(blockState: BlockState): Boolean {
private fun Set<Map<BlockProperties, Set<Any>>>.matchesAny(blockState: BlockState): Boolean {
var matches = true
for (or in this) {
if (!or.matches(blockState)) {
matches = false
break
continue
}
matches = true
break
}
return matches
}
@ -70,26 +72,31 @@ class MultipartRootModel(
companion object {
private fun getCondition(data: MutableMap<String, Any>): MutableSet<Map<BlockProperties, Any>> {
val singleCondition: MutableSet<Map<BlockProperties, Any>> = mutableSetOf()
private fun getCondition(data: MutableMap<String, Any>): MutableMap<BlockProperties, Set<Any>> {
val condition: MutableMap<BlockProperties, Set<Any>> = mutableMapOf()
for ((propertyName, value) in data) {
val properties: MutableMap<BlockProperties, Any> = mutableMapOf()
var property: BlockProperties? = null
val values: MutableSet<Any> = mutableSetOf()
for (propertyValue in value.toString().split("|")) {
properties += BlockProperties.parseProperty(propertyName, propertyValue)
val (parsedProperty, parsedValue) = BlockProperties.parseProperty(propertyName, propertyValue)
if (property == null) {
property = parsedProperty
}
values += parsedValue
}
singleCondition += properties
condition[property!!] = values
}
return singleCondition
return condition
}
operator fun invoke(models: Map<ResourceLocation, GenericUnbakedModel>, data: List<Any>): MultipartRootModel {
val conditions: MutableMap<MutableSet<Set<Map<BlockProperties, Any>>>, Set<UnbakedBlockStateModel>> = mutableMapOf()
val conditions: MutableMap<MutableSet<Map<BlockProperties, Set<Any>>>, MutableSet<UnbakedBlockStateModel>> = mutableMapOf()
for (modelData in data) {
check(modelData is Map<*, *>)
val condition: MutableSet<Set<Map<BlockProperties, Any>>> = mutableSetOf()
val condition: MutableSet<Map<BlockProperties, Set<Any>>> = mutableSetOf()
val applyData = modelData["apply"]!!
val apply: MutableSet<UnbakedBlockStateModel> = mutableSetOf()
if (applyData is Map<*, *>) {
@ -113,7 +120,7 @@ class MultipartRootModel(
conditions[condition] = apply
conditions.getOrPut(condition) { mutableSetOf() } += apply
}
return MultipartRootModel(conditions)

View File

@ -87,7 +87,6 @@ data class UnbakedBlockStateModel(
val touchingFaceProperties: Array<MutableList<FaceProperties>> = Array(Directions.SIZE) { mutableListOf() }
for (element in model.elements) {
val rescale = element.rotation?.rescale ?: false
for (face in element.faces) {
val texture = resolvedTextures[face.texture.removePrefix("#")]!! // ToDo: Allow direct texture names?
val positions = face.direction.getPositions(element.from, element.to)
@ -119,13 +118,14 @@ data class UnbakedBlockStateModel(
texturePositions = texturePositions.rotateLeft((face.rotation % 360) / 90).toTypedArray()
}
if (this.uvLock && this.rotation != null && face.direction.axis != Axes.Z) {
var rad = this.rotation[face.direction.axis].rad
if (direction.negative) {
rad = -rad
if (this.uvLock && this.rotation != null) {
val axis = when (face.direction) {
Directions.UP, Directions.DOWN -> Axes.Y
else -> Axes.X
}
val rad = this.rotation[axis].rad
for ((index, position) in texturePositions.withIndex()) {
texturePositions[index] = (Vec3(position.x - 0.5f, 0.0f, position.y - 0.5f).apply { rotateAssign(rad, direction.axis) }).xz + 0.5f
texturePositions[index] = (Vec3(position.x - 0.5f, 0.0f, position.y - 0.5f).apply { rotateAssign(rad, axis) }).xz + 0.5f
}
}

View File

@ -141,37 +141,24 @@ object VecUtil {
return this * cos + (axis cross this) * sin + axis * (axis dot this) * (1 - cos)
}
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))
get() = Vec2i(x shr 4, z shr 4)
val Vec3i.inChunkPosition: Vec3i
get() = Vec3i(x and 0x0F, y, this.z and 0x0F)
val Vec3i.inChunkSectionPosition: Vec3i
get() {
val inVec2i = inChunkPosition
val y = if (y < 0) {
((ProtocolDefinition.SECTION_HEIGHT_Y + (y % ProtocolDefinition.SECTION_HEIGHT_Y))) % ProtocolDefinition.SECTION_HEIGHT_Y
} else {
y % ProtocolDefinition.SECTION_HEIGHT_Y
}
return Vec3i(inVec2i.x, y, inVec2i.z)
get() = Vec3i(x and 0x0F, y.inSectionHeight, z and 0x0F)
val Int.inSectionHeight: Int
get() = if (this < 0) {
((ProtocolDefinition.SECTION_HEIGHT_Y + (this % ProtocolDefinition.SECTION_HEIGHT_Y))) % ProtocolDefinition.SECTION_HEIGHT_Y
} else {
this % ProtocolDefinition.SECTION_HEIGHT_Y
}
val Int.sectionHeight: Int
get() = if (this < 0) {
(this + 1) / ProtocolDefinition.SECTION_HEIGHT_Y - 1
} else {
this / ProtocolDefinition.SECTION_HEIGHT_Y
}
get() = this shr 4
val Vec3i.sectionHeight: Int
get() = y.sectionHeight

View File

@ -67,8 +67,8 @@ object Vec3Util {
this -= 0.5f
}
rotateAssign(-rotation.x, Axes.X)
rotateAssign(rotation.y, Axes.Y)
rotateAssign(rotation.x, Axes.X)
if (centerBlock) {
this += 0.5f