Compare commits

...

2 Commits

Author SHA1 Message Date
7a5ce91995
switch hud elements to gui layers 2024-12-10 07:07:24 +03:00
72b1b5550d
AMD User — Сегодня, в 6:50
Просто вынеси в верх тика
Итерацию
2024-12-10 06:52:24 +03:00
4 changed files with 380 additions and 349 deletions

View File

@ -129,6 +129,8 @@ object OverdriveThatMatters {
MOD_BUS.addListener(EventPriority.NORMAL, ChartTooltipElement.Companion::register) MOD_BUS.addListener(EventPriority.NORMAL, ChartTooltipElement.Companion::register)
MOD_BUS.addListener(EventPriority.HIGH, MatteryGUI::registerGuiLayers)
MBlockColors.register(MOD_BUS) MBlockColors.register(MOD_BUS)
} }
@ -206,7 +208,6 @@ object OverdriveThatMatters {
FORGE_BUS.addListener(EventPriority.NORMAL, MatteryGUI::onScreenRender) FORGE_BUS.addListener(EventPriority.NORMAL, MatteryGUI::onScreenRender)
FORGE_BUS.addListener(EventPriority.LOWEST, MatteryGUI::onOpenGUIEvent) 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.HIGH, MatteryGUI::onLayerRenderEvent)
FORGE_BUS.addListener(EventPriority.NORMAL, ShockwaveRenderer::onRender) FORGE_BUS.addListener(EventPriority.NORMAL, ShockwaveRenderer::onRender)

View File

@ -1101,6 +1101,11 @@ class MatteryPlayer(val ply: Player) {
if (NeoForge.EVENT_BUS.post(PreTick(this)).isCanceled) return if (NeoForge.EVENT_BUS.post(PreTick(this)).isCanceled) return
if (shouldSendIteration) {
sendNetwork(PlayerIterationPacket(iteration, deathLog))
shouldSendIteration = false
}
ticksIExist++ ticksIExist++
tickList.tick() tickList.tick()
@ -1341,11 +1346,6 @@ class MatteryPlayer(val ply: Player) {
} }
} }
if (shouldSendIteration) {
sendNetwork(PlayerIterationPacket(iteration, deathLog))
shouldSendIteration = false
}
if (hasExopack && ply.containerMenu == ply.inventoryMenu) { if (hasExopack && ply.containerMenu == ply.inventoryMenu) {
exoPackMenu.broadcastChanges() exoPackMenu.broadcastChanges()
} }

View File

