Cosmetic Module

Overview

The cosmetic module allows you to interact and utilize all the various cosmetic types found in Lunar Client.

  • Add wearable cosmetics to NPC entities
    • Grants the ability to put any cosmetic on an NPC
    • Uniquely customize various cosmetic options
  • Add sprays to any location
    • Grants the ability to put any spray on a block
    • Customize the rotation, direction options, and duration

The cosmetic module is a private module and not publicly available. To use this module, you must be granted access by the Lunar Client team. Learn More

Integration

Sample Code

Explore each integration by cycling through each tab to find the best fit for your requirements and needs.

⚠️

NPC UUIDs must have their least significant bits set to 0 (i.e. new UUID(msb, 0L)). Lunar Client rejects cosmetic packets for UUIDs that do not follow this format.

Apollo API examples. See General for common patterns and helpers.

Equip cosmetics on an NPC

public void equipNpcCosmeticsExample(Player viewer, UUID npcUuid) {
    List<Cosmetic> cosmetics = Lists.newArrayList(
        Cosmetic.builder()
            .id(434)
            .build(),
        Cosmetic.builder()
            .id(3654)
            .build(),
        Cosmetic.builder()
            .id(5095)
            .options(PetOptions.builder()
                .flipShoulder(true)
                .build())
            .build(),
        Cosmetic.builder()
            .id(3)
            .options(CloakOptions.builder()
                .useClothPhysics(true)
                .build())
            .build(),
        Cosmetic.builder()
            .id(3977)
            .build()
    );
 
    Optional<ApolloPlayer> apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId());
    apolloPlayerOpt.ifPresent(apolloPlayer -> this.cosmeticModule.equipNpcCosmetics(apolloPlayer, npcUuid, cosmetics));
}

Unequip cosmetics from an NPC

public void unequipNpcCosmeticsExample(Player viewer, UUID npcUuid) {
    Optional<ApolloPlayer> apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId());
    apolloPlayerOpt.ifPresent(apolloPlayer -> {
        List<Integer> cosmeticIds = Lists.newArrayList(434, 3654, 5095, 3, 3977);
        this.cosmeticModule.unequipNpcCosmetics(apolloPlayer, npcUuid, cosmeticIds);
    });
}

Reset NPC cosmetics

public void resetNpcCosmeticsExample(UUID npcUuid) {
    this.cosmeticModule.resetNpcCosmetics(Recipients.ofEveryone(), npcUuid);
}

Display spray

public void displaySprayExample(Player viewer, int sprayId) {
    Block block = viewer.getTargetBlockExact(10);
    if (block == null) {
        return;
    }
 
    Material material = block.getType();
    if (material.isAir() || !material.isSolid()) {
        return;
    }
 
    ApolloBlockLocation location = ApolloBlockLocation.builder()
        .world(block.getWorld().getName())
        .x(block.getX())
        .y(block.getY())
        .z(block.getZ())
        .build();
 
    Spray spray = Spray.builder()
        .sprayId(sprayId)
        .location(location)
        .facing(Direction.UP)
        .rotation(0f)
        .duration(Duration.ofSeconds(60))
        .build();
 
    this.cosmeticModule.displaySpray(Recipients.ofEveryone(), spray);
}

Sprays are client-local and validated against loaded chunks. When the backing chunk unloads, sprays are removed and do not come back until the server sends a display spray packet again.

Remove sprays

public void removeSprayExample(int sprayId) {
    this.cosmeticModule.removeSpray(Recipients.ofEveryone(), sprayId);
}

Reset sprays

public void resetSpraysExample() {
    this.cosmeticModule.resetSprays(Recipients.ofEveryone());
}

Cosmetic Options

.id(int) is the Lunar Client cosmetic id for this entry.

.id(434)

.options(CosmeticOptions) is optional. Pass one concrete subtype such as HatOptions, CloakOptions, PetOptions, or BodyOptions (omit or pass null for id-only cosmetics).

HatOptions

.options(HatOptions.builder()
    .showOverHelmet(true)
    .showOverSkinLayer(true)
    .heightOffset(0.05f)
    .build())

CloakOptions

.options(CloakOptions.builder()
    .useClothPhysics(true)
    .build())

PetOptions

.options(PetOptions.builder()
    .flipShoulder(true)
    .build())

BodyOptions

.options(BodyOptions.builder()
    .showOverChestplate(true)
    .showOverLeggings(true)
    .showOverBoots(true)
    .build())

Spray Options

.sprayId(int) is the Lunar Client spray cosmetic id.

.sprayId(sprayId)

.location(ApolloBlockLocation) is the block the spray is placed on. See the locations page for more.

.location(ApolloBlockLocation.builder()
    .world(block.getWorld().getName())
    .x(block.getX())
    .y(block.getY())
    .z(block.getZ())
    .build())

.facing(Direction) selects which face of the block the spray uses.

.facing(Direction.UP)

.rotation(float) is rotation in degrees on the client (default 0f).

.rotation(0f)

.duration(java.time.Duration) is how long the spray stays visible. See the java.time.Duration Javadocs (opens in a new tab) for more.

.duration(Duration.ofSeconds(60))