Skip to content

Implementation Policy: Bridges and Mixins

Chris Sanders edited this page Dec 8, 2020 · 29 revisions

Preamble

In the past, Sponge had no distinct structural policy beyond a couple of followed "rules" when adding new mixins/interfaces to the various projects. One of these rules, IMixin-style interfaces, served us well and is followed by many projects out there but leads to hard-to-maintain code when it isn't clear where things are coming from and going to. Likewise prefixing or lack thereof in several Mixins and their injectors/redirectors/etc makes for hard to decipher logs of exactly where problems are at and, on a more alarming level, general comprehension of the codebase. After discussion and coming to terms with this, @gabizou and @Zidane have decided to iron this out with a policy once and for all.

Packages

Rules

  • Package root for Mixin config trees should be mixin.
  • Package trees for mixins should begin with the Mixin config`s name.
  • Package branches should follow their target's package structure 1:1.
    • Branches starting with com, net, or other widely used top-level domains as well as net.minecraft are exempted and should be omitted.
      • Based on this exemption, if you are mixing into net.minecraft.world.chunk.Chunk from core, the mixin would be located in org.spongepowered.common.mixin.core.world.chunk.
  • For multi-target mixins1, it is at the discretion of the team on the most applicable spot to place the mixin.

Mixins

Rules

  • Mixin class names should be prefixed with the Mixin target's name then the word Mixin followed by _ and finally the Mixin config's name.
    • Only one config is exempt from this and that is mixins originating from the core config in SpongeCommon as that is the baseline for the entire Sponge implementation.
      • Based on this rule, if you are mixing into net.minecraft.world.chunk.Chunk from core, the mixin would be named ChunkMixin.
      • Based on this rule, if you are mixing into Chunk from forge, the mixin would be named ChunkMixin_Forge.
  • For multi-target mixins1, names should be prefixed with the most relevant name then the word Mixin followed by _ and finally the Mixin config's name.
    • Only one config is exempt from this and that is mixins originating from the core config in SpongeCommon as that is the baseline for the entire Sponge implementation.
      • Based on this rule, if you are mixing into Entity and TileEntity to implement DataHolder from core, the mixin would be DataHolderMixin2.
      • Based on this rule, if you are mixing into Entity and TileEntity to implement DataHolder from forge, the mixin would be DataHolderMixin_Forge.

Bridges

Definition

Bridges bridge the gap between Minecraft classes (ex. net.minecraft.world.chunk.Chunk) and the Sponge implemented code via Mixins (ex. MixinChunk. There are many times where we need to call methods to perform logic off of those classes and can do so via these distinct interfaces. Replaces legacy IMixin interfaces (ex. IMixinChunk).

Rules

  • Bridge class names should be prefixed with the Mixin's target name then the word "Bridge" followed by an underscore and finally the Mixin config's name.
    • Only one config is exempt from this and that is bridges originating from the core config in SpongeCommon as that is the baseline for the entire Sponge implementation.
      • Based on this exemption, if you are writing a bridge for ChunkMixin from core, the bridge would be ChunkBridge.
      • Based on this rule, if you are writing a bridge for ChunkMixin_Forge from forge, the bridge would be ChunkBridge_Forge.
  • For multi-target bridges, names should be prefixed with the most relevant name then the word Bridge followed by _ and finally the Mixin config's name.
    • Only one config is exempt from this and that is bridges originating from the core config in SpongeCommon as that is the baseline for the entire Sponge implementation.
      • Based on this rule, if you are mixing into Entity and TileEntity to implement Creator tracking in core, the bridge would be OwnershipTrackableBridge.
      • Based on this rule, if you are mixing into Entity and TileEntity to implement Creator tracking in forge, the bridge would be OwnershipTrackableBridge_Forge.
  • Bridge method names should be prefixed with the Mixin config's name followed by the word bridge followed by an additional $.
    • Only one config is exempt from this and that is bridges originating from the core config in SpongeCommon as that is the baseline for the entire Sponge implementation.
      • Based on this rule, setTransform in EntityBridge from core would be named bridge$setTransform.
      • Based on this rule, setTransform in EntityBridge_Forge from forge would be named forgeBridge$setTransform.
  • Bridges are not allowed to extend from other bridges, even if the bridge is effectively a subclass of another bridge (ex. ChunkBridge_Forge is effectively a child of ChunkBridge)
    • The reasoning for this is to prevent potential corner cases where a developer inadvertently performs a cast on code that will not exist on the platform currently running it.
      • For example, casting ChunkProviderClient to ChunkProviderServerBridge simply to call a method inherited from ChunkProviderBridge.

Injections

Definition

Injections "inject" Sponge logic into classes at explictly defined targets.

Rules

  • Injection method names should be prefixed with the Mixin config's name followed by an appropriate method name for the context.
    • Only one config is exempt from this and that is injections originating from the core config in SpongeCommon as that is the baseline for the entire Sponge implementation. Instead we make this impl.
      • Based on this rule, an injection into onUpdate of Entity in EntityMixin in core would be named impl$onUpdate.
      • Based on this rule, an injection into onUpdate of Entity in EntityMixin in forge would be named forge$onUpdate.

Accessors and Invokers

Definition

Accessor and Invoker mixins allow Sponge logic to access fields in Minecraft classes whose visibility would not be available otherwise.

Rules

  • Accessor class names should be prefixed with the Mixin target's name then the word Accessor.
    • Based on this rule, if you are accessing a field/method in Entity the accessor would be named EntityAccessor.
  • Accessor fields should be prefixed with the word accessor followed by an additional $ and finally the name of the field being targeted.
    • Based on this rule, a getter for the rand field in Entity would be named accessor$rand().
    • Based on this rule, a setter for the rand field in Entity would be named accessor$rand(Random random).
  • Invoker method names should be prefixed with the word invoker followed by an additional $ and finally the name of the method being targeted.
    • Based on this rule, method getRandom in Entity would be named invoker$getRandom().