Kappa is aimed at bringing OptiFine capes to snapshots without being fragile to code changes perceived unrelated. It was spawned after Dragonostic's OF Capes mod broke in 1.17 snapshots due to the screen refactor (originally as a fork) and then also broke again because entity models were refactored, and their mod duplicated the cape code, as well as pretty much every other mod in the block at the time.
Kappa uses a much more direct approach of injecting the cape texture directly into the metaphysical player. Additionally, it doesn't override any texture, and does not register its own cape renderer whatsoever. Kappa's implementation is as close as you are going to get to vanilla.
Kappa's only requirement is Fabric Loader. There's no settings that need to be set before being used. With Kappa installed, any players with an OptiFine cape will have it be shown. If you'd like an OptiFine cape, consider purchasing one from sp614x. This mod does not allow players without OptiFine capes to have them.
If you have an OptiFine cape and would like to change it, you'll have to go to the skin customization screen, and press the "Open Cape Editor" button on the bottom right corner. A web browser window will show up where you can edit your cape. You'll have to restart your game for it to take effect.
Kappa is tested on every new snapshot when they are published, including experiments. Testing has three major points:
This section includes more implementational details. Any vanilla field and method names will be using Yarn mapping names as they're unencumbered.
Historically, Kappa v. 3.0.0 was intented to have multiple cape providers for a one-size-fits-all. This would include Mantle, MinecraftCapes, Wynntils, LabyMod, and even Lunar Client with a bit of reversing, however that was dropped in favor of keeping only OptiFine. The upside of this is that the provider (OptiFine) is completely separate from any code handling integration with the videogame.
The cape provider is defined in hibiii.kappa.Provider
and defines the following fields and methods:
void loadCape(GameProfile, CapeTextureAvailableCallback)
loadCape
first checks if the cape has already been loaded to prevent it from being downloaded again. Then, the provider attempts to download with tryUrl()
, first from the secure url at https://optifine.net/capes/<username>.png
but if that's unavailabe, then try with http://s.optifine.net/capes/<username>.png
, where historically has been used but does not support HTTPS. The callback is used to put the cape texture into the player profile. This workflow is pushed onto the main thread to prevent stutters.
boolean tryUrl(GameProfile, CapeTextureAvailableCallback, String)
tryUrl
attempts the full workflow of retrieving a cape. It reads the contents of the url given by the string, turns into an image, uncrops it with uncrop
, resizes into a power of 2, and registers this texture. The Identifier
for this cape is stored, and the callback provided is called. For logic's sake, it returns true
if it could successfully get a cape, or check if the player doesn't have one, or it returns false if it fails to connect, as a signal to retry.
NativeImage uncrop(NativeImage)
uncrop
takes an input image and pads it such its dimensions are powers of two because the original images are cropped. The workflow is as follows:
zoom
in the code. The height is used because some OptiFine server implementations don't use elytra textures, but cape textures with or without elytra don't go taller than 32 pixels.NativeImage
with width w' = 64 × rdpx and height h' = 32 × rdpx.NativeImage.copyFrom()
.String getChangeUrl(Session)
getChangeUrl
returns an URL where the current player can change their OptiFine cape. It does more than generate a change URL because OptiFine uses vanilla auth, and vanilla auth requires the username, the UUID, and randomly generated salt. No login details are required as long as you have a valid Minecraft session.
Cape injection is done by mixing into PlayerListEntry
, and calling the provider to load the cape from the shadowed GameProfile
. The injection is defined in hibiii.kappa.mixin.PlayerListEntryMixin
. The callback that's required simply saves the Identifier
to the cape texture onto the profile's textures map if there's no cape already present. This check makes sure an official vanilla cape isn't overwritten by an OptiFine cape.
Inserting the cape editor button onto the skin customization screen is done with a mixin into SkinOptionsScreen
and code inserted at the end of init. The inserted code is only a button, on the very bottom right corner with five pixel padding on both sides. The button is set to open a web browser with the URL to the editor provided. Additionally, the button text is a translatable text where the key isn't a more traditional kappa.cape_editor
, but a deliberately much more human legible Open Cape Editor...
because Fabric API may not be present to load the localization files and indeed, without them, only the key is displayed. The button is defined in hibiii.kappa.mixin.SkinOptionsScreenMixin
.