diff --git a/ReadMe.md b/ReadMe.md index ccb7cf9c8..e43bffda8 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -134,7 +134,7 @@ Not compatible (yet) 1. Install Maven and java 11+ (On Ubuntu based distributions: `sudo apt install maven openjdk-11-jdk`). For Windows users, download and install java from oracle or openjdk. Also download maven and follow along 2. Clone this repository (`git clone https://gitlab.bixilon.de/bixilon/minosoft.git`) 3. Change directory (`cd minosoft`) -4. Optional: Checkout the branch of the feature you want to test (`git checkout `) +4. Optional: Checkout a current feature branch (Warning: might be unstable; might not even build) (`git checkout `) 5. Build and run Minosoft with `mvn clean verify exec:java`. If any errors occur, feel free to open an issue. In this early stage it might be helpful to delete the config file 6. (Optional) Build a fat jar with `mvn package`. You'll find the jar with all dependencies in `target/`. Then you don't need to recompile everytime diff --git a/src/main/java/de/bixilon/minosoft/data/direction/AbstractDirection.kt b/src/main/java/de/bixilon/minosoft/data/direction/AbstractDirection.kt deleted file mode 100644 index 2ee6c8204..000000000 --- a/src/main/java/de/bixilon/minosoft/data/direction/AbstractDirection.kt +++ /dev/null @@ -1,24 +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 . - * - * This software is not affiliated with Mojang AB, the original developer of Minecraft. - */ - -package de.bixilon.minosoft.data.direction - -import glm_.vec3.Vec3 -import glm_.vec3.Vec3d -import glm_.vec3.Vec3i - -interface AbstractDirection { - val vector: Vec3i - val vectorf: Vec3 - val vectord: Vec3d -} diff --git a/src/main/java/de/bixilon/minosoft/data/direction/Directions.kt b/src/main/java/de/bixilon/minosoft/data/direction/Directions.kt index ff8279a7b..c97566d47 100644 --- a/src/main/java/de/bixilon/minosoft/data/direction/Directions.kt +++ b/src/main/java/de/bixilon/minosoft/data/direction/Directions.kt @@ -27,8 +27,8 @@ import kotlin.math.abs enum class Directions( val horizontalId: Int, - override val vector: Vec3i, -) : AbstractDirection { + val vector: Vec3i, +) { DOWN(-1, Vec3i(0, -1, 0)), UP(-1, Vec3i(0, 1, 0)), NORTH(2, Vec3i(0, 0, -1)), @@ -38,8 +38,8 @@ enum class Directions( val negative = ordinal % 2 == 0 - override val vectorf = Vec3(vector) - override val vectord = Vec3d(vector) + val vectorf = Vec3(vector) + val vectord = Vec3d(vector) val axis: Axes get() = Axes[this] // ToDo val debugColor = ChatColors[ordinal] diff --git a/src/main/java/de/bixilon/minosoft/data/direction/FakeDirection.kt b/src/main/java/de/bixilon/minosoft/data/direction/FakeDirection.kt deleted file mode 100644 index 5bb6a2f3d..000000000 --- a/src/main/java/de/bixilon/minosoft/data/direction/FakeDirection.kt +++ /dev/null @@ -1,33 +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 . - * - * This software is not affiliated with Mojang AB, the original developer of Minecraft. - */ - -package de.bixilon.minosoft.data.direction - -import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus -import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3 -import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3d -import glm_.vec3.Vec3 -import glm_.vec3.Vec3d -import glm_.vec3.Vec3i - -class FakeDirection(override val vector: Vec3i) : AbstractDirection { - override val vectorf: Vec3 = vector.toVec3 - override val vectord: Vec3d = vector.toVec3d - - companion object { - val NORTH_WEST = FakeDirection(Directions.NORTH + Directions.WEST) - val NORTH_EAST = FakeDirection(Directions.NORTH + Directions.EAST) - val SOUTH_WEST = FakeDirection(Directions.SOUTH + Directions.WEST) - val SOUTH_EAST = FakeDirection(Directions.SOUTH + Directions.EAST) - } -} diff --git a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/KelpBlock.kt b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/KelpBlock.kt index 1f7c2bbb0..e518286e2 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/KelpBlock.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/KelpBlock.kt @@ -16,10 +16,11 @@ package de.bixilon.minosoft.data.registries.blocks.types import de.bixilon.minosoft.data.registries.ResourceLocation import de.bixilon.minosoft.data.registries.blocks.BlockFactory import de.bixilon.minosoft.data.registries.fluid.DefaultFluids +import de.bixilon.minosoft.data.registries.fluid.Fluid import de.bixilon.minosoft.data.registries.registries.Registries open class KelpBlock(resourceLocation: ResourceLocation, registries: Registries, data: Map) : Block(resourceLocation, registries, data), FluidFillable { - override val fluid: ResourceLocation = DefaultFluids.WATER + override val fluid: Fluid = registries.fluidRegistry[DefaultFluids.WATER]!! companion object : BlockFactory { diff --git a/src/main/java/de/bixilon/minosoft/data/registries/fluid/FlowableFluid.kt b/src/main/java/de/bixilon/minosoft/data/registries/fluid/FlowableFluid.kt index 64fbe2f5a..63ed9a1e5 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/fluid/FlowableFluid.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/fluid/FlowableFluid.kt @@ -15,8 +15,8 @@ package de.bixilon.minosoft.data.registries.fluid import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.data.registries.ResourceLocation import de.bixilon.minosoft.data.registries.blocks.BlockState -import de.bixilon.minosoft.data.registries.blocks.types.FluidBlock import de.bixilon.minosoft.data.registries.registries.Registries +import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection @@ -28,30 +28,26 @@ abstract class FlowableFluid( registries: Registries, data: Map, ) : Fluid(resourceLocation, registries, data) { - open val flowingTexture: ResourceLocation? = null + abstract val flowingTextureName: ResourceLocation + var flowingTexture: AbstractTexture? = null abstract fun getVelocityMultiplier(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i): Double open fun getVelocity(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i): Vec3d { - if (blockState.block !is FluidBlock || !blockState.block.fluid.matches(this)) { + if (!this.matches(blockState)) { return Vec3d.EMPTY } val fluidHeight = getHeight(blockState) val velocity = Vec3d.EMPTY - for (direction in Directions.SIDES) { val neighbourBlockState = connection.world[blockPosition + direction] ?: continue - if (neighbourBlockState.block !is FluidBlock) { + if (!this.matches(neighbourBlockState)) { continue } - val fluid = neighbourBlockState.block.fluid - if (!matches(fluid)) { - continue - } - val height = neighbourBlockState.block.fluid.getHeight(neighbourBlockState) + val height = getHeight(neighbourBlockState) var heightDifference = 0.0f @@ -64,11 +60,14 @@ abstract class FlowableFluid( if (heightDifference != 0.0f) { velocity += (direction.vectord * heightDifference) } - } // ToDo: Falling fluid + if (velocity.x == 0.0 && velocity.y == 0.0 && velocity.z == 0.0) { + return velocity + } + return velocity.normalize() } } diff --git a/src/main/java/de/bixilon/minosoft/data/registries/fluid/Fluid.kt b/src/main/java/de/bixilon/minosoft/data/registries/fluid/Fluid.kt index 0a64c1286..c9d93816e 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/fluid/Fluid.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/fluid/Fluid.kt @@ -23,6 +23,8 @@ import de.bixilon.minosoft.data.registries.particle.ParticleType import de.bixilon.minosoft.data.registries.registries.Registries import de.bixilon.minosoft.data.registries.registries.registry.RegistryItem import de.bixilon.minosoft.data.registries.registries.registry.ResourceLocationDeserializer +import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture +import de.bixilon.minosoft.gui.rendering.tint.TintProvider import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.util.KUtil.nullCast import de.bixilon.minosoft.util.KUtil.unsafeCast @@ -36,7 +38,9 @@ open class Fluid( registries: Registries, data: Map, ) : RegistryItem() { - open val stillTexture: ResourceLocation? = null + open val tintProvider: TintProvider? = null + open val stillTextureName: ResourceLocation? = null + var stillTexture: AbstractTexture? = null val dripParticle: ParticleType? = null val bucketItem: Item? = null diff --git a/src/main/java/de/bixilon/minosoft/data/registries/fluid/lava/LavaFluid.kt b/src/main/java/de/bixilon/minosoft/data/registries/fluid/lava/LavaFluid.kt index 8d8baa496..6b9f6e77a 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/fluid/lava/LavaFluid.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/fluid/lava/LavaFluid.kt @@ -42,8 +42,8 @@ class LavaFluid( data: Map, ) : FlowableFluid(resourceLocation, registries, data) { private val lavaParticleType: ParticleType? = null - override val stillTexture: ResourceLocation = "minecraft:block/lava_still".toResourceLocation() - override val flowingTexture: ResourceLocation = "minecraft:block/lava_flow".toResourceLocation() + override val stillTextureName: ResourceLocation = "minecraft:block/lava_still".toResourceLocation() + override val flowingTextureName: ResourceLocation = "minecraft:block/lava_flow".toResourceLocation() init { this::lavaParticleType.inject(LavaParticle) diff --git a/src/main/java/de/bixilon/minosoft/data/registries/fluid/water/WaterFluid.kt b/src/main/java/de/bixilon/minosoft/data/registries/fluid/water/WaterFluid.kt index 68c54be5b..d69525344 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/fluid/water/WaterFluid.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/fluid/water/WaterFluid.kt @@ -28,6 +28,8 @@ import de.bixilon.minosoft.data.registries.fluid.Fluid import de.bixilon.minosoft.data.registries.fluid.FluidFactory import de.bixilon.minosoft.data.registries.registries.Registries import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.water.UnderwaterParticle +import de.bixilon.minosoft.gui.rendering.tint.TintProvider +import de.bixilon.minosoft.gui.rendering.tint.WaterTintProvider import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3d import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection @@ -46,8 +48,9 @@ class WaterFluid( ) : FlowableFluid(resourceLocation, registries, data) { private val depthStriderEnchantment: Enchantment? = null private val dolphinsGraceStatusEffect: StatusEffect? = null - override val stillTexture: ResourceLocation = "minecraft:block/water_still".toResourceLocation() - override val flowingTexture: ResourceLocation = "minecraft:block/water_flow".toResourceLocation() + override val stillTextureName: ResourceLocation = "minecraft:block/water_still".toResourceLocation() + override val flowingTextureName: ResourceLocation = "minecraft:block/water_flow".toResourceLocation() + override val tintProvider: TintProvider = WaterTintProvider init { diff --git a/src/main/java/de/bixilon/minosoft/data/registries/registries/registry/Registry.kt b/src/main/java/de/bixilon/minosoft/data/registries/registries/registry/Registry.kt index b38988b5d..8e6d00df3 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/registries/registry/Registry.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/registries/registry/Registry.kt @@ -171,6 +171,7 @@ open class Registry( this.valueIdMap.putAll(valueIdMap) } + @Deprecated("Too slow, should be used with a ToDo: RegistryIterator") fun forEachItem(lambda: (T) -> Unit) { for (item in resourceLocationMap.values) { lambda(item) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedFace.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedFace.kt index 68f3b655b..09947dfa4 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedFace.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/baked/block/BakedFace.kt @@ -19,6 +19,7 @@ import de.bixilon.minosoft.data.text.RGBColor import de.bixilon.minosoft.gui.rendering.models.FaceProperties import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture +import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.getMesh import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.get import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rgb import de.bixilon.minosoft.gui.rendering.world.mesh.SingleWorldMesh @@ -41,11 +42,7 @@ class BakedFace( get() = texture.transparency // ToDo fun singleRender(position: FloatArray, mesh: WorldMesh, light: Int, ambientLight: FloatArray, tint: Int) { - val meshToUse = when (texture.transparency) { - TextureTransparencies.OPAQUE -> mesh.opaqueMesh - TextureTransparencies.TRANSLUCENT -> mesh.translucentMesh - TextureTransparencies.TRANSPARENT -> mesh.transparentMesh - }!! + val meshToUse = transparency.getMesh(mesh) // ToDo: Ambient light val color = Vec3(shade) if (tint >= 0) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/textures/TextureUtil.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/textures/TextureUtil.kt index 3748e5813..2eff5c365 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/textures/TextureUtil.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/textures/TextureUtil.kt @@ -14,6 +14,9 @@ package de.bixilon.minosoft.gui.rendering.textures import de.bixilon.minosoft.data.registries.ResourceLocation +import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies +import de.bixilon.minosoft.gui.rendering.world.mesh.SingleWorldMesh +import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh import de.bixilon.minosoft.util.KUtil.toResourceLocation object TextureUtil { @@ -32,4 +35,12 @@ object TextureUtil { return "$namespace:$path".toResourceLocation() } + + fun TextureTransparencies.getMesh(mesh: WorldMesh): SingleWorldMesh { + return when (this) { + TextureTransparencies.OPAQUE -> mesh.opaqueMesh + TextureTransparencies.TRANSLUCENT -> mesh.translucentMesh + TextureTransparencies.TRANSPARENT -> mesh.transparentMesh + }!! + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/tint/TintManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/tint/TintManager.kt index d8029a9de..584c84017 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/tint/TintManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/tint/TintManager.kt @@ -20,6 +20,7 @@ import de.bixilon.minosoft.data.registries.blocks.BlockState import de.bixilon.minosoft.data.registries.blocks.MinecraftBlocks import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties import de.bixilon.minosoft.data.registries.blocks.properties.Halves +import de.bixilon.minosoft.data.registries.fluid.Fluid import de.bixilon.minosoft.data.text.RGBColor import de.bixilon.minosoft.data.text.RGBColor.Companion.asRGBColor import de.bixilon.minosoft.data.world.Chunk @@ -43,8 +44,7 @@ class TintManager(private val connection: PlayConnection) { } } - fun getAverageTint(chunk: Chunk, neighbours: Array, blockState: BlockState, x: Int, y: Int, z: Int): IntArray? { - val tintProvider = blockState.block.tintProvider ?: return null + private fun getAverageTint(chunk: Chunk, neighbours: Array, blockState: BlockState, tintProvider: TintProvider, x: Int, y: Int, z: Int): IntArray? { val inChunkX = x and 0x0F val inChunkZ = z and 0x0F val biome = chunk.getBiome(inChunkX, y, inChunkZ) @@ -56,6 +56,14 @@ class TintManager(private val connection: PlayConnection) { return tints } + fun getAverageTint(chunk: Chunk, neighbours: Array, blockState: BlockState, x: Int, y: Int, z: Int): IntArray? { + return getAverageTint(chunk, neighbours, blockState, blockState.block.tintProvider ?: return null, x, y, z) + } + + fun getAverageTint(chunk: Chunk, neighbours: Array, blockState: BlockState, fluid: Fluid, x: Int, y: Int, z: Int): IntArray? { + return getAverageTint(chunk, neighbours, blockState, fluid.tintProvider ?: return null, x, y, z) + } + fun getTint(blockState: BlockState, biome: Biome?, x: Int, y: Int, z: Int): IntArray? { val tintProvider = blockState.block.tintProvider ?: return null connection.world.getBiome(x, y, z) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt index d94848389..7e732cf0c 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt @@ -15,7 +15,6 @@ package de.bixilon.minosoft.gui.rendering.util import de.bixilon.minosoft.Minosoft import de.bixilon.minosoft.data.Axes -import de.bixilon.minosoft.data.direction.AbstractDirection import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.data.registries.AABB import de.bixilon.minosoft.data.registries.blocks.RandomOffsetTypes @@ -208,7 +207,7 @@ object VecUtil { return Vec3i((x + vec2.x), y, (z + vec2.y)) } - infix operator fun Vec3i.plus(direction: AbstractDirection?): Vec3i { + infix operator fun Vec3i.plus(direction: Directions?): Vec3i { return this + direction?.vector } @@ -220,7 +219,7 @@ object VecUtil { return Vec2i(x + vec3.x, y + vec3.z) } - infix operator fun Vec2i.plus(direction: AbstractDirection): Vec2i { + infix operator fun Vec2i.plus(direction: Directions): Vec2i { return this + direction.vector } @@ -409,7 +408,7 @@ object VecUtil { } } - operator fun AbstractDirection.plus(direction: AbstractDirection): Vec3i { + operator fun Directions.plus(direction: Directions): Vec3i { return this.vector + direction.vector } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3Util.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3Util.kt index c9ae62fad..71b301470 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3Util.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3Util.kt @@ -42,7 +42,7 @@ object Vec3Util { val Vec3.rgb: Int get() = ((r * RGBColor.COLOR_FLOAT_DIVIDER).toInt() shl 16) or ((g * RGBColor.COLOR_FLOAT_DIVIDER).toInt() shl 8) or (b * RGBColor.COLOR_FLOAT_DIVIDER).toInt() - fun rotateAssign(x: Float, y: Float, sin: Float, cos: Float, rescale: Boolean): Vec2 { + fun rotate(x: Float, y: Float, sin: Float, cos: Float, rescale: Boolean): Vec2 { val result = Vec2(x * cos - y * sin, x * sin + y * cos) if (rescale) { return result / cos @@ -56,9 +56,9 @@ object Vec3Util { return } when (axis) { - Axes.X -> this.yz = rotateAssign(this.y, this.z, angle.sin, angle.cos, rescale) - Axes.Y -> this.xz = rotateAssign(this.x, this.z, angle.sin, angle.cos, rescale) - Axes.Z -> this.xy = rotateAssign(this.x, this.y, angle.sin, angle.cos, rescale) + Axes.X -> this.yz = rotate(this.y, this.z, angle.sin, angle.cos, rescale) + Axes.Y -> this.xz = rotate(this.x, this.z, angle.sin, angle.cos, rescale) + Axes.Z -> this.xy = rotate(this.x, this.y, angle.sin, angle.cos, rescale) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt index 98ce3c74f..a31f29f92 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt @@ -20,6 +20,7 @@ import de.bixilon.minosoft.data.assets.AssetsUtil import de.bixilon.minosoft.data.assets.Resources import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.data.registries.ResourceLocation +import de.bixilon.minosoft.data.registries.fluid.FlowableFluid import de.bixilon.minosoft.data.world.Chunk import de.bixilon.minosoft.data.world.ChunkSection import de.bixilon.minosoft.data.world.World @@ -35,6 +36,7 @@ import de.bixilon.minosoft.gui.rendering.system.base.RenderingCapabilities import de.bixilon.minosoft.gui.rendering.system.base.phases.OpaqueDrawable import de.bixilon.minosoft.gui.rendering.system.base.phases.TranslucentDrawable import de.bixilon.minosoft.gui.rendering.system.base.phases.TransparentDrawable +import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition import de.bixilon.minosoft.gui.rendering.util.VecUtil.empty import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkSectionPosition @@ -131,6 +133,13 @@ class WorldRenderer( val zip = ZipInputStream(GZIPInputStream(FileInputStream(AssetsUtil.getAssetDiskPath(asset.clientJarHash!!, true)))) val modelLoader = ModelLoader(zip, renderWindow) modelLoader.load() + + connection.registries.fluidRegistry.forEachItem { + if (it is FlowableFluid) { + it.flowingTexture = renderWindow.textureManager.staticTextures.createTexture(it.flowingTextureName.texture()) + } + it.stillTexture = it.stillTextureName?.let { texture -> renderWindow.textureManager.staticTextures.createTexture(texture.texture()) } + } } override fun postInit() { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/FluidCullSectionPreparer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/FluidCullSectionPreparer.kt index 1656b9693..c934235d7 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/FluidCullSectionPreparer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/preparer/cull/FluidCullSectionPreparer.kt @@ -1,31 +1,45 @@ package de.bixilon.minosoft.gui.rendering.world.preparer.cull +import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.data.registries.blocks.BlockState import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties import de.bixilon.minosoft.data.registries.blocks.types.FluidBlock import de.bixilon.minosoft.data.registries.blocks.types.FluidFillable import de.bixilon.minosoft.data.registries.fluid.DefaultFluids +import de.bixilon.minosoft.data.registries.fluid.FlowableFluid +import de.bixilon.minosoft.data.registries.fluid.Fluid import de.bixilon.minosoft.data.world.Chunk import de.bixilon.minosoft.data.world.ChunkSection +import de.bixilon.minosoft.data.world.World import de.bixilon.minosoft.gui.rendering.RenderWindow +import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture +import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.getMesh +import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus +import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2Util.EMPTY +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rotate +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.toVec3 import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh import de.bixilon.minosoft.gui.rendering.world.preparer.FluidSectionPreparer import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.util.chunk.ChunkUtil.acquire import de.bixilon.minosoft.util.chunk.ChunkUtil.release -import de.bixilon.minosoft.util.logging.Log -import de.bixilon.minosoft.util.logging.LogLevels -import de.bixilon.minosoft.util.logging.LogMessageType +import glm_.func.cos +import glm_.func.sin +import glm_.vec2.Vec2 import glm_.vec2.Vec2i +import glm_.vec3.Vec3 import glm_.vec3.Vec3i +import kotlin.math.atan2 class FluidCullSectionPreparer( val renderWindow: RenderWindow, ) : FluidSectionPreparer { + private val world: World = renderWindow.connection.world private val water = renderWindow.connection.registries.fluidRegistry[DefaultFluids.WATER] - private val tintColorCalculator = renderWindow.tintManager + private val tintManager = renderWindow.tintManager + // ToDo: Should this be combined with the solid renderer (but we'd need to render faces twice, because of cullface) override fun prepareFluid(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, section: ChunkSection, neighbours: Array, neighbourChunks: Array): WorldMesh? { val mesh = WorldMesh(renderWindow, chunkPosition, sectionHeight, smallMesh = true) @@ -56,7 +70,147 @@ class FluidCullSectionPreparer( block is FluidFillable -> block.fluid else -> continue } - Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Can not render fluid: $fluid" } + position = Vec3i(offsetX + x, offsetY + y, offsetZ + z) + tints = tintManager.getAverageTint(chunk, neighbourChunks, blockState, fluid, position.x, position.y, position.z) + + val skipTop = fluid.matches(chunk.get(x, offsetY + y + 1, z)) + val skipBottom = !shouldRenderSide(position, Directions.DOWN) + val skipNorth = !shouldRenderSide(position, Directions.NORTH) + val skipSouth = !shouldRenderSide(position, Directions.SOUTH) + val skipWest = !shouldRenderSide(position, Directions.WEST) + val skipEast = !shouldRenderSide(position, Directions.EAST) + + if (skipTop && skipBottom && skipNorth && skipSouth && skipWest && skipEast) { + continue + } + val cornerHeights = floatArrayOf( + getCornerHeight(position, fluid), + getCornerHeight(position + Directions.EAST, fluid), + getCornerHeight(position + Directions.EAST + Directions.SOUTH, fluid), + getCornerHeight(position + Directions.SOUTH, fluid), + ) + val floatPosition = position.toVec3() + floatPosition.y += cornerHeights[0] + if (!skipTop) { + val velocity = if (fluid is FlowableFluid) fluid.getVelocity(renderWindow.connection, blockState, position) else null + val still = velocity == null || velocity.x == 0.0 && velocity.z == 0.0 + val texture: AbstractTexture + val minUV = Vec2.EMPTY + val maxUV = Vec2(if (still) 1.0f else 0.5f) // Minecraft just uses half of the sprite + + + val texturePositions = arrayOf( + Vec2(maxUV.x, minUV.y), + minUV, + Vec2(minUV.x, maxUV.y), + maxUV, + ) + + + if (still) { + texture = fluid.stillTexture!! + } else { + texture = (fluid as FlowableFluid).flowingTexture!! + maxUV.x = 0.5f + + val atan = atan2(velocity!!.x, velocity.z).toFloat() + val sin = atan.sin + val cos = atan.cos + + for (i in 0 until 4) { + texturePositions[i] = (rotate(texturePositions[i].x - TEXTURE_CENTER, texturePositions[i].y - TEXTURE_CENTER, sin, cos, false) + TEXTURE_CENTER) + } + } + + val meshToUse = texture.transparency.getMesh(mesh) + + val positions = arrayOf( + Vec3(position.x, position.y + cornerHeights[0], position.z), + Vec3(position.x + 1, position.y + cornerHeights[1], position.z), + Vec3(position.x + 1, position.y + cornerHeights[2], position.z + 1), + Vec3(position.x, position.y + cornerHeights[3], position.z + 1), + ) + + + for ((positionIndex, textureIndex) in meshToUse.order) { + meshToUse.addVertex(positions[positionIndex].array, texturePositions[textureIndex], texture, tints?.get(0) ?: 0xFFFFFF, chunk.getLight(position)) + } + rendered = true + } + // ToDo: Sides: Minecraft uses (for water) a overlay texture (with cullface) that is used, when the face fits to a non opaque block + // ToDo: Sides that are connecting with non full cubes (e.g. air) also have cullface disabled + + + for (direction in 0 until 4) { + var faceX = 0.0f + var faceXEnd = 0.0f + var faceZ = 0.0f + var faceZEnd = 0.0f + var v1 = 0.0f + var v2 = 0.0f + + when (direction) { + 0 -> { + if (skipNorth) { + continue + } + + faceXEnd = 1.0f + v1 = cornerHeights[0] + v2 = cornerHeights[1] + } + 1 -> { + if (skipSouth) { + continue + } + faceX = 1.0f + faceZ = 1.0f + faceZEnd = 1.0f + v1 = cornerHeights[2] + v2 = cornerHeights[3] + } + 2 -> { + if (skipWest) { + continue + } + faceZ = 1.0f + v1 = cornerHeights[3] + v2 = cornerHeights[0] + } + 3 -> { + if (skipEast) { + continue + } + + faceX = 1.0f + faceXEnd = 1.0f + faceZEnd = 1.0f + v1 = cornerHeights[1] + v2 = cornerHeights[2] + } + } + + val positions = arrayOf( + Vec3(position.x + faceX, position.y + v1, position.z + faceZ), + Vec3(position.x + faceX, position.y, position.z + faceZ), + Vec3(position.x + faceXEnd, position.y, position.z + faceZEnd), + Vec3(position.x + faceXEnd, position.y + v2, position.z + faceZEnd), + ) + val texturePositions = arrayOf( + Vec2(0.5f, v2 / 2), + Vec2(0.5f, 0.0f), + Vec2(0.0f, 0.0f), + Vec2(0.0f, v1 / 2), + ) + + val texture = (fluid as FlowableFluid).flowingTexture!! + + val meshToUse = texture.transparency.getMesh(mesh) + for ((positionIndex, textureIndex) in meshToUse.order) { + meshToUse.addVertex(positions[positionIndex].array, texturePositions[textureIndex], texture, tints?.get(0) ?: 0xFFFFFF, 0xFF) + } + rendered = true + } if (rendered) { @@ -75,4 +229,51 @@ class FluidCullSectionPreparer( return mesh } + private fun isSideCovered(position: Vec3i, direction: Directions, height: Float): Boolean { + return world[position + direction] != null + } + + private fun shouldRenderSide(position: Vec3i, direction: Directions, height: Float = 1.0f): Boolean { + return !isSideCovered(position, direction, height) /* && fluid.matches(other) */ + } + + private fun getCornerHeight(position: Vec3i, fluid: Fluid): Float { + // ToDo: Optimize + var totalHeight = 0.0f + var count = 0 + + for (side in 0 until 4) { + val blockPosition = position + Vec3i(-(side and 0x01), 0, -(side shr 1 and 0x01)) + if (fluid.matches(world[blockPosition + Directions.UP])) { + return 1.0f + } + + val blockState = world[blockPosition] + + if (blockState == null || !fluid.matches(blockState)) { + if (blockState?.material?.solid != true) { + count++ + } + continue + } + + val height = fluid.getHeight(blockState) + + if (height >= 0.8f) { + totalHeight += height * 10.0f + count += 10 + } else { + totalHeight += height + count++ + } + } + + + return totalHeight / count + } + + private companion object { + private const val TEXTURE_CENTER = 1.0f / 2.0f + } + } diff --git a/src/main/java/de/bixilon/minosoft/util/SystemInformation.kt b/src/main/java/de/bixilon/minosoft/util/SystemInformation.kt index 5f4445329..3236d0330 100644 --- a/src/main/java/de/bixilon/minosoft/util/SystemInformation.kt +++ b/src/main/java/de/bixilon/minosoft/util/SystemInformation.kt @@ -25,7 +25,7 @@ object SystemInformation { val SYSTEM_MEMORY = HARDWARE_SYSTEM_INFO.memory.total val OS_TEXT: String = "${System.getProperty("os.name")}: ${SYSTEM_INFO.operatingSystem.family} ${SYSTEM_INFO.operatingSystem.bitness}bit" - val PROCESSOR_TEXT = " ${RUNTIME.availableProcessors()}x ${HARDWARE_SYSTEM_INFO.processor.processorIdentifier.name.replace("\\s{2,}".toRegex(), "")}" + val PROCESSOR_TEXT = "${RUNTIME.availableProcessors()}x ${HARDWARE_SYSTEM_INFO.processor.processorIdentifier.name.replace("\\s{2,}".toRegex(), "")}" val MAX_MEMORY_TEXT: String = getFormattedMaxMemory() val PROCESSOR_SPEED = HARDWARE_SYSTEM_INFO.processor.maxFreq