Skip to content

Instantly share code, notes, and snippets.

@zomb-676
Created February 29, 2024 18:24
Show Gist options
  • Select an option

  • Save zomb-676/fce06b6369444739c19dcc2aa44fbd71 to your computer and use it in GitHub Desktop.

Select an option

Save zomb-676/fce06b6369444739c19dcc2aa44fbd71 to your computer and use it in GitHub Desktop.
Choose Bus automatically
import net.minecraftforge.common.MinecraftForge
import net.minecraftforge.eventbus.api.Event
import net.minecraftforge.eventbus.api.EventPriority
import net.minecraftforge.eventbus.api.GenericEvent
import net.minecraftforge.eventbus.api.IEventBus
import net.minecraftforge.fml.event.IModBusEvent
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext
import net.minecraftforge.registries.DeferredRegister
import org.apache.http.util.Asserts

object Dispatcher {
    val modBus get() = FMLJavaModLoadingContext.get().modEventBus!!
    val forgeBus get() = MinecraftForge.EVENT_BUS!!

    @JvmName("registerForNoneGenericEvent")
    inline operator fun <reified T : GenericEvent<out V>, reified V : Any> invoke(crossinline codeBlock: (T) -> Unit) {
        invoke<T, V>(EventPriority.NORMAL, false, codeBlock)
    }

    @JvmName("registerForNoneGenericEvent")
    inline operator fun <reified T : GenericEvent<out V>, reified V : Any> invoke(
        priority: EventPriority = EventPriority.NORMAL,
        receiveCanceled: Boolean = false,
        crossinline codeBlock: (T) -> Unit,
    ) {
        Asserts.check(T::class.java.isGenericEvent(), "${T::class.java.simpleName} is not GenericEvent<T>")
        switchEvent<T>().addGenericListener(
            V::class.java, priority, receiveCanceled, T::class.java
        ) { e -> codeBlock(e) }
    }

    @JvmName("registerForGenericEvent")
    inline operator fun <reified T : Event> invoke(crossinline codeBlock: (T) -> Unit) {
        invoke<T>(EventPriority.NORMAL, false, codeBlock)
    }

    @JvmName("registerForGenericEvent")
    inline operator fun <reified T : Event> invoke(
        priority: EventPriority = EventPriority.NORMAL,
        receiveCanceled: Boolean = false,
        crossinline codeBlock: (T) -> Unit,
    ) {
        Asserts.check(!T::class.java.isGenericEvent(), "${T::class.java.simpleName} is GenericEvent<T>")
        switchEvent<T>().addListener(priority, receiveCanceled, T::class.java) { e -> codeBlock.invoke(e) }
    }

    fun <T : DeferredRegister<*>> registerDeferred(register: T) {
        register.register(modBus)
    }

    @PublishedApi
    internal fun <T> Class<T>.isGenericEvent() = GenericEvent::class.java.isAssignableFrom(this)

    @PublishedApi
    internal fun <T> Class<T>.isModEvent() = IModBusEvent::class.java.isAssignableFrom(this)

    @PublishedApi
    internal inline fun <reified T : Event> switchEvent(): IEventBus {
        return when {
            T::class.java.isModEvent() -> modBus
            else -> forgeBus
        }
    }
}

for example

  fun test(dispatcher: Dispatcher) {
      //for none-GenericEvent
      dispatcher<FMLClientSetupEvent> { event ->
      }
      dispatcher<_, _> { event: FMLClientSetupEvent ->
          //compile error
      }
      //for GenericEvent
      dispatcher<_, _> { event: AttachCapabilitiesEvent<LevelChunk> ->
      }
      dispatcher<AttachCapabilitiesEvent<LevelChunk>, _> { event ->
      }
      dispatcher<_> { event: AttachCapabilitiesEvent<LevelChunk> ->
          //cause runtime check error
      }
  }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment