diff options
Diffstat (limited to 'src/main/kotlin/events')
44 files changed, 886 insertions, 0 deletions
diff --git a/src/main/kotlin/events/AllowChatEvent.kt b/src/main/kotlin/events/AllowChatEvent.kt new file mode 100644 index 0000000..3069843 --- /dev/null +++ b/src/main/kotlin/events/AllowChatEvent.kt @@ -0,0 +1,16 @@ + + +package moe.nea.firmament.events + +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() { + val unformattedString = text.unformattedString + + companion object : FirmamentEventBus<AllowChatEvent>() +} diff --git a/src/main/kotlin/events/AttackBlockEvent.kt b/src/main/kotlin/events/AttackBlockEvent.kt new file mode 100644 index 0000000..bbaa81d --- /dev/null +++ b/src/main/kotlin/events/AttackBlockEvent.kt @@ -0,0 +1,18 @@ + +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 + +data class AttackBlockEvent( + val player: PlayerEntity, + val world: World, + val hand: Hand, + val blockPos: BlockPos, + val direction: Direction +) : FirmamentEvent.Cancellable() { + companion object : FirmamentEventBus<AttackBlockEvent>() +} diff --git a/src/main/kotlin/events/BakeExtraModelsEvent.kt b/src/main/kotlin/events/BakeExtraModelsEvent.kt new file mode 100644 index 0000000..f75bedc --- /dev/null +++ b/src/main/kotlin/events/BakeExtraModelsEvent.kt @@ -0,0 +1,21 @@ + +package moe.nea.firmament.events + +import java.util.function.Consumer +import net.minecraft.client.util.ModelIdentifier + +class BakeExtraModelsEvent( + private val addItemModel: Consumer<ModelIdentifier>, + private val addAnyModel: Consumer<ModelIdentifier>, +) : FirmamentEvent() { + + fun addNonItemModel(modelIdentifier: ModelIdentifier) { + this.addAnyModel.accept(modelIdentifier) + } + + fun addItemModel(modelIdentifier: ModelIdentifier) { + this.addItemModel.accept(modelIdentifier) + } + + companion object : FirmamentEventBus<BakeExtraModelsEvent>() +} diff --git a/src/main/kotlin/events/ClientStartedEvent.kt b/src/main/kotlin/events/ClientStartedEvent.kt new file mode 100644 index 0000000..637916d --- /dev/null +++ b/src/main/kotlin/events/ClientStartedEvent.kt @@ -0,0 +1,6 @@ + +package moe.nea.firmament.events + +class ClientStartedEvent : FirmamentEvent() { + companion object : FirmamentEventBus<ClientStartedEvent>() +} diff --git a/src/main/kotlin/events/CommandEvent.kt b/src/main/kotlin/events/CommandEvent.kt new file mode 100644 index 0000000..cc9cf45 --- /dev/null +++ b/src/main/kotlin/events/CommandEvent.kt @@ -0,0 +1,45 @@ + + +package moe.nea.firmament.events + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.tree.LiteralCommandNode +import net.minecraft.command.CommandRegistryAccess +import moe.nea.firmament.commands.CaseInsensitiveLiteralCommandNode +import moe.nea.firmament.commands.DefaultSource +import moe.nea.firmament.commands.literal +import moe.nea.firmament.commands.thenLiteral + +data class CommandEvent( + val dispatcher: CommandDispatcher<DefaultSource>, + val ctx: CommandRegistryAccess, + val serverCommands: CommandDispatcher<*>?, +) : FirmamentEvent() { + companion object : FirmamentEventBus<CommandEvent>() + + /** + * Register subcommands to `/firm`. For new top level commands use [CommandEvent]. Cannot be used to register + * subcommands to other commands. + */ + data class SubCommand( + val builder: CaseInsensitiveLiteralCommandNode.Builder<DefaultSource>, + ) : FirmamentEvent() { + companion object : FirmamentEventBus<SubCommand>() + + fun subcommand(name: String, block: CaseInsensitiveLiteralCommandNode.Builder<DefaultSource>.() -> Unit) { + builder.thenLiteral(name, block) + } + } + + fun deleteCommand(name: String) { + dispatcher.root.children.removeIf { it.name.equals(name, ignoreCase = false) } + serverCommands?.root?.children?.removeIf { it.name.equals(name, ignoreCase = false) } + } + + fun register( + name: String, + block: CaseInsensitiveLiteralCommandNode.Builder<DefaultSource>.() -> Unit + ): LiteralCommandNode<DefaultSource> { + return dispatcher.register(literal(name, block)) + } +} diff --git a/src/main/kotlin/events/CustomItemModelEvent.kt b/src/main/kotlin/events/CustomItemModelEvent.kt new file mode 100644 index 0000000..27524a9 --- /dev/null +++ b/src/main/kotlin/events/CustomItemModelEvent.kt @@ -0,0 +1,43 @@ + + +package moe.nea.firmament.events + +import java.util.* +import net.minecraft.client.render.model.BakedModel +import net.minecraft.client.render.model.BakedModelManager +import net.minecraft.client.util.ModelIdentifier +import net.minecraft.item.ItemStack + +data class CustomItemModelEvent( + val itemStack: ItemStack, + var overrideModel: ModelIdentifier? = null, +) : FirmamentEvent() { + companion object : FirmamentEventBus<CustomItemModelEvent>() { + private val cache = IdentityHashMap<ItemStack?, Any>() + private val sentinelNull = Object() + + fun clearCache() { + cache.clear() + } + + @JvmStatic + fun getModelIdentifier(itemStack: ItemStack?): ModelIdentifier? { + if (itemStack == null) return null + return publish(CustomItemModelEvent(itemStack)).overrideModel + } + + @JvmStatic + fun getModel(itemStack: ItemStack?, thing: BakedModelManager): BakedModel? { + if (itemStack == null) return null + val cachedValue = cache.getOrPut(itemStack) { + val modelId = getModelIdentifier(itemStack) ?: return@getOrPut sentinelNull + val bakedModel = thing.getModel(modelId) + if (bakedModel === thing.missingModel) return@getOrPut sentinelNull + bakedModel + } + if (cachedValue === sentinelNull) + return null + return cachedValue as BakedModel + } + } +} diff --git a/src/main/kotlin/events/EarlyResourceReloadEvent.kt b/src/main/kotlin/events/EarlyResourceReloadEvent.kt new file mode 100644 index 0000000..ec8377a --- /dev/null +++ b/src/main/kotlin/events/EarlyResourceReloadEvent.kt @@ -0,0 +1,10 @@ + +package moe.nea.firmament.events + +import java.util.concurrent.Executor +import net.minecraft.resource.ResourceManager + +data class EarlyResourceReloadEvent(val resourceManager: ResourceManager, val preparationExecutor: Executor) : + FirmamentEvent() { + companion object : FirmamentEventBus<EarlyResourceReloadEvent>() +} diff --git a/src/main/kotlin/events/EntityDespawnEvent.kt b/src/main/kotlin/events/EntityDespawnEvent.kt new file mode 100644 index 0000000..93dc477 --- /dev/null +++ b/src/main/kotlin/events/EntityDespawnEvent.kt @@ -0,0 +1,11 @@ + +package moe.nea.firmament.events + +import net.minecraft.entity.Entity + +data class EntityDespawnEvent( + val entity: Entity?, val entityId: Int, + val reason: Entity.RemovalReason, +) : FirmamentEvent() { + companion object: FirmamentEventBus<EntityDespawnEvent>() +} diff --git a/src/main/kotlin/events/EntityInteractionEvent.kt b/src/main/kotlin/events/EntityInteractionEvent.kt new file mode 100644 index 0000000..123ea39 --- /dev/null +++ b/src/main/kotlin/events/EntityInteractionEvent.kt @@ -0,0 +1,29 @@ + +package moe.nea.firmament.events + +import net.minecraft.entity.Entity +import net.minecraft.util.Hand + +data class EntityInteractionEvent( + val kind: InteractionKind, + val entity: Entity, + val hand: Hand, +) : FirmamentEvent() { + companion object : FirmamentEventBus<EntityInteractionEvent>() + enum class InteractionKind { + /** + * Is sent when left-clicking an entity + */ + ATTACK, + + /** + * Is a fallback when [INTERACT_AT_LOCATION] fails + */ + INTERACT, + + /** + * Is tried first on right click + */ + INTERACT_AT_LOCATION, + } +} diff --git a/src/main/kotlin/events/EntityUpdateEvent.kt b/src/main/kotlin/events/EntityUpdateEvent.kt new file mode 100644 index 0000000..d091984 --- /dev/null +++ b/src/main/kotlin/events/EntityUpdateEvent.kt @@ -0,0 +1,31 @@ + +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 + +/** + * This event is fired when some entity properties are updated. + * It is not fired for common changes like position, but is for less common ones, + * like health, tracked data, names, equipment. It is always fired + * *after* the values have been applied to the entity. + */ +sealed class EntityUpdateEvent : FirmamentEvent() { + companion object : FirmamentEventBus<EntityUpdateEvent>() + + abstract val entity: Entity + + 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() + +// TODO: onEntityPassengersSet, onEntityAttach?, onEntityEquipmentUpdate, onEntityStatusEffect +} diff --git a/src/main/kotlin/events/FeaturesInitializedEvent.kt b/src/main/kotlin/events/FeaturesInitializedEvent.kt new file mode 100644 index 0000000..ad2ad8a --- /dev/null +++ b/src/main/kotlin/events/FeaturesInitializedEvent.kt @@ -0,0 +1,8 @@ + +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 new file mode 100644 index 0000000..c43ad3b --- /dev/null +++ b/src/main/kotlin/events/FinalizeResourceManagerEvent.kt @@ -0,0 +1,10 @@ + +package moe.nea.firmament.events + +import net.minecraft.resource.ReloadableResourceManagerImpl + +data class FinalizeResourceManagerEvent( + val resourceManager: ReloadableResourceManagerImpl, +) : FirmamentEvent() { + companion object : FirmamentEventBus<FinalizeResourceManagerEvent>() +} diff --git a/src/main/kotlin/events/FirmamentEvent.kt b/src/main/kotlin/events/FirmamentEvent.kt new file mode 100644 index 0000000..1a93ef5 --- /dev/null +++ b/src/main/kotlin/events/FirmamentEvent.kt @@ -0,0 +1,38 @@ + + +package moe.nea.firmament.events + +/** + * An event that can be fired by a [FirmamentEventBus]. + * + * Typically, that event bus is implemented as a companion object + * + * ``` + * class SomeEvent : FirmamentEvent() { + * companion object : FirmamentEventBus<SomeEvent>() + * } + * ``` + */ +abstract class FirmamentEvent { + /** + * A [FirmamentEvent] that can be [cancelled] + */ + abstract class Cancellable : FirmamentEvent() { + /** + * Cancels this is event. + * + * @see cancelled + */ + fun cancel() { + cancelled = true + } + + /** + * Whether this event is cancelled. + * + * Cancelled events will bypass handlers unless otherwise specified and will prevent the action that this + * event was originally fired for. + */ + var cancelled: Boolean = false + } +} diff --git a/src/main/kotlin/events/FirmamentEventBus.kt b/src/main/kotlin/events/FirmamentEventBus.kt new file mode 100644 index 0000000..ee9e6c8 --- /dev/null +++ b/src/main/kotlin/events/FirmamentEventBus.kt @@ -0,0 +1,52 @@ + + +package moe.nea.firmament.events + +import java.util.concurrent.CopyOnWriteArrayList +import moe.nea.firmament.Firmament +import moe.nea.firmament.util.MC + +/** + * A pubsub event bus. + * + * [subscribe] to events [publish]ed on this event bus. + * Subscriptions may not necessarily be delivered in the order of registering. + */ +open class FirmamentEventBus<T : FirmamentEvent> { + data class Handler<T>( + val invocation: (T) -> Unit, val receivesCancelled: Boolean, + var knownErrors: MutableSet<Class<*>> = mutableSetOf(), + ) + + private val toHandle: MutableList<Handler<T>> = CopyOnWriteArrayList() + fun subscribe(handle: (T) -> Unit) { + subscribe(false, handle) + } + + fun subscribe(receivesCancelled: Boolean, handle: (T) -> Unit) { + toHandle.add(Handler(handle, receivesCancelled)) + } + + fun publish(event: T): T { + for (function in toHandle) { + if (function.receivesCancelled || event !is FirmamentEvent.Cancellable || !event.cancelled) { + try { + function.invocation(event) + } catch (e: Exception) { + 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) + } + } + } + } + return event + } + + fun publishSync(event: T) { + MC.onMainThread { + publish(event) + } + } +} diff --git a/src/main/kotlin/events/HandledScreenClickEvent.kt b/src/main/kotlin/events/HandledScreenClickEvent.kt new file mode 100644 index 0000000..4c3003c --- /dev/null +++ b/src/main/kotlin/events/HandledScreenClickEvent.kt @@ -0,0 +1,10 @@ + + +package moe.nea.firmament.events + +import net.minecraft.client.gui.screen.ingame.HandledScreen + +data class HandledScreenClickEvent(val screen: HandledScreen<*>, 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 new file mode 100644 index 0000000..f16d30e --- /dev/null +++ b/src/main/kotlin/events/HandledScreenForegroundEvent.kt @@ -0,0 +1,16 @@ + + +package moe.nea.firmament.events + +import net.minecraft.client.gui.DrawContext +import net.minecraft.client.gui.screen.ingame.HandledScreen + +data class HandledScreenForegroundEvent( + val screen: HandledScreen<*>, + val context: DrawContext, + val mouseX: Int, + val mouseY: Int, + val delta: Float +) : FirmamentEvent() { + companion object : FirmamentEventBus<HandledScreenForegroundEvent>() +} diff --git a/src/main/kotlin/events/HandledScreenKeyPressedEvent.kt b/src/main/kotlin/events/HandledScreenKeyPressedEvent.kt new file mode 100644 index 0000000..7ec2abb --- /dev/null +++ b/src/main/kotlin/events/HandledScreenKeyPressedEvent.kt @@ -0,0 +1,24 @@ + + +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 + +data class HandledScreenKeyPressedEvent( + val screen: HandledScreen<*>, + val keyCode: Int, + val scanCode: Int, + val modifiers: Int +) : FirmamentEvent.Cancellable() { + companion object : FirmamentEventBus<HandledScreenKeyPressedEvent>() + + fun matches(keyBinding: KeyBinding): Boolean { + return matches(IKeyBinding.minecraft(keyBinding)) + } + + fun matches(keyBinding: IKeyBinding): Boolean { + return keyBinding.matches(keyCode, scanCode, modifiers) + } +} diff --git a/src/main/kotlin/events/HandledScreenPushREIEvent.kt b/src/main/kotlin/events/HandledScreenPushREIEvent.kt new file mode 100644 index 0000000..1bb495a --- /dev/null +++ b/src/main/kotlin/events/HandledScreenPushREIEvent.kt @@ -0,0 +1,18 @@ + + +package moe.nea.firmament.events + +import me.shedaniel.math.Rectangle +import net.minecraft.client.gui.screen.ingame.HandledScreen + +data class HandledScreenPushREIEvent( + val screen: HandledScreen<*>, + val rectangles: MutableList<Rectangle> = mutableListOf() +) : FirmamentEvent() { + + fun block(rectangle: Rectangle) { + rectangles.add(rectangle) + } + + companion object : FirmamentEventBus<HandledScreenPushREIEvent>() +} diff --git a/src/main/kotlin/events/HotbarItemRenderEvent.kt b/src/main/kotlin/events/HotbarItemRenderEvent.kt new file mode 100644 index 0000000..a1940e6 --- /dev/null +++ b/src/main/kotlin/events/HotbarItemRenderEvent.kt @@ -0,0 +1,17 @@ + + +package moe.nea.firmament.events + +import net.minecraft.client.gui.DrawContext +import net.minecraft.client.render.RenderTickCounter +import net.minecraft.item.ItemStack + +data class HotbarItemRenderEvent( + val item: ItemStack, + val context: DrawContext, + val x: Int, + val y: Int, + val tickDelta: RenderTickCounter, +) : FirmamentEvent() { + companion object : FirmamentEventBus<HotbarItemRenderEvent>() +} diff --git a/src/main/kotlin/events/HudRenderEvent.kt b/src/main/kotlin/events/HudRenderEvent.kt new file mode 100644 index 0000000..555b3c8 --- /dev/null +++ b/src/main/kotlin/events/HudRenderEvent.kt @@ -0,0 +1,13 @@ + + +package moe.nea.firmament.events + +import net.minecraft.client.gui.DrawContext +import net.minecraft.client.render.RenderTickCounter + +/** + * Called when hud elements should be rendered, before the screen, but after the world. + */ +data class HudRenderEvent(val context: DrawContext, val tickDelta: RenderTickCounter) : FirmamentEvent() { + companion object : FirmamentEventBus<HudRenderEvent>() +} diff --git a/src/main/kotlin/events/IsSlotProtectedEvent.kt b/src/main/kotlin/events/IsSlotProtectedEvent.kt new file mode 100644 index 0000000..cd431f7 --- /dev/null +++ b/src/main/kotlin/events/IsSlotProtectedEvent.kt @@ -0,0 +1,46 @@ + + +package moe.nea.firmament.events + +import net.minecraft.item.ItemStack +import net.minecraft.screen.slot.Slot +import net.minecraft.screen.slot.SlotActionType +import net.minecraft.text.Text +import moe.nea.firmament.util.CommonSoundEffects +import moe.nea.firmament.util.MC + +data class IsSlotProtectedEvent( + val slot: Slot?, + val actionType: SlotActionType, + var isProtected: Boolean, + val itemStackOverride: ItemStack?, + var silent: Boolean = false, +) : FirmamentEvent() { + val itemStack get() = itemStackOverride ?: slot!!.stack + + fun protect() { + isProtected = true + } + + fun protectSilent() { + if (!isProtected) { + silent = true + } + isProtected = true + } + + 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.player?.sendMessage(Text.translatable("firmament.protectitem").append(event.itemStack.name)) + CommonSoundEffects.playFailure() + } + return event.isProtected + } + } +} diff --git a/src/main/kotlin/events/ItemTooltipEvent.kt b/src/main/kotlin/events/ItemTooltipEvent.kt new file mode 100644 index 0000000..d86e06f --- /dev/null +++ b/src/main/kotlin/events/ItemTooltipEvent.kt @@ -0,0 +1,14 @@ + + +package moe.nea.firmament.events + +import net.minecraft.item.Item.TooltipContext +import net.minecraft.item.ItemStack +import net.minecraft.item.tooltip.TooltipType +import net.minecraft.text.Text + +data class ItemTooltipEvent( + val stack: ItemStack, val context: TooltipContext, val type: TooltipType, val lines: MutableList<Text> +) : FirmamentEvent() { + companion object : FirmamentEventBus<ItemTooltipEvent>() +} diff --git a/src/main/kotlin/events/MaskCommands.kt b/src/main/kotlin/events/MaskCommands.kt new file mode 100644 index 0000000..35aade0 --- /dev/null +++ b/src/main/kotlin/events/MaskCommands.kt @@ -0,0 +1,13 @@ + + +package moe.nea.firmament.events + +import com.mojang.brigadier.CommandDispatcher + +data class MaskCommands(val dispatcher: CommandDispatcher<*>) : FirmamentEvent() { + companion object : FirmamentEventBus<MaskCommands>() + + fun mask(name: String) { + dispatcher.root.children.removeIf { it.name.equals(name, ignoreCase = true) } + } +} diff --git a/src/main/kotlin/events/ModifyChatEvent.kt b/src/main/kotlin/events/ModifyChatEvent.kt new file mode 100644 index 0000000..a5868e8 --- /dev/null +++ b/src/main/kotlin/events/ModifyChatEvent.kt @@ -0,0 +1,21 @@ + + +package moe.nea.firmament.events + +import moe.nea.firmament.util.unformattedString +import net.minecraft.text.Text + +/** + * Allow modification of a chat message before it is sent off to the user. Intended for display purposes. + */ +data class ModifyChatEvent(val originalText: Text) : FirmamentEvent() { + var unformattedString = originalText.unformattedString + private set + var replaceWith: Text = originalText + set(value) { + field = value + unformattedString = value.unformattedString + } + + companion object : FirmamentEventBus<ModifyChatEvent>() +} diff --git a/src/main/kotlin/events/OutgoingPacketEvent.kt b/src/main/kotlin/events/OutgoingPacketEvent.kt new file mode 100644 index 0000000..93890ea --- /dev/null +++ b/src/main/kotlin/events/OutgoingPacketEvent.kt @@ -0,0 +1,9 @@ + + +package moe.nea.firmament.events + +import net.minecraft.network.packet.Packet + +data class OutgoingPacketEvent(val packet: Packet<*>) : FirmamentEvent.Cancellable() { + companion object : FirmamentEventBus<OutgoingPacketEvent>() +} diff --git a/src/main/kotlin/events/ParticleSpawnEvent.kt b/src/main/kotlin/events/ParticleSpawnEvent.kt new file mode 100644 index 0000000..9359e4b --- /dev/null +++ b/src/main/kotlin/events/ParticleSpawnEvent.kt @@ -0,0 +1,18 @@ + + +package moe.nea.firmament.events + +import org.joml.Vector3f +import net.minecraft.particle.ParticleEffect +import net.minecraft.util.math.Vec3d + +data class ParticleSpawnEvent( + val particleEffect: ParticleEffect, + val position: Vec3d, + val offset: Vector3f, + val longDistance: Boolean, + val count: Int, + val speed: Float, +) : FirmamentEvent.Cancellable() { + companion object : FirmamentEventBus<ParticleSpawnEvent>() +} diff --git a/src/main/kotlin/events/PlayerInventoryUpdate.kt b/src/main/kotlin/events/PlayerInventoryUpdate.kt new file mode 100644 index 0000000..6e8203a --- /dev/null +++ b/src/main/kotlin/events/PlayerInventoryUpdate.kt @@ -0,0 +1,11 @@ + +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() + +} diff --git a/src/main/kotlin/events/ProcessChatEvent.kt b/src/main/kotlin/events/ProcessChatEvent.kt new file mode 100644 index 0000000..76c0b27 --- /dev/null +++ b/src/main/kotlin/events/ProcessChatEvent.kt @@ -0,0 +1,28 @@ + + +package moe.nea.firmament.events + +import net.minecraft.text.Text +import moe.nea.firmament.util.unformattedString + +/** + * Behaves like [AllowChatEvent], but is triggered even when cancelled by other mods. Intended for data collection. + * Make sure to subscribe to cancellable events as well when using. + */ +data class ProcessChatEvent(val text: Text, val wasExternallyCancelled: Boolean) : FirmamentEvent.Cancellable() { + val unformattedString = text.unformattedString + + val nameHeuristic: String? = run { + val firstColon = unformattedString.indexOf(':') + if (firstColon < 0) return@run null + val firstSpace = unformattedString.lastIndexOf(' ', firstColon) + unformattedString.substring(firstSpace + 1 until firstColon).takeIf { it.isNotEmpty() } + } + + init { + if (wasExternallyCancelled) + cancelled = true + } + + companion object : FirmamentEventBus<ProcessChatEvent>() +} diff --git a/src/main/kotlin/events/ReloadRegistrationEvent.kt b/src/main/kotlin/events/ReloadRegistrationEvent.kt new file mode 100644 index 0000000..4c3083e --- /dev/null +++ b/src/main/kotlin/events/ReloadRegistrationEvent.kt @@ -0,0 +1,7 @@ +package moe.nea.firmament.events + +import io.github.moulberry.repo.NEURepository + +data class ReloadRegistrationEvent(val repo: NEURepository) : FirmamentEvent() { + companion object : FirmamentEventBus<ReloadRegistrationEvent>() +} diff --git a/src/main/kotlin/events/ScreenChangeEvent.kt b/src/main/kotlin/events/ScreenChangeEvent.kt new file mode 100644 index 0000000..489e487 --- /dev/null +++ b/src/main/kotlin/events/ScreenChangeEvent.kt @@ -0,0 +1,10 @@ + + +package moe.nea.firmament.events + +import net.minecraft.client.gui.screen.Screen + +data class ScreenChangeEvent(val old: Screen?, val new: Screen?) : FirmamentEvent.Cancellable() { + var overrideScreen: Screen? = null + companion object : FirmamentEventBus<ScreenChangeEvent>() +} diff --git a/src/main/kotlin/events/ScreenRenderPostEvent.kt b/src/main/kotlin/events/ScreenRenderPostEvent.kt new file mode 100644 index 0000000..79f4913 --- /dev/null +++ b/src/main/kotlin/events/ScreenRenderPostEvent.kt @@ -0,0 +1,16 @@ + + +package moe.nea.firmament.events + +import net.minecraft.client.gui.DrawContext +import net.minecraft.client.gui.screen.Screen + +data class ScreenRenderPostEvent( + val screen: Screen, + val mouseX: Int, + val mouseY: Int, + val tickDelta: Float, + val drawContext: DrawContext +) : FirmamentEvent() { + companion object : FirmamentEventBus<ScreenRenderPostEvent>() +} diff --git a/src/main/kotlin/events/ServerConnectedEvent.kt b/src/main/kotlin/events/ServerConnectedEvent.kt new file mode 100644 index 0000000..26897f2 --- /dev/null +++ b/src/main/kotlin/events/ServerConnectedEvent.kt @@ -0,0 +1,18 @@ +package moe.nea.firmament.events + +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents +import net.minecraft.client.MinecraftClient +import net.minecraft.client.network.ClientPlayNetworkHandler +import net.minecraft.network.ClientConnection + +data class ServerConnectedEvent( + val connection: ClientConnection +) : FirmamentEvent() { + companion object : FirmamentEventBus<ServerConnectedEvent>() { + init { + ClientPlayConnectionEvents.INIT.register(ClientPlayConnectionEvents.Init { clientPlayNetworkHandler: ClientPlayNetworkHandler, minecraftClient: MinecraftClient -> + publishSync(ServerConnectedEvent(clientPlayNetworkHandler.connection)) + }) + } + } +} diff --git a/src/main/kotlin/events/SkyblockServerUpdateEvent.kt b/src/main/kotlin/events/SkyblockServerUpdateEvent.kt new file mode 100644 index 0000000..0bc5143 --- /dev/null +++ b/src/main/kotlin/events/SkyblockServerUpdateEvent.kt @@ -0,0 +1,15 @@ + + +package moe.nea.firmament.events + +import moe.nea.firmament.util.Locraw + +/** + * This event gets published whenever `/locraw` is queried and HyPixel returns a location different to the old one. + * + * **N.B.:** This event may get fired multiple times while on the server (for example, first to null, then to the + * correct location). + */ +data class SkyblockServerUpdateEvent(val oldLocraw: Locraw?, val newLocraw: Locraw?) : FirmamentEvent() { + companion object : FirmamentEventBus<SkyblockServerUpdateEvent>() +} diff --git a/src/main/kotlin/events/SlotClickEvent.kt b/src/main/kotlin/events/SlotClickEvent.kt new file mode 100644 index 0000000..d4abfb0 --- /dev/null +++ b/src/main/kotlin/events/SlotClickEvent.kt @@ -0,0 +1,15 @@ + +package moe.nea.firmament.events + +import net.minecraft.item.ItemStack +import net.minecraft.screen.slot.Slot +import net.minecraft.screen.slot.SlotActionType + +data class SlotClickEvent( + val slot: Slot, + val stack: ItemStack, + val button: Int, + val actionType: SlotActionType, +) : FirmamentEvent() { + companion object : FirmamentEventBus<SlotClickEvent>() +} diff --git a/src/main/kotlin/events/SlotRenderEvents.kt b/src/main/kotlin/events/SlotRenderEvents.kt new file mode 100644 index 0000000..8352581 --- /dev/null +++ b/src/main/kotlin/events/SlotRenderEvents.kt @@ -0,0 +1,34 @@ + + +package moe.nea.firmament.events + +import net.minecraft.client.gui.DrawContext +import net.minecraft.screen.slot.Slot + +interface SlotRenderEvents { + val context: DrawContext + val slot: Slot + val mouseX: Int + val mouseY: Int + val delta: Float + + data class Before( + override val context: DrawContext, override val slot: Slot, + override val mouseX: Int, + override val mouseY: Int, + override val delta: Float + ) : FirmamentEvent(), + SlotRenderEvents { + companion object : FirmamentEventBus<Before>() + } + + data class After( + override val context: DrawContext, override val slot: Slot, + override val mouseX: Int, + override val mouseY: Int, + override val delta: Float + ) : FirmamentEvent(), + SlotRenderEvents { + companion object : FirmamentEventBus<After>() + } +} diff --git a/src/main/kotlin/events/SoundReceiveEvent.kt b/src/main/kotlin/events/SoundReceiveEvent.kt new file mode 100644 index 0000000..d1b85b6 --- /dev/null +++ b/src/main/kotlin/events/SoundReceiveEvent.kt @@ -0,0 +1,18 @@ + +package moe.nea.firmament.events + +import net.minecraft.registry.entry.RegistryEntry +import net.minecraft.sound.SoundCategory +import net.minecraft.sound.SoundEvent +import net.minecraft.util.math.Vec3d + +data class SoundReceiveEvent( + val sound: RegistryEntry<SoundEvent>, + val category: SoundCategory, + val position: Vec3d, + val pitch: Float, + val volume: Float, + val seed: Long +) : FirmamentEvent.Cancellable() { + companion object : FirmamentEventBus<SoundReceiveEvent>() +} diff --git a/src/main/kotlin/events/TickEvent.kt b/src/main/kotlin/events/TickEvent.kt new file mode 100644 index 0000000..18007f8 --- /dev/null +++ b/src/main/kotlin/events/TickEvent.kt @@ -0,0 +1,7 @@ + + +package moe.nea.firmament.events + +data class TickEvent(val tickCount: Int) : FirmamentEvent() { + companion object : FirmamentEventBus<TickEvent>() +} diff --git a/src/main/kotlin/events/TooltipEvent.kt b/src/main/kotlin/events/TooltipEvent.kt new file mode 100644 index 0000000..630ba56 --- /dev/null +++ b/src/main/kotlin/events/TooltipEvent.kt @@ -0,0 +1,17 @@ + + +package moe.nea.firmament.events + +import net.minecraft.client.gui.tooltip.Tooltip +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.item.Item +import net.minecraft.item.ItemStack + +data class TooltipEvent( + val itemStack: ItemStack, + val tooltip: Tooltip, + val tooltipContext: Item.TooltipContext, + val player: PlayerEntity? +) : FirmamentEvent() { + companion object : FirmamentEventBus<TooltipEvent>() +} diff --git a/src/main/kotlin/events/UseBlockEvent.kt b/src/main/kotlin/events/UseBlockEvent.kt new file mode 100644 index 0000000..8bbe0de --- /dev/null +++ b/src/main/kotlin/events/UseBlockEvent.kt @@ -0,0 +1,11 @@ + +package moe.nea.firmament.events + +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.util.Hand +import net.minecraft.util.hit.BlockHitResult +import net.minecraft.world.World + +data class UseBlockEvent(val player: PlayerEntity, val world: World, val hand: Hand, val hitResult: BlockHitResult) : FirmamentEvent.Cancellable() { + companion object : FirmamentEventBus<UseBlockEvent>() +} diff --git a/src/main/kotlin/events/WorldKeyboardEvent.kt b/src/main/kotlin/events/WorldKeyboardEvent.kt new file mode 100644 index 0000000..e8566fd --- /dev/null +++ b/src/main/kotlin/events/WorldKeyboardEvent.kt @@ -0,0 +1,18 @@ + + +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>() + + fun matches(keyBinding: KeyBinding): Boolean { + return matches(IKeyBinding.minecraft(keyBinding)) + } + + fun matches(keyBinding: IKeyBinding): Boolean { + return keyBinding.matches(keyCode, scanCode, modifiers) + } +} diff --git a/src/main/kotlin/events/WorldReadyEvent.kt b/src/main/kotlin/events/WorldReadyEvent.kt new file mode 100644 index 0000000..2c76c44 --- /dev/null +++ b/src/main/kotlin/events/WorldReadyEvent.kt @@ -0,0 +1,7 @@ + + +package moe.nea.firmament.events + +class WorldReadyEvent : FirmamentEvent() { + companion object : FirmamentEventBus<WorldReadyEvent>() +} diff --git a/src/main/kotlin/events/WorldRenderLastEvent.kt b/src/main/kotlin/events/WorldRenderLastEvent.kt new file mode 100644 index 0000000..21a670d --- /dev/null +++ b/src/main/kotlin/events/WorldRenderLastEvent.kt @@ -0,0 +1,27 @@ + + +package moe.nea.firmament.events + +import net.minecraft.client.render.Camera +import net.minecraft.client.render.GameRenderer +import net.minecraft.client.render.LightmapTextureManager +import net.minecraft.client.render.RenderTickCounter +import net.minecraft.client.render.VertexConsumerProvider +import net.minecraft.client.util.math.MatrixStack +import net.minecraft.util.math.Position +import net.minecraft.util.math.Vec3d + +/** + * This event is called after all world rendering is done, but before any GUI rendering (including hand) has been done. + */ +data class WorldRenderLastEvent( + val matrices: MatrixStack, + val tickCounter: RenderTickCounter, + val renderBlockOutline: Boolean, + val camera: Camera, + val gameRenderer: GameRenderer, + val lightmapTextureManager: LightmapTextureManager, + val vertexConsumers: VertexConsumerProvider.Immediate, +) : FirmamentEvent() { + companion object : FirmamentEventBus<WorldRenderLastEvent>() +} diff --git a/src/main/kotlin/events/registration/ChatEvents.kt b/src/main/kotlin/events/registration/ChatEvents.kt new file mode 100644 index 0000000..4c1c63f --- /dev/null +++ b/src/main/kotlin/events/registration/ChatEvents.kt @@ -0,0 +1,54 @@ + + +package moe.nea.firmament.events.registration + +import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents +import net.fabricmc.fabric.api.event.player.AttackBlockCallback +import net.fabricmc.fabric.api.event.player.UseBlockCallback +import net.minecraft.text.Text +import net.minecraft.util.ActionResult +import moe.nea.firmament.events.AllowChatEvent +import moe.nea.firmament.events.AttackBlockEvent +import moe.nea.firmament.events.ModifyChatEvent +import moe.nea.firmament.events.ProcessChatEvent +import moe.nea.firmament.events.UseBlockEvent + +private var lastReceivedMessage: Text? = null + +fun registerFirmamentEvents() { + ClientReceiveMessageEvents.ALLOW_CHAT.register(ClientReceiveMessageEvents.AllowChat { message, signedMessage, sender, params, receptionTimestamp -> + lastReceivedMessage = message + !ProcessChatEvent.publish(ProcessChatEvent(message, false)).cancelled + && !AllowChatEvent.publish(AllowChatEvent(message)).cancelled + }) + ClientReceiveMessageEvents.ALLOW_GAME.register(ClientReceiveMessageEvents.AllowGame { message, overlay -> + lastReceivedMessage = message + overlay || (!ProcessChatEvent.publish(ProcessChatEvent(message, false)).cancelled && + !AllowChatEvent.publish(AllowChatEvent(message)).cancelled) + }) + ClientReceiveMessageEvents.MODIFY_GAME.register(ClientReceiveMessageEvents.ModifyGame { message, overlay -> + if (overlay) message + else ModifyChatEvent.publish(ModifyChatEvent(message)).replaceWith + }) + ClientReceiveMessageEvents.GAME_CANCELED.register(ClientReceiveMessageEvents.GameCanceled { message, overlay -> + if (!overlay && lastReceivedMessage !== message) { + ProcessChatEvent.publish(ProcessChatEvent(message, true)) + } + }) + ClientReceiveMessageEvents.CHAT_CANCELED.register(ClientReceiveMessageEvents.ChatCanceled { message, signedMessage, sender, params, receptionTimestamp -> + if (lastReceivedMessage !== message) { + ProcessChatEvent.publish(ProcessChatEvent(message, true)) + } + }) + + AttackBlockCallback.EVENT.register(AttackBlockCallback { player, world, hand, pos, direction -> + if (AttackBlockEvent.publish(AttackBlockEvent(player, world, hand, pos, direction)).cancelled) + ActionResult.CONSUME + else ActionResult.PASS + }) + UseBlockCallback.EVENT.register(UseBlockCallback { player, world, hand, hitResult -> + if (UseBlockEvent.publish(UseBlockEvent(player, world, hand, hitResult)).cancelled) + ActionResult.CONSUME + else ActionResult.PASS + }) +} diff --git a/src/main/kotlin/events/subscription/Subscription.kt b/src/main/kotlin/events/subscription/Subscription.kt new file mode 100644 index 0000000..83b91c9 --- /dev/null +++ b/src/main/kotlin/events/subscription/Subscription.kt @@ -0,0 +1,16 @@ + +package moe.nea.firmament.events.subscription + +import moe.nea.firmament.events.FirmamentEvent +import moe.nea.firmament.events.FirmamentEventBus +import moe.nea.firmament.features.FirmamentFeature + +interface SubscriptionOwner { + val delegateFeature: FirmamentFeature +} + +data class Subscription<T : FirmamentEvent>( + val owner: Any, + val invoke: (T) -> Unit, + val eventBus: FirmamentEventBus<T>, +) |