From 56e2e70a5c6d9a040373a73c1ba194c4d555cc54 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 3 Nov 2024 12:21:12 +0700 Subject: [PATCH] "Low power" HUD element --- .../mc/otm/datagen/lang/English.kt | 8 ++ .../mc/otm/datagen/lang/Russian.kt | 4 + .../dbotthepony/mc/otm/client/MatteryGUI.kt | 132 +++++++++++++++++- .../kotlin/ru/dbotthepony/mc/otm/core/Ext.kt | 32 +++++ 4 files changed, 169 insertions(+), 7 deletions(-) diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt index 9e1a28a10..d9514b613 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt @@ -134,6 +134,14 @@ private fun sounds(provider: MatteryLanguageProvider) { private fun misc(provider: MatteryLanguageProvider) { with(provider.english) { + misc("pwr_alert1", "[%s]") + misc("pwr_alert2", "PWR: ALERT") + misc("pwr_alert3", "WARNING ERROR:") + misc("pwr_alert4", "system_crash_log") + // Error 06E has occurred at 0027F:C0082E2270273 in VXE VMMXDE + // Error has occurred at : in + misc("pwr_alert5", "Error %s has occurred at %s:%s in %s") + gui("double_processing", "Processes two items at once") misc("painted.black", "Painted Black") diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt index 4b2fc7937..6bcbe1a0a 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt @@ -146,6 +146,10 @@ private fun sounds(provider: MatteryLanguageProvider) { private fun misc(provider: MatteryLanguageProvider) { with(provider.russian) { + misc("pwr_alert2", "ПТН: ВНИМАНИЕ") + misc("pwr_alert3", "ПРЕДУПРЕЖДЕНИЕ ОБ ОШИБКЕ:") + misc("pwr_alert5", "Ошибка %s была обнаружена по адресу %s:%s в %s") + gui("double_processing", "Обрабатывает два предмета одновременно") misc("painted.black", "Окрашено в чёрный") diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/MatteryGUI.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/MatteryGUI.kt index df3199543..fa7a9462b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/MatteryGUI.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/MatteryGUI.kt @@ -1,6 +1,8 @@ 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.gui.Font import net.minecraft.client.gui.Gui import net.minecraft.client.gui.GuiGraphics @@ -9,7 +11,6 @@ import net.minecraft.client.gui.screens.DeathScreen import net.minecraft.client.gui.screens.InBedChatScreen import net.minecraft.client.player.LocalPlayer import net.minecraft.network.chat.Component -import net.minecraft.resources.ResourceLocation import net.minecraft.world.effect.MobEffects import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.player.Player @@ -20,11 +21,9 @@ 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 net.neoforged.neoforge.common.ItemAbility 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.MatteryCapability import ru.dbotthepony.mc.otm.capability.MatteryPlayer import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.client.render.* @@ -34,6 +33,8 @@ 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.core.math.Decimal +import ru.dbotthepony.mc.otm.core.random import ru.dbotthepony.mc.otm.core.util.formatPower import ru.dbotthepony.mc.otm.registry.AndroidFeatures import java.util.* @@ -118,10 +119,6 @@ object MatteryGUI { val deathLog = ArrayList>() private fun showIteration(event: RenderGuiEvent.Post) { - if (minecraft.player?.matteryPlayer?.isAndroid != true) { - return - } - val time = System.currentTimeMillis() if (time > showIterationUntilFade) { @@ -190,8 +187,129 @@ object MatteryGUI { 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) { + val player = minecraft.player ?: return + + if (!player.matteryPlayer.isAndroid) { + return + } + showIteration(event) + drawLowPower(event, player) } private fun renderFoodAndAir(event: RenderGuiLayerEvent.Pre, gui: Gui) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt index 2c848e6ba..850f75af0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt @@ -28,6 +28,7 @@ import net.minecraft.network.chat.contents.TranslatableContents import net.minecraft.resources.ResourceKey import net.minecraft.resources.ResourceLocation import net.minecraft.tags.TagKey +import net.minecraft.util.RandomSource import net.minecraft.world.entity.Entity import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack @@ -63,6 +64,7 @@ import java.util.function.Supplier import java.util.random.RandomGenerator import java.util.stream.Stream import java.util.stream.StreamSupport +import kotlin.NoSuchElementException import kotlin.jvm.optionals.getOrNull import kotlin.reflect.KProperty @@ -178,6 +180,36 @@ fun MutableList.shuffle(random: RandomGenerator) { } } +fun IntArray.shuffle(random: RandomSource) { + for (i in lastIndex downTo 1) { + val j = random.nextInt(i + 1) + val copy = this[i] + this[i] = this[j] + this[j] = copy + } +} + +fun MutableList.shuffle(random: RandomSource) { + for (i in lastIndex downTo 1) { + val j = random.nextInt(i + 1) + val copy = this[i] + this[i] = this[j] + this[j] = copy + } +} + +fun List.random(random: RandomGenerator): T { + if (isEmpty()) + throw NoSuchElementException("This list is empty") + return get(random.nextInt(size)) +} + +fun List.random(random: RandomSource): T { + if (isEmpty()) + throw NoSuchElementException("This list is empty") + return get(random.nextInt(size)) +} + inline fun immutableList(size: Int, initializer: (index: Int) -> T): ImmutableList { require(size >= 0) { "Invalid list size $size" }