feat: Highlight century cake slice players

This commit is contained in:
Linnea Gräf
2025-02-02 00:08:18 +01:00
parent c2aefe09ab
commit 89bceb6735
18 changed files with 559 additions and 3 deletions

View File

@@ -254,6 +254,7 @@ fun firmamentCommand() = literal("firmament") {
val player = MC.player ?: return@thenExecute
player.world.getOtherEntities(player, player.boundingBox.expand(12.0))
.forEach(PowerUserTools::showEntity)
PowerUserTools.showEntity(player)
}
}
thenLiteral("callUrsa") {

View File

@@ -0,0 +1,66 @@
package moe.nea.firmament.events
import net.minecraft.client.render.GameRenderer
import net.minecraft.client.render.OverlayTexture
import net.minecraft.client.render.entity.state.EntityRenderState
import net.minecraft.entity.Entity
import net.minecraft.entity.LivingEntity
import moe.nea.firmament.util.render.TintedOverlayTexture
/**
* Change the tint color of a [LivingEntity]
*/
class EntityRenderTintEvent(
val entity: Entity,
val renderState: HasTintRenderState
) : FirmamentEvent.Cancellable() {
init {
if (entity !is LivingEntity) {
cancel()
}
}
companion object : FirmamentEventBus<EntityRenderTintEvent>() {
/**
* Static variable containing an override for [GameRenderer.getOverlayTexture]. Should be only set briefly.
*
* This variable only affects render layers that naturally make use of the overlay texture, have proper overlay UVs set (`overlay u != 0`), and have a shader that makes use of the overlay (does not have the `NO_OVERLAY` flag set in its json definition).
*
* Currently supported layers: [net.minecraft.client.render.entity.equipment.EquipmentRenderer], [net.minecraft.client.render.entity.model.PlayerEntityModel], as well as some others naturally.
*
* @see moe.nea.firmament.mixins.render.entitytints.ReplaceOverlayTexture
* @see TintedOverlayTexture
*/
@JvmField
var overlayOverride: OverlayTexture? = null
}
@Suppress("PropertyName", "FunctionName")
interface HasTintRenderState {
/**
* Multiplicative tint applied before the overlay.
*/
var tint_firmament: Int
/**
* Must be set for [tint_firmament] to have any effect.
*/
var hasTintOverride_firmament: Boolean
// TODO: allow for more specific selection of which layers get tinted
/**
* Specify a [TintedOverlayTexture] to be used. This does not apply to render layers not using the overlay texture.
* @see overlayOverride
*/
var overlayTexture_firmament: TintedOverlayTexture?
fun reset_firmament()
companion object {
@JvmStatic
fun cast(state: EntityRenderState): HasTintRenderState {
return state as HasTintRenderState
}
}
}
}

View File

@@ -1,22 +1,31 @@
package moe.nea.firmament.features.debug
import com.mojang.serialization.Codec
import com.mojang.serialization.DynamicOps
import com.mojang.serialization.JsonOps
import com.mojang.serialization.codecs.RecordCodecBuilder
import kotlin.jvm.optionals.getOrNull
import net.minecraft.block.SkullBlock
import net.minecraft.block.entity.SkullBlockEntity
import net.minecraft.component.DataComponentTypes
import net.minecraft.component.type.ProfileComponent
import net.minecraft.entity.Entity
import net.minecraft.entity.EntityType
import net.minecraft.entity.LivingEntity
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.nbt.NbtCompound
import net.minecraft.nbt.NbtOps
import net.minecraft.nbt.NbtString
import net.minecraft.predicate.NbtPredicate
import net.minecraft.text.Text
import net.minecraft.text.TextCodecs
import net.minecraft.util.Identifier
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.hit.EntityHitResult
import net.minecraft.util.hit.HitResult
import net.minecraft.util.math.Position
import net.minecraft.util.math.Vec3d
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.CustomItemModelEvent
import moe.nea.firmament.events.HandledScreenKeyPressedEvent
@@ -31,6 +40,7 @@ import moe.nea.firmament.util.ClipboardUtils
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.focusedItemStack
import moe.nea.firmament.util.mc.IntrospectableItemModelManager
import moe.nea.firmament.util.mc.SNbtFormatter
import moe.nea.firmament.util.mc.SNbtFormatter.Companion.toPrettyString
import moe.nea.firmament.util.mc.displayNameAccordingToNbt
import moe.nea.firmament.util.mc.loreAccordingToNbt
@@ -88,6 +98,11 @@ object PowerUserTools : FirmamentFeature {
}
fun showEntity(target: Entity) {
val nbt = NbtPredicate.entityToNbt(target)
nbt.remove("Inventory")
nbt.put("StyledName", TextCodecs.CODEC.encodeStart(NbtOps.INSTANCE, target.styledDisplayName).orThrow)
println(SNbtFormatter.prettify(nbt))
ClipboardUtils.setTextContent(SNbtFormatter.prettify(nbt))
MC.sendChat(Text.translatable("firmament.poweruser.entity.type", target.type))
MC.sendChat(Text.translatable("firmament.poweruser.entity.name", target.name))
MC.sendChat(Text.stringifiedTranslatable("firmament.poweruser.entity.position", target.pos))

View File

@@ -0,0 +1,63 @@
package moe.nea.firmament.features.events.anniversity
import java.util.Optional
import me.shedaniel.math.Color
import kotlin.jvm.optionals.getOrNull
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.text.Style
import net.minecraft.util.Formatting
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.EntityRenderTintEvent
import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.render.TintedOverlayTexture
import moe.nea.firmament.util.skyBlockId
import moe.nea.firmament.util.skyblock.SkyBlockItems
object CenturyRaffleFeatures {
object TConfig : ManagedConfig("centuryraffle", Category.EVENTS) {
val highlightPlayersForSlice by toggle("highlight-cake-players") { true }
// val highlightAllPlayers by toggle("highlight-all-cake-players") { true }
}
val cakeIcon = ""
val cakeColors = listOf(
CakeTeam(SkyBlockItems.SLICE_OF_BLUEBERRY_CAKE, Formatting.BLUE),
CakeTeam(SkyBlockItems.SLICE_OF_CHEESECAKE, Formatting.YELLOW),
CakeTeam(SkyBlockItems.SLICE_OF_GREEN_VELVET_CAKE, Formatting.GREEN),
CakeTeam(SkyBlockItems.SLICE_OF_RED_VELVET_CAKE, Formatting.RED),
CakeTeam(SkyBlockItems.SLICE_OF_STRAWBERRY_SHORTCAKE, Formatting.LIGHT_PURPLE),
)
data class CakeTeam(
val id: SkyblockId,
val formatting: Formatting,
) {
val searchedTextRgb = formatting.colorValue!!
val brightenedRgb = Color.ofOpaque(searchedTextRgb)//.brighter(2.0)
val tintOverlay by lazy {
TintedOverlayTexture().setColor(brightenedRgb)
}
}
val sliceToColor = cakeColors.associateBy { it.id }
@Subscribe
fun onEntityRender(event: EntityRenderTintEvent) {
if (!TConfig.highlightPlayersForSlice) return
val requestedCakeTeam = sliceToColor[MC.stackInHand?.skyBlockId] ?: return
// TODO: cache the requested color
val player = event.entity as? PlayerEntity ?: return
val cakeColor: Style = player.styledDisplayName.visit(
{ style, text ->
if (text == cakeIcon) Optional.of(style)
else Optional.empty()
}, Style.EMPTY).getOrNull() ?: return
if (cakeColor.color?.rgb == requestedCakeTeam.searchedTextRgb) {
event.renderState.overlayTexture_firmament = requestedCakeTeam.tintOverlay
}
}
}

View File

@@ -7,11 +7,13 @@ import net.minecraft.client.gui.hud.InGameHud
import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.client.network.ClientPlayerEntity
import net.minecraft.client.render.GameRenderer
import net.minecraft.client.render.WorldRenderer
import net.minecraft.client.render.item.ItemRenderer
import net.minecraft.client.world.ClientWorld
import net.minecraft.entity.Entity
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.network.packet.c2s.play.CommandExecutionC2SPacket
import net.minecraft.registry.BuiltinRegistries
import net.minecraft.registry.RegistryKeys
@@ -85,6 +87,7 @@ object MC {
inline val resourceManager get() = (instance.resourceManager as ReloadableResourceManagerImpl)
inline val itemRenderer: ItemRenderer get() = instance.itemRenderer
inline val worldRenderer: WorldRenderer get() = instance.worldRenderer
inline val gameRenderer: GameRenderer get() = instance.gameRenderer
inline val networkHandler get() = player?.networkHandler
inline val instance get() = MinecraftClient.getInstance()
inline val keyboard get() = instance.keyboard
@@ -96,6 +99,7 @@ object MC {
inline val soundManager get() = instance.soundManager
inline val player: ClientPlayerEntity? get() = TestUtil.unlessTesting { instance.player }
inline val camera: Entity? get() = instance.cameraEntity
inline val stackInHand: ItemStack? get() = player?.inventory?.mainHandStack
inline val guiAtlasManager get() = instance.guiAtlasManager
inline val world: ClientWorld? get() = TestUtil.unlessTesting { instance.world }
inline val playerName: String? get() = player?.name?.unformattedString

View File

@@ -0,0 +1,44 @@
package moe.nea.firmament.util.render
import com.mojang.blaze3d.platform.GlConst
import com.mojang.blaze3d.systems.RenderSystem
import me.shedaniel.math.Color
import net.minecraft.client.render.OverlayTexture
import net.minecraft.util.math.ColorHelper
import moe.nea.firmament.util.ErrorUtil
class TintedOverlayTexture : OverlayTexture() {
companion object {
val size = 16
}
private var lastColor: Color? = null
fun setColor(color: Color): TintedOverlayTexture {
val image = ErrorUtil.notNullOr(texture.image, "Disposed TintedOverlayTexture written to") { return this }
if (color == lastColor) return this
lastColor = color
for (i in 0..<size) {
for (j in 0..<size) {
if (i < 8) {
image.setColorArgb(j, i, 0xB2FF0000.toInt())
} else {
val k = ((1F - j / 15F * 0.75F) * 255F).toInt()
image.setColorArgb(j, i, ColorHelper.withAlpha(k, color.color))
}
}
}
RenderSystem.activeTexture(GlConst.GL_TEXTURE1)
texture.bindTexture()
texture.setFilter(false, false)
texture.setClamp(true)
image.upload(0,
0, 0,
0, 0,
image.width, image.height,
false)
RenderSystem.activeTexture(GlConst.GL_TEXTURE0)
return this
}
}

View File

@@ -8,4 +8,9 @@ object SkyBlockItems {
val DIAMOND = SkyblockId("DIAMOND")
val ANCESTRAL_SPADE = SkyblockId("ANCESTRAL_SPADE")
val REFORGE_ANVIL = SkyblockId("REFORGE_ANVIL")
val SLICE_OF_BLUEBERRY_CAKE = SkyblockId("SLICE_OF_BLUEBERRY_CAKE")
val SLICE_OF_CHEESECAKE = SkyblockId("SLICE_OF_CHEESECAKE")
val SLICE_OF_GREEN_VELVET_CAKE = SkyblockId("SLICE_OF_GREEN_VELVET_CAKE")
val SLICE_OF_RED_VELVET_CAKE = SkyblockId("SLICE_OF_RED_VELVET_CAKE")
val SLICE_OF_STRAWBERRY_SHORTCAKE = SkyblockId("SLICE_OF_STRAWBERRY_SHORTCAKE")
}