/*
* Skytils - Hypixel Skyblock Quality of Life Mod
* Copyright (C) 2021 Skytils
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
package skytils.skytilsmod.utils.toasts
import gg.essential.universal.UResolution
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.Gui
import net.minecraft.client.gui.ScaledResolution
import net.minecraft.client.renderer.GlStateManager
import net.minecraft.client.renderer.RenderHelper
import net.minecraft.util.MathHelper
import org.lwjgl.opengl.GL11
import java.nio.FloatBuffer
import java.util.*
/**
* Taken from Skyblockcatia under MIT License
* Modified
* https://github.com/SteveKunG/SkyBlockcatia/blob/1.8.9/LICENSE.md
*
* @author SteveKunG
*/
class GuiToast(val mc: Minecraft) : Gui() {
private val visible = arrayOfNulls?>(5)
private val toastsQueue: Deque> = ArrayDeque()
fun drawToast(resolution: ScaledResolution) {
RenderHelper.disableStandardItemLighting()
for (i in visible.indices) {
val toastinstance = visible[i]
if (toastinstance != null && toastinstance.render(resolution.scaledWidth, i)) {
visible[i] = null
}
if (visible[i] == null && !toastsQueue.isEmpty()) {
visible[i] = ToastInstance>(toastsQueue.removeFirst())
}
}
}
@Suppress("unchecked_cast")
fun > getToast(clazz: Class, obj: Any): T? {
for (ins in visible) {
if (ins != null && clazz.isAssignableFrom(ins.toast!!.javaClass) && ins.toast.getType() == obj) {
return ins.toast as T
}
}
for (toast in toastsQueue) {
if (clazz.isAssignableFrom(toast.javaClass) && toast.getType() == obj) {
return toast as T
}
}
return null
}
fun clear() {
Arrays.fill(visible, null)
toastsQueue.clear()
}
fun add(toast: IToast<*>): Boolean {
return toastsQueue.add(toast)
}
internal inner class ToastInstance?>(toast: T) {
val toast: T
private var animationTime: Long
private var visibleTime: Long
private var visibility: IToast.Visibility?
private fun getVisibility(delta: Long): Float {
var f = MathHelper.clamp_float((delta - animationTime) / 600.0f, 0.0f, 1.0f)
f *= f
return if (visibility == IToast.Visibility.HIDE) 1.0f - f else f
}
fun render(x: Int, z: Int): Boolean {
val i = Minecraft.getSystemTime()
if (animationTime == -1L) {
animationTime = i
}
if (visibility == IToast.Visibility.SHOW && i - animationTime <= 600L) {
visibleTime = i
}
GlStateManager.pushMatrix()
GlStateManager.enableBlend()
GlStateManager.enableAlpha()
GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0)
GlStateManager.translate(x - 160.0f * getVisibility(i), (z * 32).toFloat(), (500 + z).toFloat())
val toastVisibility = toast!!.draw(this@GuiToast, i - visibleTime)
GlStateManager.disableBlend()
GlStateManager.popMatrix()
if (toastVisibility != visibility) {
animationTime = i - ((1.0f - getVisibility(i)) * 600.0f).toInt()
visibility = toastVisibility
}
return visibility == IToast.Visibility.HIDE && i - animationTime > 600L
}
init {
animationTime = -1L
visibleTime = -1L
visibility = IToast.Visibility.SHOW
this.toast = toast
}
}
companion object {
fun drawSubline(
toastGui: GuiToast,
delta: Long,
firstDrawTime: Long,
maxDrawTime: Long,
buffer: FloatBuffer,
subLine: String?,
shadow: Boolean
) {
val minDraw = (maxDrawTime * 0.1).toLong()
val maxDraw = maxDrawTime + 500L
val backwardDraw = (maxDrawTime * 0.5).toLong()
val textSpeed = 1500L + (maxDrawTime * 0.1).toLong()
var x = 30
val textWidth = toastGui.mc.fontRendererObj.getStringWidth(subLine)
val maxSize = textWidth - 135
val timeElapsed = delta - firstDrawTime - minDraw
val timeElapsed2 = maxDraw - delta - backwardDraw
val maxTextLength = 125
if (textWidth > maxSize && textWidth > maxTextLength) {
if (timeElapsed > 0) {
x = (-textWidth * timeElapsed / textSpeed + x).toInt().coerceAtLeast(-maxSize + 16)
}
val backward =
(-(textWidth * timeElapsed2 / textSpeed)).toInt().coerceAtMost(30).coerceAtLeast(-maxSize + 16)
if (timeElapsed > timeElapsed2) {
x = backward
}
}
val res = UResolution
val height = res.scaledHeight.toDouble()
val scale = res.scaleFactor
val trans = FloatArray(16)
buffer.clear()
GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, buffer)
buffer[trans]
val xpos = trans[12]
GL11.glEnable(GL11.GL_SCISSOR_TEST)
GL11.glScissor(
((xpos + 29) * scale).toInt(),
((height - 196) * scale).toInt(),
(126 * scale).toInt(),
(195 * scale).toInt()
)
if (shadow) {
toastGui.mc.fontRendererObj.drawStringWithShadow(subLine, x.toFloat(), 18f, 0xFFFFFF)
} else {
toastGui.mc.fontRendererObj.drawString(subLine, x, 18, 0xFFFFFF)
}
GL11.glDisable(GL11.GL_SCISSOR_TEST)
}
}
}