Merge branch 'work/camera' into 'master'

Refactor camera

See merge request bixilon/minosoft!37
This commit is contained in:
Bixilon 2021-12-14 10:36:20 +01:00
commit 543dda505a
64 changed files with 900 additions and 727 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
target/
/target/
out/
.idea/
*.iml

View File

@ -5,17 +5,3 @@ There is a config file located in:
* Windows: `%AppData%\Minosoft`
* MacOS: `"~/Library/Application Support/Minosoft"`
* Linux (and all others): `~\Minosoft`
- Profiles
- Select profile per server
- Config reloading
- From disk
- In eros
- Per key combination
- Migration
- Automatic saving (periodic, per event, maybe use delegates?)
- Config editor
- Config value checker
- Change event, batch those, apply event
- Multiple config files (e.g. eros, key combinations, particles, accounts, log, audio, blocks, entities, hit boxes, world, network, assets, physics, hud, other)

View File

@ -15,14 +15,14 @@ package de.bixilon.minosoft.data.entities
import glm_.func.cos
import glm_.func.rad
import glm_.func.sin
import glm_.vec3.Vec3d
import glm_.vec3.Vec3
data class EntityRotation(
val yaw: Double,
val pitch: Double,
) {
val front: Vec3d
get() = Vec3d(
val front: Vec3
get() = Vec3(
(yaw + 90).rad.cos * (-pitch).rad.cos,
(-pitch).rad.sin,
(yaw + 90).rad.sin * (-pitch).rad.cos

View File

@ -49,7 +49,7 @@ import de.bixilon.minosoft.gui.rendering.util.VecUtil.empty
import de.bixilon.minosoft.gui.rendering.util.VecUtil.floor
import de.bixilon.minosoft.gui.rendering.util.VecUtil.horizontal
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkPosition
import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3d
import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
@ -128,10 +128,10 @@ abstract class Entity(
}
open val positionInfo = EntityPositionInfo(connection, this)
val eyePosition: Vec3d
val eyePosition: Vec3
get() = cameraPosition + Vec3(0.0f, eyeHeight, 0.0f)
var cameraPosition: Vec3d = position.toVec3d
var cameraPosition: Vec3 = position.toVec3
private set
open val spawnSprintingParticles: Boolean
@ -362,7 +362,7 @@ abstract class Entity(
postTick()
lastTickTime = currentTime
}
cameraPosition = VecUtil.lerp((currentTime - lastTickTime) / ProtocolDefinition.TICK_TIMEd, previousPosition, position)
cameraPosition = VecUtil.lerp((currentTime - lastTickTime) / ProtocolDefinition.TICK_TIMEf, Vec3(previousPosition), Vec3(position))
}
open val pushableByFluids: Boolean = false

View File

@ -28,7 +28,7 @@ import de.bixilon.minosoft.data.registries.items.Item
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.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionResults
import de.bixilon.minosoft.gui.rendering.tint.TintProvider
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
@ -75,7 +75,7 @@ open class Block(
return resourceLocation.full
}
open fun getPlacementState(connection: PlayConnection, hit: BlockRaycastHit): BlockState? = defaultState
open fun getPlacementState(connection: PlayConnection, target: BlockTarget): BlockState? = defaultState
open fun onBreak(connection: PlayConnection, blockPosition: Vec3i, blockState: BlockState, blockEntity: BlockEntity?) = Unit
@ -83,7 +83,7 @@ open class Block(
open fun canPlaceAt(connection: PlayConnection, blockPosition: Vec3i, blockState: BlockState): Boolean = true
open fun onUse(connection: PlayConnection, hit: BlockRaycastHit, hand: Hands, itemStack: ItemStack?): InteractionResults {
open fun onUse(connection: PlayConnection, target: BlockTarget, hand: Hands, itemStack: ItemStack?): InteractionResults {
if (blockEntityType == null) {
return InteractionResults.PASS
}

View File

@ -21,7 +21,7 @@ import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties
import de.bixilon.minosoft.data.registries.items.tools.ShovelItem
import de.bixilon.minosoft.data.registries.registries.Registries
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionResults
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.campfire.CampfireSmokeParticle
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.fire.SmokeParticle
@ -92,13 +92,13 @@ open class CampfireBlock(resourceLocation: ResourceLocation, registries: Registr
}
}
override fun onUse(connection: PlayConnection, hit: BlockRaycastHit, hand: Hands, itemStack: ItemStack?): InteractionResults {
override fun onUse(connection: PlayConnection, target: BlockTarget, hand: Hands, itemStack: ItemStack?): InteractionResults {
// ToDo: Ignite (flint and steel, etc)
if (itemStack?.item !is ShovelItem || hit.blockState.properties[BlockProperties.LIT] != true) {
return super.onUse(connection, hit, hand, itemStack)
if (itemStack?.item !is ShovelItem || target.blockState.properties[BlockProperties.LIT] != true) {
return super.onUse(connection, target, hand, itemStack)
}
connection.world.setBlockState(hit.blockPosition, hit.blockState.withProperties(BlockProperties.LIT to false))
extinguish(connection, hit.blockState, hit.blockPosition)
connection.world.setBlockState(target.blockPosition, target.blockState.withProperties(BlockProperties.LIT to false))
extinguish(connection, target.blockState, target.blockPosition)
return InteractionResults.SUCCESS
}

View File

@ -21,22 +21,22 @@ import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties
import de.bixilon.minosoft.data.registries.materials.DefaultMaterials
import de.bixilon.minosoft.data.registries.registries.Registries
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionResults
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
open class DoorBlock(resourceLocation: ResourceLocation, registries: Registries, data: Map<String, Any>) : DoubleSizeBlock(resourceLocation, registries, data) {
override fun getPlacementState(connection: PlayConnection, hit: BlockRaycastHit): BlockState? {
override fun getPlacementState(connection: PlayConnection, target: BlockTarget): BlockState? {
TODO()
}
override fun onUse(connection: PlayConnection, hit: BlockRaycastHit, hand: Hands, itemStack: ItemStack?): InteractionResults {
if (hit.blockState.material.resourceLocation == DefaultMaterials.METAL) {
override fun onUse(connection: PlayConnection, target: BlockTarget, hand: Hands, itemStack: ItemStack?): InteractionResults {
if (target.blockState.material.resourceLocation == DefaultMaterials.METAL) {
return InteractionResults.CONSUME
}
connection.world[hit.blockPosition] = hit.blockState.cycle(BlockProperties.DOOR_OPEN)
connection.world[target.blockPosition] = target.blockState.cycle(BlockProperties.DOOR_OPEN)
return InteractionResults.SUCCESS
}

View File

@ -18,13 +18,13 @@ import de.bixilon.minosoft.data.player.Hands
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.blocks.BlockFactory
import de.bixilon.minosoft.data.registries.registries.Registries
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionResults
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
open class NoteBlock(resourceLocation: ResourceLocation, registries: Registries, data: Map<String, Any>) : Block(resourceLocation, registries, data) {
override fun onUse(connection: PlayConnection, hit: BlockRaycastHit, hand: Hands, itemStack: ItemStack?): InteractionResults {
override fun onUse(connection: PlayConnection, target: BlockTarget, hand: Hands, itemStack: ItemStack?): InteractionResults {
return InteractionResults.SUCCESS
}

View File

@ -19,17 +19,17 @@ import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties
import de.bixilon.minosoft.data.registries.blocks.types.Block
import de.bixilon.minosoft.data.registries.registries.Registries
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionResults
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
abstract class AbstractButtonBlock(resourceLocation: ResourceLocation, registries: Registries, data: Map<String, Any>) : Block(resourceLocation, registries, data) {
override fun onUse(connection: PlayConnection, hit: BlockRaycastHit, hand: Hands, itemStack: ItemStack?): InteractionResults {
if (hit.blockState.properties[BlockProperties.POWERED] == true) {
override fun onUse(connection: PlayConnection, target: BlockTarget, hand: Hands, itemStack: ItemStack?): InteractionResults {
if (target.blockState.properties[BlockProperties.POWERED] == true) {
return InteractionResults.CONSUME
}
connection.world[hit.blockPosition] = hit.blockState.withProperties(BlockProperties.POWERED to true)
connection.world[target.blockPosition] = target.blockState.withProperties(BlockProperties.POWERED to true)
return InteractionResults.SUCCESS
}
}

View File

@ -20,7 +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.types.Block
import de.bixilon.minosoft.data.registries.registries.Registries
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
@ -30,12 +30,12 @@ open class PlantBlock(resourceLocation: ResourceLocation, registries: Registries
return blockState.block.resourceLocation == MinecraftBlocks.DIRT || blockState.block.resourceLocation == MinecraftBlocks.FARMLAND
}
override fun getPlacementState(connection: PlayConnection, hit: BlockRaycastHit): BlockState? {
val below = connection.world[hit.blockPosition + hit.hitDirection + Directions.DOWN] ?: return null
override fun getPlacementState(connection: PlayConnection, target: BlockTarget): BlockState? {
val below = connection.world[target.blockPosition + target.direction + Directions.DOWN] ?: return null
if (!canPlaceOn(below)) {
return null
}
return super.getPlacementState(connection, hit)
return super.getPlacementState(connection, target)
}
companion object : BlockFactory<PlantBlock> {

View File

@ -20,18 +20,18 @@ import de.bixilon.minosoft.data.registries.blocks.BlockFactory
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties
import de.bixilon.minosoft.data.registries.registries.Registries
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionResults
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
open class ComparatorBlock(resourceLocation: ResourceLocation, registries: Registries, data: Map<String, Any>) : RedstoneGateBlock(resourceLocation, registries, data) {
override fun getPlacementState(connection: PlayConnection, hit: BlockRaycastHit): BlockState? {
override fun getPlacementState(connection: PlayConnection, target: BlockTarget): BlockState? {
TODO()
}
override fun onUse(connection: PlayConnection, hit: BlockRaycastHit, hand: Hands, itemStack: ItemStack?): InteractionResults {
connection.world[hit.blockPosition] = hit.blockState.cycle(BlockProperties.STRUCTURE_BLOCK_MODE)
override fun onUse(connection: PlayConnection, target: BlockTarget, hand: Hands, itemStack: ItemStack?): InteractionResults {
connection.world[target.blockPosition] = target.blockState.cycle(BlockProperties.STRUCTURE_BLOCK_MODE)
return InteractionResults.SUCCESS
}

View File

@ -20,18 +20,18 @@ import de.bixilon.minosoft.data.registries.blocks.BlockFactory
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties
import de.bixilon.minosoft.data.registries.registries.Registries
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionResults
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
open class RepeaterBlock(resourceLocation: ResourceLocation, registries: Registries, data: Map<String, Any>) : RedstoneGateBlock(resourceLocation, registries, data) {
override fun getPlacementState(connection: PlayConnection, hit: BlockRaycastHit): BlockState? {
override fun getPlacementState(connection: PlayConnection, target: BlockTarget): BlockState? {
TODO()
}
override fun onUse(connection: PlayConnection, hit: BlockRaycastHit, hand: Hands, itemStack: ItemStack?): InteractionResults {
connection.world[hit.blockPosition] = hit.blockState.cycle(BlockProperties.REPEATER_DELAY)
override fun onUse(connection: PlayConnection, target: BlockTarget, hand: Hands, itemStack: ItemStack?): InteractionResults {
connection.world[target.blockPosition] = target.blockState.cycle(BlockProperties.REPEATER_DELAY)
return InteractionResults.SUCCESS
}

View File

@ -23,7 +23,7 @@ import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties
import de.bixilon.minosoft.data.registries.particle.data.DustParticleData
import de.bixilon.minosoft.data.registries.registries.Registries
import de.bixilon.minosoft.data.text.Colors
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionResults
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.dust.DustParticle
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY
@ -55,14 +55,14 @@ open class LeverBlock(resourceLocation: ResourceLocation, registries: Registries
}
}
override fun getPlacementState(connection: PlayConnection, hit: BlockRaycastHit): BlockState? {
override fun getPlacementState(connection: PlayConnection, target: BlockTarget): BlockState? {
TODO()
}
override fun onUse(connection: PlayConnection, hit: BlockRaycastHit, hand: Hands, itemStack: ItemStack?): InteractionResults {
val nextState = hit.blockState.cycle(BlockProperties.POWERED)
connection.world[hit.blockPosition] = nextState
spawnParticles(connection, nextState, hit.blockPosition, 1.0f)
override fun onUse(connection: PlayConnection, target: BlockTarget, hand: Hands, itemStack: ItemStack?): InteractionResults {
val nextState = target.blockState.cycle(BlockProperties.POWERED)
connection.world[target.blockPosition] = nextState
spawnParticles(connection, nextState, target.blockPosition, 1.0f)
return InteractionResults.SUCCESS
}

View File

@ -40,8 +40,8 @@ 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.data.registries.registries.registry.Translatable
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.input.camera.hit.EntityRaycastHit
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.camera.target.targets.EntityTarget
import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionResults
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.util.KUtil.toBoolean
@ -69,15 +69,15 @@ open class Item(
return 1.0f
}
open fun interactBlock(connection: PlayConnection, raycastHit: BlockRaycastHit, hand: Hands, itemStack: ItemStack): InteractionResults {
open fun interactBlock(connection: PlayConnection, target: BlockTarget, hand: Hands, itemStack: ItemStack): InteractionResults {
return InteractionResults.PASS
}
open fun interactEntity(connection: PlayConnection, raycastHit: EntityRaycastHit, hand: Hands, itemStack: ItemStack): InteractionResults {
open fun interactEntity(connection: PlayConnection, target: EntityTarget, hand: Hands, itemStack: ItemStack): InteractionResults {
return InteractionResults.PASS
}
open fun interactEntityAt(connection: PlayConnection, raycastHit: EntityRaycastHit, hand: Hands, itemStack: ItemStack): InteractionResults {
open fun interactEntityAt(connection: PlayConnection, target: EntityTarget, hand: Hands, itemStack: ItemStack): InteractionResults {
return InteractionResults.PASS
}

View File

@ -21,7 +21,7 @@ import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.registries.blocks.types.Block
import de.bixilon.minosoft.data.registries.items.Item
import de.bixilon.minosoft.data.registries.registries.Registries
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionResults
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plusAssign
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
@ -37,14 +37,14 @@ open class BlockItem(
this::block.inject(data["block"])
}
override fun interactBlock(connection: PlayConnection, raycastHit: BlockRaycastHit, hand: Hands, itemStack: ItemStack): InteractionResults {
override fun interactBlock(connection: PlayConnection, target: BlockTarget, hand: Hands, itemStack: ItemStack): InteractionResults {
if (!connection.player.gamemode.canBuild) {
return InteractionResults.PASS
}
val placePosition = raycastHit.blockPosition
if (!raycastHit.blockState.material.replaceable) {
placePosition += raycastHit.hitDirection
val placePosition = target.blockPosition
if (!target.blockState.material.replaceable) {
placePosition += target.direction
if (connection.world[placePosition]?.material?.replaceable == false) {
return InteractionResults.PASS
@ -62,7 +62,7 @@ open class BlockItem(
var placeBlockState: BlockState = block!!.defaultState
try {
placeBlockState = block.getPlacementState(connection, raycastHit) ?: return InteractionResults.PASS
placeBlockState = block.getPlacementState(connection, target) ?: return InteractionResults.PASS
} catch (exception: Throwable) {
exception.printStackTrace()
}

View File

@ -18,7 +18,7 @@ import de.bixilon.minosoft.data.player.Hands
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.blocks.types.Block
import de.bixilon.minosoft.data.registries.registries.Registries
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionResults
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.util.KUtil.mapCast
@ -39,12 +39,12 @@ open class AxeItem(
entries.toMap()
}
override fun interactBlock(connection: PlayConnection, raycastHit: BlockRaycastHit, hand: Hands, itemStack: ItemStack): InteractionResults {
override fun interactBlock(connection: PlayConnection, target: BlockTarget, hand: Hands, itemStack: ItemStack): InteractionResults {
if (!connection.profiles.controls.interaction.stripping) {
return InteractionResults.CONSUME
}
return super.interactWithTool(connection, raycastHit.blockPosition, strippableBlocks?.get(raycastHit.blockState.block)?.withProperties(raycastHit.blockState.properties))
return super.interactWithTool(connection, target.blockPosition, strippableBlocks?.get(target.blockState.block)?.withProperties(target.blockState.properties))
}
companion object {

View File

@ -20,7 +20,7 @@ import de.bixilon.minosoft.data.registries.ResourceLocation
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
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionResults
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
@ -42,16 +42,16 @@ open class HoeItem(
entries.toMap()
}
override fun interactBlock(connection: PlayConnection, raycastHit: BlockRaycastHit, hand: Hands, itemStack: ItemStack): InteractionResults {
override fun interactBlock(connection: PlayConnection, target: BlockTarget, hand: Hands, itemStack: ItemStack): InteractionResults {
if (!connection.profiles.controls.interaction.tilling) {
return InteractionResults.CONSUME
}
if (connection.world[raycastHit.blockPosition + Directions.UP] != null) {
if (connection.world[target.blockPosition + Directions.UP] != null) {
return InteractionResults.PASS
}
return super.interactWithTool(connection, raycastHit.blockPosition, tillableBlockStates?.get(raycastHit.blockState.block))
return super.interactWithTool(connection, target.blockPosition, tillableBlockStates?.get(target.blockState.block))
}
companion object {

View File

@ -20,7 +20,7 @@ import de.bixilon.minosoft.data.registries.ResourceLocation
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
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionResults
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
@ -43,16 +43,16 @@ open class ShovelItem(
}
override fun interactBlock(connection: PlayConnection, raycastHit: BlockRaycastHit, hand: Hands, itemStack: ItemStack): InteractionResults {
override fun interactBlock(connection: PlayConnection, target: BlockTarget, hand: Hands, itemStack: ItemStack): InteractionResults {
if (!connection.profiles.controls.interaction.flattening) {
return InteractionResults.CONSUME
}
if (connection.world[raycastHit.blockPosition + Directions.UP] != null) {
if (connection.world[target.blockPosition + Directions.UP] != null) {
return InteractionResults.PASS
}
return super.interactWithTool(connection, raycastHit.blockPosition, flattenableBlockStates?.get(raycastHit.blockState.block))
return super.interactWithTool(connection, target.blockPosition, flattenableBlockStates?.get(target.blockState.block))
}

View File

@ -22,6 +22,6 @@ object RainGradientSetGameEventHandler : GameEventHandler {
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:rain_gradient_set".toResourceLocation()
override fun handle(data: Float, connection: PlayConnection) {
connection.world.rainGradient = data
connection.world.weather.rainGradient = data
}
}

View File

@ -22,6 +22,6 @@ object ThunderGradientSetGameEventHandler : GameEventHandler {
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:thunder_gradient_set".toResourceLocation()
override fun handle(data: Float, connection: PlayConnection) {
connection.world.thunderGradient = data
connection.world.weather.thunderGradient = data
}
}

View File

@ -22,7 +22,7 @@ object RainStartGameEventHandler : GameEventHandler {
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:rain_start".toResourceLocation()
override fun handle(data: Float, connection: PlayConnection) {
connection.world.raining = true
connection.world.rainGradient = 1.0f
connection.world.weather.raining = true
connection.world.weather.rainGradient = 1.0f
}
}

View File

@ -22,7 +22,7 @@ object RainStopGameEventHandler : GameEventHandler {
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:rain_stop".toResourceLocation()
override fun handle(data: Float, connection: PlayConnection) {
connection.world.raining = false
connection.world.rainGradient = 0.0f
connection.world.weather.raining = false
connection.world.weather.rainGradient = 0.0f
}
}

View File

@ -22,7 +22,9 @@ import de.bixilon.minosoft.data.registries.blocks.types.FluidBlock
import de.bixilon.minosoft.data.registries.dimension.DimensionProperties
import de.bixilon.minosoft.data.world.biome.accessor.BiomeAccessor
import de.bixilon.minosoft.data.world.biome.accessor.NoiseBiomeAccessor
import de.bixilon.minosoft.data.world.time.WorldTime
import de.bixilon.minosoft.data.world.view.WorldView
import de.bixilon.minosoft.data.world.weather.WorldWeather
import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer
import de.bixilon.minosoft.gui.rendering.particle.types.Particle
import de.bixilon.minosoft.gui.rendering.util.VecUtil.blockPosition
@ -35,10 +37,8 @@ import de.bixilon.minosoft.modding.event.events.BlockSetEvent
import de.bixilon.minosoft.modding.event.events.ChunkDataChangeEvent
import de.bixilon.minosoft.modding.event.events.ChunkUnloadEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.KUtil.lockMapOf
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
import de.bixilon.minosoft.util.MMath
import de.bixilon.minosoft.util.ReadWriteLock
import de.bixilon.minosoft.util.chunk.ChunkUtil.canBuildBiomeCache
import de.bixilon.minosoft.util.chunk.ChunkUtil.getChunkNeighbourPositions
@ -46,13 +46,9 @@ import de.bixilon.minosoft.util.chunk.ChunkUtil.isInViewDistance
import de.bixilon.minosoft.util.chunk.ChunkUtil.received
import de.bixilon.minosoft.util.collections.LockMap
import de.bixilon.minosoft.util.delegate.DelegateManager.delegate
import glm_.func.common.clamp
import glm_.vec2.Vec2i
import glm_.vec3.Vec3
import glm_.vec3.Vec3i
import kotlin.math.PI
import kotlin.math.abs
import kotlin.math.cos
import kotlin.random.Random
/**
@ -70,11 +66,8 @@ class World(
var difficulty: Difficulties? = null
var difficultyLocked = false
var hashedSeed = 0L
var time = 0L
var age = 0L
var raining = false
var rainGradient = 0.0f
var thunderGradient = 0.0f
val time = WorldTime(this)
val weather = WorldWeather()
val view = WorldView(connection)
private val random = Random
@ -234,25 +227,6 @@ class World(
return get(blockPosition.chunkPosition)?.getLight(blockPosition.inChunkPosition) ?: 0x00
}
val skyAngle: Double
get() {
val fractionalPath = MMath.fractionalPart(abs(time) / ProtocolDefinition.TICKS_PER_DAYf - 0.25)
val angle = 0.5 - cos(fractionalPath * Math.PI) / 2.0
return (fractionalPath * 2.0 + angle) / 3.0
}
val lightBase: Double
get() {
var base = 1.0f - (cos(skyAngle * 2.0 * PI) * 2.0 + 0.2)
base = base.clamp(0.0, 1.0)
base = 1.0 - base
base *= 1.0 - ((rainGradient * 5.0) / 16.0)
base *= 1.0 - (((thunderGradient * rainGradient) * 5.0) / 16.0)
return base * 0.8 + 0.2
}
/**
* @return All 8 neighbour chunks
*/

View File

@ -0,0 +1,37 @@
package de.bixilon.minosoft.data.world.time
import de.bixilon.minosoft.data.world.World
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.MMath
import glm_.func.common.clamp
import kotlin.math.PI
import kotlin.math.abs
import kotlin.math.cos
class WorldTime(
private val world: World,
) {
var time = 0L
var age = 0L
val skyAngle: Float
get() {
val fractionalPath = MMath.fractionalPart(abs(time) / ProtocolDefinition.TICKS_PER_DAYf - 0.25)
val angle = 0.5 - cos(fractionalPath * Math.PI) / 2.0
return ((fractionalPath * 2.0 + angle) / 3.0).toFloat()
}
val lightBase: Double
get() {
var base = 1.0f - (cos(skyAngle * 2.0 * PI) * 2.0 + 0.2)
base = base.clamp(0.0, 1.0)
base = 1.0 - base
base *= 1.0 - ((world.weather.rainGradient * 5.0) / 16.0)
base *= 1.0 - (((world.weather.thunderGradient * world.weather.rainGradient) * 5.0) / 16.0)
return base * 0.8 + 0.2
}
}

View File

@ -0,0 +1,8 @@
package de.bixilon.minosoft.data.world.weather
class WorldWeather {
var raining = false
var rainGradient = 0.0f
var thunderGradient = 0.0f
}

View File

@ -21,6 +21,7 @@ import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.text.BaseComponent
import de.bixilon.minosoft.data.text.ChatColors
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.gui.rendering.camera.Camera
import de.bixilon.minosoft.gui.rendering.entity.EntityHitboxRenderer
import de.bixilon.minosoft.gui.rendering.font.Font
import de.bixilon.minosoft.gui.rendering.font.FontLoader
@ -76,6 +77,7 @@ class RenderWindow(
private val profile = connection.profiles.rendering
val window: BaseWindow = GLFWWindow(this, connection)
val renderSystem: RenderSystem = OpenGLRenderSystem(this)
val camera = Camera(this)
var initialized = false
private set
private lateinit var renderThread: Thread
@ -163,7 +165,7 @@ class RenderWindow(
window.init(connection.profiles.rendering)
window.setDefaultIcon(connection.assetsManager)
inputHandler.camera.init(this)
camera.init()
tintManager.init(connection.assetsManager)
@ -360,6 +362,7 @@ class RenderWindow(
window.pollEvents()
inputHandler.draw(deltaFrameTime)
camera.draw()
// handle opengl context tasks, but limit it per frame
queue.timeWork(RenderConstants.MAXIMUM_QUEUE_TIME_PER_FRAME)

View File

@ -0,0 +1,23 @@
package de.bixilon.minosoft.gui.rendering.camera
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.camera.target.TargetHandler
class Camera(
renderWindow: RenderWindow,
) {
val matrixHandler = MatrixHandler(renderWindow)
val targetHandler = TargetHandler(renderWindow, this)
val fogManager = FogManager(renderWindow)
fun init() {
matrixHandler.init()
}
fun draw() {
matrixHandler.entity.tick()
matrixHandler.draw()
targetHandler.raycast()
fogManager.draw()
}
}

View File

@ -0,0 +1,61 @@
package de.bixilon.minosoft.gui.rendering.camera
import de.bixilon.minosoft.data.text.ChatColors
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.sky.SkyRenderer
import de.bixilon.minosoft.util.delegate.watcher.SimpleDelegateWatcher.Companion.watchRendering
@Deprecated("Needs some refactoring and improvements")
class FogManager(
private val renderWindow: RenderWindow,
) {
private var upToDate = false
var fogColor: RGBColor = ChatColors.GREEN
set(value) {
field = value
upToDate = false
}
private var fogStart = 0.0f
private var fogEnd = 0.0f
fun init() {
renderWindow.connection.world.view::viewDistance.watchRendering(this, true) { calculateFog() }
}
fun draw() {
if (upToDate) {
return
}
calculateFog()
updateShaders()
}
private fun calculateFog() {
if (!renderWindow.connection.profiles.rendering.fog.enabled) {
// ToDo: This is not improving performance
fogStart = Float.MAX_VALUE
fogEnd = Float.MAX_VALUE
} else {
fogStart = renderWindow.connection.world.view.viewDistance * 16.0f - 8.0f // ToDo
fogEnd = fogStart + 10.0f
}
renderWindow[SkyRenderer]?.let { fogColor = it.baseColor }
}
private fun updateShaders() {
for (shader in renderWindow.renderSystem.shaders) {
if (!shader.uniforms.contains("uFogColor")) {
continue
}
shader.use()
shader.setFloat("uFogStart", fogStart)
shader.setFloat("uFogEnd", fogEnd)
shader["uFogColor"] = fogColor
}
}
}

View File

@ -0,0 +1,147 @@
package de.bixilon.minosoft.gui.rendering.camera
import de.bixilon.minosoft.data.entities.EntityRotation
import de.bixilon.minosoft.data.entities.entities.Entity
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.camera.frustum.Frustum
import de.bixilon.minosoft.gui.rendering.modding.events.CameraMatrixChangeEvent
import de.bixilon.minosoft.gui.rendering.modding.events.CameraPositionChangeEvent
import de.bixilon.minosoft.gui.rendering.modding.events.FrustumChangeEvent
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
import glm_.func.rad
import glm_.glm
import glm_.mat4x4.Mat4
import glm_.vec2.Vec2
import glm_.vec3.Vec3
class MatrixHandler(
private val renderWindow: RenderWindow,
) {
private val connection = renderWindow.connection
private val profile = renderWindow.connection.profiles.rendering.camera
val frustum = Frustum(this)
var entity: Entity = renderWindow.connection.player
set(value) {
field = value
upToDate = false
}
var eyePosition = Vec3.EMPTY
private set
var rotation = EntityRotation(0.0, 0.0)
private set
private var previousFOV = 0.0
var cameraFront = Vec3(0.0, 0.0, -1.0)
private set
var cameraRight = Vec3(0.0, 0.0, -1.0)
private set
var cameraUp = Vec3(0.0, 1.0, 0.0)
private set
var zoom = 0.0f
set(value) {
field = value
upToDate = false
}
private var upToDate = false
var viewMatrix = calculateViewMatrix()
private set
var projectionMatrix = calculateProjectionMatrix(renderWindow.window.sizef)
private set
var viewProjectionMatrix = projectionMatrix * viewMatrix
private set
private val fov: Double
get() {
val fov = profile.fov / (zoom + 1.0)
if (!profile.dynamicFOV) {
return fov
}
return fov * connection.player.fovMultiplier.interpolate()
}
private fun calculateViewMatrix(eyePosition: Vec3 = entity.eyePosition): Mat4 {
return glm.lookAt(eyePosition, eyePosition + cameraFront, CAMERA_UP_VEC3)
}
private fun calculateProjectionMatrix(screenDimensions: Vec2): Mat4 {
return glm.perspective(fov.rad.toFloat(), screenDimensions.x / screenDimensions.y, 0.01f, 10000.0f)
}
fun init() {
connection.registerEvent(CallbackEventInvoker.of<ResizeWindowEvent> {
projectionMatrix = calculateProjectionMatrix(Vec2(it.size))
upToDate = false
})
draw() // set initial values
}
fun draw() {
val fov = fov
val eyePosition = entity.eyePosition
val rotation = entity.rotation
if (upToDate && eyePosition == this.eyePosition && rotation == this.rotation && fov == previousFOV) {
return
}
this.eyePosition = eyePosition
this.rotation = rotation
previousFOV = fov
updateRotation(rotation)
updateViewMatrix(eyePosition)
updateFrustum()
connection.fireEvent(CameraPositionChangeEvent(renderWindow, eyePosition))
connection.fireEvent(CameraMatrixChangeEvent(
renderWindow = renderWindow,
viewMatrix = viewMatrix,
projectionMatrix = projectionMatrix,
viewProjectionMatrix = viewProjectionMatrix,
))
updateShaders()
}
private fun updateViewMatrix(eyePosition: Vec3) {
viewMatrix = calculateViewMatrix(eyePosition)
viewProjectionMatrix = projectionMatrix * viewMatrix
}
private fun updateFrustum() {
frustum.recalculate()
connection.fireEvent(FrustumChangeEvent(renderWindow, frustum))
}
private fun updateRotation(rotation: EntityRotation = entity.rotation) {
cameraFront = rotation.front
cameraRight = (cameraFront cross CAMERA_UP_VEC3).normalize()
cameraUp = (cameraRight cross cameraFront).normalize()
}
private fun updateShaders() {
for (shader in renderWindow.renderSystem.shaders) {
if (shader.uniforms.contains("uViewProjectionMatrix")) {
shader.use().setMat4("uViewProjectionMatrix", viewProjectionMatrix)
}
if (shader.uniforms.contains("uCameraPosition")) {
shader.use().setVec3("uCameraPosition", connection.player.cameraPosition)
}
}
}
companion object {
val CAMERA_UP_VEC3 = Vec3(0.0, 1.0, 0.0)
}
}

View File

@ -11,34 +11,31 @@
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.input.camera.frustum
package de.bixilon.minosoft.gui.rendering.camera.frustum
import de.bixilon.minosoft.data.registries.AABB
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.input.camera.Camera
import de.bixilon.minosoft.gui.rendering.camera.MatrixHandler
import de.bixilon.minosoft.gui.rendering.util.VecUtil.of
import de.bixilon.minosoft.gui.rendering.util.vec.vec4.Vec4Util.dot
import de.bixilon.minosoft.util.KUtil
import de.bixilon.minosoft.util.KUtil.get
import de.bixilon.minosoft.util.enum.ValuesEnum
import glm_.mat3x3.Mat3
import glm_.mat4x4.Mat4
import glm_.vec2.Vec2i
import glm_.vec3.Vec3
import glm_.vec3.Vec3i
import glm_.vec4.Vec4
// Big thanks to: https://gist.github.com/podgorskiy/e698d18879588ada9014768e3e82a644
class Frustum(private val camera: Camera) {
class Frustum(
private val matrixHandler: MatrixHandler,
) {
private lateinit var data: FrustumData
init {
recalculate()
}
fun recalculate() {
val matrix = Mat4(camera.viewProjectionMatrix).transpose()
val matrix = matrixHandler.viewProjectionMatrix.transpose()
val planes = arrayOf(
matrix[3] + matrix[0],
matrix[3] - matrix[0],

View File

@ -0,0 +1,138 @@
package de.bixilon.minosoft.gui.rendering.camera.target
import de.bixilon.minosoft.data.player.LocalPlayerEntity
import de.bixilon.minosoft.data.registries.VoxelShape
import de.bixilon.minosoft.data.registries.blocks.types.FluidBlock
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.camera.Camera
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.camera.target.targets.EntityTarget
import de.bixilon.minosoft.gui.rendering.camera.target.targets.FluidTarget
import de.bixilon.minosoft.gui.rendering.camera.target.targets.GenericTarget
import de.bixilon.minosoft.gui.rendering.util.VecUtil
import de.bixilon.minosoft.gui.rendering.util.VecUtil.floor
import de.bixilon.minosoft.gui.rendering.util.VecUtil.getWorldOffset
import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3d
import de.bixilon.minosoft.util.KUtil.decide
import glm_.vec3.Vec3
import glm_.vec3.Vec3d
class TargetHandler(
private val renderWindow: RenderWindow,
private var camera: Camera,
) {
private val connection = renderWindow.connection
/**
* Can ba a BlockTarget or an EntityTarget. Not a FluidTarget
*/
var target: GenericTarget? = null
private set
var fluidTarget: FluidTarget? = null
private set
fun raycast() {
val eyePosition = camera.matrixHandler.eyePosition.toVec3d
val cameraFront = camera.matrixHandler.cameraFront.toVec3d
target = raycast(eyePosition, cameraFront, blocks = true, fluids = false, entities = true)
fluidTarget = raycast(eyePosition, cameraFront, blocks = false, fluids = true, entities = false) as FluidTarget?
}
private fun raycastEntity(origin: Vec3d, direction: Vec3d): EntityTarget? {
var currentHit: EntityTarget? = null
val originF = Vec3(origin)
for (entity in connection.world.entities) {
if (entity is LocalPlayerEntity) {
continue
}
if ((entity.cameraPosition - originF).length2() > MAX_ENTITY_DISTANCE) {
continue
}
val target = VoxelShape(entity.cameraAABB).raycast(origin, direction)
if (!target.hit) {
continue
}
if ((currentHit?.distance ?: Double.MAX_VALUE) < target.distance) {
continue
}
currentHit = EntityTarget(origin + direction * target.distance, target.distance, target.direction, entity)
}
return currentHit
}
private fun raycast(origin: Vec3d, direction: Vec3d, blocks: Boolean, fluids: Boolean, entities: Boolean): GenericTarget? {
if (!blocks && !fluids && entities) {
// only raycast entities
return raycastEntity(origin, direction)
}
val currentPosition = Vec3d(origin)
fun getTotalDistance(): Double {
return (origin - currentPosition).length()
}
var target: GenericTarget? = null
for (i in 0..RAYCAST_MAX_STEPS) {
val blockPosition = currentPosition.floor
val blockState = connection.world[blockPosition]
if (blockState == null) {
currentPosition += direction * (VecUtil.getDistanceToNextIntegerAxisInDirection(currentPosition, direction) + 0.001)
continue
}
val voxelShapeRaycastResult = (blockState.block.getOutlineShape(connection, blockState, blockPosition) + blockPosition + blockPosition.getWorldOffset(blockState.block)).raycast(currentPosition, direction)
if (voxelShapeRaycastResult.hit) {
val distance = getTotalDistance()
currentPosition += direction * voxelShapeRaycastResult.distance
currentPosition += direction * (VecUtil.getDistanceToNextIntegerAxisInDirection(currentPosition, direction) + 0.001)
if (blockState.block is FluidBlock) {
if (!fluids) {
continue
}
target = FluidTarget(
currentPosition,
distance,
voxelShapeRaycastResult.direction,
blockState,
blockPosition,
blockState.block.fluid,
)
break
}
if (!blocks) {
continue
}
target = BlockTarget(
currentPosition,
distance,
voxelShapeRaycastResult.direction,
blockState,
blockPosition,
)
break
} else {
currentPosition += direction * (VecUtil.getDistanceToNextIntegerAxisInDirection(currentPosition, direction) + 0.001)
}
}
if (entities) {
val entityRaycastHit = raycastEntity(origin, direction) ?: return target
target ?: return null
return (entityRaycastHit.distance < target.distance).decide(entityRaycastHit, target)
}
return target
}
companion object {
private const val RAYCAST_MAX_STEPS = 100
private const val MAX_ENTITY_DISTANCE = 20.0f * 20.0f // length2 does not get the square root
}
}

View File

@ -11,7 +11,7 @@
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.input.camera.hit
package de.bixilon.minosoft.gui.rendering.camera.target.targets
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.BlockState
@ -21,13 +21,13 @@ import de.bixilon.minosoft.data.text.TextFormattable
import glm_.vec3.Vec3d
import glm_.vec3.Vec3i
open class BlockRaycastHit(
open class BlockTarget(
position: Vec3d,
distance: Double,
hitDirection: Directions,
direction: Directions,
val blockState: BlockState,
val blockPosition: Vec3i,
) : RaycastHit(position, distance, hitDirection), TextFormattable {
) : GenericTarget(position, distance, direction), TextFormattable {
val hitPosition = position - blockPosition
override fun toString(): String {

View File

@ -11,7 +11,7 @@
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.input.camera.hit
package de.bixilon.minosoft.gui.rendering.camera.target.targets
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.entities.entities.Entity
@ -20,12 +20,12 @@ import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.data.text.TextFormattable
import glm_.vec3.Vec3d
class EntityRaycastHit(
class EntityTarget(
position: Vec3d,
distance: Double,
hitDirection: Directions,
direction: Directions,
val entity: Entity,
) : RaycastHit(position, distance, hitDirection), TextFormattable {
) : GenericTarget(position, distance, direction), TextFormattable {
override fun toString(): String {
return toText().legacyText

View File

@ -11,7 +11,7 @@
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.input.camera.hit
package de.bixilon.minosoft.gui.rendering.camera.target.targets
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.BlockState
@ -22,14 +22,14 @@ import de.bixilon.minosoft.data.text.TextFormattable
import glm_.vec3.Vec3d
import glm_.vec3.Vec3i
class FluidRaycastHit(
class FluidTarget(
position: Vec3d,
distance: Double,
hitDirection: Directions,
direction: Directions,
val blockState: BlockState,
val blockPosition: Vec3i,
val fluid: Fluid,
) : RaycastHit(position, distance, hitDirection), TextFormattable {
) : GenericTarget(position, distance, direction), TextFormattable {
override fun toString(): String {
return toText().legacyText

View File

@ -11,13 +11,13 @@
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.input.camera.hit
package de.bixilon.minosoft.gui.rendering.camera.target.targets
import de.bixilon.minosoft.data.direction.Directions
import glm_.vec3.Vec3d
abstract class RaycastHit(
abstract class GenericTarget(
val position: Vec3d,
val distance: Double,
val hitDirection: Directions,
val direction: Directions,
)

View File

@ -18,7 +18,7 @@ import de.bixilon.minosoft.data.entities.entities.Entity
import de.bixilon.minosoft.data.registries.AABB
import de.bixilon.minosoft.data.text.ChatColors
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.input.camera.frustum.Frustum
import de.bixilon.minosoft.gui.rendering.camera.frustum.Frustum
import de.bixilon.minosoft.gui.rendering.util.VecUtil.empty
import de.bixilon.minosoft.gui.rendering.util.mesh.LineMesh
import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh

View File

@ -45,7 +45,7 @@ class EntityHitboxRenderer(
) : Renderer, OpaqueDrawable, SkipAll {
override val renderSystem: RenderSystem = renderWindow.renderSystem
val profile = connection.profiles.entity.hitbox
private val frustum = renderWindow.inputHandler.camera.frustum
private val frustum = renderWindow.camera.matrixHandler.frustum
private val meshes: LockMap<Entity, EntityHitbox> = lockMapOf()
private val toUnload: MutableSet<EntityHitbox> = synchronizedSetOf()

View File

@ -16,13 +16,13 @@ package de.bixilon.minosoft.gui.rendering.gui.hud.elements.other
import de.bixilon.minosoft.config.profile.delegate.watcher.SimpleProfileDelegateWatcher.Companion.profileWatch
import de.bixilon.minosoft.data.abilities.Gamemodes
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.camera.target.targets.EntityTarget
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.gui.hud.atlas.HUDAtlasElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.CustomHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDBuilder
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.input.camera.hit.EntityRaycastHit
import de.bixilon.minosoft.gui.rendering.system.base.BlendingFunctions
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
@ -69,8 +69,8 @@ class CrosshairHUDElement(hudRenderer: HUDRenderer) : CustomHUDElement(hudRender
// Custom draw to make the crosshair inverted
if (renderWindow.connection.player.gamemode == Gamemodes.SPECTATOR) {
val hitResult = renderWindow.inputHandler.camera.target ?: return
if (hitResult !is EntityRaycastHit && (hitResult !is BlockRaycastHit || renderWindow.connection.world.getBlockEntity(hitResult.blockPosition) == null)) {
val hitResult = renderWindow.camera.targetHandler.target ?: return
if (hitResult !is EntityTarget && (hitResult !is BlockTarget || renderWindow.connection.world.getBlockEntity(hitResult.blockPosition) == null)) {
return
}
}

View File

@ -128,7 +128,7 @@ class DebugHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<GridLayout>
layout += AutoTextElement(hudRenderer, 1) {
val text = BaseComponent("Facing ")
Directions.byDirection(hudRenderer.renderWindow.inputHandler.camera.cameraFront).apply {
Directions.byDirection(hudRenderer.renderWindow.camera.matrixHandler.cameraFront).apply {
text += this
text += " "
text += vector
@ -227,7 +227,7 @@ class DebugHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<GridLayout>
layout += LineSpacerElement(hudRenderer)
renderWindow.inputHandler.camera.apply {
renderWindow.camera.targetHandler.apply {
layout += AutoTextElement(hudRenderer, 1, HorizontalAlignments.RIGHT) {
// ToDo: Tags
target ?: "No target"

View File

@ -0,0 +1,148 @@
package de.bixilon.minosoft.gui.rendering.input
import de.bixilon.minosoft.config.key.KeyAction
import de.bixilon.minosoft.config.key.KeyBinding
import de.bixilon.minosoft.config.key.KeyCodes
import de.bixilon.minosoft.data.entities.EntityRotation
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.camera.MatrixHandler
import de.bixilon.minosoft.gui.rendering.input.camera.MovementInput
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import glm_.glm
import glm_.vec2.Vec2d
class CameraInput(
private val renderWindow: RenderWindow,
val matrixHandler: MatrixHandler,
) {
private val connection = renderWindow.connection
private val player = connection.player
private val controlsProfile = connection.profiles.controls
private val ignoreInput: Boolean
get() {
val entity = matrixHandler.entity
if (entity != player) {
return true
}
return false
}
private fun registerKeyBindings() {
renderWindow.inputHandler.registerCheckCallback(
MOVE_SPRINT_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_LEFT_CONTROL),
),
),
MOVE_FORWARDS_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_W),
),
),
MOVE_BACKWARDS_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_S),
),
),
MOVE_LEFT_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_A),
),
),
MOVE_RIGHT_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_D),
),
),
FLY_UP_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_SPACE),
),
),
FLY_DOWN_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_LEFT_SHIFT),
),
),
JUMP_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_SPACE),
),
),
SNEAK_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_LEFT_SHIFT),
),
),
TOGGLE_FLY_KEYBINDING to KeyBinding(
mapOf(
KeyAction.DOUBLE_PRESS to setOf(KeyCodes.KEY_SPACE),
),
),
)
renderWindow.inputHandler.registerKeyCallback(ZOOM_KEYBINDING, KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_C),
),
)) { matrixHandler.zoom = if (it) 2.0f else 0.0f }
}
fun init() {
registerKeyBindings()
}
fun update() {
val input = if (ignoreInput) {
MovementInput()
} else {
MovementInput(
pressingForward = renderWindow.inputHandler.isKeyBindingDown(MOVE_FORWARDS_KEYBINDING),
pressingBack = renderWindow.inputHandler.isKeyBindingDown(MOVE_BACKWARDS_KEYBINDING),
pressingLeft = renderWindow.inputHandler.isKeyBindingDown(MOVE_LEFT_KEYBINDING),
pressingRight = renderWindow.inputHandler.isKeyBindingDown(MOVE_RIGHT_KEYBINDING),
jumping = renderWindow.inputHandler.isKeyBindingDown(JUMP_KEYBINDING),
sneaking = renderWindow.inputHandler.isKeyBindingDown(SNEAK_KEYBINDING),
sprinting = renderWindow.inputHandler.isKeyBindingDown(MOVE_SPRINT_KEYBINDING),
flyDown = renderWindow.inputHandler.isKeyBindingDown(FLY_DOWN_KEYBINDING),
flyUp = renderWindow.inputHandler.isKeyBindingDown(FLY_UP_KEYBINDING),
toggleFlyDown = renderWindow.inputHandler.isKeyBindingDown(TOGGLE_FLY_KEYBINDING),
)
}
connection.player.input = input
}
fun mouseCallback(delta: Vec2d) {
delta *= 0.1f * controlsProfile.mouse.sensitivity
var yaw = delta.x + player.rotation.yaw
if (yaw > 180) {
yaw -= 360
} else if (yaw < -180) {
yaw += 360
}
yaw %= 180
val pitch = glm.clamp(delta.y + player.rotation.pitch, -89.9, 89.9)
val rotation = EntityRotation(yaw, pitch)
player.rotation = rotation
}
private companion object {
private val MOVE_SPRINT_KEYBINDING = "minosoft:move_sprint".toResourceLocation()
private val MOVE_FORWARDS_KEYBINDING = "minosoft:move_forward".toResourceLocation()
private val MOVE_BACKWARDS_KEYBINDING = "minosoft:move_backwards".toResourceLocation()
private val MOVE_LEFT_KEYBINDING = "minosoft:move_left".toResourceLocation()
private val MOVE_RIGHT_KEYBINDING = "minosoft:move_right".toResourceLocation()
private val SNEAK_KEYBINDING = "minosoft:move_sneak".toResourceLocation()
private val JUMP_KEYBINDING = "minosoft:move_jump".toResourceLocation()
private val TOGGLE_FLY_KEYBINDING = "minosoft:move_toggle_fly".toResourceLocation()
private val FLY_UP_KEYBINDING = "minosoft:move_fly_up".toResourceLocation()
private val FLY_DOWN_KEYBINDING = "minosoft:move_fly_down".toResourceLocation()
private val ZOOM_KEYBINDING = "minosoft:zoom".toResourceLocation()
}
}

View File

@ -1,477 +0,0 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger, Lukas Eisenhauer
*
* 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.gui.rendering.input.camera
import de.bixilon.minosoft.config.key.KeyAction
import de.bixilon.minosoft.config.key.KeyBinding
import de.bixilon.minosoft.config.key.KeyCodes
import de.bixilon.minosoft.data.entities.EntityRotation
import de.bixilon.minosoft.data.player.LocalPlayerEntity
import de.bixilon.minosoft.data.registries.VoxelShape
import de.bixilon.minosoft.data.registries.blocks.types.FluidBlock
import de.bixilon.minosoft.data.registries.fluid.DefaultFluids
import de.bixilon.minosoft.data.text.ChatColors
import de.bixilon.minosoft.data.world.view.ViewDistanceChangeEvent
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.input.camera.frustum.Frustum
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.input.camera.hit.EntityRaycastHit
import de.bixilon.minosoft.gui.rendering.input.camera.hit.FluidRaycastHit
import de.bixilon.minosoft.gui.rendering.input.camera.hit.RaycastHit
import de.bixilon.minosoft.gui.rendering.modding.events.CameraMatrixChangeEvent
import de.bixilon.minosoft.gui.rendering.modding.events.CameraPositionChangeEvent
import de.bixilon.minosoft.gui.rendering.modding.events.FrustumChangeEvent
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
import de.bixilon.minosoft.gui.rendering.sky.SkyRenderer
import de.bixilon.minosoft.gui.rendering.util.VecUtil
import de.bixilon.minosoft.gui.rendering.util.VecUtil.floor
import de.bixilon.minosoft.gui.rendering.util.VecUtil.getWorldOffset
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.packets.c2s.play.PlayerActionC2SP
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.KUtil
import de.bixilon.minosoft.util.KUtil.decide
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import de.bixilon.minosoft.util.Previous
import glm_.func.rad
import glm_.glm
import glm_.mat4x4.Mat4
import glm_.mat4x4.Mat4d
import glm_.vec2.Vec2
import glm_.vec2.Vec2d
import glm_.vec3.Vec3d
class Camera(
val connection: PlayConnection,
val renderWindow: RenderWindow,
) {
private val profile = connection.profiles.rendering.camera
private val controlsProfile = connection.profiles.controls
var fogColor = Previous(ChatColors.GREEN)
var fogStart = connection.world.view.viewDistance * ProtocolDefinition.SECTION_WIDTH_X.toFloat() // ToDo
private var zoom = 0.0f
var cameraFront = Vec3d(0.0, 0.0, -1.0)
var cameraRight = Vec3d(0.0, 0.0, -1.0)
private var cameraUp = Vec3d(0.0, 1.0, 0.0)
// ToDo: They should also be available in headless mode
var nonFluidTarget: RaycastHit? = null
private set
var target: RaycastHit? = null
private set
var blockTarget: BlockRaycastHit? = null // Block target or if blocked by entity null
private set
var fluidTarget: FluidRaycastHit? = null
private set
var entityTarget: EntityRaycastHit? = null
private set
private val fov: Double
get() {
val fov = profile.fov / (zoom + 1.0)
if (!profile.dynamicFOV) {
return fov
}
return fov * connection.player.fovMultiplier.interpolate()
}
var viewMatrix = calculateViewMatrix()
private set
var projectionMatrix = calculateProjectionMatrix(renderWindow.window.sizef)
private set
var viewProjectionMatrix = projectionMatrix * viewMatrix
private set
var previousEyePosition = Vec3d(connection.player.position)
var previousRotation = connection.player.rotation.copy()
var previousZoom = zoom
private var lastDropPacketSent = -1L
val frustum: Frustum = Frustum(this)
fun mouseCallback(delta: Vec2d) {
delta *= 0.1f * controlsProfile.mouse.sensitivity
var yaw = delta.x + connection.player.rotation.yaw
if (yaw > 180) {
yaw -= 360
} else if (yaw < -180) {
yaw += 360
}
yaw %= 180
val pitch = glm.clamp(delta.y + connection.player.rotation.pitch, -89.9, 89.9)
val rotation = EntityRotation(yaw, pitch)
connection.player.rotation = rotation
setRotation(rotation)
}
private fun calculateFogDistance() {
if (!connection.profiles.rendering.fog.enabled) {
fogStart = Float.MAX_VALUE
return
}
fogStart = if (connection.player.submergedFluid?.resourceLocation == DefaultFluids.WATER) {
10.0f
} else {
connection.world.view.viewDistance * ProtocolDefinition.SECTION_WIDTH_X.toFloat() // ToDo
}
}
private fun applyFog() {
for (shader in renderWindow.renderSystem.shaders) {
if (!shader.uniforms.contains("uFogColor")) {
continue
}
shader.use()
shader.setFloat("uFogStart", fogStart)
shader.setFloat("uFogEnd", fogStart + 10.0f)
shader["uFogColor"] = fogColor
}
fogColor.assign()
}
fun init(renderWindow: RenderWindow) {
renderWindow.inputHandler.registerCheckCallback(
MOVE_SPRINT_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_LEFT_CONTROL),
),
),
MOVE_FORWARDS_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_W),
),
),
MOVE_BACKWARDS_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_S),
),
),
MOVE_LEFT_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_A),
),
),
MOVE_RIGHT_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_D),
),
),
FLY_UP_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_SPACE),
),
),
FLY_DOWN_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_LEFT_SHIFT),
),
),
ZOOM_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_C),
),
),
JUMP_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_SPACE),
),
),
SNEAK_KEYBINDING to KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_LEFT_SHIFT),
),
),
TOGGLE_FLY_KEYBINDING to KeyBinding(
mapOf(
KeyAction.DOUBLE_PRESS to setOf(KeyCodes.KEY_SPACE),
),
),
)
connection.registerEvent(CallbackEventInvoker.of<ResizeWindowEvent> { recalculateViewProjectionMatrix() })
connection.registerEvent(CallbackEventInvoker.of<ViewDistanceChangeEvent> { it.viewDistance * ProtocolDefinition.SECTION_WIDTH_X.toFloat() }) // ToDo
fun dropItem(stack: Boolean) {
val time = KUtil.time
if (time - lastDropPacketSent < ProtocolDefinition.TICK_TIME) {
return
}
val type = if (stack) {
connection.player.inventory.getHotbarSlot()?.count = 0
PlayerActionC2SP.Actions.DROP_ITEM_STACK
} else {
connection.player.inventory.getHotbarSlot()?.let {
it.count--
}
PlayerActionC2SP.Actions.DROP_ITEM
}
connection.sendPacket(PlayerActionC2SP(type))
lastDropPacketSent = time
}
// ToDo: This has nothing todo with the camera, should be in the interaction manager
renderWindow.inputHandler.registerKeyCallback(DROP_ITEM_STACK_KEYBINDING, KeyBinding(
mapOf(
KeyAction.PRESS to setOf(KeyCodes.KEY_Q),
KeyAction.MODIFIER to setOf(KeyCodes.KEY_LEFT_CONTROL)
),
)) { dropItem(true) }
renderWindow.inputHandler.registerKeyCallback(DROP_ITEM_KEYBINDING, KeyBinding(
mapOf(
KeyAction.PRESS to setOf(KeyCodes.KEY_Q),
),
)) { dropItem(false) }
frustum.recalculate()
connection.fireEvent(FrustumChangeEvent(renderWindow, frustum))
}
private fun recalculateViewProjectionMatrix() {
viewMatrix = calculateViewMatrix()
projectionMatrix = calculateProjectionMatrix(renderWindow.window.sizef)
viewProjectionMatrix = projectionMatrix * viewMatrix
connection.fireEvent(CameraMatrixChangeEvent(
renderWindow = renderWindow,
viewMatrix = viewMatrix,
projectionMatrix = projectionMatrix,
viewProjectionMatrix = viewProjectionMatrix,
))
for (shader in renderWindow.renderSystem.shaders) {
shader.use()
if (shader.uniforms.contains("uViewProjectionMatrix")) {
shader.setMat4("uViewProjectionMatrix", Mat4(viewProjectionMatrix))
}
if (shader.uniforms.contains("uCameraPosition")) {
shader.setVec3("uCameraPosition", connection.player.cameraPosition)
}
}
}
private fun onPositionChange() {
setRotation(connection.player.rotation)
recalculateViewProjectionMatrix()
frustum.recalculate()
connection.fireEvent(FrustumChangeEvent(renderWindow, frustum))
connection.fireEvent(CameraPositionChangeEvent(renderWindow, connection.player.eyePosition))
previousEyePosition = Vec3d(connection.player.eyePosition)
previousRotation = connection.player.rotation.copy()
previousZoom = zoom
setSkyColor()
}
private fun setSkyColor() {
renderWindow[SkyRenderer]?.let { skyRenderer ->
skyRenderer.baseColor = connection.world.getBiome(connection.player.positionInfo.blockPosition)?.skyColor ?: RenderConstants.DEFAULT_SKY_COLOR
connection.world.dimension?.hasSkyLight?.let {
if (it) {
skyRenderer.baseColor = connection.player.positionInfo.biome?.skyColor ?: RenderConstants.DEFAULT_SKY_COLOR
} else {
skyRenderer.baseColor = RenderConstants.BLACK_COLOR
}
} ?: let { skyRenderer.baseColor = RenderConstants.DEFAULT_SKY_COLOR }
}
}
private fun calculateProjectionMatrix(screenDimensions: Vec2): Mat4d {
return glm.perspective(fov.rad, screenDimensions.x.toDouble() / screenDimensions.y, 0.01, 10000.0)
}
private fun calculateViewMatrix(): Mat4d {
val eyePosition = connection.player.eyePosition
return glm.lookAt(eyePosition, eyePosition + cameraFront, CAMERA_UP_VEC3)
}
private fun setRotation(rotation: EntityRotation) {
cameraFront = rotation.front
cameraRight = (cameraFront cross CAMERA_UP_VEC3).normalize()
cameraUp = (cameraRight cross cameraFront).normalize()
recalculateViewProjectionMatrix()
}
fun draw() {
calculateFogDistance()
if (!fogColor.equals()) {
applyFog()
}
//val input = if (renderWindow.inputHandler.currentKeyConsumer == null) {
val input = MovementInput(
pressingForward = renderWindow.inputHandler.isKeyBindingDown(MOVE_FORWARDS_KEYBINDING),
pressingBack = renderWindow.inputHandler.isKeyBindingDown(MOVE_BACKWARDS_KEYBINDING),
pressingLeft = renderWindow.inputHandler.isKeyBindingDown(MOVE_LEFT_KEYBINDING),
pressingRight = renderWindow.inputHandler.isKeyBindingDown(MOVE_RIGHT_KEYBINDING),
jumping = renderWindow.inputHandler.isKeyBindingDown(JUMP_KEYBINDING),
sneaking = renderWindow.inputHandler.isKeyBindingDown(SNEAK_KEYBINDING),
sprinting = renderWindow.inputHandler.isKeyBindingDown(MOVE_SPRINT_KEYBINDING),
flyDown = renderWindow.inputHandler.isKeyBindingDown(FLY_DOWN_KEYBINDING),
flyUp = renderWindow.inputHandler.isKeyBindingDown(FLY_UP_KEYBINDING),
toggleFlyDown = renderWindow.inputHandler.isKeyBindingDown(TOGGLE_FLY_KEYBINDING),
)
//} else {
// MovementInput()
// }
connection.player.input = input
connection.player.tick() // The thread pool might be busy, we force a tick here to avoid lagging
zoom = if (renderWindow.inputHandler.isKeyBindingDown(ZOOM_KEYBINDING)) {
2f
} else {
0.0f
}
val eyePosition = connection.player.eyePosition
if (previousEyePosition != eyePosition || previousRotation != connection.player.rotation || zoom != previousZoom) {
onPositionChange()
} else {
setSkyColor()
}
val cameraFront = cameraFront
target = raycast(eyePosition, cameraFront, blocks = true, fluids = true, entities = true)
nonFluidTarget = raycast(eyePosition, cameraFront, blocks = true, fluids = false, entities = true)
blockTarget = raycast(eyePosition, cameraFront, blocks = true, fluids = false, entities = false) as BlockRaycastHit?
fluidTarget = raycast(eyePosition, cameraFront, blocks = false, fluids = true, entities = false) as FluidRaycastHit?
entityTarget = raycast(eyePosition, cameraFront, blocks = false, fluids = false, entities = true) as EntityRaycastHit?
}
private fun raycastEntity(origin: Vec3d, direction: Vec3d): EntityRaycastHit? {
var currentHit: EntityRaycastHit? = null
for (entity in connection.world.entities) {
if (entity is LocalPlayerEntity) {
continue
}
val hit = VoxelShape(entity.cameraAABB).raycast(origin, direction)
if (!hit.hit) {
continue
}
if ((currentHit?.distance ?: Double.MAX_VALUE) < hit.distance) {
continue
}
currentHit = EntityRaycastHit(origin + direction * hit.distance, hit.distance, hit.direction, entity)
}
return currentHit
}
private fun raycast(origin: Vec3d, direction: Vec3d, blocks: Boolean, fluids: Boolean, entities: Boolean): RaycastHit? {
if (!blocks && !fluids && entities) {
// only raycast entities
return raycastEntity(origin, direction)
}
val currentPosition = Vec3d(origin)
fun getTotalDistance(): Double {
return (origin - currentPosition).length()
}
var hit: RaycastHit? = null
for (i in 0..RAYCAST_MAX_STEPS) {
val blockPosition = currentPosition.floor
val blockState = connection.world[blockPosition]
if (blockState == null) {
currentPosition += direction * (VecUtil.getDistanceToNextIntegerAxisInDirection(currentPosition, direction) + 0.001)
continue
}
val voxelShapeRaycastResult = (blockState.block.getOutlineShape(connection, blockState, blockPosition) + blockPosition + blockPosition.getWorldOffset(blockState.block)).raycast(currentPosition, direction)
if (voxelShapeRaycastResult.hit) {
val distance = getTotalDistance()
currentPosition += direction * voxelShapeRaycastResult.distance
currentPosition += direction * (VecUtil.getDistanceToNextIntegerAxisInDirection(currentPosition, direction) + 0.001)
if (blockState.block is FluidBlock) {
if (!fluids) {
continue
}
hit = FluidRaycastHit(
currentPosition,
distance,
voxelShapeRaycastResult.direction,
blockState,
blockPosition,
blockState.block.fluid,
)
break
}
if (!blocks) {
continue
}
hit = BlockRaycastHit(
currentPosition,
distance,
voxelShapeRaycastResult.direction,
blockState,
blockPosition,
)
break
} else {
currentPosition += direction * (VecUtil.getDistanceToNextIntegerAxisInDirection(currentPosition, direction) + 0.001)
}
}
if (entities) {
val entityRaycastHit = raycastEntity(origin, direction) ?: return hit
hit ?: return null
return (entityRaycastHit.distance < hit.distance).decide(entityRaycastHit, hit)
}
return hit
}
companion object {
val CAMERA_UP_VEC3 = Vec3d(0.0, 1.0, 0.0)
private const val RAYCAST_MAX_STEPS = 100
private val MOVE_SPRINT_KEYBINDING = "minosoft:move_sprint".toResourceLocation()
private val MOVE_FORWARDS_KEYBINDING = "minosoft:move_forward".toResourceLocation()
private val MOVE_BACKWARDS_KEYBINDING = "minosoft:move_backwards".toResourceLocation()
private val MOVE_LEFT_KEYBINDING = "minosoft:move_left".toResourceLocation()
private val MOVE_RIGHT_KEYBINDING = "minosoft:move_right".toResourceLocation()
private val SNEAK_KEYBINDING = "minosoft:move_sneak".toResourceLocation()
private val JUMP_KEYBINDING = "minosoft:move_jump".toResourceLocation()
private val TOGGLE_FLY_KEYBINDING = "minosoft:move_toggle_fly".toResourceLocation()
private val FLY_UP_KEYBINDING = "minosoft:move_fly_up".toResourceLocation()
private val FLY_DOWN_KEYBINDING = "minosoft:move_fly_down".toResourceLocation()
private val ZOOM_KEYBINDING = "minosoft:zoom".toResourceLocation()
private val DROP_ITEM_KEYBINDING = "minosoft:drop_item".toResourceLocation()
private val DROP_ITEM_STACK_KEYBINDING = "minosoft:drop_item_stack".toResourceLocation()
}
}

View File

@ -24,7 +24,7 @@ import de.bixilon.minosoft.data.registries.enchantment.DefaultEnchantments
import de.bixilon.minosoft.data.registries.fluid.DefaultFluids
import de.bixilon.minosoft.data.registries.items.tools.MiningToolItem
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.modding.event.events.BlockBreakAckEvent
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
import de.bixilon.minosoft.protocol.packets.c2s.play.ArmSwingC2SP
@ -98,9 +98,9 @@ class BreakInteractionHandler(
cancelDigging()
return false
}
val raycastHit = renderWindow.inputHandler.camera.nonFluidTarget
val raycastHit = renderWindow.camera.targetHandler.target
if (raycastHit !is BlockRaycastHit) {
if (raycastHit !is BlockTarget) {
cancelDigging()
return false
}
@ -120,7 +120,7 @@ class BreakInteractionHandler(
if (breakPosition != null) {
return
}
connection.sendPacket(PlayerActionC2SP(PlayerActionC2SP.Actions.START_DIGGING, raycastHit.blockPosition, raycastHit.hitDirection))
connection.sendPacket(PlayerActionC2SP(PlayerActionC2SP.Actions.START_DIGGING, raycastHit.blockPosition, raycastHit.direction))
breakPosition = raycastHit.blockPosition
breakBlockState = raycastHit.blockState
@ -130,7 +130,7 @@ class BreakInteractionHandler(
}
fun finishDigging() {
connection.sendPacket(PlayerActionC2SP(PlayerActionC2SP.Actions.FINISHED_DIGGING, raycastHit.blockPosition, raycastHit.hitDirection))
connection.sendPacket(PlayerActionC2SP(PlayerActionC2SP.Actions.FINISHED_DIGGING, raycastHit.blockPosition, raycastHit.direction))
clearDigging()
connection.world.setBlockState(raycastHit.blockPosition, null)

View File

@ -0,0 +1,57 @@
package de.bixilon.minosoft.gui.rendering.input.interaction
import de.bixilon.minosoft.config.key.KeyAction
import de.bixilon.minosoft.config.key.KeyBinding
import de.bixilon.minosoft.config.key.KeyCodes
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.protocol.RateLimiter
import de.bixilon.minosoft.protocol.packets.c2s.play.PlayerActionC2SP
import de.bixilon.minosoft.util.KUtil
import de.bixilon.minosoft.util.KUtil.toResourceLocation
class DropInteractionManager(
private val renderWindow: RenderWindow,
) {
private val connection = renderWindow.connection
private val rateLimiter = RateLimiter()
fun init() {
// ToDo: This creates a weird condition, because we first drop the stack and then the single item
// ToDo: Does this swing the arm?
renderWindow.inputHandler.registerKeyCallback(DROP_ITEM_STACK_KEYBINDING, KeyBinding(
mapOf(
KeyAction.PRESS to setOf(KeyCodes.KEY_Q),
KeyAction.MODIFIER to setOf(KeyCodes.KEY_LEFT_CONTROL)
),
)) { dropItem(true) }
renderWindow.inputHandler.registerKeyCallback(DROP_ITEM_KEYBINDING, KeyBinding(
mapOf(
KeyAction.PRESS to setOf(KeyCodes.KEY_Q),
),
)) { dropItem(false) }
}
fun dropItem(stack: Boolean) {
val time = KUtil.time
val type = if (stack) {
connection.player.inventory.getHotbarSlot()?.count = 0
PlayerActionC2SP.Actions.DROP_ITEM_STACK
} else {
connection.player.inventory.getHotbarSlot()?.let {
it.count--
}
PlayerActionC2SP.Actions.DROP_ITEM
}
rateLimiter += { connection.sendPacket(PlayerActionC2SP(type)) }
}
fun draw(delta: Double) {
rateLimiter.work()
}
companion object {
private val DROP_ITEM_KEYBINDING = "minosoft:drop_item".toResourceLocation()
private val DROP_ITEM_STACK_KEYBINDING = "minosoft:drop_item_stack".toResourceLocation()
}
}

View File

@ -21,8 +21,8 @@ import de.bixilon.minosoft.data.inventory.ItemStack
import de.bixilon.minosoft.data.player.Hands
import de.bixilon.minosoft.data.registries.items.UsableItem
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.input.camera.hit.EntityRaycastHit
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.camera.target.targets.EntityTarget
import de.bixilon.minosoft.protocol.packets.c2s.play.BlockInteractC2SP
import de.bixilon.minosoft.protocol.packets.c2s.play.ItemUseC2SP
import de.bixilon.minosoft.protocol.packets.c2s.play.PlayerActionC2SP
@ -71,16 +71,16 @@ class InteractInteractionHandler(
interactingTicksLeft = 0
}
fun interactBlock(hit: BlockRaycastHit, item: ItemStack?, hand: Hands): InteractionResults {
if (hit.distance >= connection.player.reachDistance) {
fun interactBlock(target: BlockTarget, item: ItemStack?, hand: Hands): InteractionResults {
if (target.distance >= connection.player.reachDistance) {
return InteractionResults.PASS
}
// if out of world (border): return CONSUME
connection.sendPacket(BlockInteractC2SP(
position = hit.blockPosition,
direction = hit.hitDirection,
cursorPosition = Vec3(hit.hitPosition),
position = target.blockPosition,
direction = target.direction,
cursorPosition = Vec3(target.hitPosition),
item = item,
hand = hand,
insideBlock = false, // ToDo: insideBlock
@ -90,7 +90,7 @@ class InteractInteractionHandler(
return InteractionResults.SUCCESS
}
val result = hit.blockState.block.onUse(connection, hit, hand, item)
val result = target.blockState.block.onUse(connection, target, hand, item)
if (result == InteractionResults.SUCCESS) {
return InteractionResults.SUCCESS
}
@ -102,13 +102,13 @@ class InteractInteractionHandler(
return InteractionResults.PASS // ToDo: Check
}
return item.item.interactBlock(connection, hit, hand, item)
return item.item.interactBlock(connection, target, hand, item)
}
fun interactEntityAt(hit: EntityRaycastHit, hand: Hands): InteractionResults {
fun interactEntityAt(target: EntityTarget, hand: Hands): InteractionResults {
// used in armor stands
val player = connection.player
connection.sendPacket(EntityInteractAtC2SP(connection, hit.entity, Vec3(hit.position), hand, player.isSneaking))
connection.sendPacket(EntityInteractAtC2SP(connection, target.entity, Vec3(target.position), hand, player.isSneaking))
if (player.gamemode == Gamemodes.SPECTATOR) {
return InteractionResults.PASS
@ -117,9 +117,9 @@ class InteractInteractionHandler(
return InteractionResults.PASS
}
fun interactEntity(hit: EntityRaycastHit, hand: Hands): InteractionResults {
fun interactEntity(target: EntityTarget, hand: Hands): InteractionResults {
val player = connection.player
connection.sendPacket(EntityInteractC2SP(connection, hit.entity, hand, player.isSneaking))
connection.sendPacket(EntityInteractC2SP(connection, target.entity, hand, player.isSneaking))
if (player.gamemode == Gamemodes.SPECTATOR) {
return InteractionResults.PASS
@ -155,12 +155,12 @@ class InteractInteractionHandler(
// if riding: return
val selectedSlot = connection.player.selectedHotbarSlot
val target = renderWindow.inputHandler.camera.nonFluidTarget
val target = renderWindow.camera.targetHandler.target
for (hand in Hands.VALUES) {
val item = connection.player.inventory[hand]
when (target) {
is EntityRaycastHit -> {
is EntityTarget -> {
var result = interactEntityAt(target, hand)
if (result == InteractionResults.PASS) {
@ -175,7 +175,7 @@ class InteractInteractionHandler(
return
}
}
is BlockRaycastHit -> {
is BlockTarget -> {
val result = interactBlock(target, item, hand)
if (result == InteractionResults.SUCCESS) {
interactionManager.swingHand(hand)

View File

@ -28,6 +28,8 @@ class InteractionManager(
val attack = AttackInteractionHandler(renderWindow)
val `break` = BreakInteractionHandler(renderWindow)
val use = InteractInteractionHandler(renderWindow, this)
val drop = DropInteractionManager(renderWindow)
val spectate = SpectateInteractionManager(renderWindow)
private val swingArmRateLimiter = RateLimiter()
@ -38,6 +40,8 @@ class InteractionManager(
pick.init()
`break`.init()
use.init()
drop.init()
spectate.init()
}
fun draw(delta: Double) {
@ -46,6 +50,8 @@ class InteractionManager(
// attack.draw(delta)
`break`.draw(delta)
use.draw(delta)
drop.draw(delta)
spectate.draw(delta)
swingArmRateLimiter.work()
}

View File

@ -20,8 +20,8 @@ import de.bixilon.minosoft.data.inventory.InventorySlots
import de.bixilon.minosoft.data.inventory.ItemStack
import de.bixilon.minosoft.data.registries.other.containers.PlayerInventory
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.input.camera.hit.EntityRaycastHit
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.camera.target.targets.EntityTarget
import de.bixilon.minosoft.protocol.RateLimiter
import de.bixilon.minosoft.protocol.packets.c2s.play.ItemStackCreateC2SP
import de.bixilon.minosoft.util.KUtil.toResourceLocation
@ -48,25 +48,25 @@ class ItemPickInteractionHandler(
if (!connection.player.baseAbilities.creative) {
return
}
val raycast = renderWindow.inputHandler.camera.nonFluidTarget ?: return
val target = renderWindow.camera.targetHandler.target ?: return
if (raycast.distance > connection.player.reachDistance) {
if (target.distance > connection.player.reachDistance) {
return
}
val itemStack: ItemStack?
when (raycast) {
is BlockRaycastHit -> {
itemStack = ItemStack(raycast.blockState.block.item!!, connection, 1)
when (target) {
is BlockTarget -> {
itemStack = ItemStack(target.blockState.block.item!!, connection, 1)
if (copyNBT) {
val blockEntity = connection.world.getBlockEntity(raycast.blockPosition)
val blockEntity = connection.world.getBlockEntity(target.blockPosition)
blockEntity?.nbt?.let { itemStack.nbt.putAll(it) }
}
}
is EntityRaycastHit -> {
val entity = raycast.entity
is EntityTarget -> {
val entity = target.entity
itemStack = entity.entityType.spawnEgg?.let { ItemStack(it, connection) } ?: let {
entity.equipment[InventorySlots.EquipmentSlots.MAIN_HAND]?.copy()
}

View File

@ -0,0 +1,48 @@
package de.bixilon.minosoft.gui.rendering.input.interaction
import de.bixilon.minosoft.config.key.KeyAction
import de.bixilon.minosoft.config.key.KeyBinding
import de.bixilon.minosoft.config.key.KeyCodes
import de.bixilon.minosoft.data.abilities.Gamemodes
import de.bixilon.minosoft.data.entities.entities.Entity
import de.bixilon.minosoft.data.registries.other.game.event.handlers.gamemode.GamemodeChangeEvent
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.modding.event.events.CameraSetEvent
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
import de.bixilon.minosoft.protocol.RateLimiter
import de.bixilon.minosoft.util.KUtil.toResourceLocation
class SpectateInteractionManager(
private val renderWindow: RenderWindow,
) {
private val connection = renderWindow.connection
private val rateLimiter = RateLimiter()
fun init() {
renderWindow.inputHandler.registerKeyCallback(STOP_SPECTATING, KeyBinding(
mapOf(
KeyAction.PRESS to setOf(KeyCodes.KEY_LEFT_SHIFT),
),
)) { spectate(null) }
renderWindow.connection.registerEvent(CallbackEventInvoker.of<GamemodeChangeEvent> { spectate(null) })
renderWindow.connection.registerEvent(CallbackEventInvoker.of<CameraSetEvent> { spectate(it.entity) })
}
fun spectate(entity: Entity?) {
var entity = entity ?: connection.player
if (connection.player.gamemode != Gamemodes.SPECTATOR) {
entity = connection.player
}
renderWindow.camera.matrixHandler.entity = entity
}
fun draw(delta: Double) {
rateLimiter.work()
}
companion object {
private val STOP_SPECTATING = "minosoft:stop_spectating".toResourceLocation()
}
}

View File

@ -21,7 +21,7 @@ import de.bixilon.minosoft.config.profile.delegate.watcher.entry.MapProfileDeleg
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.input.camera.Camera
import de.bixilon.minosoft.gui.rendering.input.CameraInput
import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionManager
import de.bixilon.minosoft.gui.rendering.modding.events.input.MouseMoveEvent
import de.bixilon.minosoft.gui.rendering.modding.events.input.RawCharInputEvent
@ -38,7 +38,7 @@ class RenderWindowInputHandler(
val renderWindow: RenderWindow,
) {
val connection: PlayConnection = renderWindow.connection
val camera: Camera = Camera(connection, renderWindow)
val cameraInput = CameraInput(renderWindow, renderWindow.camera.matrixHandler)
private val profile = connection.profiles.controls
private val keyBindingCallbacks: MutableMap<ResourceLocation, KeyBindingCallbackPair> = mutableMapOf()
@ -80,7 +80,8 @@ class RenderWindowInputHandler(
//if (renderWindow.inputHandler.currentKeyConsumer != null) {
// return
//}
camera.mouseCallback(it.delta)
cameraInput.mouseCallback(it.delta)
})
profile::keyBindings.profileWatchMap(this, profile = profile) {
@ -93,6 +94,7 @@ class RenderWindowInputHandler(
keyBinding.keyBinding = it.valueAdded
}
}
cameraInput.init()
}
@ -275,8 +277,7 @@ class RenderWindowInputHandler(
}
fun draw(delta: Double) {
camera.draw()
cameraInput.update()
interactionManager.draw(delta)
}
}

View File

@ -15,20 +15,20 @@ package de.bixilon.minosoft.gui.rendering.modding.events
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.Rendering
import glm_.mat4x4.Mat4d
import glm_.mat4x4.Mat4
class CameraMatrixChangeEvent(
renderWindow: RenderWindow = Rendering.currentContext!!,
viewMatrix: Mat4d,
projectionMatrix: Mat4d,
viewProjectionMatrix: Mat4d,
viewMatrix: Mat4,
projectionMatrix: Mat4,
viewProjectionMatrix: Mat4,
) : RenderEvent(renderWindow) {
val viewMatrix: Mat4d = viewMatrix
get() = Mat4d(field)
val viewMatrix: Mat4 = viewMatrix
get() = Mat4(field)
val projectionMatrix: Mat4d = projectionMatrix
get() = Mat4d(field)
val projectionMatrix: Mat4 = projectionMatrix
get() = Mat4(field)
val viewProjectionMatrix: Mat4d = viewProjectionMatrix
get() = Mat4d(field)
val viewProjectionMatrix: Mat4 = viewProjectionMatrix
get() = Mat4(field)
}

View File

@ -15,12 +15,12 @@ package de.bixilon.minosoft.gui.rendering.modding.events
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.Rendering
import glm_.vec3.Vec3d
import glm_.vec3.Vec3
class CameraPositionChangeEvent(
renderWindow: RenderWindow = Rendering.currentContext!!,
newPosition: Vec3d,
newPosition: Vec3,
) : RenderEvent(renderWindow) {
val newPosition: Vec3d = newPosition
get() = Vec3d(field)
val newPosition: Vec3 = newPosition
get() = Vec3(field)
}

View File

@ -15,7 +15,7 @@ package de.bixilon.minosoft.gui.rendering.modding.events
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.Rendering
import de.bixilon.minosoft.gui.rendering.input.camera.frustum.Frustum
import de.bixilon.minosoft.gui.rendering.camera.frustum.Frustum
class FrustumChangeEvent(
renderWindow: RenderWindow = Rendering.currentContext!!,

View File

@ -14,7 +14,6 @@
package de.bixilon.minosoft.gui.rendering.sky
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.fluid.DefaultFluids
import de.bixilon.minosoft.data.text.ChatColors
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.RenderConstants
@ -35,9 +34,7 @@ import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import glm_.func.rad
import glm_.mat4x4.Mat4
import glm_.mat4x4.Mat4d
import glm_.vec3.Vec3
import glm_.vec3.Vec3d
class SkyRenderer(
private val connection: PlayConnection,
@ -49,7 +46,7 @@ class SkyRenderer(
private val skyboxMesh = SkyboxMesh(renderWindow)
private var skySunMesh = SimpleTextureMesh(renderWindow)
private lateinit var sunTexture: AbstractTexture
private var sunMatrixUpToDate: Boolean = true
private var updateSun: Boolean = true
var baseColor = RenderConstants.DEFAULT_SKY_COLOR
@ -69,22 +66,21 @@ class SkyRenderer(
}
})
connection.registerEvent(CallbackEventInvoker.of<TimeChangeEvent> {
if (connection.world.time != it.time) {
sunMatrixUpToDate = true
if (connection.world.time.time != it.time) {
updateSun = true
}
})
sunTexture = renderWindow.textureManager.staticTextures.createTexture(SUN_TEXTURE_RESOURCE_LOCATION)
}
private fun setSunMatrix(projectionViewMatrix: Mat4d) {
val timeAngle = (connection.world.skyAngle * 360.0).rad
val rotatedMatrix = if (timeAngle == 0.0) {
private fun setSunMatrix(projectionViewMatrix: Mat4) {
val timeAngle = (connection.world.time.skyAngle * 360.0f).rad
val rotatedMatrix = if (timeAngle == 0.0f) {
projectionViewMatrix
} else {
projectionViewMatrix.rotate(timeAngle, Vec3d(0.0f, 0.0f, 1.0f))
projectionViewMatrix.rotate(timeAngle, Vec3(0.0f, 0.0f, 1.0f))
}
skySunShader.use().setMat4("uSkyViewProjectionMatrix", Mat4(rotatedMatrix))
sunMatrixUpToDate = false
skySunShader.use().setMat4("uSkyViewProjectionMatrix", rotatedMatrix)
}
override fun postInit() {
@ -92,8 +88,8 @@ class SkyRenderer(
}
private fun drawSun() {
if (sunMatrixUpToDate) {
setSunMatrix(renderWindow.inputHandler.camera.projectionMatrix * renderWindow.inputHandler.camera.viewMatrix.toMat3().toMat4())
if (updateSun) {
setSunMatrix(renderWindow.camera.matrixHandler.projectionMatrix * renderWindow.camera.matrixHandler.viewMatrix.toMat3().toMat4())
skySunMesh.unload()
skySunMesh = SimpleTextureMesh(renderWindow)
@ -105,11 +101,12 @@ class SkyRenderer(
position = position,
texture = sunTexture,
uv = uv,
tintColor = ChatColors.WHITE.with(alpha = 1.0f - connection.world.rainGradient), // ToDo: Depends on time
tintColor = ChatColors.WHITE.with(alpha = 1.0f - connection.world.weather.rainGradient), // ToDo: Depends on time
)
}
)
skySunMesh.load()
updateSun = false
}
renderSystem.enable(RenderingCapabilities.BLENDING)
@ -123,18 +120,18 @@ class SkyRenderer(
val brightness = 1.0f
val skyColor = RGBColor((baseColor.red * brightness).toInt(), (baseColor.green * brightness).toInt(), (baseColor.blue * brightness).toInt())
renderWindow.inputHandler.camera.fogColor.value = if (connection.player.submergedFluid?.resourceLocation == DefaultFluids.WATER) {
connection.player.positionInfo.biome?.waterFogColor ?: skyColor
} else {
skyColor
}
baseColor = connection.world.getBiome(connection.player.positionInfo.blockPosition)?.skyColor ?: RenderConstants.DEFAULT_SKY_COLOR
for (shader in renderWindow.renderSystem.shaders) {
if (shader.uniforms.contains("uSkyColor")) {
shader.use().setRGBColor("uSkyColor", skyColor)
connection.world.dimension?.hasSkyLight?.let {
baseColor = if (it) {
connection.player.positionInfo.biome?.skyColor ?: RenderConstants.DEFAULT_SKY_COLOR
} else {
RenderConstants.BLACK_COLOR
}
}
} ?: let { baseColor = RenderConstants.DEFAULT_SKY_COLOR }
skyboxShader.use().setRGBColor("uSkyColor", skyColor)
}
private fun drawSkybox() {

View File

@ -17,7 +17,7 @@ import de.bixilon.minosoft.config.profile.delegate.watcher.SimpleProfileDelegate
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.world.AbstractAudioPlayer
import de.bixilon.minosoft.gui.rendering.Rendering
import de.bixilon.minosoft.gui.rendering.input.camera.Camera
import de.bixilon.minosoft.gui.rendering.camera.MatrixHandler
import de.bixilon.minosoft.gui.rendering.modding.events.CameraPositionChangeEvent
import de.bixilon.minosoft.gui.rendering.sound.sounds.Sound
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY
@ -96,7 +96,7 @@ class AudioPlayer(
connection.registerEvent(CallbackEventInvoker.of<CameraPositionChangeEvent> {
queue += {
listener.position = Vec3(it.newPosition)
listener.setOrientation(it.renderWindow.inputHandler.camera.cameraFront, Camera.CAMERA_UP_VEC3)
listener.setOrientation(it.renderWindow.camera.matrixHandler.cameraFront, MatrixHandler.CAMERA_UP_VEC3)
}
})

View File

@ -14,9 +14,7 @@
package de.bixilon.minosoft.gui.rendering.sound
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY
import glm_.vec3.Vec3
import glm_.vec3.Vec3d
import org.lwjgl.openal.AL10.*
class SoundListener(position: Vec3 = Vec3.EMPTY) {
@ -36,13 +34,13 @@ class SoundListener(position: Vec3 = Vec3.EMPTY) {
get() = alGetListenerf(AL_MAX_GAIN)
set(value) = alListenerf(AL_MAX_GAIN, value)
fun setOrientation(look: Vec3d, up: Vec3d) {
alListenerfv(AL_ORIENTATION, floatArrayOf(look.x.toFloat(), look.y.toFloat(), look.z.toFloat(), up.x.toFloat(), up.y.toFloat(), up.z.toFloat()))
fun setOrientation(look: Vec3, up: Vec3) {
alListenerfv(AL_ORIENTATION, floatArrayOf(look.x, look.y, look.z, up.x, up.y, up.z))
}
init {
this.position = position
this.velocity = Vec3.EMPTY
setOrientation(Vec3d.EMPTY, Vec3d(0.0, 1.0, 0.0))
setOrientation(Vec3.EMPTY, Vec3(0.0, 1.0, 0.0))
}
}

View File

@ -29,7 +29,7 @@ import kotlin.math.max
import kotlin.math.pow
import kotlin.math.sin
@Deprecated("Needs refactoring")
class LightMap(private val connection: PlayConnection) {
private val profile = connection.profiles.rendering.light
private val nightVisionStatusEffect = connection.registries.statusEffectRegistry[DefaultStatusEffects.NIGHT_VISION]
@ -50,7 +50,7 @@ class LightMap(private val connection: PlayConnection) {
}
fun update() {
val skyGradient = connection.world.lightBase.toFloat()
val skyGradient = connection.world.time.lightBase.toFloat()
// ToDo: Lightning

View File

@ -46,7 +46,6 @@ import de.bixilon.minosoft.gui.rendering.util.VecUtil.of
import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.toVec3
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.EMPTY
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.toVec3
import de.bixilon.minosoft.gui.rendering.world.mesh.VisibleMeshes
@ -87,7 +86,7 @@ class WorldRenderer(
) : Renderer, OpaqueDrawable, TranslucentDrawable, TransparentDrawable {
private val profile = connection.profiles.block
override val renderSystem: RenderSystem = renderWindow.renderSystem
private val frustum = renderWindow.inputHandler.camera.frustum
private val frustum = renderWindow.camera.matrixHandler.frustum
private val shader = renderSystem.createShader("minosoft:world".toResourceLocation())
private val transparentShader = renderSystem.createShader("minosoft:world".toResourceLocation())
private val world: World = connection.world
@ -660,7 +659,7 @@ class WorldRenderer(
private fun onFrustumChange() {
var sortQueue = false
val cameraPosition = connection.player.cameraPosition.toVec3()
val cameraPosition = connection.player.cameraPosition
if (this.cameraPosition != cameraPosition) {
this.cameraPosition = cameraPosition
this.cameraChunkPosition = connection.player.positionInfo.chunkPosition

View File

@ -21,7 +21,7 @@ import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.Renderer
import de.bixilon.minosoft.gui.rendering.RendererBuilder
import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit
import de.bixilon.minosoft.gui.rendering.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.system.base.DepthFunctions
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
import de.bixilon.minosoft.gui.rendering.system.base.phases.OtherDrawable
@ -82,7 +82,7 @@ class BlockOutlineRenderer(
}
override fun prepareDraw() {
val raycastHit = renderWindow.inputHandler.camera.target.nullCast<BlockRaycastHit>()
val raycastHit = renderWindow.camera.targetHandler.target.nullCast<BlockTarget>()
var currentMesh = currentMesh

View File

@ -0,0 +1,10 @@
package de.bixilon.minosoft.modding.event.events
import de.bixilon.minosoft.data.entities.entities.Entity
import de.bixilon.minosoft.modding.event.events.connection.play.PlayConnectionEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
class CameraSetEvent(
connection: PlayConnection,
val entity: Entity,
) : PlayConnectionEvent(connection)

View File

@ -16,6 +16,7 @@ import de.bixilon.minosoft.modding.event.EventInitiators
import de.bixilon.minosoft.modding.event.events.connection.play.PlayConnectionEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.packets.s2c.play.WorldTimeSetS2CP
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
class TimeChangeEvent(
connection: PlayConnection,
@ -25,5 +26,5 @@ class TimeChangeEvent(
) : PlayConnectionEvent(connection, initiator) {
constructor(connection: PlayConnection, packet: WorldTimeSetS2CP) : this(connection, EventInitiators.SERVER, packet.age, packet.time)
constructor(connection: PlayConnection, packet: WorldTimeSetS2CP) : this(connection, EventInitiators.SERVER, packet.age, packet.time % ProtocolDefinition.TICKS_PER_DAY)
}

View File

@ -19,6 +19,9 @@ import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType
import java.util.*
/**
* Teleports our self in spectator mode to an entity
*/
class EntitySpectateC2SP(
val entityUUID: UUID,
) : PlayC2SPacket {

View File

@ -12,6 +12,8 @@
*/
package de.bixilon.minosoft.protocol.packets.s2c.play
import de.bixilon.minosoft.modding.event.events.CameraSetEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
import de.bixilon.minosoft.util.logging.Log
@ -21,6 +23,11 @@ import de.bixilon.minosoft.util.logging.LogMessageType
class CameraS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
val entityId: Int = buffer.readVarInt()
override fun handle(connection: PlayConnection) {
val entity = connection.world.entities[entityId] ?: return
connection.fireEvent(CameraSetEvent(connection, entity))
}
override fun log(reducedLog: Boolean) {
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Camera (entityId=$entityId)" }
}

View File

@ -16,6 +16,7 @@ import de.bixilon.minosoft.modding.event.events.TimeChangeEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.logging.Log
import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType
@ -25,8 +26,8 @@ class WorldTimeSetS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
val time = buffer.readLong()
override fun handle(connection: PlayConnection) {
connection.world.age = age
connection.world.time = time
connection.world.time.age = age
connection.world.time.time = time % ProtocolDefinition.TICKS_PER_DAY
connection.fireEvent(TimeChangeEvent(connection, this))
}

View File

@ -19,7 +19,7 @@ import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.protocol.network.connection.Connection
import de.bixilon.minosoft.util.Util
import de.bixilon.minosoft.util.nbt.tag.NBTTagTypes
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.type
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.nbtType
import glm_.vec3.Vec3
import glm_.vec3.Vec3d
import glm_.vec3.Vec3i
@ -178,7 +178,7 @@ open class OutByteBuffer(open val connection: Connection? = null) {
this.writeNBTTagType(type)
}
val type = tag.type
val type = tag.nbtType
writeNBTTagType(type)
if (type == NBTTagTypes.END) {
return
@ -206,7 +206,7 @@ open class OutByteBuffer(open val connection: Connection? = null) {
this.writeNBTTagType(if (tag.isEmpty()) {
NBTTagTypes.END
} else {
tag.iterator().next().type
tag.iterator().next().nbtType
})
writeInt(tag.size)
@ -217,7 +217,7 @@ open class OutByteBuffer(open val connection: Connection? = null) {
}
is Map<*, *> -> {
for ((key, value) in tag) {
val valueType = value.type
val valueType = value.nbtType
if (valueType == NBTTagTypes.END) {
error("NBT does not support null as value in a compound tag!")
}

View File

@ -60,7 +60,7 @@ object NBTUtil {
return null
}
val Any?.type: NBTTagTypes
val Any?.nbtType: NBTTagTypes
get() {
return when (this) {
null -> NBTTagTypes.END
@ -76,7 +76,7 @@ object NBTUtil {
is Map<*, *> -> NBTTagTypes.COMPOUND
is IntArray -> NBTTagTypes.INT_ARRAY
is LongArray -> NBTTagTypes.LONG_ARRAY
else -> throw IllegalArgumentException("NBT does not support ${type::class.java.name}")
else -> throw IllegalArgumentException("NBT does not support ${this::class.java.name}")
}
}
}