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/ out/
.idea/ .idea/
*.iml *.iml

View File

@ -5,17 +5,3 @@ There is a config file located in:
* Windows: `%AppData%\Minosoft` * Windows: `%AppData%\Minosoft`
* MacOS: `"~/Library/Application Support/Minosoft"` * MacOS: `"~/Library/Application Support/Minosoft"`
* Linux (and all others): `~\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.cos
import glm_.func.rad import glm_.func.rad
import glm_.func.sin import glm_.func.sin
import glm_.vec3.Vec3d import glm_.vec3.Vec3
data class EntityRotation( data class EntityRotation(
val yaw: Double, val yaw: Double,
val pitch: Double, val pitch: Double,
) { ) {
val front: Vec3d val front: Vec3
get() = Vec3d( get() = Vec3(
(yaw + 90).rad.cos * (-pitch).rad.cos, (yaw + 90).rad.cos * (-pitch).rad.cos,
(-pitch).rad.sin, (-pitch).rad.sin,
(yaw + 90).rad.sin * (-pitch).rad.cos (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.floor
import de.bixilon.minosoft.gui.rendering.util.VecUtil.horizontal 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.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.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
@ -128,10 +128,10 @@ abstract class Entity(
} }
open val positionInfo = EntityPositionInfo(connection, this) open val positionInfo = EntityPositionInfo(connection, this)
val eyePosition: Vec3d val eyePosition: Vec3
get() = cameraPosition + Vec3(0.0f, eyeHeight, 0.0f) get() = cameraPosition + Vec3(0.0f, eyeHeight, 0.0f)
var cameraPosition: Vec3d = position.toVec3d var cameraPosition: Vec3 = position.toVec3
private set private set
open val spawnSprintingParticles: Boolean open val spawnSprintingParticles: Boolean
@ -362,7 +362,7 @@ abstract class Entity(
postTick() postTick()
lastTickTime = currentTime 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 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.Registries
import de.bixilon.minosoft.data.registries.registries.registry.RegistryItem 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.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.input.interaction.InteractionResults
import de.bixilon.minosoft.gui.rendering.tint.TintProvider import de.bixilon.minosoft.gui.rendering.tint.TintProvider
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
@ -75,7 +75,7 @@ open class Block(
return resourceLocation.full 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 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 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) { if (blockEntityType == null) {
return InteractionResults.PASS 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.blocks.properties.BlockProperties
import de.bixilon.minosoft.data.registries.items.tools.ShovelItem import de.bixilon.minosoft.data.registries.items.tools.ShovelItem
import de.bixilon.minosoft.data.registries.registries.Registries 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.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.campfire.CampfireSmokeParticle
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.fire.SmokeParticle 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) // ToDo: Ignite (flint and steel, etc)
if (itemStack?.item !is ShovelItem || hit.blockState.properties[BlockProperties.LIT] != true) { if (itemStack?.item !is ShovelItem || target.blockState.properties[BlockProperties.LIT] != true) {
return super.onUse(connection, hit, hand, itemStack) return super.onUse(connection, target, hand, itemStack)
} }
connection.world.setBlockState(hit.blockPosition, hit.blockState.withProperties(BlockProperties.LIT to false)) connection.world.setBlockState(target.blockPosition, target.blockState.withProperties(BlockProperties.LIT to false))
extinguish(connection, hit.blockState, hit.blockPosition) extinguish(connection, target.blockState, target.blockPosition)
return InteractionResults.SUCCESS 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.blocks.properties.BlockProperties
import de.bixilon.minosoft.data.registries.materials.DefaultMaterials import de.bixilon.minosoft.data.registries.materials.DefaultMaterials
import de.bixilon.minosoft.data.registries.registries.Registries 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.input.interaction.InteractionResults
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
open class DoorBlock(resourceLocation: ResourceLocation, registries: Registries, data: Map<String, Any>) : DoubleSizeBlock(resourceLocation, registries, data) { 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() TODO()
} }
override fun onUse(connection: PlayConnection, hit: BlockRaycastHit, hand: Hands, itemStack: ItemStack?): InteractionResults { override fun onUse(connection: PlayConnection, target: BlockTarget, hand: Hands, itemStack: ItemStack?): InteractionResults {
if (hit.blockState.material.resourceLocation == DefaultMaterials.METAL) { if (target.blockState.material.resourceLocation == DefaultMaterials.METAL) {
return InteractionResults.CONSUME 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 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.ResourceLocation
import de.bixilon.minosoft.data.registries.blocks.BlockFactory import de.bixilon.minosoft.data.registries.blocks.BlockFactory
import de.bixilon.minosoft.data.registries.registries.Registries 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.input.interaction.InteractionResults
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
open class NoteBlock(resourceLocation: ResourceLocation, registries: Registries, data: Map<String, Any>) : Block(resourceLocation, registries, data) { 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 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.properties.BlockProperties
import de.bixilon.minosoft.data.registries.blocks.types.Block import de.bixilon.minosoft.data.registries.blocks.types.Block
import de.bixilon.minosoft.data.registries.registries.Registries 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.input.interaction.InteractionResults
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
abstract class AbstractButtonBlock(resourceLocation: ResourceLocation, registries: Registries, data: Map<String, Any>) : Block(resourceLocation, registries, data) { 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 { override fun onUse(connection: PlayConnection, target: BlockTarget, hand: Hands, itemStack: ItemStack?): InteractionResults {
if (hit.blockState.properties[BlockProperties.POWERED] == true) { if (target.blockState.properties[BlockProperties.POWERED] == true) {
return InteractionResults.CONSUME 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 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.MinecraftBlocks
import de.bixilon.minosoft.data.registries.blocks.types.Block import de.bixilon.minosoft.data.registries.blocks.types.Block
import de.bixilon.minosoft.data.registries.registries.Registries 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.gui.rendering.util.VecUtil.plus
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection 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 return blockState.block.resourceLocation == MinecraftBlocks.DIRT || blockState.block.resourceLocation == MinecraftBlocks.FARMLAND
} }
override fun getPlacementState(connection: PlayConnection, hit: BlockRaycastHit): BlockState? { override fun getPlacementState(connection: PlayConnection, target: BlockTarget): BlockState? {
val below = connection.world[hit.blockPosition + hit.hitDirection + Directions.DOWN] ?: return null val below = connection.world[target.blockPosition + target.direction + Directions.DOWN] ?: return null
if (!canPlaceOn(below)) { if (!canPlaceOn(below)) {
return null return null
} }
return super.getPlacementState(connection, hit) return super.getPlacementState(connection, target)
} }
companion object : BlockFactory<PlantBlock> { 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.BlockState
import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties
import de.bixilon.minosoft.data.registries.registries.Registries 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.input.interaction.InteractionResults
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
open class ComparatorBlock(resourceLocation: ResourceLocation, registries: Registries, data: Map<String, Any>) : RedstoneGateBlock(resourceLocation, registries, data) { 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() TODO()
} }
override fun onUse(connection: PlayConnection, hit: BlockRaycastHit, hand: Hands, itemStack: ItemStack?): InteractionResults { override fun onUse(connection: PlayConnection, target: BlockTarget, hand: Hands, itemStack: ItemStack?): InteractionResults {
connection.world[hit.blockPosition] = hit.blockState.cycle(BlockProperties.STRUCTURE_BLOCK_MODE) connection.world[target.blockPosition] = target.blockState.cycle(BlockProperties.STRUCTURE_BLOCK_MODE)
return InteractionResults.SUCCESS 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.BlockState
import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties
import de.bixilon.minosoft.data.registries.registries.Registries 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.input.interaction.InteractionResults
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
open class RepeaterBlock(resourceLocation: ResourceLocation, registries: Registries, data: Map<String, Any>) : RedstoneGateBlock(resourceLocation, registries, data) { 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() TODO()
} }
override fun onUse(connection: PlayConnection, hit: BlockRaycastHit, hand: Hands, itemStack: ItemStack?): InteractionResults { override fun onUse(connection: PlayConnection, target: BlockTarget, hand: Hands, itemStack: ItemStack?): InteractionResults {
connection.world[hit.blockPosition] = hit.blockState.cycle(BlockProperties.REPEATER_DELAY) connection.world[target.blockPosition] = target.blockState.cycle(BlockProperties.REPEATER_DELAY)
return InteractionResults.SUCCESS 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.particle.data.DustParticleData
import de.bixilon.minosoft.data.registries.registries.Registries import de.bixilon.minosoft.data.registries.registries.Registries
import de.bixilon.minosoft.data.text.Colors 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.input.interaction.InteractionResults
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.dust.DustParticle import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.dust.DustParticle
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY 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() TODO()
} }
override fun onUse(connection: PlayConnection, hit: BlockRaycastHit, hand: Hands, itemStack: ItemStack?): InteractionResults { override fun onUse(connection: PlayConnection, target: BlockTarget, hand: Hands, itemStack: ItemStack?): InteractionResults {
val nextState = hit.blockState.cycle(BlockProperties.POWERED) val nextState = target.blockState.cycle(BlockProperties.POWERED)
connection.world[hit.blockPosition] = nextState connection.world[target.blockPosition] = nextState
spawnParticles(connection, nextState, hit.blockPosition, 1.0f) spawnParticles(connection, nextState, target.blockPosition, 1.0f)
return InteractionResults.SUCCESS 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.RegistryItem
import de.bixilon.minosoft.data.registries.registries.registry.ResourceLocationDeserializer import de.bixilon.minosoft.data.registries.registries.registry.ResourceLocationDeserializer
import de.bixilon.minosoft.data.registries.registries.registry.Translatable 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.camera.target.targets.BlockTarget
import de.bixilon.minosoft.gui.rendering.input.camera.hit.EntityRaycastHit import de.bixilon.minosoft.gui.rendering.camera.target.targets.EntityTarget
import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionResults import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionResults
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.util.KUtil.toBoolean import de.bixilon.minosoft.util.KUtil.toBoolean
@ -69,15 +69,15 @@ open class Item(
return 1.0f 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 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 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 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.blocks.types.Block
import de.bixilon.minosoft.data.registries.items.Item import de.bixilon.minosoft.data.registries.items.Item
import de.bixilon.minosoft.data.registries.registries.Registries 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.input.interaction.InteractionResults
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plusAssign import de.bixilon.minosoft.gui.rendering.util.VecUtil.plusAssign
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
@ -37,14 +37,14 @@ open class BlockItem(
this::block.inject(data["block"]) 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) { if (!connection.player.gamemode.canBuild) {
return InteractionResults.PASS return InteractionResults.PASS
} }
val placePosition = raycastHit.blockPosition val placePosition = target.blockPosition
if (!raycastHit.blockState.material.replaceable) { if (!target.blockState.material.replaceable) {
placePosition += raycastHit.hitDirection placePosition += target.direction
if (connection.world[placePosition]?.material?.replaceable == false) { if (connection.world[placePosition]?.material?.replaceable == false) {
return InteractionResults.PASS return InteractionResults.PASS
@ -62,7 +62,7 @@ open class BlockItem(
var placeBlockState: BlockState = block!!.defaultState var placeBlockState: BlockState = block!!.defaultState
try { try {
placeBlockState = block.getPlacementState(connection, raycastHit) ?: return InteractionResults.PASS placeBlockState = block.getPlacementState(connection, target) ?: return InteractionResults.PASS
} catch (exception: Throwable) { } catch (exception: Throwable) {
exception.printStackTrace() 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.ResourceLocation
import de.bixilon.minosoft.data.registries.blocks.types.Block import de.bixilon.minosoft.data.registries.blocks.types.Block
import de.bixilon.minosoft.data.registries.registries.Registries 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.input.interaction.InteractionResults
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.util.KUtil.mapCast import de.bixilon.minosoft.util.KUtil.mapCast
@ -39,12 +39,12 @@ open class AxeItem(
entries.toMap() 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) { if (!connection.profiles.controls.interaction.stripping) {
return InteractionResults.CONSUME 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 { 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.BlockState
import de.bixilon.minosoft.data.registries.blocks.types.Block import de.bixilon.minosoft.data.registries.blocks.types.Block
import de.bixilon.minosoft.data.registries.registries.Registries 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.input.interaction.InteractionResults
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
@ -42,16 +42,16 @@ open class HoeItem(
entries.toMap() 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) { if (!connection.profiles.controls.interaction.tilling) {
return InteractionResults.CONSUME return InteractionResults.CONSUME
} }
if (connection.world[raycastHit.blockPosition + Directions.UP] != null) { if (connection.world[target.blockPosition + Directions.UP] != null) {
return InteractionResults.PASS 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 { 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.BlockState
import de.bixilon.minosoft.data.registries.blocks.types.Block import de.bixilon.minosoft.data.registries.blocks.types.Block
import de.bixilon.minosoft.data.registries.registries.Registries 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.input.interaction.InteractionResults
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection 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) { if (!connection.profiles.controls.interaction.flattening) {
return InteractionResults.CONSUME return InteractionResults.CONSUME
} }
if (connection.world[raycastHit.blockPosition + Directions.UP] != null) { if (connection.world[target.blockPosition + Directions.UP] != null) {
return InteractionResults.PASS 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 val RESOURCE_LOCATION: ResourceLocation = "minecraft:rain_gradient_set".toResourceLocation()
override fun handle(data: Float, connection: PlayConnection) { 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 val RESOURCE_LOCATION: ResourceLocation = "minecraft:thunder_gradient_set".toResourceLocation()
override fun handle(data: Float, connection: PlayConnection) { 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 val RESOURCE_LOCATION: ResourceLocation = "minecraft:rain_start".toResourceLocation()
override fun handle(data: Float, connection: PlayConnection) { override fun handle(data: Float, connection: PlayConnection) {
connection.world.raining = true connection.world.weather.raining = true
connection.world.rainGradient = 1.0f 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 val RESOURCE_LOCATION: ResourceLocation = "minecraft:rain_stop".toResourceLocation()
override fun handle(data: Float, connection: PlayConnection) { override fun handle(data: Float, connection: PlayConnection) {
connection.world.raining = false connection.world.weather.raining = false
connection.world.rainGradient = 0.0f 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.registries.dimension.DimensionProperties
import de.bixilon.minosoft.data.world.biome.accessor.BiomeAccessor import de.bixilon.minosoft.data.world.biome.accessor.BiomeAccessor
import de.bixilon.minosoft.data.world.biome.accessor.NoiseBiomeAccessor import de.bixilon.minosoft.data.world.biome.accessor.NoiseBiomeAccessor
import de.bixilon.minosoft.data.world.time.WorldTime
import de.bixilon.minosoft.data.world.view.WorldView 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.ParticleRenderer
import de.bixilon.minosoft.gui.rendering.particle.types.Particle import de.bixilon.minosoft.gui.rendering.particle.types.Particle
import de.bixilon.minosoft.gui.rendering.util.VecUtil.blockPosition 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.ChunkDataChangeEvent
import de.bixilon.minosoft.modding.event.events.ChunkUnloadEvent import de.bixilon.minosoft.modding.event.events.ChunkUnloadEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection 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.lockMapOf
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
import de.bixilon.minosoft.util.MMath
import de.bixilon.minosoft.util.ReadWriteLock import de.bixilon.minosoft.util.ReadWriteLock
import de.bixilon.minosoft.util.chunk.ChunkUtil.canBuildBiomeCache import de.bixilon.minosoft.util.chunk.ChunkUtil.canBuildBiomeCache
import de.bixilon.minosoft.util.chunk.ChunkUtil.getChunkNeighbourPositions 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.chunk.ChunkUtil.received
import de.bixilon.minosoft.util.collections.LockMap import de.bixilon.minosoft.util.collections.LockMap
import de.bixilon.minosoft.util.delegate.DelegateManager.delegate import de.bixilon.minosoft.util.delegate.DelegateManager.delegate
import glm_.func.common.clamp
import glm_.vec2.Vec2i import glm_.vec2.Vec2i
import glm_.vec3.Vec3 import glm_.vec3.Vec3
import glm_.vec3.Vec3i import glm_.vec3.Vec3i
import kotlin.math.PI
import kotlin.math.abs
import kotlin.math.cos
import kotlin.random.Random import kotlin.random.Random
/** /**
@ -70,11 +66,8 @@ class World(
var difficulty: Difficulties? = null var difficulty: Difficulties? = null
var difficultyLocked = false var difficultyLocked = false
var hashedSeed = 0L var hashedSeed = 0L
var time = 0L val time = WorldTime(this)
var age = 0L val weather = WorldWeather()
var raining = false
var rainGradient = 0.0f
var thunderGradient = 0.0f
val view = WorldView(connection) val view = WorldView(connection)
private val random = Random private val random = Random
@ -234,25 +227,6 @@ class World(
return get(blockPosition.chunkPosition)?.getLight(blockPosition.inChunkPosition) ?: 0x00 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 * @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.BaseComponent
import de.bixilon.minosoft.data.text.ChatColors import de.bixilon.minosoft.data.text.ChatColors
import de.bixilon.minosoft.data.text.ChatComponent 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.entity.EntityHitboxRenderer
import de.bixilon.minosoft.gui.rendering.font.Font import de.bixilon.minosoft.gui.rendering.font.Font
import de.bixilon.minosoft.gui.rendering.font.FontLoader import de.bixilon.minosoft.gui.rendering.font.FontLoader
@ -76,6 +77,7 @@ class RenderWindow(
private val profile = connection.profiles.rendering private val profile = connection.profiles.rendering
val window: BaseWindow = GLFWWindow(this, connection) val window: BaseWindow = GLFWWindow(this, connection)
val renderSystem: RenderSystem = OpenGLRenderSystem(this) val renderSystem: RenderSystem = OpenGLRenderSystem(this)
val camera = Camera(this)
var initialized = false var initialized = false
private set private set
private lateinit var renderThread: Thread private lateinit var renderThread: Thread
@ -163,7 +165,7 @@ class RenderWindow(
window.init(connection.profiles.rendering) window.init(connection.profiles.rendering)
window.setDefaultIcon(connection.assetsManager) window.setDefaultIcon(connection.assetsManager)
inputHandler.camera.init(this) camera.init()
tintManager.init(connection.assetsManager) tintManager.init(connection.assetsManager)
@ -360,6 +362,7 @@ class RenderWindow(
window.pollEvents() window.pollEvents()
inputHandler.draw(deltaFrameTime) inputHandler.draw(deltaFrameTime)
camera.draw()
// handle opengl context tasks, but limit it per frame // handle opengl context tasks, but limit it per frame
queue.timeWork(RenderConstants.MAXIMUM_QUEUE_TIME_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. * 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.data.registries.AABB
import de.bixilon.minosoft.gui.rendering.RenderConstants 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.VecUtil.of
import de.bixilon.minosoft.gui.rendering.util.vec.vec4.Vec4Util.dot import de.bixilon.minosoft.gui.rendering.util.vec.vec4.Vec4Util.dot
import de.bixilon.minosoft.util.KUtil import de.bixilon.minosoft.util.KUtil
import de.bixilon.minosoft.util.KUtil.get import de.bixilon.minosoft.util.KUtil.get
import de.bixilon.minosoft.util.enum.ValuesEnum import de.bixilon.minosoft.util.enum.ValuesEnum
import glm_.mat3x3.Mat3 import glm_.mat3x3.Mat3
import glm_.mat4x4.Mat4
import glm_.vec2.Vec2i import glm_.vec2.Vec2i
import glm_.vec3.Vec3 import glm_.vec3.Vec3
import glm_.vec3.Vec3i import glm_.vec3.Vec3i
import glm_.vec4.Vec4 import glm_.vec4.Vec4
// Big thanks to: https://gist.github.com/podgorskiy/e698d18879588ada9014768e3e82a644 // 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 private lateinit var data: FrustumData
init {
recalculate()
}
fun recalculate() { fun recalculate() {
val matrix = Mat4(camera.viewProjectionMatrix).transpose() val matrix = matrixHandler.viewProjectionMatrix.transpose()
val planes = arrayOf( val planes = arrayOf(
matrix[3] + matrix[0], matrix[3] + matrix[0],
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. * 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.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.BlockState 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.Vec3d
import glm_.vec3.Vec3i import glm_.vec3.Vec3i
open class BlockRaycastHit( open class BlockTarget(
position: Vec3d, position: Vec3d,
distance: Double, distance: Double,
hitDirection: Directions, direction: Directions,
val blockState: BlockState, val blockState: BlockState,
val blockPosition: Vec3i, val blockPosition: Vec3i,
) : RaycastHit(position, distance, hitDirection), TextFormattable { ) : GenericTarget(position, distance, direction), TextFormattable {
val hitPosition = position - blockPosition val hitPosition = position - blockPosition
override fun toString(): String { override fun toString(): String {

View File

@ -11,7 +11,7 @@
* This software is not affiliated with Mojang AB, the original developer of Minecraft. * 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.direction.Directions
import de.bixilon.minosoft.data.entities.entities.Entity 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 de.bixilon.minosoft.data.text.TextFormattable
import glm_.vec3.Vec3d import glm_.vec3.Vec3d
class EntityRaycastHit( class EntityTarget(
position: Vec3d, position: Vec3d,
distance: Double, distance: Double,
hitDirection: Directions, direction: Directions,
val entity: Entity, val entity: Entity,
) : RaycastHit(position, distance, hitDirection), TextFormattable { ) : GenericTarget(position, distance, direction), TextFormattable {
override fun toString(): String { override fun toString(): String {
return toText().legacyText return toText().legacyText

View File

@ -11,7 +11,7 @@
* This software is not affiliated with Mojang AB, the original developer of Minecraft. * 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.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.BlockState 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.Vec3d
import glm_.vec3.Vec3i import glm_.vec3.Vec3i
class FluidRaycastHit( class FluidTarget(
position: Vec3d, position: Vec3d,
distance: Double, distance: Double,
hitDirection: Directions, direction: Directions,
val blockState: BlockState, val blockState: BlockState,
val blockPosition: Vec3i, val blockPosition: Vec3i,
val fluid: Fluid, val fluid: Fluid,
) : RaycastHit(position, distance, hitDirection), TextFormattable { ) : GenericTarget(position, distance, direction), TextFormattable {
override fun toString(): String { override fun toString(): String {
return toText().legacyText return toText().legacyText

View File

@ -11,13 +11,13 @@
* This software is not affiliated with Mojang AB, the original developer of Minecraft. * 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.direction.Directions
import glm_.vec3.Vec3d import glm_.vec3.Vec3d
abstract class RaycastHit( abstract class GenericTarget(
val position: Vec3d, val position: Vec3d,
val distance: Double, 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.registries.AABB
import de.bixilon.minosoft.data.text.ChatColors import de.bixilon.minosoft.data.text.ChatColors
import de.bixilon.minosoft.gui.rendering.RenderConstants 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.VecUtil.empty
import de.bixilon.minosoft.gui.rendering.util.mesh.LineMesh import de.bixilon.minosoft.gui.rendering.util.mesh.LineMesh
import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh

View File

@ -45,7 +45,7 @@ class EntityHitboxRenderer(
) : Renderer, OpaqueDrawable, SkipAll { ) : Renderer, OpaqueDrawable, SkipAll {
override val renderSystem: RenderSystem = renderWindow.renderSystem override val renderSystem: RenderSystem = renderWindow.renderSystem
val profile = connection.profiles.entity.hitbox 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 meshes: LockMap<Entity, EntityHitbox> = lockMapOf()
private val toUnload: MutableSet<EntityHitbox> = synchronizedSetOf() 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.config.profile.delegate.watcher.SimpleProfileDelegateWatcher.Companion.profileWatch
import de.bixilon.minosoft.data.abilities.Gamemodes import de.bixilon.minosoft.data.abilities.Gamemodes
import de.bixilon.minosoft.data.registries.ResourceLocation 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.HUDRenderer
import de.bixilon.minosoft.gui.rendering.gui.hud.atlas.HUDAtlasElement 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.CustomHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDBuilder 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.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.gui.rendering.system.base.BlendingFunctions
import de.bixilon.minosoft.util.KUtil.toResourceLocation import de.bixilon.minosoft.util.KUtil.toResourceLocation
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList 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 // Custom draw to make the crosshair inverted
if (renderWindow.connection.player.gamemode == Gamemodes.SPECTATOR) { if (renderWindow.connection.player.gamemode == Gamemodes.SPECTATOR) {
val hitResult = renderWindow.inputHandler.camera.target ?: return val hitResult = renderWindow.camera.targetHandler.target ?: return
if (hitResult !is EntityRaycastHit && (hitResult !is BlockRaycastHit || renderWindow.connection.world.getBlockEntity(hitResult.blockPosition) == null)) { if (hitResult !is EntityTarget && (hitResult !is BlockTarget || renderWindow.connection.world.getBlockEntity(hitResult.blockPosition) == null)) {
return return
} }
} }

View File

@ -128,7 +128,7 @@ class DebugHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<GridLayout>
layout += AutoTextElement(hudRenderer, 1) { layout += AutoTextElement(hudRenderer, 1) {
val text = BaseComponent("Facing ") val text = BaseComponent("Facing ")
Directions.byDirection(hudRenderer.renderWindow.inputHandler.camera.cameraFront).apply { Directions.byDirection(hudRenderer.renderWindow.camera.matrixHandler.cameraFront).apply {
text += this text += this
text += " " text += " "
text += vector text += vector
@ -227,7 +227,7 @@ class DebugHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<GridLayout>
layout += LineSpacerElement(hudRenderer) layout += LineSpacerElement(hudRenderer)
renderWindow.inputHandler.camera.apply { renderWindow.camera.targetHandler.apply {
layout += AutoTextElement(hudRenderer, 1, HorizontalAlignments.RIGHT) { layout += AutoTextElement(hudRenderer, 1, HorizontalAlignments.RIGHT) {
// ToDo: Tags // ToDo: Tags
target ?: "No target" 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.fluid.DefaultFluids
import de.bixilon.minosoft.data.registries.items.tools.MiningToolItem import de.bixilon.minosoft.data.registries.items.tools.MiningToolItem
import de.bixilon.minosoft.gui.rendering.RenderWindow 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.events.BlockBreakAckEvent
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
import de.bixilon.minosoft.protocol.packets.c2s.play.ArmSwingC2SP import de.bixilon.minosoft.protocol.packets.c2s.play.ArmSwingC2SP
@ -98,9 +98,9 @@ class BreakInteractionHandler(
cancelDigging() cancelDigging()
return false return false
} }
val raycastHit = renderWindow.inputHandler.camera.nonFluidTarget val raycastHit = renderWindow.camera.targetHandler.target
if (raycastHit !is BlockRaycastHit) { if (raycastHit !is BlockTarget) {
cancelDigging() cancelDigging()
return false return false
} }
@ -120,7 +120,7 @@ class BreakInteractionHandler(
if (breakPosition != null) { if (breakPosition != null) {
return 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 breakPosition = raycastHit.blockPosition
breakBlockState = raycastHit.blockState breakBlockState = raycastHit.blockState
@ -130,7 +130,7 @@ class BreakInteractionHandler(
} }
fun finishDigging() { 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() clearDigging()
connection.world.setBlockState(raycastHit.blockPosition, null) 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.player.Hands
import de.bixilon.minosoft.data.registries.items.UsableItem import de.bixilon.minosoft.data.registries.items.UsableItem
import de.bixilon.minosoft.gui.rendering.RenderWindow 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.gui.rendering.input.camera.hit.EntityRaycastHit 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.BlockInteractC2SP
import de.bixilon.minosoft.protocol.packets.c2s.play.ItemUseC2SP import de.bixilon.minosoft.protocol.packets.c2s.play.ItemUseC2SP
import de.bixilon.minosoft.protocol.packets.c2s.play.PlayerActionC2SP import de.bixilon.minosoft.protocol.packets.c2s.play.PlayerActionC2SP
@ -71,16 +71,16 @@ class InteractInteractionHandler(
interactingTicksLeft = 0 interactingTicksLeft = 0
} }
fun interactBlock(hit: BlockRaycastHit, item: ItemStack?, hand: Hands): InteractionResults { fun interactBlock(target: BlockTarget, item: ItemStack?, hand: Hands): InteractionResults {
if (hit.distance >= connection.player.reachDistance) { if (target.distance >= connection.player.reachDistance) {
return InteractionResults.PASS return InteractionResults.PASS
} }
// if out of world (border): return CONSUME // if out of world (border): return CONSUME
connection.sendPacket(BlockInteractC2SP( connection.sendPacket(BlockInteractC2SP(
position = hit.blockPosition, position = target.blockPosition,
direction = hit.hitDirection, direction = target.direction,
cursorPosition = Vec3(hit.hitPosition), cursorPosition = Vec3(target.hitPosition),
item = item, item = item,
hand = hand, hand = hand,
insideBlock = false, // ToDo: insideBlock insideBlock = false, // ToDo: insideBlock
@ -90,7 +90,7 @@ class InteractInteractionHandler(
return InteractionResults.SUCCESS 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) { if (result == InteractionResults.SUCCESS) {
return InteractionResults.SUCCESS return InteractionResults.SUCCESS
} }
@ -102,13 +102,13 @@ class InteractInteractionHandler(
return InteractionResults.PASS // ToDo: Check 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 // used in armor stands
val player = connection.player 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) { if (player.gamemode == Gamemodes.SPECTATOR) {
return InteractionResults.PASS return InteractionResults.PASS
@ -117,9 +117,9 @@ class InteractInteractionHandler(
return InteractionResults.PASS return InteractionResults.PASS
} }
fun interactEntity(hit: EntityRaycastHit, hand: Hands): InteractionResults { fun interactEntity(target: EntityTarget, hand: Hands): InteractionResults {
val player = connection.player 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) { if (player.gamemode == Gamemodes.SPECTATOR) {
return InteractionResults.PASS return InteractionResults.PASS
@ -155,12 +155,12 @@ class InteractInteractionHandler(
// if riding: return // if riding: return
val selectedSlot = connection.player.selectedHotbarSlot val selectedSlot = connection.player.selectedHotbarSlot
val target = renderWindow.inputHandler.camera.nonFluidTarget val target = renderWindow.camera.targetHandler.target
for (hand in Hands.VALUES) { for (hand in Hands.VALUES) {
val item = connection.player.inventory[hand] val item = connection.player.inventory[hand]
when (target) { when (target) {
is EntityRaycastHit -> { is EntityTarget -> {
var result = interactEntityAt(target, hand) var result = interactEntityAt(target, hand)
if (result == InteractionResults.PASS) { if (result == InteractionResults.PASS) {
@ -175,7 +175,7 @@ class InteractInteractionHandler(
return return
} }
} }
is BlockRaycastHit -> { is BlockTarget -> {
val result = interactBlock(target, item, hand) val result = interactBlock(target, item, hand)
if (result == InteractionResults.SUCCESS) { if (result == InteractionResults.SUCCESS) {
interactionManager.swingHand(hand) interactionManager.swingHand(hand)

View File

@ -28,6 +28,8 @@ class InteractionManager(
val attack = AttackInteractionHandler(renderWindow) val attack = AttackInteractionHandler(renderWindow)
val `break` = BreakInteractionHandler(renderWindow) val `break` = BreakInteractionHandler(renderWindow)
val use = InteractInteractionHandler(renderWindow, this) val use = InteractInteractionHandler(renderWindow, this)
val drop = DropInteractionManager(renderWindow)
val spectate = SpectateInteractionManager(renderWindow)
private val swingArmRateLimiter = RateLimiter() private val swingArmRateLimiter = RateLimiter()
@ -38,6 +40,8 @@ class InteractionManager(
pick.init() pick.init()
`break`.init() `break`.init()
use.init() use.init()
drop.init()
spectate.init()
} }
fun draw(delta: Double) { fun draw(delta: Double) {
@ -46,6 +50,8 @@ class InteractionManager(
// attack.draw(delta) // attack.draw(delta)
`break`.draw(delta) `break`.draw(delta)
use.draw(delta) use.draw(delta)
drop.draw(delta)
spectate.draw(delta)
swingArmRateLimiter.work() 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.inventory.ItemStack
import de.bixilon.minosoft.data.registries.other.containers.PlayerInventory import de.bixilon.minosoft.data.registries.other.containers.PlayerInventory
import de.bixilon.minosoft.gui.rendering.RenderWindow 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.gui.rendering.input.camera.hit.EntityRaycastHit import de.bixilon.minosoft.gui.rendering.camera.target.targets.EntityTarget
import de.bixilon.minosoft.protocol.RateLimiter import de.bixilon.minosoft.protocol.RateLimiter
import de.bixilon.minosoft.protocol.packets.c2s.play.ItemStackCreateC2SP import de.bixilon.minosoft.protocol.packets.c2s.play.ItemStackCreateC2SP
import de.bixilon.minosoft.util.KUtil.toResourceLocation import de.bixilon.minosoft.util.KUtil.toResourceLocation
@ -48,25 +48,25 @@ class ItemPickInteractionHandler(
if (!connection.player.baseAbilities.creative) { if (!connection.player.baseAbilities.creative) {
return 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 return
} }
val itemStack: ItemStack? val itemStack: ItemStack?
when (raycast) { when (target) {
is BlockRaycastHit -> { is BlockTarget -> {
itemStack = ItemStack(raycast.blockState.block.item!!, connection, 1) itemStack = ItemStack(target.blockState.block.item!!, connection, 1)
if (copyNBT) { if (copyNBT) {
val blockEntity = connection.world.getBlockEntity(raycast.blockPosition) val blockEntity = connection.world.getBlockEntity(target.blockPosition)
blockEntity?.nbt?.let { itemStack.nbt.putAll(it) } blockEntity?.nbt?.let { itemStack.nbt.putAll(it) }
} }
} }
is EntityRaycastHit -> { is EntityTarget -> {
val entity = raycast.entity val entity = target.entity
itemStack = entity.entityType.spawnEgg?.let { ItemStack(it, connection) } ?: let { itemStack = entity.entityType.spawnEgg?.let { ItemStack(it, connection) } ?: let {
entity.equipment[InventorySlots.EquipmentSlots.MAIN_HAND]?.copy() 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.data.registries.ResourceLocation
import de.bixilon.minosoft.gui.rendering.RenderConstants import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.RenderWindow 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.input.interaction.InteractionManager
import de.bixilon.minosoft.gui.rendering.modding.events.input.MouseMoveEvent import de.bixilon.minosoft.gui.rendering.modding.events.input.MouseMoveEvent
import de.bixilon.minosoft.gui.rendering.modding.events.input.RawCharInputEvent import de.bixilon.minosoft.gui.rendering.modding.events.input.RawCharInputEvent
@ -38,7 +38,7 @@ class RenderWindowInputHandler(
val renderWindow: RenderWindow, val renderWindow: RenderWindow,
) { ) {
val connection: PlayConnection = renderWindow.connection 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 profile = connection.profiles.controls
private val keyBindingCallbacks: MutableMap<ResourceLocation, KeyBindingCallbackPair> = mutableMapOf() private val keyBindingCallbacks: MutableMap<ResourceLocation, KeyBindingCallbackPair> = mutableMapOf()
@ -80,7 +80,8 @@ class RenderWindowInputHandler(
//if (renderWindow.inputHandler.currentKeyConsumer != null) { //if (renderWindow.inputHandler.currentKeyConsumer != null) {
// return // return
//} //}
camera.mouseCallback(it.delta)
cameraInput.mouseCallback(it.delta)
}) })
profile::keyBindings.profileWatchMap(this, profile = profile) { profile::keyBindings.profileWatchMap(this, profile = profile) {
@ -93,6 +94,7 @@ class RenderWindowInputHandler(
keyBinding.keyBinding = it.valueAdded keyBinding.keyBinding = it.valueAdded
} }
} }
cameraInput.init()
} }
@ -275,8 +277,7 @@ class RenderWindowInputHandler(
} }
fun draw(delta: Double) { fun draw(delta: Double) {
camera.draw() cameraInput.update()
interactionManager.draw(delta) 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.RenderWindow
import de.bixilon.minosoft.gui.rendering.Rendering import de.bixilon.minosoft.gui.rendering.Rendering
import glm_.mat4x4.Mat4d import glm_.mat4x4.Mat4
class CameraMatrixChangeEvent( class CameraMatrixChangeEvent(
renderWindow: RenderWindow = Rendering.currentContext!!, renderWindow: RenderWindow = Rendering.currentContext!!,
viewMatrix: Mat4d, viewMatrix: Mat4,
projectionMatrix: Mat4d, projectionMatrix: Mat4,
viewProjectionMatrix: Mat4d, viewProjectionMatrix: Mat4,
) : RenderEvent(renderWindow) { ) : RenderEvent(renderWindow) {
val viewMatrix: Mat4d = viewMatrix val viewMatrix: Mat4 = viewMatrix
get() = Mat4d(field) get() = Mat4(field)
val projectionMatrix: Mat4d = projectionMatrix val projectionMatrix: Mat4 = projectionMatrix
get() = Mat4d(field) get() = Mat4(field)
val viewProjectionMatrix: Mat4d = viewProjectionMatrix val viewProjectionMatrix: Mat4 = viewProjectionMatrix
get() = Mat4d(field) 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.RenderWindow
import de.bixilon.minosoft.gui.rendering.Rendering import de.bixilon.minosoft.gui.rendering.Rendering
import glm_.vec3.Vec3d import glm_.vec3.Vec3
class CameraPositionChangeEvent( class CameraPositionChangeEvent(
renderWindow: RenderWindow = Rendering.currentContext!!, renderWindow: RenderWindow = Rendering.currentContext!!,
newPosition: Vec3d, newPosition: Vec3,
) : RenderEvent(renderWindow) { ) : RenderEvent(renderWindow) {
val newPosition: Vec3d = newPosition val newPosition: Vec3 = newPosition
get() = Vec3d(field) 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.RenderWindow
import de.bixilon.minosoft.gui.rendering.Rendering 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( class FrustumChangeEvent(
renderWindow: RenderWindow = Rendering.currentContext!!, renderWindow: RenderWindow = Rendering.currentContext!!,

View File

@ -14,7 +14,6 @@
package de.bixilon.minosoft.gui.rendering.sky package de.bixilon.minosoft.gui.rendering.sky
import de.bixilon.minosoft.data.registries.ResourceLocation 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.ChatColors
import de.bixilon.minosoft.data.text.RGBColor import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.RenderConstants 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 de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import glm_.func.rad import glm_.func.rad
import glm_.mat4x4.Mat4 import glm_.mat4x4.Mat4
import glm_.mat4x4.Mat4d
import glm_.vec3.Vec3 import glm_.vec3.Vec3
import glm_.vec3.Vec3d
class SkyRenderer( class SkyRenderer(
private val connection: PlayConnection, private val connection: PlayConnection,
@ -49,7 +46,7 @@ class SkyRenderer(
private val skyboxMesh = SkyboxMesh(renderWindow) private val skyboxMesh = SkyboxMesh(renderWindow)
private var skySunMesh = SimpleTextureMesh(renderWindow) private var skySunMesh = SimpleTextureMesh(renderWindow)
private lateinit var sunTexture: AbstractTexture private lateinit var sunTexture: AbstractTexture
private var sunMatrixUpToDate: Boolean = true private var updateSun: Boolean = true
var baseColor = RenderConstants.DEFAULT_SKY_COLOR var baseColor = RenderConstants.DEFAULT_SKY_COLOR
@ -69,22 +66,21 @@ class SkyRenderer(
} }
}) })
connection.registerEvent(CallbackEventInvoker.of<TimeChangeEvent> { connection.registerEvent(CallbackEventInvoker.of<TimeChangeEvent> {
if (connection.world.time != it.time) { if (connection.world.time.time != it.time) {
sunMatrixUpToDate = true updateSun = true
} }
}) })
sunTexture = renderWindow.textureManager.staticTextures.createTexture(SUN_TEXTURE_RESOURCE_LOCATION) sunTexture = renderWindow.textureManager.staticTextures.createTexture(SUN_TEXTURE_RESOURCE_LOCATION)
} }
private fun setSunMatrix(projectionViewMatrix: Mat4d) { private fun setSunMatrix(projectionViewMatrix: Mat4) {
val timeAngle = (connection.world.skyAngle * 360.0).rad val timeAngle = (connection.world.time.skyAngle * 360.0f).rad
val rotatedMatrix = if (timeAngle == 0.0) { val rotatedMatrix = if (timeAngle == 0.0f) {
projectionViewMatrix projectionViewMatrix
} else { } 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)) skySunShader.use().setMat4("uSkyViewProjectionMatrix", rotatedMatrix)
sunMatrixUpToDate = false
} }
override fun postInit() { override fun postInit() {
@ -92,8 +88,8 @@ class SkyRenderer(
} }
private fun drawSun() { private fun drawSun() {
if (sunMatrixUpToDate) { if (updateSun) {
setSunMatrix(renderWindow.inputHandler.camera.projectionMatrix * renderWindow.inputHandler.camera.viewMatrix.toMat3().toMat4()) setSunMatrix(renderWindow.camera.matrixHandler.projectionMatrix * renderWindow.camera.matrixHandler.viewMatrix.toMat3().toMat4())
skySunMesh.unload() skySunMesh.unload()
skySunMesh = SimpleTextureMesh(renderWindow) skySunMesh = SimpleTextureMesh(renderWindow)
@ -105,11 +101,12 @@ class SkyRenderer(
position = position, position = position,
texture = sunTexture, texture = sunTexture,
uv = uv, 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() skySunMesh.load()
updateSun = false
} }
renderSystem.enable(RenderingCapabilities.BLENDING) renderSystem.enable(RenderingCapabilities.BLENDING)
@ -123,18 +120,18 @@ class SkyRenderer(
val brightness = 1.0f val brightness = 1.0f
val skyColor = RGBColor((baseColor.red * brightness).toInt(), (baseColor.green * brightness).toInt(), (baseColor.blue * brightness).toInt()) 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) { baseColor = connection.world.getBiome(connection.player.positionInfo.blockPosition)?.skyColor ?: RenderConstants.DEFAULT_SKY_COLOR
connection.player.positionInfo.biome?.waterFogColor ?: skyColor
connection.world.dimension?.hasSkyLight?.let {
baseColor = if (it) {
connection.player.positionInfo.biome?.skyColor ?: RenderConstants.DEFAULT_SKY_COLOR
} else { } else {
skyColor RenderConstants.BLACK_COLOR
} }
} ?: let { baseColor = RenderConstants.DEFAULT_SKY_COLOR }
for (shader in renderWindow.renderSystem.shaders) { skyboxShader.use().setRGBColor("uSkyColor", skyColor)
if (shader.uniforms.contains("uSkyColor")) {
shader.use().setRGBColor("uSkyColor", skyColor)
}
}
} }
private fun drawSkybox() { 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.registries.ResourceLocation
import de.bixilon.minosoft.data.world.AbstractAudioPlayer import de.bixilon.minosoft.data.world.AbstractAudioPlayer
import de.bixilon.minosoft.gui.rendering.Rendering 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.modding.events.CameraPositionChangeEvent
import de.bixilon.minosoft.gui.rendering.sound.sounds.Sound import de.bixilon.minosoft.gui.rendering.sound.sounds.Sound
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY
@ -96,7 +96,7 @@ class AudioPlayer(
connection.registerEvent(CallbackEventInvoker.of<CameraPositionChangeEvent> { connection.registerEvent(CallbackEventInvoker.of<CameraPositionChangeEvent> {
queue += { queue += {
listener.position = Vec3(it.newPosition) 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 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.Vec3Util.EMPTY
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY
import glm_.vec3.Vec3 import glm_.vec3.Vec3
import glm_.vec3.Vec3d
import org.lwjgl.openal.AL10.* import org.lwjgl.openal.AL10.*
class SoundListener(position: Vec3 = Vec3.EMPTY) { class SoundListener(position: Vec3 = Vec3.EMPTY) {
@ -36,13 +34,13 @@ class SoundListener(position: Vec3 = Vec3.EMPTY) {
get() = alGetListenerf(AL_MAX_GAIN) get() = alGetListenerf(AL_MAX_GAIN)
set(value) = alListenerf(AL_MAX_GAIN, value) set(value) = alListenerf(AL_MAX_GAIN, value)
fun setOrientation(look: Vec3d, up: Vec3d) { fun setOrientation(look: Vec3, up: Vec3) {
alListenerfv(AL_ORIENTATION, floatArrayOf(look.x.toFloat(), look.y.toFloat(), look.z.toFloat(), up.x.toFloat(), up.y.toFloat(), up.z.toFloat())) alListenerfv(AL_ORIENTATION, floatArrayOf(look.x, look.y, look.z, up.x, up.y, up.z))
} }
init { init {
this.position = position this.position = position
this.velocity = Vec3.EMPTY 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.pow
import kotlin.math.sin import kotlin.math.sin
@Deprecated("Needs refactoring")
class LightMap(private val connection: PlayConnection) { class LightMap(private val connection: PlayConnection) {
private val profile = connection.profiles.rendering.light private val profile = connection.profiles.rendering.light
private val nightVisionStatusEffect = connection.registries.statusEffectRegistry[DefaultStatusEffects.NIGHT_VISION] private val nightVisionStatusEffect = connection.registries.statusEffectRegistry[DefaultStatusEffects.NIGHT_VISION]
@ -50,7 +50,7 @@ class LightMap(private val connection: PlayConnection) {
} }
fun update() { fun update() {
val skyGradient = connection.world.lightBase.toFloat() val skyGradient = connection.world.time.lightBase.toFloat()
// ToDo: Lightning // 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.VecUtil.sectionHeight
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY 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.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.EMPTY
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.toVec3 import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.toVec3
import de.bixilon.minosoft.gui.rendering.world.mesh.VisibleMeshes import de.bixilon.minosoft.gui.rendering.world.mesh.VisibleMeshes
@ -87,7 +86,7 @@ class WorldRenderer(
) : Renderer, OpaqueDrawable, TranslucentDrawable, TransparentDrawable { ) : Renderer, OpaqueDrawable, TranslucentDrawable, TransparentDrawable {
private val profile = connection.profiles.block private val profile = connection.profiles.block
override val renderSystem: RenderSystem = renderWindow.renderSystem 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 shader = renderSystem.createShader("minosoft:world".toResourceLocation())
private val transparentShader = renderSystem.createShader("minosoft:world".toResourceLocation()) private val transparentShader = renderSystem.createShader("minosoft:world".toResourceLocation())
private val world: World = connection.world private val world: World = connection.world
@ -660,7 +659,7 @@ class WorldRenderer(
private fun onFrustumChange() { private fun onFrustumChange() {
var sortQueue = false var sortQueue = false
val cameraPosition = connection.player.cameraPosition.toVec3() val cameraPosition = connection.player.cameraPosition
if (this.cameraPosition != cameraPosition) { if (this.cameraPosition != cameraPosition) {
this.cameraPosition = cameraPosition this.cameraPosition = cameraPosition
this.cameraChunkPosition = connection.player.positionInfo.chunkPosition 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.RenderWindow
import de.bixilon.minosoft.gui.rendering.Renderer import de.bixilon.minosoft.gui.rendering.Renderer
import de.bixilon.minosoft.gui.rendering.RendererBuilder 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.DepthFunctions
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
import de.bixilon.minosoft.gui.rendering.system.base.phases.OtherDrawable import de.bixilon.minosoft.gui.rendering.system.base.phases.OtherDrawable
@ -82,7 +82,7 @@ class BlockOutlineRenderer(
} }
override fun prepareDraw() { override fun prepareDraw() {
val raycastHit = renderWindow.inputHandler.camera.target.nullCast<BlockRaycastHit>() val raycastHit = renderWindow.camera.targetHandler.target.nullCast<BlockTarget>()
var currentMesh = currentMesh 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.modding.event.events.connection.play.PlayConnectionEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.packets.s2c.play.WorldTimeSetS2CP import de.bixilon.minosoft.protocol.packets.s2c.play.WorldTimeSetS2CP
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
class TimeChangeEvent( class TimeChangeEvent(
connection: PlayConnection, connection: PlayConnection,
@ -25,5 +26,5 @@ class TimeChangeEvent(
) : PlayConnectionEvent(connection, initiator) { ) : 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 de.bixilon.minosoft.util.logging.LogMessageType
import java.util.* import java.util.*
/**
* Teleports our self in spectator mode to an entity
*/
class EntitySpectateC2SP( class EntitySpectateC2SP(
val entityUUID: UUID, val entityUUID: UUID,
) : PlayC2SPacket { ) : PlayC2SPacket {

View File

@ -12,6 +12,8 @@
*/ */
package de.bixilon.minosoft.protocol.packets.s2c.play 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.packets.s2c.PlayS2CPacket
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
import de.bixilon.minosoft.util.logging.Log import de.bixilon.minosoft.util.logging.Log
@ -21,6 +23,11 @@ import de.bixilon.minosoft.util.logging.LogMessageType
class CameraS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { class CameraS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
val entityId: Int = buffer.readVarInt() 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) { override fun log(reducedLog: Boolean) {
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Camera (entityId=$entityId)" } 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.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer 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.Log
import de.bixilon.minosoft.util.logging.LogLevels import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType import de.bixilon.minosoft.util.logging.LogMessageType
@ -25,8 +26,8 @@ class WorldTimeSetS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
val time = buffer.readLong() val time = buffer.readLong()
override fun handle(connection: PlayConnection) { override fun handle(connection: PlayConnection) {
connection.world.age = age connection.world.time.age = age
connection.world.time = time connection.world.time.time = time % ProtocolDefinition.TICKS_PER_DAY
connection.fireEvent(TimeChangeEvent(connection, this)) 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.protocol.network.connection.Connection
import de.bixilon.minosoft.util.Util import de.bixilon.minosoft.util.Util
import de.bixilon.minosoft.util.nbt.tag.NBTTagTypes 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.Vec3
import glm_.vec3.Vec3d import glm_.vec3.Vec3d
import glm_.vec3.Vec3i import glm_.vec3.Vec3i
@ -178,7 +178,7 @@ open class OutByteBuffer(open val connection: Connection? = null) {
this.writeNBTTagType(type) this.writeNBTTagType(type)
} }
val type = tag.type val type = tag.nbtType
writeNBTTagType(type) writeNBTTagType(type)
if (type == NBTTagTypes.END) { if (type == NBTTagTypes.END) {
return return
@ -206,7 +206,7 @@ open class OutByteBuffer(open val connection: Connection? = null) {
this.writeNBTTagType(if (tag.isEmpty()) { this.writeNBTTagType(if (tag.isEmpty()) {
NBTTagTypes.END NBTTagTypes.END
} else { } else {
tag.iterator().next().type tag.iterator().next().nbtType
}) })
writeInt(tag.size) writeInt(tag.size)
@ -217,7 +217,7 @@ open class OutByteBuffer(open val connection: Connection? = null) {
} }
is Map<*, *> -> { is Map<*, *> -> {
for ((key, value) in tag) { for ((key, value) in tag) {
val valueType = value.type val valueType = value.nbtType
if (valueType == NBTTagTypes.END) { if (valueType == NBTTagTypes.END) {
error("NBT does not support null as value in a compound tag!") error("NBT does not support null as value in a compound tag!")
} }

View File

@ -60,7 +60,7 @@ object NBTUtil {
return null return null
} }
val Any?.type: NBTTagTypes val Any?.nbtType: NBTTagTypes
get() { get() {
return when (this) { return when (this) {
null -> NBTTagTypes.END null -> NBTTagTypes.END
@ -76,7 +76,7 @@ object NBTUtil {
is Map<*, *> -> NBTTagTypes.COMPOUND is Map<*, *> -> NBTTagTypes.COMPOUND
is IntArray -> NBTTagTypes.INT_ARRAY is IntArray -> NBTTagTypes.INT_ARRAY
is LongArray -> NBTTagTypes.LONG_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}")
} }
} }
} }