Skip to content
LLytho edited this page Oct 4, 2023 · 5 revisions

Event

LootJS provides the lootjs KubeJS event to create your loot modifications or for other stuff. The event is server-sided and can be reloaded by invoking /reload.
To learn more about KubeJS events, please refer to their wiki.

onEvent("lootjs", (event) => {
    // your code
});

addBlockLootModifier(...blocks)

Adds a new loot modifier for blocks.
The function returns a builder object so you can add conditions and actions.

onEvent("lootjs", (event) => {
    event.addBlockLootModifier("minecraft:gravel").randomChance(0.3).thenAdd("minecraft:gunpowder");
});

addEntityLootModifier(...entities)

Adds a new loot modifier for entities.
The function returns a builder object so you can add conditions and actions.

onEvent("lootjs", (event) => {
    event.addEntityLootModifier("minecraft:creeper").thenAdd("minecraft:gunpowder");
});

addLootTableModifier(...values)

Adds a new loot modifier for loot tables. You can use multiple loot table ids or use a regular expression for values.
The function returns a builder object so you can add conditions and actions.

onEvent("lootjs", (event) => {
    // by id
    event.addLootTableModifier("minecraft:entities/creeper").randomChance(0.3).thenAdd("minecraft:gunpowder");

    // by regular expression
    event.addLootTableModifier(".*creeper.*").randomChance(0.3).thenAdd("minecraft:gunpowder");
});

addLootTypeModifier(...types)

Adds a new loot modifier for a loot type. You can also use multiple LootType's for types.
The function returns a builder object so you can add conditions and actions.

onEvent("lootjs", (event) => {
    event
        .addLootTypeModifier(LootType.ENTITY) // or multiple LootType.BLOCK, LootType.ENTITY ...
        .randomChance(0.3)
        .thenAdd("minecraft:gravel");
});

enableLogging()

Enables the log output.

onEvent("lootjs", (event) => {
    event.enableLogging();
});

getGlobalModifiers()

Returns a list of all registered global loot modifiers from other mods.

onEvent("lootjs", (event) => {
    const modifiers = event.getGlobalModifiers();
    modifiers.forEach((modifier) => {
        console.log(modifier);
    });
});

removeGlobalModifier(...values)

Remove one or multiple global loot modifiers from other mods. Can be used to prevent mods from adding their own loot through global loot. This will not work if the mod adds their items directly into the loot tables.
You can pass multiple loot tables or mod ids.

onEvent("lootjs", (event) => {
    event.removeGlobalModifier("examplemod:example_loot_change"); // by location
    event.removeGlobalModifier("@examplemod"); // by mod id. Use `@` as prefix
});

disableLootModification(...values)

Disables the loot modification for given values.
values can be resource locations for the loot table or a regular expression.

