|
|
|
@ -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")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|