rendering: Improve HUD structure, internal changes

* Before joining a server rendering will be started now.
* Rendering now uses (partly) the modding api
This commit is contained in:
Bixilon 2021-02-12 20:50:47 +01:00
parent 14a7ad6e61
commit edcc288898
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
17 changed files with 402 additions and 157 deletions

View File

@ -43,6 +43,9 @@ public abstract class ChatComponent {
if (raw == null) {
return new BaseComponent();
}
if (raw instanceof ChatComponent component) {
return component;
}
if (raw instanceof JsonPrimitive primitive) {
raw = primitive.getAsString();
}

View File

@ -4,9 +4,11 @@ import de.bixilon.minosoft.data.entities.EntityRotation
import de.bixilon.minosoft.data.entities.Location
import de.bixilon.minosoft.gui.rendering.chunk.ChunkRenderer
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.hud.elements.RenderStats
import de.bixilon.minosoft.protocol.network.Connection
import de.bixilon.minosoft.protocol.packets.serverbound.play.PacketPlayerPositionAndRotationSending
import de.bixilon.minosoft.util.CountUpAndDownLatch
import de.bixilon.minosoft.util.logging.Log
import org.lwjgl.*
import org.lwjgl.glfw.Callbacks
import org.lwjgl.glfw.GLFW.*
@ -17,26 +19,27 @@ import org.lwjgl.opengl.GL11.*
import org.lwjgl.system.MemoryStack
import org.lwjgl.system.MemoryUtil
import java.util.concurrent.ConcurrentLinkedQueue
import kotlin.math.roundToInt
class RenderWindow(private val connection: Connection, val rendering: Rendering) {
private var screenWidth = 800
private var screenHeight = 600
val renderStats = RenderStats()
var screenWidth = 800
var screenHeight = 600
private var polygonEnabled = false
private var windowId: Long = 0
private var deltaTime = 0.0 // time between current frame and last frame
private var lastFrame = 0.0
lateinit var camera: Camera
var latch = CountUpAndDownLatch(1)
// all renderers
val chunkRenderer: ChunkRenderer = ChunkRenderer(connection.player.world, this)
val chunkRenderer: ChunkRenderer = ChunkRenderer(connection, connection.player.world, this)
val hudRenderer: HUDRenderer = HUDRenderer(connection, this)
val renderQueue = ConcurrentLinkedQueue<Runnable>()
fun init(latch: CountUpAndDownLatch? = null) {
fun init(latch: CountUpAndDownLatch) {
// Setup an error callback. The default implementation
// will print the error message in System.err.
GLFWErrorCallback.createPrint(System.err).set()
@ -107,9 +110,9 @@ class RenderWindow(private val connection: Connection, val rendering: Rendering)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
chunkRenderer.init(connection)
chunkRenderer.init()
hudRenderer.init(connection)
hudRenderer.init()
glfwSetWindowSizeCallback(windowId, object : GLFWWindowSizeCallback() {
@ -128,23 +131,22 @@ class RenderWindow(private val connection: Connection, val rendering: Rendering)
camera.calculateProjectionMatrix(screenWidth, screenHeight, chunkRenderer.chunkShader)
camera.calculateViewMatrix(chunkRenderer.chunkShader)
glfwShowWindow(windowId)
latch?.countDown()
Log.debug("Rendering is prepared and ready to go!")
latch.countDown()
latch.waitUntilZero()
this.latch.waitUntilZero()
glfwShowWindow(windowId)
}
fun startRenderLoop() {
var framesLastSecond = 0
var lastCalcTime = glfwGetTime()
var frameTimeLastCalc = 0.0
var lastPositionChangeTime = 0.0
while (!glfwWindowShouldClose(windowId)) {
renderStats.startFrame()
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) // clear the framebuffer
val currentFrame = glfwGetTime()
deltaTime = currentFrame - lastFrame
lastFrame = currentFrame
@ -153,26 +155,15 @@ class RenderWindow(private val connection: Connection, val rendering: Rendering)
chunkRenderer.draw()
hudRenderer.draw()
renderStats.endDraw()
glfwSwapBuffers(windowId)
glfwPollEvents()
camera.handleInput(deltaTime)
frameTimeLastCalc += glfwGetTime() - currentFrame
if (glfwGetTime() - lastCalcTime >= 0.25) {
glfwSetWindowTitle(windowId, "Minosoft | FPS: ${framesLastSecond * 4} (${(0.25 * framesLastSecond / (frameTimeLastCalc)).roundToInt()})")
hudRenderer.fps = framesLastSecond * 4
lastCalcTime = glfwGetTime()
framesLastSecond = 0
frameTimeLastCalc = 0.0
}
framesLastSecond++
if (glfwGetTime() - lastPositionChangeTime > 0.05) {
// ToDo: Replace this with proper movement and only send it, when our position changed
@ -181,10 +172,13 @@ class RenderWindow(private val connection: Connection, val rendering: Rendering)
}
// handle opengl context tasks
for (renderQueueElement in renderQueue) {
renderQueueElement.run()
renderQueue.remove(renderQueueElement)
}
renderStats.endFrame()
}
}

View File

@ -1,10 +1,7 @@
package de.bixilon.minosoft.gui.rendering
import de.bixilon.minosoft.protocol.network.Connection
interface Renderer {
fun init(connection: Connection)
fun init()
fun draw()
fun screenChangeResizeCallback(width: Int, height: Int) {}
}

View File

@ -13,10 +13,10 @@ import java.util.concurrent.Executors
class Rendering(private val connection: Connection) {
val renderWindow: RenderWindow = RenderWindow(connection, this)
val latch = CountUpAndDownLatch(1)
val executor: ExecutorService = Executors.newFixedThreadPool(4, Util.getThreadFactory(String.format("Rendering#%d", connection.connectionId)))
fun start() {
fun start(latch: CountUpAndDownLatch) {
latch.countUp()
Thread({
Log.info("Hello LWJGL " + Version.getVersion() + "!")
renderWindow.init(latch)
@ -27,6 +27,10 @@ class Rendering(private val connection: Connection) {
fun teleport(position: Location) {
// tell the window we are ready (received position)
if (renderWindow.latch.count > 0) {
renderWindow.latch.countDown()
}
renderWindow.renderQueue.add {
renderWindow.camera.cameraPosition = Vec3(position.x, position.y, position.z)
}

View File

@ -19,7 +19,7 @@ import org.lwjgl.opengl.GL11.glEnable
import org.lwjgl.opengl.GL13.GL_TEXTURE0
import java.util.concurrent.ConcurrentHashMap
class ChunkRenderer(private val world: World, val renderWindow: RenderWindow) : Renderer {
class ChunkRenderer(private val connection: Connection, private val world: World, val renderWindow: RenderWindow) : Renderer {
private lateinit var minecraftTextures: TextureArray
lateinit var chunkShader: Shader
private val chunkSectionsToDraw = ConcurrentHashMap<ChunkLocation, ConcurrentHashMap<Int, WorldMesh>>()
@ -81,7 +81,7 @@ class ChunkRenderer(private val world: World, val renderWindow: RenderWindow) :
return data.toFloatArray()
}
override fun init(connection: Connection) {
override fun init() {
minecraftTextures = TextureArray.createTextureArray(connection.version.assetsManager, resolveBlockTextureIds(connection.version.mapping.blockMap.values), 16, 16) // ToDo :Remove fixed size
minecraftTextures.load()
@ -124,7 +124,6 @@ class ChunkRenderer(private val world: World, val renderWindow: RenderWindow) :
fun prepareChunkSection(chunkLocation: ChunkLocation, sectionHeight: Int, section: ChunkSection) {
renderWindow.rendering.executor.execute {
renderWindow.rendering.latch.waitUntilZero() // Wait until rendering is started
try {
val data = prepareChunk(chunkLocation, sectionHeight, section)
val sectionMap = chunkSectionsToDraw[chunkLocation]!!

View File

@ -1,135 +1,54 @@
package de.bixilon.minosoft.gui.rendering.hud
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.data.mappings.ModIdentifier
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.Renderer
import de.bixilon.minosoft.gui.rendering.font.Font
import de.bixilon.minosoft.gui.rendering.font.FontBindings
import de.bixilon.minosoft.gui.rendering.shader.Shader
import de.bixilon.minosoft.gui.rendering.textures.TextureArray
import de.bixilon.minosoft.gui.rendering.hud.elements.HUDElement
import de.bixilon.minosoft.gui.rendering.hud.elements.text.HUDTextElement
import de.bixilon.minosoft.protocol.network.Connection
import glm_.glm
import glm_.mat4x4.Mat4
import glm_.vec2.Vec2
import org.lwjgl.opengl.GL11.GL_DEPTH_TEST
import org.lwjgl.opengl.GL11.glDisable
import org.lwjgl.opengl.GL13.GL_TEXTURE0
import java.util.concurrent.ConcurrentLinkedQueue
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
class HUDRenderer(private val connection: Connection, private val renderWindow: RenderWindow) : Renderer {
private val font = Font()
private val hudScale = HUDScale.MEDIUM
var fps: Int = 0
var frame = 0
private lateinit var fontShader: Shader
private lateinit var fontAtlasTexture: TextureArray
private lateinit var hudMeshHUD: HUDFontMesh
private var screenWidth = 0
private var screenHeight = 0
var chatMessages: ConcurrentLinkedQueue<Pair<ChatComponent, Long>> = ConcurrentLinkedQueue()
private var showChat = true
private var showDebugScreen = true
private val fontBindingPerspectiveMatrices = mutableListOf(Mat4(), Mat4(), Mat4(), Mat4()) // according to FontBindings::ordinal
class HUDRenderer(private val connection: Connection, renderWindow: RenderWindow) : Renderer {
var hudScale = HUDScale.MEDIUM
val hudElements: MutableMap<ModIdentifier, HUDElement> = mutableMapOf(
ModIdentifier("minosoft:hud_text_renderer") to HUDTextElement(connection, this, renderWindow),
)
var lastTimePrepared = 0L
override fun init(connection: Connection) {
font.load(connection.version.assetsManager)
fontAtlasTexture = font.createAtlasTexture()
fontAtlasTexture.load()
fontShader = Shader("font_vertex.glsl", "font_fragment.glsl")
fontShader.load()
hudMeshHUD = HUDFontMesh(floatArrayOf())
override fun init() {
for (element in hudElements.values) {
element.init()
}
}
fun drawChatComponent(position: Vec2, binding: FontBindings, text: ChatComponent, meshData: MutableList<Float>, maxSize: Vec2) {
hudMeshHUD.unload()
text.addVerticies(position, Vec2(0, 0), fontBindingPerspectiveMatrices[binding.ordinal], binding, font, hudScale, meshData, maxSize)
}
fun screenChangeResizeCallback(width: Int, height: Int) {
fontShader.use()
screenWidth = width
screenHeight = height
fontBindingPerspectiveMatrices[FontBindings.LEFT_UP.ordinal] = glm.ortho(0.0f, width.toFloat(), height.toFloat(), 0.0f)
fontBindingPerspectiveMatrices[FontBindings.RIGHT_UP.ordinal] = glm.ortho(width.toFloat(), 0.0f, height.toFloat(), 0.0f)
fontBindingPerspectiveMatrices[FontBindings.RIGHT_DOWN.ordinal] = glm.ortho(width.toFloat(), 0.0f, 0.0f, height.toFloat())
fontBindingPerspectiveMatrices[FontBindings.LEFT_DOWN.ordinal] = glm.ortho(0.0f, width.toFloat(), 0.0f, height.toFloat())
prepare()
override fun screenChangeResizeCallback(width: Int, height: Int) {
for (element in hudElements.values) {
element.screenChangeResizeCallback(width, height)
}
}
override fun draw() {
fontAtlasTexture.use(GL_TEXTURE0)
fontShader.use()
glDisable(GL_DEPTH_TEST)
frame++
if (frame % 15 == 0) {
if (System.currentTimeMillis() - lastTimePrepared > ProtocolDefinition.TICK_TIME) {
prepare()
update()
lastTimePrepared = System.currentTimeMillis()
}
hudMeshHUD.draw()
for (element in hudElements.values) {
element.draw()
}
}
fun prepare() {
val runtime = Runtime.getRuntime()!!
val meshData: MutableList<Float> = mutableListOf()
val componentsBindingMap: Map<FontBindings, MutableList<Any>> = mapOf(
FontBindings.LEFT_UP to mutableListOf(
"§aMinosoft (0.1-pre1)",
),
FontBindings.RIGHT_UP to mutableListOf(),
FontBindings.RIGHT_DOWN to mutableListOf(),
FontBindings.LEFT_DOWN to mutableListOf(),
)
if (showDebugScreen) {
componentsBindingMap[FontBindings.LEFT_UP]!!.addAll(listOf(
"§fFPS: §8$fps",
"§fXYZ §8${"%.4f".format(renderWindow.camera.cameraPosition.x)} / ${"%.4f".format(renderWindow.camera.cameraPosition.y)} / ${"%.4f".format(renderWindow.camera.cameraPosition.z)}",
"§fConnected to: §8${connection.address}",
))
componentsBindingMap[FontBindings.RIGHT_UP]!!.addAll(listOf(
"§fJava: §8${Runtime.version()} ${System.getProperty("sun.arch.data.model")}bit",
"§fMemory: §8${runtime.freeMemory() * 100 / runtime.maxMemory()}% ${(runtime.totalMemory() - runtime.freeMemory()) / (1024 * 1024)}/${runtime.maxMemory() / (1024 * 1024)}MB",
"§fAllocated: §8${runtime.totalMemory() * 100 / runtime.maxMemory()}% ${runtime.totalMemory() / (1024 * 1024)}MB",
" ",
"CPU: §8${runtime.availableProcessors()}x TODO",
"OS: §8${System.getProperty("os.name")}",
" ",
"Display: §8${screenWidth}x${screenHeight}",
))
for (element in hudElements.values) {
element.prepare()
}
if (showChat) {
for (entry in chatMessages) {
if (System.currentTimeMillis() - entry.second > 10000) {
chatMessages.remove(entry)
continue
}
componentsBindingMap[FontBindings.LEFT_DOWN]!!.add(entry.first)
}
}
for ((binding, components) in componentsBindingMap) {
val offset = Vec2(3, 3)
}
if (binding == FontBindings.RIGHT_DOWN || binding == FontBindings.LEFT_DOWN) {
components.reverse()
}
for ((_, component) in components.withIndex()) {
val currentOffset = Vec2()
val chatComponent = if (component is ChatComponent) {
component
} else {
ChatComponent.valueOf(component)
}
drawChatComponent(offset, binding, chatComponent, meshData, currentOffset)
offset += Vec2(0, currentOffset.y + 1)
}
hudMeshHUD = HUDFontMesh(meshData.toFloatArray())
fun update() {
for (element in hudElements.values) {
element.update()
}
}
}

View File

@ -0,0 +1,10 @@
package de.bixilon.minosoft.gui.rendering.hud.elements
interface HUDElement {
fun init()
fun prepare()
fun update()
fun draw()
fun screenChangeResizeCallback(width: Int, height: Int) {}
}

View File

@ -0,0 +1,43 @@
package de.bixilon.minosoft.gui.rendering.hud.elements
class RenderStats {
var fpsLastSecond = -1
var minFrameTime = Long.MAX_VALUE
var maxFrameTime = 0L
var avgFrameTime = 0L
var frames = 0L
private var lastFPSCalcTime = 0L
private var framesLastSecond = 0
private var frameStartTime = 0L
fun startFrame() {
frameStartTime = System.nanoTime()
}
fun endDraw() {
}
fun endFrame() {
val frameEndTime = System.nanoTime()
val frameTime = frameEndTime - frameStartTime
if (frameTime < minFrameTime) {
minFrameTime = frameTime
}
if (frameTime > maxFrameTime) {
maxFrameTime = frameTime
}
if (frameEndTime - lastFPSCalcTime > 1E9) {
// 1 second
fpsLastSecond = framesLastSecond
framesLastSecond = 0
lastFPSCalcTime = frameEndTime
}
frames++
framesLastSecond++
}
}

View File

@ -0,0 +1,30 @@
package de.bixilon.minosoft.gui.rendering.hud.elements.text
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.gui.rendering.font.FontBindings
import de.bixilon.minosoft.modding.event.EventInvokerCallback
import de.bixilon.minosoft.modding.event.events.ChatMessageReceivingEvent
import java.util.concurrent.ConcurrentLinkedQueue
class HUDChatElement(hudTextElement: HUDTextElement) : HUDText {
private var showChat = true
var chatMessages: ConcurrentLinkedQueue<Pair<ChatComponent, Long>> = ConcurrentLinkedQueue()
init {
hudTextElement.connection.registerEvent(EventInvokerCallback<ChatMessageReceivingEvent> {
chatMessages.add(Pair(it.message, System.currentTimeMillis()))
})
}
override fun prepare(chatComponents: Map<FontBindings, MutableList<Any>>) {
if (showChat) {
for (entry in chatMessages) {
if (System.currentTimeMillis() - entry.second > 10000) {
chatMessages.remove(entry)
continue
}
chatComponents[FontBindings.LEFT_DOWN]!!.add(entry.first)
}
}
}
}

View File

@ -0,0 +1,113 @@
package de.bixilon.minosoft.gui.rendering.hud.elements.text
import de.bixilon.minosoft.gui.rendering.font.FontBindings
class HUDDebugScreenElement(private val hudTextElement: HUDTextElement) : HUDText {
private val runtime = Runtime.getRuntime()
override fun prepare(chatComponents: Map<FontBindings, MutableList<Any>>) {
chatComponents[FontBindings.LEFT_UP]!!.addAll(listOf(
"§fFPS: §8${getFPS()}",
"§fTimings: §8avg ${getAvgFrameTime()}ms, min ${getMinFrameTime()}ms, max ${getMaxFrameTime()}ms",
"§fXYZ §8${getLocation()}",
"§fConnected to: §8${hudTextElement.connection.address}",
))
chatComponents[FontBindings.RIGHT_UP]!!.addAll(listOf(
"§fJava: §8${Runtime.version()} ${System.getProperty("sun.arch.data.model")}bit",
"§fMemory: §8${getUsedMemoryPercent()}% ${getFormattedUsedMemory()}/${getFormattedMaxMemory()}",
"§fAllocated: §8${getAllocatedMemoryPercent()}% ${getFormattedAllocatedMemory()}",
" ",
"CPU: §8${runtime.availableProcessors()}x TODO",
"OS: §8${System.getProperty("os.name")}",
" ",
"Display: §8${getScreenDimensions()}",
))
}
private fun nanoToMillis1d(nanos: Long): String {
return "%.1f".format(nanos / 1000000f)
}
private fun getFPS(): String {
val renderStats = hudTextElement.renderWindow.renderStats
return "${renderStats.fpsLastSecond}"
}
private fun getAvgFrameTime(): String {
return nanoToMillis1d(hudTextElement.renderWindow.renderStats.avgFrameTime)
}
private fun getMinFrameTime(): String {
return nanoToMillis1d(hudTextElement.renderWindow.renderStats.minFrameTime)
}
private fun getMaxFrameTime(): String {
return nanoToMillis1d(hudTextElement.renderWindow.renderStats.maxFrameTime)
}
private fun getUsedMemory(): Long {
return runtime.totalMemory() - runtime.freeMemory()
}
private fun getFormattedUsedMemory(): String {
return formatBytes(getUsedMemory())
}
private fun getAllocatedMemory(): Long {
return runtime.totalMemory()
}
private fun getFormattedAllocatedMemory(): String {
return formatBytes(getAllocatedMemory())
}
private fun getMaxMemory(): Long {
return runtime.maxMemory()
}
private fun getFormattedMaxMemory(): String {
return formatBytes(getMaxMemory())
}
private fun getUsedMemoryPercent(): Long {
return getUsedMemory() * 100 / runtime.maxMemory()
}
private fun getAllocatedMemoryPercent(): Long {
return getAllocatedMemory() * 100 / runtime.maxMemory()
}
private fun getLocation(): String {
val cameraPosition = hudTextElement.renderWindow.camera.cameraPosition
return "${formatCoordinate(cameraPosition.x)} / ${formatCoordinate(cameraPosition.y)} / ${formatCoordinate(cameraPosition.z)}"
}
private fun getScreenDimensions(): String {
return "${hudTextElement.renderWindow.screenWidth}x${hudTextElement.renderWindow.screenHeight}"
}
companion object {
private val UNITS = listOf("B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB")
fun formatBytes(bytes: Long): String {
var lastFactor = 1L
var currentFactor = 1024L
for (unit in UNITS) {
if (bytes < currentFactor) {
if (bytes < (lastFactor * 10)) {
return "${"%.1f".format(bytes / lastFactor.toFloat())}${unit}"
}
return "${bytes / lastFactor}${unit}"
}
lastFactor = currentFactor
currentFactor *= 1024L
}
throw IllegalArgumentException()
}
fun formatCoordinate(coordinate: Float): String {
return "%.4f".format(coordinate)
}
}
}

View File

@ -1,4 +1,4 @@
package de.bixilon.minosoft.gui.rendering.hud
package de.bixilon.minosoft.gui.rendering.hud.elements.text
import glm_.BYTES
import org.lwjgl.opengl.GL11.GL_FLOAT

View File

@ -0,0 +1,10 @@
package de.bixilon.minosoft.gui.rendering.hud.elements.text
import de.bixilon.minosoft.gui.rendering.font.FontBindings
interface HUDText {
fun prepare(chatComponents: Map<FontBindings, MutableList<Any>>)
fun update() {}
fun draw() {}
}

View File

@ -0,0 +1,108 @@
package de.bixilon.minosoft.gui.rendering.hud.elements.text
import de.bixilon.minosoft.data.mappings.ModIdentifier
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.font.Font
import de.bixilon.minosoft.gui.rendering.font.FontBindings
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.hud.elements.HUDElement
import de.bixilon.minosoft.gui.rendering.shader.Shader
import de.bixilon.minosoft.gui.rendering.textures.TextureArray
import de.bixilon.minosoft.protocol.network.Connection
import glm_.glm
import glm_.mat4x4.Mat4
import glm_.vec2.Vec2
import org.lwjgl.opengl.GL11.GL_DEPTH_TEST
import org.lwjgl.opengl.GL11.glDisable
import org.lwjgl.opengl.GL13.GL_TEXTURE0
class HUDTextElement(val connection: Connection, val hudRenderer: HUDRenderer, val renderWindow: RenderWindow) : HUDElement {
private val fontBindingPerspectiveMatrices = mutableListOf(Mat4(), Mat4(), Mat4(), Mat4()) // according to FontBindings::ordinal
private lateinit var fontShader: Shader
private lateinit var hudMeshHUD: HUDFontMesh
private lateinit var fontAtlasTexture: TextureArray
private val font = Font()
private lateinit var componentsBindingMap: Map<FontBindings, MutableList<Any>>
var hudTextElements: MutableMap<ModIdentifier, HUDText> = mutableMapOf(
ModIdentifier("minosoft:debug_screen") to HUDDebugScreenElement(this),
ModIdentifier("minosoft:chat") to HUDChatElement(this),
)
override fun screenChangeResizeCallback(width: Int, height: Int) {
fontShader.use()
fontBindingPerspectiveMatrices[FontBindings.LEFT_UP.ordinal] = glm.ortho(0.0f, width.toFloat(), height.toFloat(), 0.0f)
fontBindingPerspectiveMatrices[FontBindings.RIGHT_UP.ordinal] = glm.ortho(width.toFloat(), 0.0f, height.toFloat(), 0.0f)
fontBindingPerspectiveMatrices[FontBindings.RIGHT_DOWN.ordinal] = glm.ortho(width.toFloat(), 0.0f, 0.0f, height.toFloat())
fontBindingPerspectiveMatrices[FontBindings.LEFT_DOWN.ordinal] = glm.ortho(0.0f, width.toFloat(), 0.0f, height.toFloat())
prepare()
}
fun drawChatComponent(position: Vec2, binding: FontBindings, text: ChatComponent, meshData: MutableList<Float>, maxSize: Vec2) {
hudMeshHUD.unload()
text.addVerticies(position, Vec2(0, 0), fontBindingPerspectiveMatrices[binding.ordinal], binding, font, hudRenderer.hudScale, meshData, maxSize)
}
override fun prepare() {
componentsBindingMap = mapOf(
FontBindings.LEFT_UP to mutableListOf(
"§aMinosoft (0.1-pre1)",
),
FontBindings.RIGHT_UP to mutableListOf(),
FontBindings.RIGHT_DOWN to mutableListOf(),
FontBindings.LEFT_DOWN to mutableListOf(),
)
for (hudTextElement in hudTextElements.values) {
hudTextElement.prepare(componentsBindingMap)
}
}
override fun update() {
for (hudTextElement in hudTextElements.values) {
hudTextElement.update()
}
val meshData: MutableList<Float> = mutableListOf()
for ((binding, components) in componentsBindingMap) {
val offset = Vec2(3, 3)
if (binding == FontBindings.RIGHT_DOWN || binding == FontBindings.LEFT_DOWN) {
components.reverse()
}
for ((_, component) in components.withIndex()) {
val currentOffset = Vec2()
drawChatComponent(offset, binding, ChatComponent.valueOf(component), meshData, currentOffset)
offset += Vec2(0, currentOffset.y + 1)
}
}
hudMeshHUD.unload()
hudMeshHUD = HUDFontMesh(meshData.toFloatArray())
}
override fun init() {
font.load(connection.version.assetsManager)
fontShader = Shader("font_vertex.glsl", "font_fragment.glsl")
fontShader.load()
hudMeshHUD = HUDFontMesh(floatArrayOf())
fontAtlasTexture = font.createAtlasTexture()
fontAtlasTexture.load()
}
override fun draw() {
fontAtlasTexture.use(GL_TEXTURE0)
fontShader.use()
glDisable(GL_DEPTH_TEST)
for (hudTextElement in hudTextElements.values) {
hudTextElement.draw()
}
hudMeshHUD.draw()
}
}

View File

@ -135,11 +135,18 @@ public class Connection {
version.load(latch); // ToDo: show gui loader
this.customMapping.setVersion(version);
this.customMapping.setParentMapping(version.getMapping());
if (!StaticConfiguration.HEADLESS_MODE) {
this.rendering = new Rendering(this);
this.rendering.start(latch);
}
latch.waitForChange();
Log.info(String.format("Connecting to server: %s", address));
this.network.connect(address);
latch.countDown();
} catch (Exception e) {
Log.printException(e, LogLevels.DEBUG);
Log.fatal(String.format("Could not load mapping for %s. This version seems to be unsupported!", version));
Log.fatal(String.format("Could not load version %s. This version seems to be unsupported!", version));
this.lastException = new MappingsLoadingException("Mappings could not be loaded", e);
setConnectionState(ConnectionStates.FAILED_NO_RETRY);
}
@ -165,7 +172,6 @@ public class Connection {
this.version = version;
}
public void handle(ClientboundPacket p) {
this.handlingQueue.add(p);
}
@ -372,10 +378,6 @@ public class Connection {
case FAILED_NO_RETRY -> handlePingCallbacks(null);
case PLAY -> {
Minosoft.CONNECTIONS.put(getConnectionId(), this);
if (!StaticConfiguration.HEADLESS_MODE) {
this.rendering = new Rendering(this);
this.rendering.start();
}
if (CLI.getCurrentConnection() == null) {
CLI.setCurrentConnection(this);

View File

@ -56,8 +56,6 @@ public class PacketChatMessageReceiving extends ClientboundPacket {
case ABOVE_HOTBAR -> "[HOTBAR] ";
default -> "[CHAT] ";
} + event.getMessage());
connection.getRenderer().getRenderWindow().getHudRenderer().getChatMessages().add(new kotlin.Pair<>(this.message, System.currentTimeMillis()));
}
@Override

View File

@ -82,6 +82,10 @@ public final class ProtocolDefinition {
public static final char[] OBFUSCATED_CHARS = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".toCharArray();
public static final int TICKS_PER_SECOND = 20;
public static final int TICK_TIME = 1000 / TICKS_PER_SECOND;
static {
// java does (why ever) not allow to directly assign a null
InetAddress tempInetAddress;

View File

@ -32,6 +32,14 @@ public class CountUpAndDownLatch {
}
}
public void waitUntilZero(long timeout) throws InterruptedException {
synchronized (this.lock) {
while (this.count > 0) {
this.lock.wait(timeout);
}
}
}
public void countUp() {
synchronized (this.lock) {
this.total++;
@ -41,6 +49,9 @@ public class CountUpAndDownLatch {
}
public void countDown() {
if (this.count == 0) {
throw new IllegalStateException("Can not count down, counter is already 0");
}
synchronized (this.lock) {
this.count--;
this.lock.notifyAll();