diff options
Diffstat (limited to 'src/main/kotlin/events')
43 files changed, 481 insertions, 304 deletions
diff --git a/src/main/kotlin/events/AllowChatEvent.kt b/src/main/kotlin/events/AllowChatEvent.kt index 3069843..86395c9 100644 --- a/src/main/kotlin/events/AllowChatEvent.kt +++ b/src/main/kotlin/events/AllowChatEvent.kt @@ -2,14 +2,14 @@ package moe.nea.firmament.events +import net.minecraft.network.chat.Component import moe.nea.firmament.util.unformattedString -import net.minecraft.text.Text /** * Filter whether the user should see a chat message altogether. May or may not be called for every chat packet sent by * the server. When that quality is desired, consider [ProcessChatEvent] instead. */ -data class AllowChatEvent(val text: Text) : FirmamentEvent.Cancellable() { +data class AllowChatEvent(val text: Component) : FirmamentEvent.Cancellable() { val unformattedString = text.unformattedString companion object : FirmamentEventBus<AllowChatEvent>() diff --git a/src/main/kotlin/events/AttackBlockEvent.kt b/src/main/kotlin/events/AttackBlockEvent.kt index bbaa81d..81a2952 100644 --- a/src/main/kotlin/events/AttackBlockEvent.kt +++ b/src/main/kotlin/events/AttackBlockEvent.kt @@ -1,16 +1,16 @@ package moe.nea.firmament.events -import net.minecraft.entity.player.PlayerEntity -import net.minecraft.util.Hand -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Direction -import net.minecraft.world.World +import net.minecraft.world.entity.player.Player +import net.minecraft.world.InteractionHand +import net.minecraft.core.BlockPos +import net.minecraft.core.Direction +import net.minecraft.world.level.Level data class AttackBlockEvent( - val player: PlayerEntity, - val world: World, - val hand: Hand, + val player: Player, + val world: Level, + val hand: InteractionHand, val blockPos: BlockPos, val direction: Direction ) : FirmamentEvent.Cancellable() { diff --git a/src/main/kotlin/events/BakeExtraModelsEvent.kt b/src/main/kotlin/events/BakeExtraModelsEvent.kt deleted file mode 100644 index adaa495..0000000 --- a/src/main/kotlin/events/BakeExtraModelsEvent.kt +++ /dev/null @@ -1,24 +0,0 @@ -package moe.nea.firmament.events - -import java.util.function.BiConsumer -import net.minecraft.client.render.model.ReferencedModelsCollector -import net.minecraft.client.util.ModelIdentifier -import net.minecraft.util.Identifier - -// TODO: Rename this event, since it is not really directly baking models anymore -class BakeExtraModelsEvent( - private val addAnyModel: BiConsumer<ModelIdentifier, Identifier>, -) : FirmamentEvent() { - - fun addNonItemModel(modelIdentifier: ModelIdentifier, identifier: Identifier) { - this.addAnyModel.accept(modelIdentifier, identifier) - } - - fun addItemModel(modelIdentifier: ModelIdentifier) { - addNonItemModel( - modelIdentifier, - modelIdentifier.id.withPrefixedPath(ReferencedModelsCollector.ITEM_DIRECTORY)) - } - - companion object : FirmamentEventBus<BakeExtraModelsEvent>() -} diff --git a/src/main/kotlin/events/ChestInventoryUpdateEvent.kt b/src/main/kotlin/events/ChestInventoryUpdateEvent.kt index ddf54fc..e3acd12 100644 --- a/src/main/kotlin/events/ChestInventoryUpdateEvent.kt +++ b/src/main/kotlin/events/ChestInventoryUpdateEvent.kt @@ -1,6 +1,6 @@ package moe.nea.firmament.events -import net.minecraft.item.ItemStack +import net.minecraft.world.item.ItemStack import moe.nea.firmament.util.MC sealed class ChestInventoryUpdateEvent : FirmamentEvent() { diff --git a/src/main/kotlin/events/CommandEvent.kt b/src/main/kotlin/events/CommandEvent.kt index cc9cf45..bdd63ca 100644 --- a/src/main/kotlin/events/CommandEvent.kt +++ b/src/main/kotlin/events/CommandEvent.kt @@ -4,7 +4,7 @@ package moe.nea.firmament.events import com.mojang.brigadier.CommandDispatcher import com.mojang.brigadier.tree.LiteralCommandNode -import net.minecraft.command.CommandRegistryAccess +import net.minecraft.commands.CommandBuildContext import moe.nea.firmament.commands.CaseInsensitiveLiteralCommandNode import moe.nea.firmament.commands.DefaultSource import moe.nea.firmament.commands.literal @@ -12,7 +12,7 @@ import moe.nea.firmament.commands.thenLiteral data class CommandEvent( val dispatcher: CommandDispatcher<DefaultSource>, - val ctx: CommandRegistryAccess, + val ctx: CommandBuildContext, val serverCommands: CommandDispatcher<*>?, ) : FirmamentEvent() { companion object : FirmamentEventBus<CommandEvent>() @@ -23,6 +23,7 @@ data class CommandEvent( */ data class SubCommand( val builder: CaseInsensitiveLiteralCommandNode.Builder<DefaultSource>, + val commandRegistryAccess: CommandBuildContext, ) : FirmamentEvent() { companion object : FirmamentEventBus<SubCommand>() diff --git a/src/main/kotlin/events/CustomItemModelEvent.kt b/src/main/kotlin/events/CustomItemModelEvent.kt index 4328d77..3d96b34 100644 --- a/src/main/kotlin/events/CustomItemModelEvent.kt +++ b/src/main/kotlin/events/CustomItemModelEvent.kt @@ -1,38 +1,75 @@ package moe.nea.firmament.events +import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull -import net.minecraft.client.render.item.ItemModels -import net.minecraft.client.render.model.BakedModel -import net.minecraft.client.util.ModelIdentifier -import net.minecraft.item.ItemStack -import moe.nea.firmament.util.ErrorUtil +import net.minecraft.core.component.DataComponents +import net.minecraft.world.item.ItemStack +import net.minecraft.resources.ResourceLocation 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, - var overrideModel: ModelIdentifier? = null, + val itemStack: ItemStack, + val itemModelManager: IntrospectableItemModelManager, + var overrideModel: ResourceLocation? = null, ) : FirmamentEvent() { companion object : FirmamentEventBus<CustomItemModelEvent>() { - val cache = - WeakCache.memoize<ItemStack, ItemModels, Optional<BakedModel>>("CustomItemModels") { stack, models -> - val modelId = getModelIdentifier(stack) ?: return@memoize Optional.empty() - ErrorUtil.softCheck("Model Id needs to have an inventory variant", modelId.variant() == "inventory") - val bakedModel = models.getModel(modelId.id) - if (bakedModel == null || bakedModel === models.missingModelSupplier.get()) return@memoize Optional.empty() - Optional.of(bakedModel) + val weakCache = + object : WeakCache<ItemStack, IntrospectableItemModelManager, Optional<ResourceLocation>>("ItemModelIdentifier") { + override fun mkRef( + key: ItemStack, + extraData: IntrospectableItemModelManager + ): WeakCache<ItemStack, IntrospectableItemModelManager, Optional<ResourceLocation>>.Ref { + return IRef(key, extraData) + } + + inner class IRef(weakInstance: ItemStack, data: IntrospectableItemModelManager) : + Ref(weakInstance, data) { + override fun shouldBeEvicted(): Boolean = false + val isSimpleStack = weakInstance.componentsPatch.isEmpty || (weakInstance.componentsPatch.size() == 1 && weakInstance.get( + DataComponents.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?): ModelIdentifier? { + fun getModelIdentifier(itemStack: ItemStack?, itemModelManager: IntrospectableItemModelManager): ResourceLocation? { if (itemStack == null) return null - return publish(CustomItemModelEvent(itemStack)).overrideModel + return cache.invoke(itemStack, itemModelManager).getOrNull() } - @JvmStatic - fun getModel(itemStack: ItemStack?, thing: ItemModels): BakedModel? { - if (itemStack == null) return null - return cache.invoke(itemStack, thing).getOrNull() + fun getModelIdentifier0( + itemStack: ItemStack, + itemModelManager: IntrospectableItemModelManager + ): Optional<ResourceLocation> { + // TODO: add an error / warning if the model does not exist + return Optional.ofNullable(publish(CustomItemModelEvent(itemStack, itemModelManager)).overrideModel) } } + + fun overrideIfExists(overrideModel: ResourceLocation) { + if (itemModelManager.hasModel_firmament(overrideModel)) + this.overrideModel = overrideModel + } + + fun overrideIfEmpty(identifier: ResourceLocation) { + if (overrideModel == null) + overrideModel = identifier + } } diff --git a/src/main/kotlin/events/EarlyResourceReloadEvent.kt b/src/main/kotlin/events/EarlyResourceReloadEvent.kt index ec8377a..b9cf717 100644 --- a/src/main/kotlin/events/EarlyResourceReloadEvent.kt +++ b/src/main/kotlin/events/EarlyResourceReloadEvent.kt @@ -2,7 +2,7 @@ package moe.nea.firmament.events import java.util.concurrent.Executor -import net.minecraft.resource.ResourceManager +import net.minecraft.server.packs.resources.ResourceManager data class EarlyResourceReloadEvent(val resourceManager: ResourceManager, val preparationExecutor: Executor) : FirmamentEvent() { diff --git a/src/main/kotlin/events/EntityDespawnEvent.kt b/src/main/kotlin/events/EntityDespawnEvent.kt index 93dc477..d007f96 100644 --- a/src/main/kotlin/events/EntityDespawnEvent.kt +++ b/src/main/kotlin/events/EntityDespawnEvent.kt @@ -1,7 +1,7 @@ package moe.nea.firmament.events -import net.minecraft.entity.Entity +import net.minecraft.world.entity.Entity data class EntityDespawnEvent( val entity: Entity?, val entityId: Int, diff --git a/src/main/kotlin/events/EntityInteractionEvent.kt b/src/main/kotlin/events/EntityInteractionEvent.kt index 123ea39..8285e1b 100644 --- a/src/main/kotlin/events/EntityInteractionEvent.kt +++ b/src/main/kotlin/events/EntityInteractionEvent.kt @@ -1,13 +1,13 @@ package moe.nea.firmament.events -import net.minecraft.entity.Entity -import net.minecraft.util.Hand +import net.minecraft.world.entity.Entity +import net.minecraft.world.InteractionHand data class EntityInteractionEvent( val kind: InteractionKind, val entity: Entity, - val hand: Hand, + val hand: InteractionHand, ) : FirmamentEvent() { companion object : FirmamentEventBus<EntityInteractionEvent>() enum class InteractionKind { diff --git a/src/main/kotlin/events/EntityRenderTintEvent.kt b/src/main/kotlin/events/EntityRenderTintEvent.kt new file mode 100644 index 0000000..63528bc --- /dev/null +++ b/src/main/kotlin/events/EntityRenderTintEvent.kt @@ -0,0 +1,67 @@ +package moe.nea.firmament.events + +import net.minecraft.client.renderer.GameRenderer +import net.minecraft.client.renderer.texture.OverlayTexture +import net.minecraft.client.renderer.entity.state.EntityRenderState +import net.minecraft.world.entity.Entity +import net.minecraft.world.entity.LivingEntity +import moe.nea.firmament.events.EntityRenderTintEvent.Companion.overlayOverride +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..9f5a101 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 net.minecraft.entity.Entity -import net.minecraft.entity.LivingEntity -import net.minecraft.entity.data.DataTracker -import net.minecraft.network.packet.s2c.play.EntityAttributesS2CPacket +import com.mojang.datafixers.util.Pair +import net.minecraft.world.entity.Entity +import net.minecraft.world.entity.EquipmentSlot +import net.minecraft.world.entity.LivingEntity +import net.minecraft.network.syncher.SynchedEntityData +import net.minecraft.world.item.ItemStack +import net.minecraft.network.protocol.game.ClientboundUpdateAttributesPacket +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.inventoryMenu.findSlot(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( + data class AttributeUpdate( override val entity: LivingEntity, - val attributes: List<EntityAttributesS2CPacket.Entry>, - ) : EntityUpdateEvent() + val attributes: List<ClientboundUpdateAttributesPacket.AttributeSnapshot>, + ) : EntityUpdateEvent() + + data class TrackedDataUpdate( + override val entity: Entity, + val trackedValues: List<SynchedEntityData.DataValue<*>>, + ) : EntityUpdateEvent() - data class TrackedDataUpdate( + data class EquipmentUpdate( override val entity: Entity, - val trackedValues: List<DataTracker.SerializedEntry<*>>, - ) : EntityUpdateEvent() + val newEquipment: List<Pair<EquipmentSlot, ItemStack>>, + ) : EntityUpdateEvent() -// TODO: onEntityPassengersSet, onEntityAttach?, onEntityEquipmentUpdate, onEntityStatusEffect +// TODO: onEntityPassengersSet, onEntityAttach?, onEntityStatusEffect } diff --git a/src/main/kotlin/events/FeaturesInitializedEvent.kt b/src/main/kotlin/events/FeaturesInitializedEvent.kt deleted file mode 100644 index ad2ad8a..0000000 --- a/src/main/kotlin/events/FeaturesInitializedEvent.kt +++ /dev/null @@ -1,8 +0,0 @@ - -package moe.nea.firmament.events - -import moe.nea.firmament.features.FirmamentFeature - -data class FeaturesInitializedEvent(val features: List<FirmamentFeature>) : FirmamentEvent() { - companion object : FirmamentEventBus<FeaturesInitializedEvent>() -} diff --git a/src/main/kotlin/events/FinalizeResourceManagerEvent.kt b/src/main/kotlin/events/FinalizeResourceManagerEvent.kt index 12167f8..72fa9c4 100644 --- a/src/main/kotlin/events/FinalizeResourceManagerEvent.kt +++ b/src/main/kotlin/events/FinalizeResourceManagerEvent.kt @@ -2,25 +2,25 @@ package moe.nea.firmament.events import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import net.minecraft.resource.ReloadableResourceManagerImpl -import net.minecraft.resource.ResourceManager -import net.minecraft.resource.ResourceReloader +import net.minecraft.server.packs.resources.ReloadableResourceManager +import net.minecraft.server.packs.resources.ResourceManager +import net.minecraft.server.packs.resources.PreparableReloadListener data class FinalizeResourceManagerEvent( - val resourceManager: ReloadableResourceManagerImpl, + val resourceManager: ReloadableResourceManager, ) : FirmamentEvent() { companion object : FirmamentEventBus<FinalizeResourceManagerEvent>() inline fun registerOnApply(name: String, crossinline function: () -> Unit) { - resourceManager.registerReloader(object : ResourceReloader { + resourceManager.registerReloadListener(object : PreparableReloadListener { override fun reload( - synchronizer: ResourceReloader.Synchronizer, - manager: ResourceManager, - prepareExecutor: Executor, - applyExecutor: Executor + store: PreparableReloadListener.SharedState, + prepareExecutor: Executor, + reloadSynchronizer: PreparableReloadListener.PreparationBarrier, + applyExecutor: Executor ): CompletableFuture<Void> { return CompletableFuture.completedFuture(Unit) - .thenCompose(synchronizer::whenPrepared) + .thenCompose(reloadSynchronizer::wait) .thenAcceptAsync({ function() }, applyExecutor) } 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/HandledScreenClickEvent.kt b/src/main/kotlin/events/HandledScreenClickEvent.kt index 4c3003c..c9890af 100644 --- a/src/main/kotlin/events/HandledScreenClickEvent.kt +++ b/src/main/kotlin/events/HandledScreenClickEvent.kt @@ -1,10 +1,11 @@ - - package moe.nea.firmament.events -import net.minecraft.client.gui.screen.ingame.HandledScreen +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen -data class HandledScreenClickEvent(val screen: HandledScreen<*>, val mouseX: Double, val mouseY: Double, val button: Int) : - FirmamentEvent.Cancellable() { - companion object : FirmamentEventBus<HandledScreenClickEvent>() +data class HandledScreenClickEvent( + val screen: AbstractContainerScreen<*>, + val mouseX: Double, val mouseY: Double, val button: Int +) : + FirmamentEvent.Cancellable() { + companion object : FirmamentEventBus<HandledScreenClickEvent>() } diff --git a/src/main/kotlin/events/HandledScreenForegroundEvent.kt b/src/main/kotlin/events/HandledScreenForegroundEvent.kt index f16d30e..3a3d7f6 100644 --- a/src/main/kotlin/events/HandledScreenForegroundEvent.kt +++ b/src/main/kotlin/events/HandledScreenForegroundEvent.kt @@ -2,12 +2,12 @@ package moe.nea.firmament.events -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.gui.screen.ingame.HandledScreen +import net.minecraft.client.gui.GuiGraphics +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen data class HandledScreenForegroundEvent( - val screen: HandledScreen<*>, - val context: DrawContext, + val screen: AbstractContainerScreen<*>, + val context: GuiGraphics, val mouseX: Int, val mouseY: Int, val delta: Float diff --git a/src/main/kotlin/events/HandledScreenKeyPressedEvent.kt b/src/main/kotlin/events/HandledScreenKeyPressedEvent.kt index 183ec71..5a5f1e9 100644 --- a/src/main/kotlin/events/HandledScreenKeyPressedEvent.kt +++ b/src/main/kotlin/events/HandledScreenKeyPressedEvent.kt @@ -1,38 +1,40 @@ package moe.nea.firmament.events -import net.minecraft.client.gui.screen.ingame.HandledScreen -import net.minecraft.client.option.KeyBinding -import moe.nea.firmament.keybindings.IKeyBinding +import org.lwjgl.glfw.GLFW +import net.minecraft.client.gui.screens.Screen +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen +import moe.nea.firmament.keybindings.GenericInputAction +import moe.nea.firmament.keybindings.InputModifiers +import moe.nea.firmament.keybindings.SavedKeyBinding -sealed interface HandledScreenKeyEvent { - val screen: HandledScreen<*> - val keyCode: Int - val scanCode: Int - val modifiers: Int - - fun matches(keyBinding: KeyBinding): Boolean { - return matches(IKeyBinding.minecraft(keyBinding)) - } - - fun matches(keyBinding: IKeyBinding): Boolean { - return keyBinding.matches(keyCode, scanCode, modifiers) - } +sealed interface HandledScreenInputEvent { + val screen: Screen + val input: GenericInputAction + val modifiers: InputModifiers } data class HandledScreenKeyPressedEvent( - override val screen: HandledScreen<*>, - override val keyCode: Int, - override val scanCode: Int, - override val modifiers: Int -) : FirmamentEvent.Cancellable(), HandledScreenKeyEvent { + override val screen: Screen, + override val input: GenericInputAction, + override val modifiers: InputModifiers, + // TODO: val isRepeat: Boolean, +) : FirmamentEvent.Cancellable(), HandledScreenInputEvent { + fun matches(keyBinding: SavedKeyBinding, atLeast: Boolean = false): Boolean { + return keyBinding.matches(input, modifiers, atLeast) + } + + fun isLeftClick() = input == GenericInputAction.mouse(GLFW.GLFW_MOUSE_BUTTON_LEFT) companion object : FirmamentEventBus<HandledScreenKeyPressedEvent>() } data class HandledScreenKeyReleasedEv |