onEvent("lootjs", (event) => {
    onEvent("lootjs", (event) => {
    // all leaves disabled via regex
    event.disableLootModification(/.*:blocks\/.*_leaves/);

    // disable bats
    event.disableLootModification("minecraft:entities/bat");
});

Actions

Actions are used to change the current loot pool outcome or to trigger effects. You can simply chain multiple actions together. For every Loot Modification, you need at least one action.

thenAdd(...items)

Adds one or multiple items to the current loot pool.

onEvent("lootjs", (event) => {
    event.addBlockLootModifier("minecraft:gravel").thenAdd("minecraft:flint");
});

thenRemove(ingredient)

Removes all items from the current loot pool which matches the given ingredient.

onEvent("lootjs", (event) => {
    event.addBlockLootModifier("minecraft:gravel").thenRemove("minecraft:flint");
});

thenReplace(ingredient, item)

Replaces all items from the current loot pool which match the given ingredient.

onEvent("lootjs", (event) => {
    event.addBlockLootModifier("minecraft:gravel").thenReplace("minecraft:flint", "minecraft:diamond");
});

In this example, we want to replace flint with diamonds in the gravel loot pool.

thenModify(ingredient, callback)

For every item in the current loot pool which matches the given ingredient, a callback will be called. LootJS will pass the item into the callback to modify it and return the item. Make sure to always return an item.

onEvent("lootjs", (event) => {
    event
        .addLootTypeModifier(LootType.ENTITY)
        .weatherCheck({
            raining: true,
        })
        .thenModify(Ingredient.getAll(), (itemStack) => {
            return itemStack.withCount(itemStack.getCount() * 2);
        });
});

In this example, we will double all loot when it's raining.

thenExplode(radius, destroy, fire)

Triggers an explosion on the position where the loot will be dropped. The items will not be destroyed. The radius can be any number. For destroy and fire you can pass true or false.

onEvent("lootjs", (event) => {
    event.addBlockLootModifier("minecraft:gravel").thenExplode(1, false, false);
});

thenLightningStrike(shouldDamage)

Triggers a lightning strike on the position where the loot will be dropped. The items will not be destroyed. Use true or false for shouldDamage.

onEvent("lootjs", (event) => {
    event.addBlockLootModifier("minecraft:gravel").thenLightningStrike(false);
});

thenApply(callback)

With thenApply, you apply a custom callback onto the current loot pool. LootJS will provide you the LootContextJS.

onEvent("lootjs", (event) => {
    event.addBlockLootModifier("minecraft:gravel").thenApply((context) => {
        // do whatever you like
        // example: context.level to access the level
    });
});

Conditions

Besides Actions, you can use conditions to apply filters.
If a condition fails, no actions will be triggered after the failing condition. You also can chain multiple conditions to apply more filters to your loot modifier.

matchLoot(ingredient, exact)

Matching the loot pool by the given ingredient.
exact is optional and does not need to be passed. The default value is false. If exact is true, all items in the current loot pool need to match the ingredient.

onEvent("lootjs", (event) => {
    event.addEntityLootModifier("minecraft:cow").matchLoot("minecraft:leather").thenAdd("minecraft:carrot");
});

matchMainHand(ingredient)

Matching the players' main hand by the given ingredient.

onEvent("lootjs", (event) => {
    event
        .addBlockLootModifier("#forge:ores")
        .matchMainHand(Item.of("minecraft:netherite_pickaxe").ignoreNBT())
        .thenAdd("minecraft:gravel");
});

matchOffHand(ingredient)

Matching the players' off hand by the given ingredient.

onEvent("lootjs", (event) => {
    event
        .addBlockLootModifier("#forge:ores")
        .matchOffHand(Item.of("minecraft:netherite_pickaxe").ignoreNBT())
        .thenAdd("minecraft:gravel");
});

matchEquip(slot, ingredient)

Matching the players' equipment slot by the given ingredient.

onEvent("lootjs", (event) => {
    event
        .addBlockLootModifier("#forge:ores")
        .matchEquip(EquipmentSlot.MAINHAND, Item.of("minecraft:netherite_pickaxe").ignoreNBT())
        .thenAdd("minecraft:gravel");
});

survivesExplosion()

Returns true if the destroyed block would survive an explosion. This condition doesn't invoke an explosion.

onEvent("lootjs", (event) => {
    event.addBlockLootModifier("minecraft:gravel").survivesExplosion().thenAdd("minecraft:gravel");
});

timeCheck(period, min, max) & timeCheck(min, max)

Checks for the game time which is the age of the world in-game ticks.

From Minecraft Wiki: period-> "If present, the game time is first reduced modulo the given number before being checked against. Setting this to 24000 causes the checked time to be equal to the current daytime."

onEvent("lootjs", (event) => {
    event
        .addBlockLootModifier("minecraft:gravel")
        .timeCheck(24000, 0, 9000) // good morning
        .thenAdd("minecraft:diamond");
});

weatherCheck(value)

Checks if the current weather is rain and/or thunder.

Value syntax:

{
    raining: true, // or false
    thundering: true // or false
}

If you just use one, the other one will be ignored.

onEvent("lootjs", (event) => {
    event
        .addBlockLootModifier("minecraft:gravel")
        .weatherCheck({
            raining: true,
        })
        .thenAdd("minecraft:diamond");
});

If you want to check for clear weather, set both values to false.

randomChance(value)

onEvent("lootjs", (event) => {
    event
        .addBlockLootModifier("minecraft:gravel")
        .randomChance(0.3) // 30%
        .thenAdd("minecraft:diamond");
});

randomChanceWithLooting(value, looting)

Random chance with a looting multiplier. More on Minecraft Wiki.

onEvent("lootjs", (event) => {
    event
        .addBlockLootModifier("minecraft:gravel")
        .randomChanceWithLooting(0.3, 2) // 30%
        .thenAdd("minecraft:diamond");
});

randomChanceWithEnchantment(enchantment, [chances])

Random chance with enchantment. More on Minecraft Wiki for table_bonus.

onEvent("lootjs", (event) => {
    event
        .addBlockLootModifier("minecraft:gravel")
        .randomChanceWithEnchantment("minecraft:looting", [0, 0.1, 0.5, 1])
        .thenAdd("minecraft:diamond");

    /*
        [0, 0.1, 0.5, 1]:
          0% for no looting
         10% for looting 1
         50% for looting 2
        100% for looting 3
    */
});

biome(...biomes)

Checks for given biomes. If multiple biomes given, all biomes must match. With the prefix #, you can pass biome tags, so it's possible to check if a biome is cold for example.

onEvent("lootjs", (event) => {
    event.addBlockLootModifier("minecraft:gravel").biome("minecraft:jungle").thenAdd("minecraft:diamond");
});

anyBiome(...biomes)

Checks for given biomes. If multiple biomes are given, at least one biome must match. With the prefix #, you can pass biome tags, so it's possible to check if a biome is cold for example.

onEvent("lootjs", (event) => {
    event
        .addBlockLootModifier("minecraft:gravel")
        .anyBiome("minecraft:jungle", "minecraft:ocean")
        .thenAdd("minecraft:diamond");
});

anyDimension(...dimensions)

Checks for given dimensions. If multiple dimensions are given, at least one dimension must match.

onEvent("lootjs", (event) => {
    event.addBlockLootModifier("minecraft:gravel").anyDimension("minecraft:nether").thenAdd("minecraft:diamond");
});

anyStructure([structures], exact)

Checks for given structures. You have to pass the structures as an array-like.

If exact is true, it will check if the player is inside the structure parts (like houses in a village).
If exact is false, it will just check if the player is within the structure bounds.

onEvent("lootjs", (event) => {
    event
        .addBlockLootModifier("minecraft:gravel")
        .anyStructure(["minecraft:stronghold", "minecraft:village"], false)
        .thenAdd("minecraft:diamond");
});

lightLevel(min, max)

onEvent("lootjs", (event) => {
    event.addBlockLootModifier("minecraft:gravel").lightLevel(0, 15).thenAdd("minecraft:diamond");
});

killedByPlayer()

onEvent("lootjs", (event) => {
    event.addEntityLootModifier("minecraft:creeper").killedByPlayer().thenAdd("minecraft:diamond");
});

matchEntity(callback)

Matches against the entity that died, opened the chest or destroyed the block. LootJS will provide EntityPredicateBuilderJS in your callback to match against the entity.

onEvent("lootjs", (event) => {
    event
        .addEntityLootModifier("minecraft:creeper")
        .matchEntity((entity) => {
            // Your code. Check EntityPredicateBuilderJS for more information
        })
        .thenAdd("minecraft:diamond");
});

matchDirectKiller(callback)

Matches against the direct entity which caused the death, e.g. the arrow entity, not the shooter. LootJS will provide EntityPredicateBuilderJS in your callback to match against an entity.

onEvent("lootjs", (event) => {
    event
        .addEntityLootModifier("minecraft:creeper")
        .matchDirectKiller((entity) => {
            // Your code. Check EntityPredicateBuilderJS for more information
        })
        .thenAdd("minecraft:diamond");
});

matchKiller(callback)

Matches against the entity which caused the death. LootJS will provide EntityPredicateBuilderJS in your callback to match against an entity.

onEvent("lootjs", (event) => {
    event
        .addEntityLootModifier("minecraft:creeper")
        .matchKiller((entity) => {
            // Your code. Check EntityPredicateBuilderJS for more information
        })
        .thenAdd("minecraft:diamond");
});

matchPlayer(callback)

Matches against the player. If a player kills another player, it will check against the killer. LootJS will provide EntityPredicateBuilderJS in your callback to match against an entity.

onEvent("lootjs", (event) => {
    event
        .addEntityLootModifier("minecraft:creeper")
        .matchPlayer((player) => {
            // Your code. Check EntityPredicateBuilderJS for more information
        })
        .thenAdd("minecraft:diamond");
});

matchDamageSource(callback)

Matches against the damage source. LootJS will provide DamageSourcePredicateBuilderJS in your callback to check against.

onEvent("lootjs", (event) => {
    event
        .addEntityLootModifier("minecraft:creeper")
        .matchDamageSource((source) => {
            // Your code. Check DamageSourcePredicateBuilderJS for more information
        })
        .thenAdd("minecraft:diamond");
});

distanceToKiller(interval)

For the interval, use IntervalJS.

onEvent("lootjs", (event) => {
    event.addEntityLootModifier("minecraft:creeper").distanceToKiller(Interval.min(25)).thenAdd("minecraft:diamond");
});

hasAnyStage(...stages)

Checks for player stages.

onEvent("lootjs", (event) => {
    event.addEntityLootModifier("minecraft:pig").hasAnyStage("stoneage").thenAdd("minecraft:coal");
});

playerPredicate(callback)

Custom callback predicate to check the player. The callback must return either true or false.

onEvent("lootjs", (event) => {
    event
        .addEntityLootModifier("minecraft:pig")
        .playerPredicate((player) => player.stages.has("stoneage"))
        .thenAdd("minecraft:emerald");
});

entityPredicate(callback)

Custom callback predicate to check the entity. The callback must return either true or false.

onEvent("lootjs", (event) => {
    event
        .addEntityLootModifier("minecraft:pig")
        .entityPredicate((entity) => entity.type == "minecraft:pig")
        .thenAdd("minecraft:diamond");
});

killerPredicate(callback)

Custom callback predicate to check the killer. The callback must return either true or false.

onEvent("lootjs", (event) => {
    event
        .addEntityLootModifier("minecraft:pig")
        .killerPredicate((entity) => entity.type == "minecraft:pig")
        .thenAdd("minecraft:feather");
});

directKillerPredicate(callback)

Custom callback predicate to check the direct killer. The callback must return either true or false.

onEvent("lootjs", (event) => {
    event
        .addEntityLootModifier("minecraft:pig")
        .directKillerPredicate((entity) => entity.type == "minecraft:pig")
        .thenAdd("minecraft:stone");
});

not(callback)

Add a condition through the callback which will be negated.

onEvent("lootjs", (event) => {
    event
        .addEntityLootModifier("minecraft:creeper")
        .not((n) => {
            n.biome("minecraft:jungle");
        })
        .thenAdd("minecraft:diamond");
});

or(callback)

Add multiple conditions through the callback which will return true when at least one condition returns true.

onEvent("lootjs", (event) => {
    event
        .addEntityLootModifier("minecraft:creeper")
        .or((or) => {
            or.biome("minecraft:jungle").anyDimension("minecraft:nether");
        })
        .thenAdd("minecraft:diamond");
});

and(callback)

Add multiple conditions through the callback which will return true when all conditions return true.

onEvent("lootjs", (event) => {
    event
        .addEntityLootModifier("minecraft:creeper")
        .and((and) => {
            and.biome("minecraft:jungle").distanceToKiller(Interval.min(25));
        })
        .thenAdd("minecraft:diamond");
});

customCondition(json)

Adds a custom condition via json.

onEvent("lootjs", (event) => {
    event
        .addBlockLootModifier("minecraft:gravel")
        .customCondition({
            condition: "minecraft:survives_explosion",
        })
        .thenAdd("minecraft:diamond");
});

Types

Equipment Slots

EquipmentSlot.MAINHAND
EquipmentSlot.OFFHAND
EquipmentSlot.FEET
EquipmentSlot.LEGS
EquipmentSlot.CHEST
EquipmentSlot.HEAD

Loot Types

LootType.UNKNOWN
LootType.BLOCK
LootType.ENTITY
LootType.CHEST
LootType.FISHING
LootType.GIFT

IntervalJS

Represents an interval between two numbers. Can be accessed by using Interval in ur code.
All bounds are exclusive.

Creation

Interval.between(min, max)

Returns a new interval between the [min;max] bounds.

Interval.min(min)

Returns a new interval with a minimum bound up to infinity.

Interval.max(max)

Returns a new interval with a maximum bound down to negative infinity.

Functions

matches(value) or matchesSqr(value)

Checks if a value matches the interval.

const interval = Interval.between(0, 5);
if (interval.matches(3)) {
    console.log("matches");
}

Side note

Functions of LootJS that use Interval support simplified statements:

  • Interval.between(min, max) is equal to [min, max]
  • Interval.min(min) is equal to [min] or just a simple integer min

LootContextJS

Holds information for the current loot drop. Is mostly used for .thenApply().

getType()

Returns the LootType.

getPosition()

getEntity()

Returns an EntityJS or null if no entity exists for the context.

getKillerEntity()

Returns an EntityJS for the killer or null if no entity exists for the context.

getPlayer()

Returns a PlayerJS or null if no player exists for the context. An example for null would be that a Skeleton shoots a Creeper.

getDamageSource()

Returns a DamageSourceJS or null if no source exists.

getTool()

Returns an ItemStackJS for the tool. If no tool exists in the context, it will return an empty item.

getDestroyedBlock()

Returns a BlockContainerJS for block loot. Will be null for every other loot type.

isExploded()

Returns true if the loot drop happens by an explosion.

getExplosionRadius()

Returns the explosion radius. If isExploded() returns false, the radius is 0.

getLevel()

Returns the LevelJS.

getServer()

Returns the ServerJS.

getLuck()

getLooting()

lootSize()

addLoot(itemStack)

removeLoot(ingredient)

findLoot(ingredient)

hasLoot(ingredient)

forEachLoot(callback)

Iterates over each item and calls the given callback for it.

// callback example
const callback = (item) => {
    console.log(item);
};

EntityPredicateBuilderJS

anyType(...types)

Entity tags can also be passed when using # as a prefix. Example: #skeletons.

isOnFire(flag)

isCrouching(flag)

isSprinting(flag)

isSwimming(flag)

isBaby(flag)

isInWater(flag)

isUnderWater(flag)

isMonster(flag)

isCreature(flag)

isOnGround(flag)

isUndeadMob(flag)

isArthropodMob(flag)

isIllegarMob(flag)

isWaterMob(flag)

hasEffect(effect, amplifier) & hasEffect(effect)

nbt(json)

matchMount(callback)

Matching the mount for the current entity. LootJS provides an EntityPredicateBuilderJS for the callback.

onEvent("lootjs", (event) => {
    event
        .addLootTypeModifier([LootType.ENTITY])
        .matchEntity((entity) => {
            entity.anyType("#skeletons");
            entity.matchMount((mount) => {
                mount.anyType("minecraft:spider");
            });
        })
        .thenAdd("minecraft:magma_cream");
});

This example shows a Skeleton riding a Spider, also known as a spider jockey.

matchTargetedEntity(callback)

Matching the targeted entity for the current entity. LootJS provides a EntityPredicateBuilderJS for the callback.

matchSlot(slot, ingredient)

Returns true if the slot contains the specified ingredient.

DamageSourcePredicateBuilderJS

anyType(...types)

Returns true if at least one type matches. Possible types are: "inFire", "lightningBolt", "onFire", "lava", "hotFloor", "inWall", "cramming", "drown", "starve", "cactus", "fall", "flyIntoWall", "outOfWorld", "generic", "magic", "wither", "anvil", "fallingBlock", "dragonBreath", "dryout", "sweetBerryBush" and there might be more types added by other mods.

isProjectile(flag)

isExplosion(flag)

doesBypassArmor(flag)

doesBypassInvulnerability(flag)

doesBypassMagic(flag)

isFire(flag)

isMagic(flag)

isLightning(flag)

matchDirectEntity(callback)

Matching the direct entity. LootJS provides a EntityPredicateBuilderJS for the callback.

matchSourceEntity(callback)

Matching the source entity. LootJS provides a EntityPredicateBuilderJS for the callback.

Clone this wiki locally