diff --git a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/Block.kt b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/Block.kt index 4796c845f..29ff2f75e 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/Block.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/Block.kt @@ -33,8 +33,9 @@ import de.bixilon.minosoft.data.registries.registry.ResourceLocationDeserializer import de.bixilon.minosoft.data.registries.versions.Registries import de.bixilon.minosoft.data.text.RGBColor import de.bixilon.minosoft.gui.rendering.TintColorCalculator +import de.bixilon.minosoft.gui.rendering.chunk.VoxelShape import de.bixilon.minosoft.gui.rendering.chunk.models.renderable.BlockLikeRenderer -import de.bixilon.minosoft.gui.rendering.input.camera.RaycastHit +import de.bixilon.minosoft.gui.rendering.input.camera.hit.RaycastHit import de.bixilon.minosoft.protocol.network.connection.PlayConnection import glm_.vec3.Vec3i import kotlin.random.Random @@ -111,6 +112,10 @@ open class Block( open fun onEntityCollision(connection: PlayConnection, entity: Entity, blockState: BlockState, blockPosition: Vec3i) {} + open fun getOutlineShape(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i): VoxelShape { + return blockState.outlineShape + } + companion object : ResourceLocationDeserializer { private val CONSTRUCTORS: Map Block> = mapOf( "FluidBlock" to { resourceLocation, registries, data -> FluidBlock(resourceLocation, registries, data) }, diff --git a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/CampfireBlock.kt b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/CampfireBlock.kt index 4f28f40cb..20dce5598 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/CampfireBlock.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/CampfireBlock.kt @@ -22,7 +22,7 @@ import de.bixilon.minosoft.data.registries.blocks.BlockUsages import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties import de.bixilon.minosoft.data.registries.items.tools.ShovelItem import de.bixilon.minosoft.data.registries.versions.Registries -import de.bixilon.minosoft.gui.rendering.input.camera.RaycastHit +import de.bixilon.minosoft.gui.rendering.input.camera.hit.RaycastHit 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.lava.LavaParticle diff --git a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/DoorBlock.kt b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/DoorBlock.kt index 0526bbe5e..32e33d38a 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/DoorBlock.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/DoorBlock.kt @@ -22,7 +22,7 @@ import de.bixilon.minosoft.data.registries.blocks.BlockUsages import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties import de.bixilon.minosoft.data.registries.materials.DefaultMaterials import de.bixilon.minosoft.data.registries.versions.Registries -import de.bixilon.minosoft.gui.rendering.input.camera.RaycastHit +import de.bixilon.minosoft.gui.rendering.input.camera.hit.RaycastHit import de.bixilon.minosoft.protocol.network.connection.PlayConnection import glm_.vec3.Vec3i diff --git a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/FluidBlock.kt b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/FluidBlock.kt index e82a05baf..908221ff8 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/FluidBlock.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/FluidBlock.kt @@ -18,9 +18,13 @@ import de.bixilon.minosoft.data.registries.ResourceLocation import de.bixilon.minosoft.data.registries.blocks.BlockState import de.bixilon.minosoft.data.registries.fluid.Fluid import de.bixilon.minosoft.data.registries.versions.Registries +import de.bixilon.minosoft.gui.rendering.chunk.VoxelShape +import de.bixilon.minosoft.gui.rendering.chunk.models.AABB import de.bixilon.minosoft.gui.rendering.chunk.models.renderable.BlockLikeRenderer import de.bixilon.minosoft.gui.rendering.chunk.models.renderable.FluidRenderer +import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY import de.bixilon.minosoft.protocol.network.connection.PlayConnection +import glm_.vec3.Vec3 import glm_.vec3.Vec3i import kotlin.random.Random @@ -38,6 +42,10 @@ open class FluidBlock(resourceLocation: ResourceLocation, registries: Registries } } + override fun getOutlineShape(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i): VoxelShape { + return VoxelShape(mutableListOf(AABB(Vec3.EMPTY, Vec3(1.0f, fluid.getHeight(blockState), 1.0f)))) + } + override fun randomTick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, random: Random) { super.randomTick(connection, blockState, blockPosition, random) // ToDO diff --git a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/NoteBlock.kt b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/NoteBlock.kt index 35c82ecf2..c270071b1 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/NoteBlock.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/NoteBlock.kt @@ -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.BlockUsages import de.bixilon.minosoft.data.registries.versions.Registries -import de.bixilon.minosoft.gui.rendering.input.camera.RaycastHit +import de.bixilon.minosoft.gui.rendering.input.camera.hit.RaycastHit import de.bixilon.minosoft.protocol.network.connection.PlayConnection import glm_.vec3.Vec3i diff --git a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/redstone/ComparatorBlock.kt b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/redstone/ComparatorBlock.kt index fc416df11..570967ce9 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/redstone/ComparatorBlock.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/redstone/ComparatorBlock.kt @@ -21,7 +21,7 @@ import de.bixilon.minosoft.data.registries.blocks.BlockState import de.bixilon.minosoft.data.registries.blocks.BlockUsages import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties import de.bixilon.minosoft.data.registries.versions.Registries -import de.bixilon.minosoft.gui.rendering.input.camera.RaycastHit +import de.bixilon.minosoft.gui.rendering.input.camera.hit.RaycastHit import de.bixilon.minosoft.protocol.network.connection.PlayConnection import glm_.vec3.Vec3i diff --git a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/redstone/RepeaterBlock.kt b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/redstone/RepeaterBlock.kt index 2bdfd7f04..648d42a3d 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/redstone/RepeaterBlock.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/redstone/RepeaterBlock.kt @@ -21,7 +21,7 @@ import de.bixilon.minosoft.data.registries.blocks.BlockState import de.bixilon.minosoft.data.registries.blocks.BlockUsages import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties import de.bixilon.minosoft.data.registries.versions.Registries -import de.bixilon.minosoft.gui.rendering.input.camera.RaycastHit +import de.bixilon.minosoft.gui.rendering.input.camera.hit.RaycastHit import de.bixilon.minosoft.protocol.network.connection.PlayConnection import glm_.vec3.Vec3i diff --git a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/wall/LeverBlock.kt b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/wall/LeverBlock.kt index 298d3edb7..bb26ab09d 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/wall/LeverBlock.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/blocks/types/wall/LeverBlock.kt @@ -24,7 +24,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.versions.Registries import de.bixilon.minosoft.data.text.Colors -import de.bixilon.minosoft.gui.rendering.input.camera.RaycastHit +import de.bixilon.minosoft.gui.rendering.input.camera.hit.RaycastHit import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.dust.DustParticle import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY import de.bixilon.minosoft.protocol.network.connection.PlayConnection diff --git a/src/main/java/de/bixilon/minosoft/data/registries/items/BlockItem.kt b/src/main/java/de/bixilon/minosoft/data/registries/items/BlockItem.kt index 36f834456..008e07a83 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/items/BlockItem.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/items/BlockItem.kt @@ -18,16 +18,15 @@ import de.bixilon.minosoft.data.abilities.Gamemodes import de.bixilon.minosoft.data.inventory.ItemStack import de.bixilon.minosoft.data.player.Hands import de.bixilon.minosoft.data.registries.ResourceLocation -import de.bixilon.minosoft.data.registries.blocks.BlockState import de.bixilon.minosoft.data.registries.blocks.BlockUsages import de.bixilon.minosoft.data.registries.blocks.types.Block import de.bixilon.minosoft.data.registries.versions.Registries -import de.bixilon.minosoft.gui.rendering.input.camera.RaycastHit +import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit +import de.bixilon.minosoft.gui.rendering.input.camera.hit.RaycastHit import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.protocol.packets.c2s.play.BlockPlaceC2SP import glm_.vec3.Vec3 -import glm_.vec3.Vec3i open class BlockItem( resourceLocation: ResourceLocation, @@ -36,11 +35,15 @@ open class BlockItem( ) : Item(resourceLocation, registries, data) { val block: Block = registries.blockRegistry[data["block"].asInt] - override fun use(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack): BlockUsages { + override fun use(connection: PlayConnection, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack): BlockUsages { if (!connection.player.gamemode.canBuild) { return BlockUsages.PASS } + if (raycastHit !is BlockRaycastHit) { + return super.use(connection, raycastHit, hands, itemStack) + } + val placePosition = raycastHit.blockPosition + raycastHit.hitDirection if (!connection.world.isPositionChangeable(placePosition)) { return BlockUsages.PASS diff --git a/src/main/java/de/bixilon/minosoft/data/registries/items/Item.kt b/src/main/java/de/bixilon/minosoft/data/registries/items/Item.kt index c4fc38152..e47c584ae 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/items/Item.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/items/Item.kt @@ -27,9 +27,8 @@ import de.bixilon.minosoft.data.registries.registry.RegistryItem import de.bixilon.minosoft.data.registries.registry.ResourceLocationDeserializer import de.bixilon.minosoft.data.registries.registry.Translatable import de.bixilon.minosoft.data.registries.versions.Registries -import de.bixilon.minosoft.gui.rendering.input.camera.RaycastHit +import de.bixilon.minosoft.gui.rendering.input.camera.hit.RaycastHit import de.bixilon.minosoft.protocol.network.connection.PlayConnection -import glm_.vec3.Vec3i open class Item( override val resourceLocation: ResourceLocation, @@ -51,7 +50,7 @@ open class Item( return 1.0f } - open fun use(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack): BlockUsages { + open fun use(connection: PlayConnection, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack): BlockUsages { return BlockUsages.PASS } diff --git a/src/main/java/de/bixilon/minosoft/data/registries/items/tools/AxeItem.kt b/src/main/java/de/bixilon/minosoft/data/registries/items/tools/AxeItem.kt index 813e6e41f..c83ac0ec3 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/items/tools/AxeItem.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/items/tools/AxeItem.kt @@ -18,14 +18,13 @@ import de.bixilon.minosoft.Minosoft import de.bixilon.minosoft.data.inventory.ItemStack import de.bixilon.minosoft.data.player.Hands import de.bixilon.minosoft.data.registries.ResourceLocation -import de.bixilon.minosoft.data.registries.blocks.BlockState import de.bixilon.minosoft.data.registries.blocks.BlockUsages import de.bixilon.minosoft.data.registries.blocks.types.Block import de.bixilon.minosoft.data.registries.versions.Registries -import de.bixilon.minosoft.gui.rendering.input.camera.RaycastHit +import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit +import de.bixilon.minosoft.gui.rendering.input.camera.hit.RaycastHit import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.util.KUtil.asResourceLocation -import glm_.vec3.Vec3i open class AxeItem( resourceLocation: ResourceLocation, @@ -41,12 +40,15 @@ open class AxeItem( entries.toMap() } - override fun use(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack): BlockUsages { + override fun use(connection: PlayConnection, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack): BlockUsages { if (!Minosoft.config.config.game.controls.enableStripping) { return BlockUsages.CONSUME } + if (raycastHit !is BlockRaycastHit) { + return super.use(connection, raycastHit, hands, itemStack) + } - return super.interactWithTool(connection, blockPosition, strippableBlocks?.get(blockState.block)?.withProperties(blockState.properties)) + return super.interactWithTool(connection, raycastHit.blockPosition, strippableBlocks?.get(raycastHit.blockState.block)?.withProperties(raycastHit.blockState.properties)) } companion object { diff --git a/src/main/java/de/bixilon/minosoft/data/registries/items/tools/HoeItem.kt b/src/main/java/de/bixilon/minosoft/data/registries/items/tools/HoeItem.kt index a125b3672..19d1ec414 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/items/tools/HoeItem.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/items/tools/HoeItem.kt @@ -23,11 +23,11 @@ import de.bixilon.minosoft.data.registries.blocks.BlockState import de.bixilon.minosoft.data.registries.blocks.BlockUsages import de.bixilon.minosoft.data.registries.blocks.types.Block import de.bixilon.minosoft.data.registries.versions.Registries -import de.bixilon.minosoft.gui.rendering.input.camera.RaycastHit +import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit +import de.bixilon.minosoft.gui.rendering.input.camera.hit.RaycastHit import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.util.KUtil.asResourceLocation -import glm_.vec3.Vec3i open class HoeItem( resourceLocation: ResourceLocation, @@ -43,16 +43,19 @@ open class HoeItem( entries.toMap() } - override fun use(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack): BlockUsages { + override fun use(connection: PlayConnection, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack): BlockUsages { if (!Minosoft.config.config.game.controls.enableTilling) { return BlockUsages.CONSUME } + if (raycastHit !is BlockRaycastHit) { + return super.use(connection, raycastHit, hands, itemStack) + } - if (connection.world[blockPosition + Directions.UP] != null) { + if (connection.world[raycastHit.blockPosition + Directions.UP] != null) { return BlockUsages.PASS } - return super.interactWithTool(connection, blockPosition, tillableBlockStates?.get(blockState.block)) + return super.interactWithTool(connection, raycastHit.blockPosition, tillableBlockStates?.get(raycastHit.blockState.block)) } companion object { diff --git a/src/main/java/de/bixilon/minosoft/data/registries/items/tools/ShovelItem.kt b/src/main/java/de/bixilon/minosoft/data/registries/items/tools/ShovelItem.kt index c2eb516f5..dbf29a1ca 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/items/tools/ShovelItem.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/items/tools/ShovelItem.kt @@ -23,11 +23,11 @@ import de.bixilon.minosoft.data.registries.blocks.BlockState import de.bixilon.minosoft.data.registries.blocks.BlockUsages import de.bixilon.minosoft.data.registries.blocks.types.Block import de.bixilon.minosoft.data.registries.versions.Registries -import de.bixilon.minosoft.gui.rendering.input.camera.RaycastHit +import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit +import de.bixilon.minosoft.gui.rendering.input.camera.hit.RaycastHit import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.util.KUtil.asResourceLocation -import glm_.vec3.Vec3i open class ShovelItem( resourceLocation: ResourceLocation, @@ -44,16 +44,19 @@ open class ShovelItem( } - override fun use(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack): BlockUsages { + override fun use(connection: PlayConnection, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack): BlockUsages { if (!Minosoft.config.config.game.controls.enableFlattening) { return BlockUsages.CONSUME } + if (raycastHit !is BlockRaycastHit) { + return super.use(connection, raycastHit, hands, itemStack) + } - if (connection.world[blockPosition + Directions.UP] != null) { + if (connection.world[raycastHit.blockPosition + Directions.UP] != null) { return BlockUsages.PASS } - return super.interactWithTool(connection, blockPosition, flattenableBlockStates?.get(blockState.block)) + return super.interactWithTool(connection, raycastHit.blockPosition, flattenableBlockStates?.get(raycastHit.blockState.block)) } diff --git a/src/main/java/de/bixilon/minosoft/gui/main/GUITools.java b/src/main/java/de/bixilon/minosoft/gui/main/GUITools.java index af634b206..c6fcb384e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/GUITools.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/GUITools.java @@ -35,7 +35,6 @@ import java.util.Base64; public class GUITools { public static final Image MINOSOFT_LOGO = new Image(GUITools.class.getResourceAsStream("/assets/minosoft/textures/icons/window_icon.png")); public static final ObservableList VERSIONS = FXCollections.observableArrayList(); - public static final JFXComboBox VERSION_COMBO_BOX = new JFXComboBox<>(VERSIONS); static { VERSIONS.add(Versions.AUTOMATIC_VERSION); @@ -49,6 +48,8 @@ public class GUITools { }); } + public static final JFXComboBox VERSION_COMBO_BOX = new JFXComboBox<>(VERSIONS); + public static Image getImageFromBase64(String base64) { if (base64 == null) { return null; diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineRenderer.kt index 048f4e068..f64b42450 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineRenderer.kt @@ -21,11 +21,13 @@ import de.bixilon.minosoft.gui.rendering.RenderConstants import de.bixilon.minosoft.gui.rendering.RenderWindow import de.bixilon.minosoft.gui.rendering.Renderer import de.bixilon.minosoft.gui.rendering.RendererBuilder +import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit import de.bixilon.minosoft.gui.rendering.system.base.DepthFunctions import de.bixilon.minosoft.gui.rendering.util.VecUtil.getWorldOffset import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3d import de.bixilon.minosoft.gui.rendering.util.mesh.LineMesh import de.bixilon.minosoft.protocol.network.connection.PlayConnection +import de.bixilon.minosoft.util.KUtil.nullCast import glm_.vec3.Vec3i class BlockOutlineRenderer( @@ -56,7 +58,7 @@ class BlockOutlineRenderer( } override fun draw() { - val raycastHit = renderWindow.inputHandler.camera.getTargetBlock() + val raycastHit = renderWindow.inputHandler.camera.target?.nullCast() var currentMesh = currentMesh diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/debug/HUDSystemDebugNode.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/debug/HUDSystemDebugNode.kt index 2bb6c843b..80b9abaf2 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/debug/HUDSystemDebugNode.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/nodes/debug/HUDSystemDebugNode.kt @@ -18,14 +18,19 @@ import de.bixilon.minosoft.data.registries.ResourceLocation import de.bixilon.minosoft.gui.rendering.hud.HUDElementProperties import de.bixilon.minosoft.gui.rendering.hud.HUDRenderBuilder import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer +import de.bixilon.minosoft.gui.rendering.hud.nodes.primitive.LabelNode import de.bixilon.minosoft.gui.rendering.hud.nodes.properties.NodeAlignment +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.ResizeWindowEvent import de.bixilon.minosoft.modding.event.CallbackEventInvoker import de.bixilon.minosoft.modding.loading.ModLoader import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.util.GitInfo import de.bixilon.minosoft.util.SystemInformation -import de.bixilon.minosoft.util.UnitFormatter +import de.bixilon.minosoft.util.UnitFormatter.formatBytes import glm_.vec2.Vec2 import org.lwjgl.opengl.GL11.* @@ -73,8 +78,25 @@ class HUDSystemDebugNode(hudRenderer: HUDRenderer) : DebugScreenNode(hudRenderer text() } - private val targetPosition = text("TBA") - private val targetBlockState = text("TBA") + private val target = text("TBA") + + init { + text() + } + + private val targetBlock = text() + + init { + text() + } + + private val targetFluid = text() + + init { + text() + } + + private val targetEntity = text() override fun init() { gpuText.sText = "GPU: " + (glGetString(GL_RENDERER) ?: "unknown") @@ -92,17 +114,36 @@ class HUDSystemDebugNode(hudRenderer: HUDRenderer) : DebugScreenNode(hudRenderer memoryText.sText = "Memory: ${getUsedMemoryPercent()}% ${getFormattedUsedMemory()}/${SystemInformation.MAX_MEMORY_TEXT}" allocatedMemoryText.sText = "Allocated: ${getAllocatedMemoryPercent()}% ${getFormattedAllocatedMemory()}" - gpuMemoryText.sText = "VRAM: ${UnitFormatter.formatBytes(hudRenderer.renderWindow.renderSystem.usedVRAM)} / ${UnitFormatter.formatBytes(hudRenderer.renderWindow.renderSystem.availableVRAM)} | ${UnitFormatter.formatBytes(hudRenderer.renderWindow.renderSystem.maximumVRAM)}" + gpuMemoryText.sText = "VRAM: ${hudRenderer.renderWindow.renderSystem.usedVRAM.formatBytes()} / ${hudRenderer.renderWindow.renderSystem.availableVRAM.formatBytes()} | ${hudRenderer.renderWindow.renderSystem.maximumVRAM.formatBytes()}" - val rayCastHit = hudRenderer.renderWindow.inputHandler.camera.getTargetBlock() - if (rayCastHit == null) { - targetPosition.sText = "" - targetBlockState.sText = "" - } else { - targetPosition.sText = "Target block: ${rayCastHit.blockPosition}" - targetBlockState.sText = rayCastHit.blockState.toString() + + val target = hudRenderer.renderWindow.inputHandler.camera.target + + val targetClass = target?.let { it::class.java } + this.target.sText = target?.let { + val targetType = when (targetClass) { + FluidRaycastHit::class.java -> "Fluid" + BlockRaycastHit::class.java -> "Block" + EntityRaycastHit::class.java -> "Entity" + else -> "Unknown" + } + "Target: $targetType: $it" + } ?: "No target!" + + if (target != null) { + fun addTarget(labelNode: LabelNode, raycastHit: RaycastHit?, name: String) { + labelNode.sText = if (raycastHit != null && targetClass != raycastHit::class.java) { + "$name target: $raycastHit" + } else { + "" + } + } + + val camera = hudRenderer.renderWindow.inputHandler.camera + addTarget(this.targetBlock, camera.blockTarget, "Block") + addTarget(this.targetFluid, camera.fluidTarget, "Fluid") + addTarget(this.targetEntity, camera.entityTarget, "Entity") } - lastPrepareTime = System.currentTimeMillis() } @@ -111,7 +152,7 @@ class HUDSystemDebugNode(hudRenderer: HUDRenderer) : DebugScreenNode(hudRenderer } private fun getFormattedUsedMemory(): String { - return UnitFormatter.formatBytes(getUsedMemory()) + return getUsedMemory().formatBytes() } private fun getAllocatedMemory(): Long { @@ -119,7 +160,7 @@ class HUDSystemDebugNode(hudRenderer: HUDRenderer) : DebugScreenNode(hudRenderer } private fun getFormattedAllocatedMemory(): String { - return UnitFormatter.formatBytes(getAllocatedMemory()) + return getAllocatedMemory().formatBytes() } private fun getUsedMemoryPercent(): Long { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/LeftClickHandler.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/LeftClickHandler.kt index ee452a237..9dce77555 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/LeftClickHandler.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/LeftClickHandler.kt @@ -25,11 +25,13 @@ import de.bixilon.minosoft.data.registries.fluid.DefaultFluids import de.bixilon.minosoft.data.registries.items.tools.MiningToolItem import de.bixilon.minosoft.gui.rendering.RenderConstants import de.bixilon.minosoft.gui.rendering.RenderWindow +import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit import de.bixilon.minosoft.modding.event.CallbackEventInvoker import de.bixilon.minosoft.modding.event.events.BlockBreakAckEvent import de.bixilon.minosoft.protocol.packets.c2s.play.ArmSwingC2SP import de.bixilon.minosoft.protocol.packets.c2s.play.BlockBreakC2SP import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition +import de.bixilon.minosoft.util.KUtil.nullCast import de.bixilon.minosoft.util.KUtil.synchronizedMapOf import glm_.pow import glm_.vec3.Vec3i @@ -98,7 +100,7 @@ class LeftClickHandler( cancelDigging() return false } - val raycastHit = renderWindow.inputHandler.camera.getTargetBlock() + val raycastHit = renderWindow.inputHandler.camera.target?.nullCast() if (raycastHit == null) { cancelDigging() diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/RightClickHandler.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/RightClickHandler.kt index 40bf8d026..5fd4bcbfd 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/RightClickHandler.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/RightClickHandler.kt @@ -18,10 +18,12 @@ import de.bixilon.minosoft.data.player.Hands import de.bixilon.minosoft.data.registries.blocks.BlockUsages import de.bixilon.minosoft.gui.rendering.RenderConstants import de.bixilon.minosoft.gui.rendering.RenderWindow +import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit import de.bixilon.minosoft.protocol.packets.c2s.play.ArmSwingC2SP import de.bixilon.minosoft.protocol.packets.c2s.play.BlockPlaceC2SP import de.bixilon.minosoft.protocol.packets.c2s.play.ItemUseC2SP import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition +import de.bixilon.minosoft.util.KUtil.nullCast import glm_.vec3.Vec3 class RightClickHandler( @@ -45,7 +47,7 @@ class RightClickHandler( return } - val raycastHit = renderWindow.inputHandler.camera.getTargetBlock() ?: return + val raycastHit = renderWindow.inputHandler.camera.target?.nullCast() ?: return if (raycastHit.distance > RenderConstants.MAX_BLOCK_OUTLINE_RAYCAST_DISTANCE) { return @@ -94,7 +96,7 @@ class RightClickHandler( } - when (itemInHand.item.use(connection, raycastHit.blockState, raycastHit.blockPosition, raycastHit, Hands.MAIN_HAND, itemInHand)) { + when (itemInHand.item.use(connection, raycastHit, Hands.MAIN_HAND, itemInHand)) { BlockUsages.SUCCESS -> { connection.sendPacket(ArmSwingC2SP(Hands.MAIN_HAND)) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt index 0fc6d74d7..8473a1bd1 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt @@ -17,8 +17,13 @@ import de.bixilon.minosoft.Minosoft import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames import de.bixilon.minosoft.data.entities.EntityRotation import de.bixilon.minosoft.data.player.LocalPlayerEntity +import de.bixilon.minosoft.data.registries.blocks.types.FluidBlock import de.bixilon.minosoft.gui.rendering.RenderConstants import de.bixilon.minosoft.gui.rendering.RenderWindow +import de.bixilon.minosoft.gui.rendering.input.camera.hit.BlockRaycastHit +import de.bixilon.minosoft.gui.rendering.input.camera.hit.EntityRaycastHit +import de.bixilon.minosoft.gui.rendering.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 @@ -52,6 +57,15 @@ class Camera( var cameraRight = Vec3d(0.0, 0.0, -1.0) private var cameraUp = Vec3d(0.0, 1.0, 0.0) + var target: RaycastHit? = null + private set + var blockTarget: BlockRaycastHit? = null + private set + var fluidTarget: FluidRaycastHit? = null + private set + var entityTarget: EntityRaycastHit? = null + private set + val fov: Double get() { val fov = Minosoft.config.config.game.camera.fov / (zoom + 1.0) @@ -199,13 +213,20 @@ class Camera( } // ToDo: Only update if changed onPositionChange() + + val eyePosition = entity.eyePosition + val cameraFront = cameraFront + + target = raycast(eyePosition, cameraFront, blocks = true, fluids = true, 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? } - fun getTargetBlock(): RaycastHit? { - return raycast(entity.eyePosition, cameraFront) - } - - private fun raycast(origin: Vec3d, direction: Vec3d): RaycastHit? { + private fun raycast(origin: Vec3d, direction: Vec3d, blocks: Boolean, fluids: Boolean, entities: Boolean): RaycastHit? { + if (!blocks && !fluids && entities) { + return null // ToDo: Raycast entities + } val currentPosition = Vec3d(origin) fun getTotalDistance(): Double { @@ -215,21 +236,44 @@ class Camera( for (i in 0..RAYCAST_MAX_STEPS) { val blockPosition = currentPosition.floor val blockState = connection.world[blockPosition] - if (blockState != null) { - val voxelShapeRaycastResult = (blockState.outlineShape + blockPosition + blockPosition.getWorldOffset(blockState.block)).raycast(currentPosition, direction) - if (voxelShapeRaycastResult.hit) { - currentPosition += direction * voxelShapeRaycastResult.distance - return RaycastHit( + + 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 + } + return FluidRaycastHit( currentPosition, - blockPosition, - getTotalDistance(), - blockState, + distance, voxelShapeRaycastResult.direction, - i, + blockState, + blockPosition, + blockState.block.fluid, ) } + + if (!blocks) { + continue + } + return BlockRaycastHit( + currentPosition, + distance, + voxelShapeRaycastResult.direction, + blockState, + blockPosition, + ) + } else { + currentPosition += direction * (VecUtil.getDistanceToNextIntegerAxisInDirection(currentPosition, direction) + 0.001) } - currentPosition += direction * (VecUtil.getDistanceToNextIntegerAxisInDirection(currentPosition, direction) + 0.001) } return null } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/BlockRaycastHit.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/BlockRaycastHit.kt new file mode 100644 index 000000000..c92696385 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/BlockRaycastHit.kt @@ -0,0 +1,47 @@ +/* + * Minosoft + * Copyright (C) 2021 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.input.camera.hit + +import de.bixilon.minosoft.data.Directions +import de.bixilon.minosoft.data.registries.blocks.BlockState +import de.bixilon.minosoft.util.KUtil.format +import glm_.vec3.Vec3d +import glm_.vec3.Vec3i + +open class BlockRaycastHit( + position: Vec3d, + distance: Double, + hitDirection: Directions, + val blockState: BlockState, + val blockPosition: Vec3i, +) : RaycastHit(position, distance, hitDirection) { + val hitPosition = position - blockPosition + + override fun toString(): String { + val ret = StringBuilder() + ret.append(blockPosition) + ret.append(": ") + ret.append(blockState.block.resourceLocation) + + for ((key, value) in blockState.properties) { + ret.append('\n') + ret.append(' ') + ret.append(key.group) + ret.append(": ") + ret.append(value.format()) + } + + return ret.toString() + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/EntityRaycastHit.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/EntityRaycastHit.kt new file mode 100644 index 000000000..fdca357d9 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/EntityRaycastHit.kt @@ -0,0 +1,30 @@ +/* + * Minosoft + * Copyright (C) 2021 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.input.camera.hit + +import de.bixilon.minosoft.data.Directions +import de.bixilon.minosoft.data.entities.entities.Entity +import glm_.vec3.Vec3d + +class EntityRaycastHit( + position: Vec3d, + distance: Double, + hitDirection: Directions, + val entity: Entity, +) : RaycastHit(position, distance, hitDirection) { + + override fun toString(): String { + return "$position: ${entity.entityType.resourceLocation}" + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/FluidRaycastHit.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/FluidRaycastHit.kt new file mode 100644 index 000000000..3d22389c1 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/FluidRaycastHit.kt @@ -0,0 +1,35 @@ +/* + * Minosoft + * Copyright (C) 2021 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.input.camera.hit + +import de.bixilon.minosoft.data.Directions +import de.bixilon.minosoft.data.registries.blocks.BlockState +import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties +import de.bixilon.minosoft.data.registries.fluid.Fluid +import glm_.vec3.Vec3d +import glm_.vec3.Vec3i + +class FluidRaycastHit( + position: Vec3d, + distance: Double, + hitDirection: Directions, + blockState: BlockState, + blockPosition: Vec3i, + val fluid: Fluid, +) : BlockRaycastHit(position, distance, hitDirection, blockState, blockPosition) { + + override fun toString(): String { + return "$blockPosition: ${fluid.resourceLocation}\n Height: ${fluid.getHeight(blockState)}\n Level: ${blockState.properties[BlockProperties.FLUID_LEVEL]}" + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/RaycastHit.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/RaycastHit.kt similarity index 75% rename from src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/RaycastHit.kt rename to src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/RaycastHit.kt index 0d8c820a3..1b779fc99 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/RaycastHit.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/RaycastHit.kt @@ -11,20 +11,13 @@ * This software is not affiliated with Mojang AB, the original developer of Minecraft. */ -package de.bixilon.minosoft.gui.rendering.input.camera +package de.bixilon.minosoft.gui.rendering.input.camera.hit import de.bixilon.minosoft.data.Directions -import de.bixilon.minosoft.data.registries.blocks.BlockState import glm_.vec3.Vec3d -import glm_.vec3.Vec3i -data class RaycastHit( +abstract class RaycastHit( val position: Vec3d, - val blockPosition: Vec3i, val distance: Double, - val blockState: BlockState, val hitDirection: Directions, - val steps: Int, -) { - val hitPosition = position.minus(blockPosition) -} +) diff --git a/src/main/java/de/bixilon/minosoft/util/GitInfo.kt b/src/main/java/de/bixilon/minosoft/util/GitInfo.kt index fb933de0e..65b6ff360 100644 --- a/src/main/java/de/bixilon/minosoft/util/GitInfo.kt +++ b/src/main/java/de/bixilon/minosoft/util/GitInfo.kt @@ -104,8 +104,8 @@ object GitInfo { IS_INITIALIZED = true } catch (exception: Throwable) { - Log.log(LogMessageType.OTHER, level = LogLevels.WARN) { exception } Log.log(LogMessageType.OTHER, level = LogLevels.WARN) { "Could not load git information." } + Log.log(LogMessageType.OTHER, level = LogLevels.WARN) { exception } } } } diff --git a/src/main/java/de/bixilon/minosoft/util/KUtil.kt b/src/main/java/de/bixilon/minosoft/util/KUtil.kt index 8f1207ef8..e2ba27c15 100644 --- a/src/main/java/de/bixilon/minosoft/util/KUtil.kt +++ b/src/main/java/de/bixilon/minosoft/util/KUtil.kt @@ -15,6 +15,7 @@ package de.bixilon.minosoft.util import de.bixilon.minosoft.data.entities.entities.Entity import de.bixilon.minosoft.data.registries.ResourceLocation +import de.bixilon.minosoft.data.text.ChatComponent import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.util.collections.SynchronizedMap @@ -183,4 +184,28 @@ object KUtil { } return list.toList() } + + fun Any.format(): ChatComponent { + return ChatComponent.of(when (this) { + is Boolean -> { + if (this) { + "§atrue" + } else { + "§cfalse" + } + } + is Enum<*> -> { + val name = this.name + if (name.length == 1) { + name + } else { + name.lowercase() + } + } + is Number -> { + "§d$this" + } + else -> this.toString() + }) + } } diff --git a/src/main/java/de/bixilon/minosoft/util/SystemInformation.kt b/src/main/java/de/bixilon/minosoft/util/SystemInformation.kt index 3be655b7b..c7762d42d 100644 --- a/src/main/java/de/bixilon/minosoft/util/SystemInformation.kt +++ b/src/main/java/de/bixilon/minosoft/util/SystemInformation.kt @@ -13,6 +13,7 @@ package de.bixilon.minosoft.util +import de.bixilon.minosoft.util.UnitFormatter.formatBytes import oshi.SystemInfo object SystemInformation { @@ -20,7 +21,7 @@ object SystemInformation { val SYSTEM_INFO = SystemInfo() val HARDWARE_SYSTEM_INFO = SYSTEM_INFO.hardware - val SYSTEM_MEMORY_TEXT: String = UnitFormatter.formatBytes(HARDWARE_SYSTEM_INFO.memory.total) + val SYSTEM_MEMORY_TEXT: String = HARDWARE_SYSTEM_INFO.memory.total.formatBytes() val OS_TEXT: String = "${System.getProperty("os.name")}: ${SYSTEM_INFO.operatingSystem.family} ${SYSTEM_INFO.operatingSystem.bitness}bit" val PROCESSOR_TEXT = " ${RUNTIME.availableProcessors()}x ${HARDWARE_SYSTEM_INFO.processor.processorIdentifier.name.replace("\\s{2,}".toRegex(), "")}" @@ -34,7 +35,7 @@ object SystemInformation { } private fun getFormattedMaxMemory(): String { - return UnitFormatter.formatBytes(getMaxMemory()) + return getMaxMemory().formatBytes() } } diff --git a/src/main/java/de/bixilon/minosoft/util/UnitFormatter.kt b/src/main/java/de/bixilon/minosoft/util/UnitFormatter.kt index 2c9360787..d88c37e68 100644 --- a/src/main/java/de/bixilon/minosoft/util/UnitFormatter.kt +++ b/src/main/java/de/bixilon/minosoft/util/UnitFormatter.kt @@ -18,11 +18,11 @@ object UnitFormatter { private val UNITS = arrayOf("", "k", "M", "G", "T", "P", "E", "Z", "Y") private val TIME_UNITS = arrayOf("ns", "μs", "ms", "s", "m", "h", "d", "w", "M", "Y") - fun formatBytes(bytes: Long): String { - if (bytes < 0) { + fun Long.formatBytes(): String { + if (this < 0) { return "Unknown" } - return formatUnit(bytes, BYTE_UNITS, 1024L) + return formatUnit(this, BYTE_UNITS, 1024L) } fun formatNumber(number: Int): String {