Repository navigation
Non declared methods
PatchLib can only patch declared methods on a target class. What this means concretely will be discussed on this page.
To get an example going, let's say we want to once again expand the tooltip of another hullmod. Let's go with the Nav Relay hullmod this time.
For this, you would likely write up a patch like this:
@Patch(target = @ClassMatch(type = NavRelay.class))
public class NavRelayPatch {
@After(target = @MethodMatch(methodName = "addPostDescriptionSection"))
public static void afterAddPostDescriptionSection(AfterContext context) {
TooltipMakerAPI tooltip = (TooltipMakerAPI) context.getArg(0);
tooltip.addSpacer(10f);
tooltip.addPara("Added tooltip to NavRelay!",
0f, Misc.getHighlightColor(), Misc.getHighlightColor());
}
}However, when you launch the game, you will notice that nothing changed.

This is because of what the NavRelay class looks like.
public class NavRelay extends BaseHullMod {
private static Map mag = new HashMap();
static {
mag.put(HullSize.FRIGATE, 2f);
mag.put(HullSize.DESTROYER, 3f);
mag.put(HullSize.CRUISER, 4f);
mag.put(HullSize.CAPITAL_SHIP, 5f);
}
public void applyEffectsBeforeShipCreation(HullSize hullSize, MutableShipStatsAPI stats, String id) {
stats.getDynamic().getMod(Stats.COORDINATED_MANEUVERS_FLAT).modifyFlat(id, (Float) mag.get(hullSize));
}
public String getDescriptionParam(int index, HullSize hullSize) {
if (index == 0) return "" + ((Float) mag.get(HullSize.FRIGATE)).intValue() + "%";
if (index == 1) return "" + ((Float) mag.get(HullSize.DESTROYER)).intValue() + "%";
if (index == 2) return "" + ((Float) mag.get(HullSize.CRUISER)).intValue() + "%";
if (index == 3) return "" + ((Float) mag.get(HullSize.CAPITAL_SHIP)).intValue() + "%";
return null;
}
}Looking at it, you may notice that it does not implement the addPostDescriptionSection method.
Since NavRelay extends BaseHullMod, it inherits the method. It could be called with navRelay.addPostDescriptionSection(), but it does not declare the method.
This ends up mattering here because only declared methods can be patched. So the method to patch needs to exist within the class. Whether it is an original method or an @Override of an inherited method doesn't matter; both would declare it.
You will generally only run into this issue when you want to patch a method that is inherited from somewhere else but not implemented. The only way to get around this issue is to patch the class that the method is inherited from instead.
//Targeting all hullmod plugins, instead of a specific hullmod
@Patch(target = @ClassMatch(subtype = BaseHullMod.class))
public class NavRelayPatch {
@After(target = @MethodMatch(methodName = "addPostDescriptionSection"))
public static void afterAddPostDescriptionSection(AfterContext context) {
TooltipMakerAPI tooltip = (TooltipMakerAPI) context.getArg(0);
//Retrieve the instance of whatever you are patching
BaseHullMod self = (BaseHullMod) context.getSelf();
//Only call your code for the specific class you are targeting
if (self instanceof NavRelay) {
tooltip.addSpacer(10f);
tooltip.addPara("Added tooltip to NavRelay!",
0f, Misc.getHighlightColor(), Misc.getHighlightColor());
}
}
}As shown above, to achieve this, you want to check that the instance on which the code is running is of the type you want to patch.
We do this by retrieving self from the context and performing an instanceof check for the type of the class. Of course, you could also base this check on other factors, like the id of the hullmod spec.
This approach, however, has a downside. Since our patch targets everything that inherits from BaseHullMod, this code is inserted into:
-
addPostDescriptionSectioninBaseHullMod - The declared
@OverrideofaddPostDescriptionSectionin everything that inherits fromBaseHullMod
Effectively, it means adding additional code to every addPostDescriptionSection method and forcing part of this code to run in all of them.
For a simple and rarely called method like this, it is fine, but it may prove to be a performance problem in other cases. You should ensure that any code that you run
is not too expensive and gate anything expensive behind the if statement that only runs for your real targets.
- Home
- Introduction to Patchlib
- Patch Types
- Working with obfuscated code
- Example Patches
- Other utilities
- Patching with Kotlin
- Developer Documentation