Skip to content

Boosters

Pétrus Pradella edited this page Nov 2, 2026 · 3 revisions

Boosters

A booster makes a gain bigger for a while: a bought x2 on money, an event's +50% on a job's pay, a VIP permission, a region with a bonus. The core keeps the engine (package br.com.finalcraft.evernifecore.booster): where boosters come from, how the boosters of one gain join into one multiplier, and that multiplier on every ExecutionContext. It keeps no booster of its own - a plugin's boosters live in its own storage.

// a bought booster: x2 on money for one player, for an hour, kept in the plugin's storage
BoosterManager boosters = BoosterManager.of(getPluginData(), storage);
boosters.grant(Booster.on("money")
        .factor(2)
        .forOwner(ProgressOwner.player(player.getUniqueId()))
        .lasting(Duration.ofHours(1))
        .build());

// at the source of the gain: the multiplier of everything that counts for this context
BigDecimal multiplier = ctx.getMultiplier("money");          // same as Boosters.resolve(ctx, "money").getMultiplier()

A booster multiplies at the source of the gain, never inside a Currency: the stock money effect multiplies its amount unless it says boosted: false; the money cost never does; a job's pay multiplies where it pays.

Booster

Immutable; any thread. Built with Booster.on(gain) (money and evernifecore:money are the same id; a bare name is the core's):

Builder call Meaning
factor(2) multiplies the gain - x2
bonus(0.25) adds to the multiplier - +25% (exactly one of factor / bonus)
forOwner(ProgressOwner) whose gain: a player, a group, a region, global (the default)
lasting(Duration) / until(Instant) when it ends; neither means until revoked
during(Season) counts only while the season is open
from(Caller) who granted it (set by the manager)

getMultiplier() is the factor, or 1 + bonus; isActiveAt(now) / isOverAt(now). In a config it is written {on: money, factor: 1.5, owner: global, lasting: 1h} (codec registered by the core).

Where boosters come from - BoosterSource

Boosters.resolve(ctx, gain) asks every registered source for the boosters that count for the context:

Source Boosters
BoosterManager of each plugin (<plugin>:manager) the ones it granted, for the context's owner
PermissionBoosterSource (core) vip.booster.<gain>.<factor> held by the player - vip.booster.money.2 or .2.0; the factors tried are config.yml Boosters.permission-factors (default 1.1, 1.25, 1.5, 2.0, 3.0), the largest held counts. A node counts only when it is set on the player (FCommandSender.isPermissionSet) and granted: a Bukkit op without the node gets no booster (it used to get the largest factor), and a node negated outright gets none. A Hytale operator still gets it - hytale:Admin grants *, a set node
RegionBoosterSource (core) the region flag boosters where the player stands (see Regions)

A plugin adds its own with Boosters.addSource(owner, source) (getId(), boostersFor(ctx, gain); it must not block); it goes away with the owner.

How a gain joins its boosters - BoosterJoin

Join Multiplier
BoosterJoin.sumBonus() (default) 1 + sum of (multiplier - 1) - x2 and +25% give 2.25
BoosterJoin.max() the largest
BoosterJoin.product() the product
.cap(max) any of the above, never above max

The plugin that owns a gain declares how it joins and what a server may switch it to:

Boosters.declareJoin(getPluginData(), "myplugin:points", BoosterJoin.sumBonus().cap(new BigDecimal("3")), BoosterJoin.max());

A server overrides it in config.yml, only within what was declared (anything else keeps the default and warns once):

Boosters:
  permission-factors: [1.1, 1.25, 1.5, 2.0, 3.0]
  join:
    money:
      strategy: sum-bonus
      cap: 3

Boosters.resolve(ctx, gain) answers a BoosterResult: getMultiplier(), getParcels() (the boosters that counted), getJoin(), and explain() - the lines /ecore logic trace shows for each parcel.

BoosterManager

One per plugin; any thread.

Call What it does
BoosterManager.of(owner, storage) the plugin's manager, kept in its storage (collection ec_boosters, key the booster id)
BoosterManager.of(owner) the same, in memory only
ofIfPresent(owner) / closeOwnedBy(owner) look it up / close it (done for you when the owner leaves, by its shutdown hook or by removePluginData)
grant(booster) completes when the storage has it; posts a BoosterGrantedEvent; recorded in the owner's audit log as BOOSTER_GRANTED
revoke(id) completes with whether it existed
getActive(owner) / getAll() what counts now for an owner / everything kept

A booster past its end stops counting at once; a sweep drops it from the storage once a minute.

Testing

LogicWorld.boosters() is a BoosterManager of the fake plugin, in memory, closed with the world; the core's engine and the stock sources are registered for it. Permissions come from TestFPlayerSender.grant(node). See Testing Toolkit.

Clone this wiki locally