Skip to content

Matching targets

Lukas22041 edited this page Oct 15, 2026 · 5 revisions

As discussed on the prior page, patches in PatchLib often require you to narrow down your target. For this, there are three separate annotations:

  • @ClassMatch: For filtering down classes
  • @MethodMatch: For filtering down methods
  • @FieldMatch: For filtering down fields (class variables)

All matchers share three properties:

  • They can match multiple things at a time. The @ClassMatch in your @Patch may target multiple real classes, making your patch apply to all of the matching classes.
  • By default, they match everything. An empty @MethodMatch would make your patch handler target every single method in your target.
  • Additional filters are ANDed together. If you have multiple conditions in your matcher, all of them need to be true for the matcher to be valid.

A common example for a matcher that will target multiple classes is the subtype argument in a @ClassMatch annotation.

@Patch(target = @ClassMatch(subtype = BaseHullMod.class))
public class HullmodPatch {// ^ Matches all hullmod classes

    @After(target = @MethodMatch(methodName = "addPostDescriptionSection"))
    public static void afterAddPostDescriptionSection(AfterContext context) {
        // ^ Patches the "addPostDescriptionSection" method in all hullmods
        TooltipMakerAPI tooltip = (TooltipMakerAPI) context.getArg(0);

        tooltip.addSpacer(10f);
        tooltip.addPara("Tooltip added with PatchLib!", 0f,
                Misc.getHighlightColor(), Misc.getHighlightColor());
    }
    
}

Whereas the type parameter only ever targets one specific class, subtype matches anything that extends the specified class—in our example, every single hullmod plugin. Broad patches like those have a lot of potential, but you should be careful, as they could easily run into compatibility issues.

As explained earlier, you could further filter those broad patches down, for example by limiting them to a specific package. As the conditions are ANDed together, they all need to be true to match.

                            // Matches all hullmod classes  // But only hullmod classes in this specific package
@Patch(target = @ClassMatch(subtype = BaseHullMod.class, packageName = "com.fs.starfarer.api.combat"))
public class HullmodPatch { }

Distinguishing two method overloads

In some cases, a simple methodName condition is not enough for matching a method. This is due to the fact that in Java, multiple methods in a class can have the same name, as long as the parameters are different (overloading).

For example, below you can see how BaseHullMod has two methods called isSMod.

// Code copied from BaseHullMod 

public boolean isSMod(MutableShipStatsAPI stats) {
    if (stats == null || stats.getVariant() == null || spec == null) return false;
    return stats.getVariant().getSMods().contains(spec.getId()) ||
            stats.getVariant().getSModdedBuiltIns().contains(spec.getId());
}
public boolean isSMod(ShipAPI ship) {
    if (ship == null || ship.getVariant() == null || spec == null) return false;
    return ship.getVariant().getSMods().contains(spec.getId()) ||
            ship.getVariant().getSModdedBuiltIns().contains(spec.getId());
}

Let's say we only want to patch the overload with the ShipAPI parameter. For this, we can make use of the parameterTypes condition, which lets you provide a list of parameter types that the method has to exactly match.

@Patch(target = @ClassMatch(subtype = BaseHullMod.class))
public class HullmodPatch {
    @After(target = @MethodMatch(methodName = "isSMod", parameterTypes = { ShipAPI.class }))
    public static void afterIsSMod(AfterContext context) {
        
    }
}

Next Up

If you are interested, you can view more details about each individual matching annotation on the sidebar. However, unless you are working with obfuscated code, you do not need most of it. In most cases you can get by with:

  • type / typeName for matching specific classes in @ClassMatch
  • subtype / subtypeName for matching by inheritance in @ClassMatch
  • methodName for matching by method name in @MethodMatch
  • parameterCount / parameterTypes / parameterTypeNames for matching by method parameters in @MethodMatch

Clone this wiki locally