switch hud elements to gui layers
This commit is contained in:
parent
72b1b5550d
commit
7a5ce91995
@ -129,6 +129,8 @@ object OverdriveThatMatters {
|
||||
|
||||
MOD_BUS.addListener(EventPriority.NORMAL, ChartTooltipElement.Companion::register)
|
||||
|
||||
MOD_BUS.addListener(EventPriority.HIGH, MatteryGUI::registerGuiLayers)
|
||||
|
||||
MBlockColors.register(MOD_BUS)
|
||||
}
|
||||
|
||||
@ -206,7 +208,6 @@ object OverdriveThatMatters {
|
||||
|
||||
FORGE_BUS.addListener(EventPriority.NORMAL, MatteryGUI::onScreenRender)
|
||||
FORGE_BUS.addListener(EventPriority.LOWEST, MatteryGUI::onOpenGUIEvent)
|
||||
FORGE_BUS.addListener(EventPriority.NORMAL, MatteryGUI::onRenderGuiEvent)
|
||||
FORGE_BUS.addListener(EventPriority.HIGH, MatteryGUI::onLayerRenderEvent)
|
||||
|
||||
FORGE_BUS.addListener(EventPriority.NORMAL, ShockwaveRenderer::onRender)
|
||||
|
@ -3,9 +3,10 @@ package ru.dbotthepony.mc.otm.client
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.client.DeltaTracker
|
||||
import net.minecraft.client.gui.Font
|
||||
import net.minecraft.client.gui.Gui
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.LayeredDraw
|
||||
import net.minecraft.client.gui.components.Button
|
||||
import net.minecraft.client.gui.screens.DeathScreen
|
||||
import net.minecraft.client.gui.screens.InBedChatScreen
|
||||
@ -16,12 +17,11 @@ import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.ShieldItem
|
||||
import net.neoforged.neoforge.client.event.RenderGuiEvent
|
||||
import net.neoforged.neoforge.client.event.RegisterGuiLayersEvent
|
||||
import net.neoforged.neoforge.client.event.RenderGuiLayerEvent
|
||||
import net.neoforged.neoforge.client.event.ScreenEvent
|
||||
import net.neoforged.neoforge.client.gui.VanillaGuiLayers
|
||||
import net.neoforged.neoforge.common.ItemAbilities
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||
import ru.dbotthepony.mc.otm.android.feature.NanobotsArmorFeature
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
|
||||
@ -32,7 +32,7 @@ import ru.dbotthepony.mc.otm.client.render.sprites.MatterySprite
|
||||
import ru.dbotthepony.mc.otm.config.ClientConfig
|
||||
import ru.dbotthepony.mc.otm.core.TextComponent
|
||||
import ru.dbotthepony.kommons.math.RGBAColor
|
||||
import ru.dbotthepony.mc.otm.core.ResourceLocation
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters.loc
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.random
|
||||
import ru.dbotthepony.mc.otm.core.util.formatPower
|
||||
@ -42,24 +42,6 @@ import kotlin.math.PI
|
||||
import kotlin.math.ceil
|
||||
|
||||
object MatteryGUI {
|
||||
private val BARS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/player_bars.png"), 81f, 36f)
|
||||
val CHARGE = BARS.sprite(height = 9f)
|
||||
val CHARGE_BG = BARS.sprite(y = 9f, height = 9f)
|
||||
|
||||
val CHARGE_HUNGER = BARS.sprite(y = 18f, height = 9f)
|
||||
val CHARGE_HUNGER_BG = BARS.sprite(y = 27f, height = 9f)
|
||||
|
||||
private val BARS_HP = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/player_bars_health.png"), 81f, 63f)
|
||||
|
||||
val HEALTH = BARS_HP.sprite(height = 9f)
|
||||
val HEALTH_BG = BARS_HP.sprite(y = 9f, height = 9f)
|
||||
val HEALTH_BG_NANOBOTS = BARS_HP.sprite(y = 18f, height = 9f)
|
||||
|
||||
val HEALTH_POISON = BARS_HP.sprite(y = 27f, height = 9f)
|
||||
val HEALTH_WITHER = BARS_HP.sprite(y = 36f, height = 9f)
|
||||
val HEALTH_ABSORB = BARS_HP.sprite(y = 45f, height = 9f)
|
||||
val HEALTH_FROZEN = BARS_HP.sprite(y = 54f, height = 9f)
|
||||
|
||||
private var originalBedButtonX = -1
|
||||
private var originalBedButtonY = -1
|
||||
|
||||
@ -112,349 +94,397 @@ object MatteryGUI {
|
||||
}
|
||||
}
|
||||
|
||||
var iteration = 0
|
||||
var showIterationUntil = 0L
|
||||
var showIterationUntilFade = 0L
|
||||
|
||||
val deathLog = ArrayList<Pair<Int, Component>>()
|
||||
|
||||
private fun showIteration(event: RenderGuiEvent.Post) {
|
||||
val time = System.currentTimeMillis()
|
||||
|
||||
if (time > showIterationUntilFade) {
|
||||
return
|
||||
}
|
||||
|
||||
val guiGraphics = MGUIGraphics(event.guiGraphics)
|
||||
val stack = guiGraphics.pose
|
||||
val window = minecraft.window
|
||||
|
||||
stack.pushPose()
|
||||
|
||||
val negateScale = 1f / window.guiScale.toFloat()
|
||||
var modifyScale = 6f * negateScale
|
||||
val finalScale = modifyScale * window.guiScale.toFloat()
|
||||
|
||||
stack.scale(modifyScale, modifyScale, modifyScale)
|
||||
|
||||
var width = window.guiScaledWidth / modifyScale
|
||||
var height = window.guiScaledHeight / modifyScale
|
||||
|
||||
var x = width / 2f
|
||||
var y = height / 2f
|
||||
|
||||
val progress = if (time < showIterationUntil) 1f else 1f - (time - showIterationUntil).toFloat() / (showIterationUntilFade - showIterationUntil).toFloat()
|
||||
val scissorBase = (y - 12f) * finalScale
|
||||
val scissorHeight = (12f + (deathLog.size - 2f).coerceAtLeast(0f) * minecraft.font.lineHeight * modifyScale * 0.0875f) * finalScale
|
||||
|
||||
pushScissorRect(0, (scissorBase + scissorHeight * (1f - progress)).toInt(), window.width, (scissorHeight * progress * 2f).toInt())
|
||||
|
||||
guiGraphics.renderRect(
|
||||
0f,
|
||||
y - 12f,
|
||||
window.guiScaledWidth.toFloat(),
|
||||
24f + (deathLog.size - 2f).coerceAtLeast(0f) * minecraft.font.lineHeight * modifyScale * 0.175f,
|
||||
color = RGBAColor(1f, 1f, 1f, 0.4f))
|
||||
|
||||
val text = TranslatableComponent("otm.iteration", iteration)
|
||||
|
||||
guiGraphics.draw(text, x + 1f, y + 1f, color = RGBAColor.BLACK, gravity = RenderGravity.CENTER_CENTER)
|
||||
guiGraphics.draw(text, x, y, color = RGBAColor.WHITE, gravity = RenderGravity.CENTER_CENTER)
|
||||
|
||||
stack.scale(0.35f, 0.35f, 0.35f)
|
||||
|
||||
modifyScale *= 0.35f
|
||||
|
||||
width = window.guiScaledWidth / modifyScale
|
||||
height = window.guiScaledHeight / modifyScale
|
||||
|
||||
x = width / 2f
|
||||
y = height / 2f + minecraft.font.lineHeight * finalScale * 0.35f
|
||||
|
||||
var color = 0xFF
|
||||
|
||||
for (i in deathLog.indices.reversed()) {
|
||||
val component = deathLog[i]
|
||||
guiGraphics.draw(component.second, x + 1f, y + 1f, color = RGBAColor.BLACK, gravity = RenderGravity.CENTER_CENTER)
|
||||
guiGraphics.draw(component.second, x, y, color = RGBAColor(color, color, color), gravity = RenderGravity.CENTER_CENTER)
|
||||
|
||||
y += minecraft.font.lineHeight
|
||||
color = (color - 0x20).coerceAtLeast(0x0)
|
||||
}
|
||||
|
||||
stack.popPose()
|
||||
|
||||
popScissorRect()
|
||||
}
|
||||
|
||||
private val powerAlert = TranslatableComponent(
|
||||
"otm.pwr_alert1",
|
||||
TranslatableComponent("otm.pwr_alert2").withStyle(ChatFormatting.RED)
|
||||
).withStyle(ChatFormatting.YELLOW)
|
||||
|
||||
private val powerAlert2 = TranslatableComponent("otm.pwr_alert3").withStyle(ChatFormatting.YELLOW)
|
||||
private val powerAlert3 = TranslatableComponent("otm.pwr_alert4").withStyle(ChatFormatting.YELLOW)
|
||||
|
||||
private val errorCodes = ImmutableList.of(
|
||||
"005", "06E", "004", "0F1", "7FF", "F0A"
|
||||
)
|
||||
|
||||
private var errorCode = errorCodes[1]
|
||||
private var errorAddress = "0".repeat(16)
|
||||
|
||||
private val registerParts = ImmutableList.of("A", "B", "C", "D", "E", "F", "M", "D", "X", "Y", "Z")
|
||||
private var errorRegister = "VXE VMMXDE"
|
||||
|
||||
private val errorServerNode by lazy {
|
||||
(minecraft.player!!.uuid.leastSignificantBits and 0xFFFFFF).toString(16).uppercase()
|
||||
}
|
||||
|
||||
private var displayPowerError = false
|
||||
private var lastDisplayPowerErrorUpdate = System.nanoTime()
|
||||
private var targetErrorAlpha = System.nanoTime()
|
||||
|
||||
private fun drawLowPower(event: RenderGuiEvent.Post, player: LocalPlayer) {
|
||||
// yes, this is a reference to movie Transcendence (2014)
|
||||
if (player.matteryPlayer.androidEnergy.batteryLevel > Decimal.TEN)
|
||||
return
|
||||
|
||||
if (System.nanoTime() - lastDisplayPowerErrorUpdate > 100_000_000L) {
|
||||
lastDisplayPowerErrorUpdate = System.nanoTime()
|
||||
val newStatus = player.random.nextBoolean()
|
||||
|
||||
if (newStatus != displayPowerError && newStatus) {
|
||||
targetErrorAlpha = System.nanoTime()
|
||||
errorCode = errorCodes[player.random.nextInt(errorCodes.size)]
|
||||
errorRegister = "V${registerParts.random(player.random)}${registerParts.random(player.random)} V${registerParts.random(player.random)}${registerParts.random(player.random)}${registerParts.random(player.random)}${registerParts.random(player.random)}${registerParts.random(player.random)}"
|
||||
errorAddress = java.lang.Long.toUnsignedString(player.random.nextLong(), 16).uppercase()
|
||||
|
||||
if (errorAddress.length < 16) {
|
||||
errorAddress = "0".repeat(16 - errorAddress.length) + errorAddress
|
||||
}
|
||||
fun onLayerRenderEvent(event: RenderGuiLayerEvent.Pre) {
|
||||
if (minecraft.player?.matteryPlayer?.isAndroid == true) {
|
||||
if (event.name == VanillaGuiLayers.FOOD_LEVEL
|
||||
|| event.name == VanillaGuiLayers.AIR_LEVEL
|
||||
|| (event.name == VanillaGuiLayers.PLAYER_HEALTH && ClientConfig.HUD.ANDROID_HEALTH_BAR)) {
|
||||
event.isCanceled = true
|
||||
}
|
||||
|
||||
displayPowerError = newStatus
|
||||
}
|
||||
|
||||
if (!displayPowerError) return
|
||||
|
||||
val alpha: Float
|
||||
val diff = System.nanoTime() - targetErrorAlpha
|
||||
|
||||
if (diff > 50_000_000L) {
|
||||
alpha = 1f
|
||||
} else {
|
||||
alpha = diff / 50_000_000f
|
||||
}
|
||||
|
||||
if (alpha != 1f) RenderSystem.setShaderColor(1f, 1f, 1f, alpha)
|
||||
val window = minecraft.window
|
||||
|
||||
val x = window.guiScaledWidth / 2f
|
||||
var y = window.guiScaledHeight / 2.5f
|
||||
|
||||
minecraft.font.draw(
|
||||
event.guiGraphics.pose(),
|
||||
powerAlert,
|
||||
x, y,
|
||||
scale = 4f,
|
||||
gravity = RenderGravity.CENTER_CENTER,
|
||||
drawShadow = true
|
||||
)
|
||||
|
||||
y += 20f + minecraft.font.lineHeight * 4f
|
||||
|
||||
minecraft.font.draw(
|
||||
event.guiGraphics.pose(),
|
||||
powerAlert2,
|
||||
x, y,
|
||||
gravity = RenderGravity.CENTER_CENTER,
|
||||
drawShadow = true
|
||||
)
|
||||
|
||||
y += minecraft.font.lineHeight + 2f
|
||||
|
||||
minecraft.font.draw(
|
||||
event.guiGraphics.pose(),
|
||||
powerAlert3,
|
||||
x, y,
|
||||
gravity = RenderGravity.CENTER_CENTER,
|
||||
drawShadow = true
|
||||
)
|
||||
|
||||
y += minecraft.font.lineHeight * 2f + 4f
|
||||
|
||||
minecraft.font.draw(
|
||||
event.guiGraphics.pose(),
|
||||
TranslatableComponent(
|
||||
"otm.pwr_alert5",
|
||||
errorCode,
|
||||
errorServerNode,
|
||||
errorAddress,
|
||||
errorRegister
|
||||
).withStyle(ChatFormatting.YELLOW),
|
||||
x, y,
|
||||
gravity = RenderGravity.CENTER_CENTER,
|
||||
drawShadow = true,
|
||||
)
|
||||
|
||||
if (alpha != 1f) RenderSystem.setShaderColor(1f, 1f, 1f, 1f)
|
||||
}
|
||||
|
||||
fun onRenderGuiEvent(event: RenderGuiEvent.Post) {
|
||||
val player = minecraft.player ?: return
|
||||
fun registerGuiLayers(event: RegisterGuiLayersEvent) {
|
||||
event.registerBelow(VanillaGuiLayers.FOOD_LEVEL, loc("android_energy_bar"), AndroidEnergyBarLayer())
|
||||
event.registerBelow(VanillaGuiLayers.PLAYER_HEALTH, loc("android_health_bar"), AndroidHealthBarLayer())
|
||||
|
||||
if (!player.matteryPlayer.isAndroid) {
|
||||
return
|
||||
}
|
||||
|
||||
showIteration(event)
|
||||
drawLowPower(event, player)
|
||||
event.registerAboveAll(loc("android_iteration"), AndroidIterationLayer())
|
||||
event.registerAbove(VanillaGuiLayers.CAMERA_OVERLAYS, loc("android_low_power"), AndroidLowPowerLayer())
|
||||
}
|
||||
|
||||
private fun renderFoodAndAir(event: RenderGuiLayerEvent.Pre, gui: Gui) {
|
||||
val ply: LocalPlayer = minecraft.player ?: return
|
||||
class AndroidEnergyBarLayer : LayeredDraw.Layer {
|
||||
override fun render(
|
||||
graphics: GuiGraphics,
|
||||
delta: DeltaTracker
|
||||
) {
|
||||
val ply: LocalPlayer = minecraft.player ?: return
|
||||
|
||||
if (ply.vehicle is LivingEntity)
|
||||
return
|
||||
|
||||
val mattery = ply.matteryPlayer
|
||||
|
||||
if (mattery.isAndroid) {
|
||||
event.isCanceled = true
|
||||
|
||||
if (event.name === VanillaGuiLayers.AIR_LEVEL)
|
||||
if (ply.vehicle is LivingEntity || ply.isCreative)
|
||||
return
|
||||
|
||||
var level: Float
|
||||
val gui = minecraft.gui
|
||||
val mattery = ply.matteryPlayer
|
||||
|
||||
if (mattery.androidEnergy.maxBatteryLevel.isZero) {
|
||||
level = 0f
|
||||
if (mattery.isAndroid) {
|
||||
var level: Float
|
||||
|
||||
if (mattery.androidEnergy.maxBatteryLevel.isZero) {
|
||||
level = 0f
|
||||
} else {
|
||||
level = mattery.androidEnergy.batteryLevel.percentage(mattery.androidEnergy.maxBatteryLevel)
|
||||
|
||||
if (level >= 0.98f)
|
||||
level = 1f
|
||||
}
|
||||
|
||||
RenderSystem.enableBlend()
|
||||
RenderSystem.defaultBlendFunc()
|
||||
RenderSystem.disableDepthTest()
|
||||
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f)
|
||||
|
||||
val width = minecraft.window.guiScaledWidth
|
||||
val height = minecraft.window.guiScaledHeight
|
||||
val left = width / 2 + 10
|
||||
val top: Int = height - gui.rightHeight
|
||||
gui.rightHeight += 10
|
||||
|
||||
val leftPadding = ceil(level * 80f - 0.5f)
|
||||
|
||||
val guiGraphics = MGUIGraphics(graphics)
|
||||
|
||||
if (ply.hasEffect(MobEffects.HUNGER)) {
|
||||
CHARGE_HUNGER_BG.render(guiGraphics, left.toFloat(), top.toFloat())
|
||||
CHARGE_HUNGER.renderPartial(guiGraphics, left.toFloat() - leftPadding + 80f, top.toFloat(), width = leftPadding)
|
||||
} else {
|
||||
CHARGE_BG.render(guiGraphics, left.toFloat(), top.toFloat())
|
||||
CHARGE.renderPartial(guiGraphics, left.toFloat() - leftPadding + 80f, top.toFloat(), width = leftPadding)
|
||||
}
|
||||
|
||||
val formattedPower = mattery.androidEnergy.batteryLevel.formatPower()
|
||||
|
||||
val scale = ClientConfig.HUD.BAR_TEXT_SCALE.toFloat()
|
||||
guiGraphics.draw(formattedPower, left + CHARGE_BG.width + 2f + scale, top + CHARGE_BG.height / 2f + scale, font = gui.font, scale = scale, gravity = RenderGravity.CENTER_LEFT, color = RGBAColor.YELLOW, drawOutline = true)
|
||||
|
||||
RenderSystem.disableBlend()
|
||||
RenderSystem.enableDepthTest()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val BARS = MatteryAtlas(loc("textures/gui/player_bars.png"), 81f, 36f)
|
||||
val CHARGE = BARS.sprite(height = 9f)
|
||||
val CHARGE_BG = BARS.sprite(y = 9f, height = 9f)
|
||||
|
||||
val CHARGE_HUNGER = BARS.sprite(y = 18f, height = 9f)
|
||||
val CHARGE_HUNGER_BG = BARS.sprite(y = 27f, height = 9f)
|
||||
}
|
||||
}
|
||||
|
||||
class AndroidHealthBarLayer : LayeredDraw.Layer {
|
||||
override fun render(
|
||||
graphics: GuiGraphics,
|
||||
delta: DeltaTracker
|
||||
) {
|
||||
if (!ClientConfig.HUD.ANDROID_HEALTH_BAR) return
|
||||
|
||||
val gui = minecraft.gui
|
||||
val ply: LocalPlayer = minecraft.player ?: return
|
||||
val mattery = ply.matteryPlayer
|
||||
|
||||
if (mattery.isAndroid && !ply.isCreative) {
|
||||
val level: Float = (ply.health / ply.maxHealth).coerceIn(0.0f, 1.0f)
|
||||
val levelAbsorb: Float = (ply.absorptionAmount / ply.maxHealth).coerceIn(0.0f, 1.0f)
|
||||
|
||||
RenderSystem.enableBlend()
|
||||
RenderSystem.defaultBlendFunc()
|
||||
RenderSystem.disableDepthTest()
|
||||
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f)
|
||||
|
||||
val width = minecraft.window.guiScaledWidth
|
||||
val height = minecraft.window.guiScaledHeight
|
||||
val left = width / 2 - 10 - 81
|
||||
val top: Int = height - gui.leftHeight
|
||||
gui.leftHeight += 10
|
||||
|
||||
val guiGraphics = MGUIGraphics(graphics)
|
||||
|
||||
HEALTH_BG.render(guiGraphics, left.toFloat(), top.toFloat())
|
||||
|
||||
if (mattery.hasFeature(AndroidFeatures.NANOBOTS_ARMOR)) {
|
||||
val featArmor = mattery.getFeature(AndroidFeatures.NANOBOTS_ARMOR) as NanobotsArmorFeature
|
||||
val levelArmor: Float = (featArmor.layers.toFloat() / (featArmor.strength + 1).toFloat()).coerceIn(0.0f, 1.0f)
|
||||
|
||||
HEALTH_BG_NANOBOTS.renderPartial(guiGraphics, left.toFloat(), top.toFloat(), width = ceil(levelArmor * 81f))
|
||||
}
|
||||
|
||||
getSpriteForPlayer(ply).renderPartial(guiGraphics, left.toFloat(), top.toFloat(), width = ceil(level * 80f - 0.5f))
|
||||
if (levelAbsorb > 0) {
|
||||
HEALTH_ABSORB.renderPartial(guiGraphics, left.toFloat(), top.toFloat(), width = ceil(levelAbsorb * 80f - 0.5f))
|
||||
}
|
||||
|
||||
var formattedHealth = TextComponent("%d/%d".format(ply.health.toInt(), ply.maxHealth.toInt()))
|
||||
|
||||
if (ply.absorptionAmount > 0)
|
||||
formattedHealth = TextComponent("%d+%d/%d".format(ply.health.toInt(), ply.absorptionAmount.toInt(), ply.maxHealth.toInt()))
|
||||
|
||||
val scale = ClientConfig.HUD.BAR_TEXT_SCALE.toFloat()
|
||||
guiGraphics.draw(formattedHealth, left - 2f, top + HEALTH_BG.height / 2f + 1f * scale, scale = scale, gravity = RenderGravity.CENTER_RIGHT, color = getHealthColorForPlayer(ply), drawOutline = true)
|
||||
|
||||
RenderSystem.disableBlend()
|
||||
RenderSystem.enableDepthTest()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val BARS_HP = MatteryAtlas(loc("textures/gui/player_bars_health.png"), 81f, 63f)
|
||||
|
||||
val HEALTH = BARS_HP.sprite(height = 9f)
|
||||
val HEALTH_BG = BARS_HP.sprite(y = 9f, height = 9f)
|
||||
val HEALTH_BG_NANOBOTS = BARS_HP.sprite(y = 18f, height = 9f)
|
||||
|
||||
val HEALTH_POISON = BARS_HP.sprite(y = 27f, height = 9f)
|
||||
val HEALTH_WITHER = BARS_HP.sprite(y = 36f, height = 9f)
|
||||
val HEALTH_ABSORB = BARS_HP.sprite(y = 45f, height = 9f)
|
||||
val HEALTH_FROZEN = BARS_HP.sprite(y = 54f, height = 9f)
|
||||
|
||||
private fun getSpriteForPlayer(player: Player): MatterySprite {
|
||||
if (player.hasEffect(MobEffects.POISON)) {
|
||||
return HEALTH_POISON
|
||||
} else if (player.hasEffect(MobEffects.WITHER)) {
|
||||
return HEALTH_WITHER
|
||||
} else if (player.isFullyFrozen) {
|
||||
return HEALTH_FROZEN
|
||||
}
|
||||
|
||||
return HEALTH
|
||||
}
|
||||
|
||||
private fun getHealthColorForPlayer(player: Player): RGBAColor {
|
||||
if (player.hasEffect(MobEffects.POISON)) {
|
||||
return RGBAColor.DARK_GREEN
|
||||
} else if (player.hasEffect(MobEffects.WITHER)) {
|
||||
return RGBAColor.WHITE
|
||||
} else if (player.isFullyFrozen) {
|
||||
return RGBAColor.AQUA
|
||||
}
|
||||
|
||||
return RGBAColor.RED
|
||||
} // можно вынести в конфиг, но для этого нужен селектор цвета
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class AndroidIterationLayer : LayeredDraw.Layer {
|
||||
override fun render(
|
||||
graphics: GuiGraphics,
|
||||
delta: DeltaTracker
|
||||
) {
|
||||
val player = minecraft.player ?: return
|
||||
|
||||
if (!player.matteryPlayer.isAndroid) return
|
||||
|
||||
val time = System.currentTimeMillis()
|
||||
|
||||
if (time > showIterationUntilFade) {
|
||||
return
|
||||
}
|
||||
|
||||
val guiGraphics = MGUIGraphics(graphics)
|
||||
val stack = guiGraphics.pose
|
||||
val window = minecraft.window
|
||||
|
||||
stack.pushPose()
|
||||
|
||||
val negateScale = 1f / window.guiScale.toFloat()
|
||||
var modifyScale = 6f * negateScale
|
||||
val finalScale = modifyScale * window.guiScale.toFloat()
|
||||
|
||||
stack.scale(modifyScale, modifyScale, modifyScale)
|
||||
|
||||
var width = window.guiScaledWidth / modifyScale
|
||||
var height = window.guiScaledHeight / modifyScale
|
||||
|
||||
var x = width / 2f
|
||||
var y = height / 2f
|
||||
|
||||
val progress = if (time < showIterationUntil) 1f else 1f - (time - showIterationUntil).toFloat() / (showIterationUntilFade - showIterationUntil).toFloat()
|
||||
val scissorBase = (y - 12f) * finalScale
|
||||
val scissorHeight = (12f + (deathLog.size - 2f).coerceAtLeast(0f) * minecraft.font.lineHeight * modifyScale * 0.0875f) * finalScale
|
||||
|
||||
pushScissorRect(0, (scissorBase + scissorHeight * (1f - progress)).toInt(), window.width, (scissorHeight * progress * 2f).toInt())
|
||||
|
||||
guiGraphics.renderRect(
|
||||
0f,
|
||||
y - 12f,
|
||||
window.guiScaledWidth.toFloat(),
|
||||
24f + (deathLog.size - 2f).coerceAtLeast(0f) * minecraft.font.lineHeight * modifyScale * 0.175f,
|
||||
color = RGBAColor(1f, 1f, 1f, 0.4f))
|
||||
|
||||
val text = TranslatableComponent("otm.iteration", iteration)
|
||||
|
||||
guiGraphics.draw(text, x + 1f, y + 1f, color = RGBAColor.BLACK, gravity = RenderGravity.CENTER_CENTER)
|
||||
guiGraphics.draw(text, x, y, color = RGBAColor.WHITE, gravity = RenderGravity.CENTER_CENTER)
|
||||
|
||||
stack.scale(0.35f, 0.35f, 0.35f)
|
||||
|
||||
modifyScale *= 0.35f
|
||||
|
||||
width = window.guiScaledWidth / modifyScale
|
||||
height = window.guiScaledHeight / modifyScale
|
||||
|
||||
x = width / 2f
|
||||
y = height / 2f + minecraft.font.lineHeight * finalScale * 0.35f
|
||||
|
||||
var color = 0xFF
|
||||
|
||||
for (i in deathLog.indices.reversed()) {
|
||||
val component = deathLog[i]
|
||||
guiGraphics.draw(component.second, x + 1f, y + 1f, color = RGBAColor.BLACK, gravity = RenderGravity.CENTER_CENTER)
|
||||
guiGraphics.draw(component.second, x, y, color = RGBAColor(color, color, color), gravity = RenderGravity.CENTER_CENTER)
|
||||
|
||||
y += minecraft.font.lineHeight
|
||||
color = (color - 0x20).coerceAtLeast(0x0)
|
||||
}
|
||||
|
||||
stack.popPose()
|
||||
|
||||
popScissorRect()
|
||||
}
|
||||
|
||||
companion object {
|
||||
var iteration = 0
|
||||
var showIterationUntil = 0L
|
||||
var showIterationUntilFade = 0L
|
||||
|
||||
val deathLog = ArrayList<Pair<Int, Component>>()
|
||||
}
|
||||
}
|
||||
|
||||
class AndroidLowPowerLayer : LayeredDraw.Layer {
|
||||
private var errorCode = errorCodes[1]
|
||||
private var errorAddress = "0".repeat(16)
|
||||
|
||||
private var errorRegister = "VXE VMMXDE"
|
||||
|
||||
private val errorServerNode by lazy {
|
||||
(minecraft.player!!.uuid.leastSignificantBits and 0xFFFFFF).toString(16).uppercase()
|
||||
}
|
||||
|
||||
private var displayPowerError = false
|
||||
private var lastDisplayPowerErrorUpdate = System.nanoTime()
|
||||
private var targetErrorAlpha = System.nanoTime()
|
||||
|
||||
override fun render(
|
||||
graphics: GuiGraphics,
|
||||
delta: DeltaTracker
|
||||
) {
|
||||
val player = minecraft.player ?: return
|
||||
|
||||
if (!player.matteryPlayer.isAndroid) {
|
||||
return
|
||||
}
|
||||
|
||||
// yes, this is a reference to movie Transcendence (2014)
|
||||
if (player.matteryPlayer.androidEnergy.batteryLevel > Decimal.TEN)
|
||||
return
|
||||
|
||||
if (System.nanoTime() - lastDisplayPowerErrorUpdate > 100_000_000L) {
|
||||
lastDisplayPowerErrorUpdate = System.nanoTime()
|
||||
val newStatus = player.random.nextBoolean()
|
||||
|
||||
if (newStatus != displayPowerError && newStatus) {
|
||||
targetErrorAlpha = System.nanoTime()
|
||||
errorCode = errorCodes[player.random.nextInt(errorCodes.size)]
|
||||
errorRegister = "V${registerParts.random(player.random)}${registerParts.random(player.random)} V${registerParts.random(player.random)}${registerParts.random(player.random)}${registerParts.random(player.random)}${registerParts.random(player.random)}${registerParts.random(player.random)}"
|
||||
errorAddress = java.lang.Long.toUnsignedString(player.random.nextLong(), 16).uppercase()
|
||||
|
||||
if (errorAddress.length < 16) {
|
||||
errorAddress = "0".repeat(16 - errorAddress.length) + errorAddress
|
||||
}
|
||||
}
|
||||
|
||||
displayPowerError = newStatus
|
||||
}
|
||||
|
||||
if (!displayPowerError) return
|
||||
|
||||
val alpha: Float
|
||||
val diff = System.nanoTime() - targetErrorAlpha
|
||||
|
||||
if (diff > 50_000_000L) {
|
||||
alpha = 1f
|
||||
} else {
|
||||
level = mattery.androidEnergy.batteryLevel.percentage(mattery.androidEnergy.maxBatteryLevel)
|
||||
|
||||
if (level >= 0.98f)
|
||||
level = 1f
|
||||
alpha = diff / 50_000_000f
|
||||
}
|
||||
|
||||
RenderSystem.enableBlend()
|
||||
RenderSystem.defaultBlendFunc()
|
||||
RenderSystem.disableDepthTest()
|
||||
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f)
|
||||
if (alpha != 1f) RenderSystem.setShaderColor(1f, 1f, 1f, alpha)
|
||||
val window = minecraft.window
|
||||
|
||||
val width = minecraft.window.guiScaledWidth
|
||||
val height = minecraft.window.guiScaledHeight
|
||||
val left = width / 2 + 10
|
||||
val top: Int = height - gui.rightHeight
|
||||
gui.rightHeight += 10
|
||||
val x = window.guiScaledWidth / 2f
|
||||
var y = window.guiScaledHeight / 2.5f
|
||||
|
||||
val leftPadding = ceil(level * 80f - 0.5f)
|
||||
minecraft.font.draw(
|
||||
graphics.pose(),
|
||||
powerAlert,
|
||||
x, y,
|
||||
scale = 4f,
|
||||
gravity = RenderGravity.CENTER_CENTER,
|
||||
drawShadow = true
|
||||
)
|
||||
|
||||
val guiGraphics = MGUIGraphics(event.guiGraphics)
|
||||
y += 20f + minecraft.font.lineHeight * 4f
|
||||
|
||||
if (ply.hasEffect(MobEffects.HUNGER)) {
|
||||
CHARGE_HUNGER_BG.render(guiGraphics, left.toFloat(), top.toFloat())
|
||||
CHARGE_HUNGER.renderPartial(guiGraphics, left.toFloat() - leftPadding + 80f, top.toFloat(), width = leftPadding)
|
||||
} else {
|
||||
CHARGE_BG.render(guiGraphics, left.toFloat(), top.toFloat())
|
||||
CHARGE.renderPartial(guiGraphics, left.toFloat() - leftPadding + 80f, top.toFloat(), width = leftPadding)
|
||||
}
|
||||
minecraft.font.draw(
|
||||
graphics.pose(),
|
||||
powerAlert2,
|
||||
x, y,
|
||||
gravity = RenderGravity.CENTER_CENTER,
|
||||
drawShadow = true
|
||||
)
|
||||
|
||||
val formattedPower = mattery.androidEnergy.batteryLevel.formatPower()
|
||||
y += minecraft.font.lineHeight + 2f
|
||||
|
||||
val scale = ClientConfig.HUD.BAR_TEXT_SCALE.toFloat()
|
||||
guiGraphics.draw(formattedPower, left + CHARGE_BG.width + 2f + scale, top + CHARGE_BG.height / 2f + scale, font = gui.font, scale = scale, gravity = RenderGravity.CENTER_LEFT, color = RGBAColor.YELLOW, drawOutline = true)
|
||||
minecraft.font.draw(
|
||||
graphics.pose(),
|
||||
powerAlert3,
|
||||
x, y,
|
||||
gravity = RenderGravity.CENTER_CENTER,
|
||||
drawShadow = true
|
||||
)
|
||||
|
||||
RenderSystem.disableBlend()
|
||||
RenderSystem.enableDepthTest()
|
||||
}
|
||||
}
|
||||
y += minecraft.font.lineHeight * 2f + 4f
|
||||
|
||||
private fun getSpriteForPlayer(player: Player): MatterySprite {
|
||||
if (player.hasEffect(MobEffects.POISON)) {
|
||||
return HEALTH_POISON
|
||||
} else if (player.hasEffect(MobEffects.WITHER)) {
|
||||
return HEALTH_WITHER
|
||||
} else if (player.isFullyFrozen) {
|
||||
return HEALTH_FROZEN
|
||||
minecraft.font.draw(
|
||||
graphics.pose(),
|
||||
TranslatableComponent(
|
||||
"otm.pwr_alert5",
|
||||
errorCode,
|
||||
errorServerNode,
|
||||
errorAddress,
|
||||
errorRegister
|
||||
).withStyle(ChatFormatting.YELLOW),
|
||||
x, y,
|
||||
gravity = RenderGravity.CENTER_CENTER,
|
||||
drawShadow = true,
|
||||
)
|
||||
|
||||
if (alpha != 1f) RenderSystem.setShaderColor(1f, 1f, 1f, 1f)
|
||||
}
|
||||
|
||||
return HEALTH
|
||||
}
|
||||
companion object {
|
||||
private val powerAlert = TranslatableComponent(
|
||||
"otm.pwr_alert1",
|
||||
TranslatableComponent("otm.pwr_alert2").withStyle(ChatFormatting.RED)
|
||||
).withStyle(ChatFormatting.YELLOW)
|
||||
|
||||
private fun getHealthColorForPlayer(player: Player): RGBAColor {
|
||||
if (player.hasEffect(MobEffects.POISON)) {
|
||||
return RGBAColor.DARK_GREEN
|
||||
} else if (player.hasEffect(MobEffects.WITHER)) {
|
||||
return RGBAColor.WHITE
|
||||
} else if (player.isFullyFrozen) {
|
||||
return RGBAColor.AQUA
|
||||
}
|
||||
private val powerAlert2 = TranslatableComponent("otm.pwr_alert3").withStyle(ChatFormatting.YELLOW)
|
||||
private val powerAlert3 = TranslatableComponent("otm.pwr_alert4").withStyle(ChatFormatting.YELLOW)
|
||||
|
||||
return RGBAColor.RED
|
||||
} // можно вынести в конфиг, но для этого нужен селектор цвета
|
||||
private val errorCodes = ImmutableList.of(
|
||||
"005", "06E", "004", "0F1", "7FF", "F0A"
|
||||
)
|
||||
|
||||
private fun renderPlayerHealth(event: RenderGuiLayerEvent.Pre, gui: Gui) {
|
||||
if (!ClientConfig.HUD.ANDROID_HEALTH_BAR) return
|
||||
|
||||
val ply: LocalPlayer = minecraft.player ?: return
|
||||
val mattery = ply.matteryPlayer
|
||||
|
||||
if (mattery.isAndroid) {
|
||||
event.isCanceled = true
|
||||
|
||||
val level: Float = (ply.health / ply.maxHealth).coerceIn(0.0f, 1.0f)
|
||||
val levelAbsorb: Float = (ply.absorptionAmount / ply.maxHealth).coerceIn(0.0f, 1.0f)
|
||||
|
||||
RenderSystem.enableBlend()
|
||||
RenderSystem.defaultBlendFunc()
|
||||
RenderSystem.disableDepthTest()
|
||||
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f)
|
||||
|
||||
val width = minecraft.window.guiScaledWidth
|
||||
val height = minecraft.window.guiScaledHeight
|
||||
val left = width / 2 - 10 - 81
|
||||
val top: Int = height - gui.leftHeight
|
||||
gui.leftHeight += 10
|
||||
|
||||
val guiGraphics = MGUIGraphics(event.guiGraphics)
|
||||
|
||||
HEALTH_BG.render(guiGraphics, left.toFloat(), top.toFloat())
|
||||
|
||||
if (mattery.hasFeature(AndroidFeatures.NANOBOTS_ARMOR)) {
|
||||
val featArmor = mattery.getFeature(AndroidFeatures.NANOBOTS_ARMOR) as NanobotsArmorFeature
|
||||
val levelArmor: Float = (featArmor.layers.toFloat() / (featArmor.strength + 1).toFloat()).coerceIn(0.0f, 1.0f)
|
||||
|
||||
HEALTH_BG_NANOBOTS.renderPartial(guiGraphics, left.toFloat(), top.toFloat(), width = ceil(levelArmor * 81f))
|
||||
}
|
||||
|
||||
getSpriteForPlayer(ply).renderPartial(guiGraphics, left.toFloat(), top.toFloat(), width = ceil(level * 80f - 0.5f))
|
||||
if (levelAbsorb > 0) {
|
||||
HEALTH_ABSORB.renderPartial(guiGraphics, left.toFloat(), top.toFloat(), width = ceil(levelAbsorb * 80f - 0.5f))
|
||||
}
|
||||
|
||||
var formattedHealth = TextComponent("%d/%d".format(ply.health.toInt(), ply.maxHealth.toInt()))
|
||||
|
||||
if (ply.absorptionAmount > 0)
|
||||
formattedHealth = TextComponent("%d+%d/%d".format(ply.health.toInt(), ply.absorptionAmount.toInt(), ply.maxHealth.toInt()))
|
||||
|
||||
val scale = ClientConfig.HUD.BAR_TEXT_SCALE.toFloat()
|
||||
guiGraphics.draw(formattedHealth, left - 2f, top + HEALTH_BG.height / 2f + 1f * scale, scale = scale, gravity = RenderGravity.CENTER_RIGHT, color = getHealthColorForPlayer(ply), drawOutline = true)
|
||||
|
||||
RenderSystem.disableBlend()
|
||||
RenderSystem.enableDepthTest()
|
||||
}
|
||||
}
|
||||
|
||||
fun onLayerRenderEvent(event: RenderGuiLayerEvent.Pre) {
|
||||
val gui = minecraft.gui
|
||||
|
||||
if (minecraft.gameMode?.canHurtPlayer() == true && !minecraft.options.hideGui) {
|
||||
if (event.name == VanillaGuiLayers.FOOD_LEVEL || event.name == VanillaGuiLayers.AIR_LEVEL) {
|
||||
renderFoodAndAir(event, gui)
|
||||
} else if (event.name == VanillaGuiLayers.PLAYER_HEALTH) {
|
||||
renderPlayerHealth(event, gui)
|
||||
}
|
||||
private val registerParts = ImmutableList.of("A", "B", "C", "D", "E", "F", "M", "D", "X", "Y", "Z")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,11 +184,11 @@ class PlayerIterationPacket(val iteration: Int, val deathLog: List<Pair<Int, Com
|
||||
}
|
||||
|
||||
fun play(context: IPayloadContext) {
|
||||
MatteryGUI.iteration = iteration
|
||||
MatteryGUI.deathLog.clear()
|
||||
MatteryGUI.deathLog.addAll(deathLog)
|
||||
MatteryGUI.showIterationUntil = System.currentTimeMillis() + 4000L
|
||||
MatteryGUI.showIterationUntilFade = System.currentTimeMillis() + 5000L
|
||||
MatteryGUI.AndroidIterationLayer.iteration = iteration
|
||||
MatteryGUI.AndroidIterationLayer.deathLog.clear()
|
||||
MatteryGUI.AndroidIterationLayer.deathLog.addAll(deathLog)
|
||||
MatteryGUI.AndroidIterationLayer.showIterationUntil = System.currentTimeMillis() + 4000L
|
||||
MatteryGUI.AndroidIterationLayer.showIterationUntilFade = System.currentTimeMillis() + 5000L
|
||||
}
|
||||
|
||||
override fun type(): CustomPacketPayload.Type<out CustomPacketPayload> {
|
||||
|
Loading…
Reference in New Issue
Block a user