@ -3,9 +3,10 @@ package ru.dbotthepony.mc.otm.client
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.systems.RenderSystem
import net.minecraft.ChatFormatting import net.minecraft.ChatFormatting
import net.minecraft.client.DeltaTracker
import net.minecraft.client.gui.Font import net.minecraft.client.gui.Font
import net.minecraft.client.gui.Gui
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.LayeredDraw
import net.minecraft.client.gui.components.Button import net.minecraft.client.gui.components.Button
import net.minecraft.client.gui.screens.DeathScreen import net.minecraft.client.gui.screens.DeathScreen
import net.minecraft.client.gui.screens.InBedChatScreen 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.entity.player.Player
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.ShieldItem 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.RenderGuiLayerEvent
import net.neoforged.neoforge.client.event.ScreenEvent import net.neoforged.neoforge.client.event.ScreenEvent
import net.neoforged.neoforge.client.gui.VanillaGuiLayers import net.neoforged.neoforge.client.gui.VanillaGuiLayers
import net.neoforged.neoforge.common.ItemAbilities 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.android.feature.NanobotsArmorFeature
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.capability.MatteryPlayer 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.config.ClientConfig
import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.kommons.math.RGBAColor 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.math.Decimal
import ru.dbotthepony.mc.otm.core.random import ru.dbotthepony.mc.otm.core.random
import ru.dbotthepony.mc.otm.core.util.formatPower import ru.dbotthepony.mc.otm.core.util.formatPower
@ -42,24 +42,6 @@ import kotlin.math.PI
import kotlin.math.ceil import kotlin.math.ceil
object MatteryGUI { 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 originalBedButtonX = -1
private var originalBedButtonY = -1 private var originalBedButtonY = -1
@ -112,349 +94,397 @@ object MatteryGUI {
} }
} }
var iteration = 0 fun onLayerRenderEvent(event: RenderGuiLayerEvent.Pre) {
var showIterationUntil = 0L if (minecraft.player?.matteryPlayer?.isAndroid == true) {
var showIterationUntilFade = 0L if (event.name == VanillaGuiLayers.FOOD_LEVEL
|| event.name == VanillaGuiLayers.AIR_LEVEL
val deathLog = ArrayList<Pair<Int, Component>>() || (event.name == VanillaGuiLayers.PLAYER_HEALTH && ClientConfig.HUD.ANDROID_HEALTH_BAR)) {
event.isCanceled = true
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
}
} }
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) { fun registerGuiLayers(event: RegisterGuiLayersEvent) {
val player = minecraft.player ?: return event.registerBelow(VanillaGuiLayers.FOOD_LEVEL, loc("android_energy_bar"), AndroidEnergyBarLayer())
event.registerBelow(VanillaGuiLayers.PLAYER_HEALTH, loc("android_health_bar"), AndroidHealthBarLayer())
if (!player.matteryPlayer.isAndroid) { event.registerAboveAll(loc("android_iteration"), AndroidIterationLayer())
return event.registerAbove(VanillaGuiLayers.CAMERA_OVERLAYS, loc("android_low_power"), AndroidLowPowerLayer())
}
showIteration(event)
drawLowPower(event, player)
} }
private fun renderFoodAndAir(event: RenderGuiLayerEvent.Pre, gui: Gui) { class AndroidEnergyBarLayer : LayeredDraw.Layer {
val ply: LocalPlayer = minecraft.player ?: return override fun render(
graphics: GuiGraphics,
delta: DeltaTracker
) {
val ply: LocalPlayer = minecraft.player ?: return
if (ply.vehicle is LivingEntity) if (ply.vehicle is LivingEntity || ply.isCreative)
return
val mattery = ply.matteryPlayer
if (mattery.isAndroid) {
event.isCanceled = true
if (event.name === VanillaGuiLayers.AIR_LEVEL)
return return
var level: Float val gui = minecraft.gui
val mattery = ply.matteryPlayer
if (mattery.androidEnergy.maxBatteryLevel.isZero) { if (mattery.isAndroid) {
level = 0f 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 { } else {
level = mattery.androidEnergy.batteryLevel.percentage(mattery.androidEnergy.maxBatteryLevel) alpha = diff / 50_000_000f
if (level >= 0.98f)
level = 1f
} }
RenderSystem.enableBlend() if (alpha != 1f) RenderSystem.setShaderColor(1f, 1f, 1f, alpha)
RenderSystem.defaultBlendFunc() val window = minecraft.window
RenderSystem.disableDepthTest()
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f)
val width = minecraft.window.guiScaledWidth val x = window.guiScaledWidth / 2f
val height = minecraft.window.guiScaledHeight var y = window.guiScaledHeight / 2.5f
val left = width / 2 + 10
val top: Int = height - gui.rightHeight
gui.rightHeight += 10
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)) { minecraft.font.draw(
CHARGE_HUNGER_BG.render(guiGraphics, left.toFloat(), top.toFloat()) graphics.pose(),
CHARGE_HUNGER.renderPartial(guiGraphics, left.toFloat() - leftPadding + 80f, top.toFloat(), width = leftPadding) powerAlert2,
} else { x, y,
CHARGE_BG.render(guiGraphics, left.toFloat(), top.toFloat()) gravity = RenderGravity.CENTER_CENTER,
CHARGE.renderPartial(guiGraphics, left.toFloat() - leftPadding + 80f, top.toFloat(), width = leftPadding) drawShadow = true
} )
val formattedPower = mattery.androidEnergy.batteryLevel.formatPower() y += minecraft.font.lineHeight + 2f
val scale = ClientConfig.HUD.BAR_TEXT_SCALE.toFloat() minecraft.font.draw(
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) graphics.pose(),
powerAlert3,
x, y,
gravity = RenderGravity.CENTER_CENTER,
drawShadow = true
)
RenderSystem.disableBlend() y += minecraft.font.lineHeight * 2f + 4f
RenderSystem.enableDepthTest()
}
}
private fun getSpriteForPlayer(player: Player): MatterySprite { minecraft.font.draw(
if (player.hasEffect(MobEffects.POISON)) { graphics.pose(),
return HEALTH_POISON TranslatableComponent(
} else if (player.hasEffect(MobEffects.WITHER)) { "otm.pwr_alert5",
return HEALTH_WITHER errorCode,
} else if (player.isFullyFrozen) { errorServerNode,
return HEALTH_FROZEN 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 { private val powerAlert2 = TranslatableComponent("otm.pwr_alert3").withStyle(ChatFormatting.YELLOW)
if (player.hasEffect(MobEffects.POISON)) { private val powerAlert3 = TranslatableComponent("otm.pwr_alert4").withStyle(ChatFormatting.YELLOW)
return RGBAColor.DARK_GREEN
} else if (player.hasEffect(MobEffects.WITHER)) {
return RGBAColor.WHITE
} else if (player.isFullyFrozen) {
return RGBAColor.AQUA
}
return RGBAColor.RED private val errorCodes = ImmutableList.of(
} // можно вынести в конфиг, но для этого нужен селектор цвета "005", "06E", "004", "0F1", "7FF", "F0A"
)
private fun renderPlayerHealth(event: RenderGuiLayerEvent.Pre, gui: Gui) { private val registerParts = ImmutableList.of("A", "B", "C", "D", "E", "F", "M", "D", "X", "Y", "Z")
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)
}
} }
} }

View File

@ -184,11 +184,11 @@ class PlayerIterationPacket(val iteration: Int, val deathLog: List<Pair<Int, Com
} }
fun play(context: IPayloadContext) { fun play(context: IPayloadContext) {
MatteryGUI.iteration = iteration MatteryGUI.AndroidIterationLayer.iteration = iteration
MatteryGUI.deathLog.clear() MatteryGUI.AndroidIterationLayer.deathLog.clear()
MatteryGUI.deathLog.addAll(deathLog) MatteryGUI.AndroidIterationLayer.deathLog.addAll(deathLog)
MatteryGUI.showIterationUntil = System.currentTimeMillis() + 4000L MatteryGUI.AndroidIterationLayer.showIterationUntil = System.currentTimeMillis() + 4000L
MatteryGUI.showIterationUntilFade = System.currentTimeMillis() + 5000L MatteryGUI.AndroidIterationLayer.showIterationUntilFade = System.currentTimeMillis() + 5000L
} }
override fun type(): CustomPacketPayload.Type<out CustomPacketPayload> { override fun type(): CustomPacketPayload.Type<out CustomPacketPayload> {