aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/events
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/events')
-rw-r--r--src/main/kotlin/events/CustomItemModelEvent.kt60
-rw-r--r--src/main/kotlin/events/EntityRenderTintEvent.kt66
-rw-r--r--src/main/kotlin/events/EntityUpdateEvent.kt53
-rw-r--r--src/main/kotlin/events/FirmamentEventBus.kt3
-rw-r--r--src/main/kotlin/events/IsSlotProtectedEvent.kt81
-rw-r--r--src/main/kotlin/events/PlayerInventoryUpdate.kt19
-rw-r--r--src/main/kotlin/events/WorldKeyboardEvent.kt17
-rw-r--r--src/main/kotlin/events/WorldMouseMoveEvent.kt5
8 files changed, 243 insertions, 61 deletions
diff --git a/src/main/kotlin/events/CustomItemModelEvent.kt b/src/main/kotlin/events/CustomItemModelEvent.kt
index 11528fd..7b86980 100644
--- a/src/main/kotlin/events/CustomItemModelEvent.kt
+++ b/src/main/kotlin/events/CustomItemModelEvent.kt
@@ -1,23 +1,75 @@
package moe.nea.firmament.events
+import java.util.Objects
+import java.util.Optional
+import kotlin.jvm.optionals.getOrNull
+import net.minecraft.component.DataComponentTypes
import net.minecraft.item.ItemStack
import net.minecraft.util.Identifier
+import moe.nea.firmament.util.collections.WeakCache
+import moe.nea.firmament.util.collections.WeakCache.CacheFunction
+import moe.nea.firmament.util.mc.IntrospectableItemModelManager
// TODO: assert an order on these events
data class CustomItemModelEvent(
val itemStack: ItemStack,
+ val itemModelManager: IntrospectableItemModelManager,
var overrideModel: Identifier? = null,
) : FirmamentEvent() {
companion object : FirmamentEventBus<CustomItemModelEvent>() {
+ val weakCache =
+ object : WeakCache<ItemStack, IntrospectableItemModelManager, Optional<Identifier>>("ItemModelIdentifier") {
+ override fun mkRef(
+ key: ItemStack,
+ extraData: IntrospectableItemModelManager
+ ): WeakCache<ItemStack, IntrospectableItemModelManager, Optional<Identifier>>.Ref {
+ return IRef(key, extraData)
+ }
+
+ inner class IRef(weakInstance: ItemStack, data: IntrospectableItemModelManager) :
+ Ref(weakInstance, data) {
+ override fun shouldBeEvicted(): Boolean = false
+ val isSimpleStack = weakInstance.componentChanges.isEmpty || (weakInstance.componentChanges.size() == 1 && weakInstance.get(
+ DataComponentTypes.CUSTOM_DATA)?.isEmpty == true)
+ val item = weakInstance.item
+ override fun hashCode(): Int {
+ if (isSimpleStack)
+ return Objects.hash(item, extraData)
+ return super.hashCode()
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (other is IRef && isSimpleStack) {
+ return other.isSimpleStack && item == other.item
+ }
+ return super.equals(other)
+ }
+ }
+ }
+ val cache = CacheFunction.WithExtraData(weakCache, ::getModelIdentifier0)
+
@JvmStatic
- fun getModelIdentifier(itemStack: ItemStack?): Identifier? {
- // TODO: Re-add memoization and add an error / warning if the model does not exist
+ fun getModelIdentifier(itemStack: ItemStack?, itemModelManager: IntrospectableItemModelManager): Identifier? {
if (itemStack == null) return null
- return publish(CustomItemModelEvent(itemStack)).overrideModel
+ return cache.invoke(itemStack, itemModelManager).getOrNull()
+ }
+
+ fun getModelIdentifier0(
+ itemStack: ItemStack,
+ itemModelManager: IntrospectableItemModelManager
+ ): Optional<Identifier> {
+ // TODO: add an error / warning if the model does not exist
+ return Optional.ofNullable(publish(CustomItemModelEvent(itemStack, itemModelManager)).overrideModel)
}
}
fun overrideIfExists(overrideModel: Identifier) {
- this.overrideModel = overrideModel
+ if (itemModelManager.hasModel_firmament(overrideModel))
+ this.overrideModel = overrideModel
+ }
+
+ fun overrideIfEmpty(identifier: Identifier) {
+ if (overrideModel == null)
+ overrideModel = identifier
}
}
diff --git a/src/main/kotlin/events/EntityRenderTintEvent.kt b/src/main/kotlin/events/EntityRenderTintEvent.kt
new file mode 100644
index 0000000..29b888b
--- /dev/null
+++ b/src/main/kotlin/events/EntityRenderTintEvent.kt
@@ -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
+ }
+ }
+ }
+
+}
diff --git a/src/main/kotlin/events/EntityUpdateEvent.kt b/src/main/kotlin/events/EntityUpdateEvent.kt
index d091984..fec2fa5 100644
--- a/src/main/kotlin/events/EntityUpdateEvent.kt
+++ b/src/main/kotlin/events/EntityUpdateEvent.kt
@@ -1,10 +1,14 @@
-
package moe.nea.firmament.events
+import com.mojang.datafixers.util.Pair
import net.minecraft.entity.Entity
+import net.minecraft.entity.EquipmentSlot
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.data.DataTracker
+import net.minecraft.item.ItemStack
import net.minecraft.network.packet.s2c.play.EntityAttributesS2CPacket
+import moe.nea.firmament.annotations.Subscribe
+import moe.nea.firmament.util.MC
/**
* This event is fired when some entity properties are updated.
@@ -13,19 +17,44 @@ import net.minecraft.network.packet.s2c.play.EntityAttributesS2CPacket
* *after* the values have been applied to the entity.
*/
sealed class EntityUpdateEvent : FirmamentEvent() {
- companion object : FirmamentEventBus<EntityUpdateEvent>()
+ companion object : FirmamentEventBus<EntityUpdateEvent>() {
+ @Subscribe
+ fun onPlayerInventoryUpdate(event: PlayerInventoryUpdate) {
+ val p = MC.player ?: return
+ val updatedSlots = listOf(
+ EquipmentSlot.HEAD to 39,
+ EquipmentSlot.CHEST to 38,
+ EquipmentSlot.LEGS to 37,
+ EquipmentSlot.FEET to 36,
+ EquipmentSlot.OFFHAND to 40,
+ EquipmentSlot.MAINHAND to p.inventory.selectedSlot, // TODO: also equipment update when you swap your selected slot perhaps
+ ).mapNotNull { (slot, stackIndex) ->
+ val slotIndex = p.playerScreenHandler.getSlotIndex(p.inventory, stackIndex).asInt
+ event.getOrNull(slotIndex)?.let {
+ Pair.of(slot, it)
+ }
+ }
+ if (updatedSlots.isNotEmpty())
+ publish(EquipmentUpdate(p, updatedSlots))
+ }
+ }
+
+ abstract val entity: Entity
- abstract val entity: Entity
+ data class AttributeUpdate(
+ override val entity: LivingEntity,
+ val attributes: List<EntityAttributesS2CPacket.Entry>,
+ ) : EntityUpdateEvent()
- data class AttributeUpdate(
- override val entity: LivingEntity,
- val attributes: List<EntityAttributesS2CPacket.Entry>,
- ) : EntityUpdateEvent()
+ data class TrackedDataUpdate(
+ override val entity: Entity,
+ val trackedValues: List<DataTracker.SerializedEntry<*>>,
+ ) : EntityUpdateEvent()
- data class TrackedDataUpdate(
- override val entity: Entity,
- val trackedValues: List<DataTracker.SerializedEntry<*>>,
- ) : EntityUpdateEvent()
+ data class EquipmentUpdate(
+ override val entity: Entity,
+ val newEquipment: List<Pair<EquipmentSlot, ItemStack>>,
+ ) : EntityUpdateEvent()
-// TODO: onEntityPassengersSet, onEntityAttach?, onEntityEquipmentUpdate, onEntityStatusEffect
+// TODO: onEntityPassengersSet, onEntityAttach?, onEntityStatusEffect
}
diff --git a/src/main/kotlin/events/FirmamentEventBus.kt b/src/main/kotlin/events/FirmamentEventBus.kt
index 71331d1..af4e16a 100644
--- a/src/main/kotlin/events/FirmamentEventBus.kt
+++ b/src/main/kotlin/events/FirmamentEventBus.kt
@@ -3,6 +3,7 @@ package moe.nea.firmament.events
import java.util.concurrent.CopyOnWriteArrayList
import org.apache.commons.lang3.reflect.TypeUtils
import moe.nea.firmament.Firmament
+import moe.nea.firmament.util.ErrorUtil
import moe.nea.firmament.util.MC
/**
@@ -48,7 +49,7 @@ open class FirmamentEventBus<T : FirmamentEvent> {
val klass = e.javaClass
if (!function.knownErrors.contains(klass) || Firmament.DEBUG) {
function.knownErrors.add(klass)
- Firmament.logger.error("Caught exception during processing event $event by $function", e)
+ ErrorUtil.softError("Caught exception during processing event $event by $function", e)
}
}
}
diff --git a/src/main/kotlin/events/IsSlotProtectedEvent.kt b/src/main/kotlin/events/IsSlotProtectedEvent.kt
index cd2b676..8fe0a96 100644
--- a/src/main/kotlin/events/IsSlotProtectedEvent.kt
+++ b/src/main/kotlin/events/IsSlotProtectedEvent.kt
@@ -1,5 +1,3 @@
-
-
package moe.nea.firmament.events
import net.minecraft.item.ItemStack
@@ -8,39 +6,60 @@ import net.minecraft.screen.slot.SlotActionType
import net.minecraft.text.Text
import moe.nea.firmament.util.CommonSoundEffects
import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.grey
+import moe.nea.firmament.util.hover
+import moe.nea.firmament.util.red
+import moe.nea.firmament.util.tr
data class IsSlotProtectedEvent(
- val slot: Slot?,
- val actionType: SlotActionType,
- var isProtected: Boolean,
- val itemStackOverride: ItemStack?,
- var silent: Boolean = false,
+ val slot: Slot?,
+ val actionType: SlotActionType,
+ var isProtected: Boolean,
+ val itemStackOverride: ItemStack?,
+ val origin: MoveOrigin,
+ var silent: Boolean = false,
) : FirmamentEvent() {
- val itemStack get() = itemStackOverride ?: slot!!.stack
+ val itemStack get() = itemStackOverride ?: slot!!.stack
+
+ fun protect() {
+ isProtected = true
+ silent = false
+ }
- fun protect() {
- isProtected = true
- }
+ fun protectSilent() {
+ if (!isProtected) {
+ silent = true
+ }
+ isProtected = true
+ }
- fun protectSilent() {
- if (!isProtected) {
- silent = true
- }
- isProtected = true
- }
+ enum class MoveOrigin {
+ DROP_FROM_HOTBAR,
+ SALVAGE,
+ INVENTORY_MOVE
+ ;
+ }
- companion object : FirmamentEventBus<IsSlotProtectedEvent>() {
- @JvmStatic
- @JvmOverloads
- fun shouldBlockInteraction(slot: Slot?, action: SlotActionType, itemStackOverride: ItemStack? = null): Boolean {
- if (slot == null && itemStackOverride == null) return false
- val event = IsSlotProtectedEvent(slot, action, false, itemStackOverride)
- publish(event)
- if (event.isProtected && !event.silent) {
- MC.sendChat(Text.translatable("firmament.protectitem").append(event.itemStack.name))
- CommonSoundEffects.playFailure()
- }
- return event.isProtected
- }
- }
+ companion object : FirmamentEventBus<IsSlotProtectedEvent>() {
+ @JvmStatic
+ @JvmOverloads
+ fun shouldBlockInteraction(
+ slot: Slot?, action: SlotActionType,
+ origin: MoveOrigin,
+ itemStackOverride: ItemStack? = null,
+ ): Boolean {
+ if (slot == null && itemStackOverride == null) return false
+ val event = IsSlotProtectedEvent(slot, action, false, itemStackOverride, origin)
+ publish(event)
+ if (event.isProtected && !event.silent) {
+ MC.sendChat(tr("firmament.protectitem", "Firmament protected your item: ${event.itemStack.name}.\n")
+ .red()
+ .append(tr("firmament.protectitem.hoverhint", "Hover for more info.").grey())
+ .hover(tr("firmament.protectitem.hint",
+ "To unlock this item use the Lock Slot or Lock Item keybind from Firmament while hovering over this item.")))
+ CommonSoundEffects.playFailure()
+ }
+ return event.isProtected
+ }
+ }
}
diff --git a/src/main/kotlin/events/PlayerInventoryUpdate.kt b/src/main/kotlin/events/PlayerInventoryUpdate.kt
index 6e8203a..88439a9 100644
--- a/src/main/kotlin/events/PlayerInventoryUpdate.kt
+++ b/src/main/kotlin/events/PlayerInventoryUpdate.kt
@@ -1,11 +1,22 @@
-
package moe.nea.firmament.events
import net.minecraft.item.ItemStack
sealed class PlayerInventoryUpdate : FirmamentEvent() {
- companion object : FirmamentEventBus<PlayerInventoryUpdate>()
- data class Single(val slot: Int, val stack: ItemStack) : PlayerInventoryUpdate()
- data class Multi(val contents: List<ItemStack>) : PlayerInventoryUpdate()
+ companion object : FirmamentEventBus<PlayerInventoryUpdate>()
+ data class Single(val slot: Int, val stack: ItemStack) : PlayerInventoryUpdate() {
+ override fun getOrNull(slot: Int): ItemStack? {
+ if (slot == this.slot) return stack
+ return null
+ }
+
+ }
+
+ data class Multi(val contents: List<ItemStack>) : PlayerInventoryUpdate() {
+ override fun getOrNull(slot: Int): ItemStack? {
+ return contents.getOrNull(slot)
+ }
+ }
+ abstract fun getOrNull(slot: Int): ItemStack?
}
diff --git a/src/main/kotlin/events/WorldKeyboardEvent.kt b/src/main/kotlin/events/WorldKeyboardEvent.kt
index e8566fd..1d6a758 100644
--- a/src/main/kotlin/events/WorldKeyboardEvent.kt
+++ b/src/main/kotlin/events/WorldKeyboardEvent.kt
@@ -1,18 +1,17 @@
-
-
package moe.nea.firmament.events
import net.minecraft.client.option.KeyBinding
import moe.nea.firmament.keybindings.IKeyBinding
data class WorldKeyboardEvent(val keyCode: Int, val scanCode: Int, val modifiers: Int) : FirmamentEvent.Cancellable() {
- companion object : FirmamentEventBus<WorldKeyboardEvent>()
+ companion object : FirmamentEventBus<WorldKeyboardEvent>()
- fun matches(keyBinding: KeyBinding): Boolean {
- return matches(IKeyBinding.minecraft(keyBinding))
- }
+ fun matches(keyBinding: KeyBinding): Boolean {
+ return matches(IKeyBinding.minecraft(keyBinding))
+ }
- fun matches(keyBinding: IKeyBinding): Boolean {
- return keyBinding.matches(keyCode, scanCode, modifiers)
- }
+ fun matches(keyBinding: IKeyBinding, atLeast: Boolean = false): Boolean {
+ return if (atLeast) keyBinding.matchesAtLeast(keyCode, scanCode, modifiers) else
+ keyBinding.matches(keyCode, scanCode, modifiers)
+ }
}
diff --git a/src/main/kotlin/events/WorldMouseMoveEvent.kt b/src/main/kotlin/events/WorldMouseMoveEvent.kt
new file mode 100644
index 0000000..7a17ba4
--- /dev/null
+++ b/src/main/kotlin/events/WorldMouseMoveEvent.kt
@@ -0,0 +1,5 @@
+package moe.nea.firmament.events
+
+data class WorldMouseMoveEvent(val deltaX: Double, val deltaY: Double) : FirmamentEvent.Cancellable() {
+ companion object : FirmamentEventBus<WorldMouseMoveEvent>()
+}