-
Notifications
You must be signed in to change notification settings - Fork 0
Home
Confluence Lib is a small, generic Forge 1.20.1 library: a named, team-scoped gauge fed by one or more "sources", with a configurable threshold and Forge events fired when that threshold is crossed (in either direction). It has no lore, no entities, no content of its own, and no knowledge of whatever mod is consuming it — it just counts, and tells you when a rule is met.
If you're building a mechanic like "corruption", "reputation", "harmony" (or anything else) that should accumulate per FTB Team from multiple independent triggers, this library handles the bookkeeping so you don't have to touch team NBT or reinvent threshold-crossing logic yourself.
Confluence Lib depends hard on FTB Teams — it has no meaning without it, and gauges are
always scoped to a Team, never to an individual player directly (a solo player still works fine,
since FTB Teams auto-creates a personal team for anyone without one).
There's no public Maven repository for Confluence Lib yet. To depend on it at compile time,
flatDir the built jar the same way Cryptic Life Mod does:
repositories {
flatDir {
dirs '../confluence-lib/build/libs' // or wherever you keep the jar
}
}
dependencies {
implementation "blank:confluencelib:1.0.0"
}As a player/pack builder, just drop confluencelib-<version>.jar in your mods/ folder
alongside FTB Teams — it does nothing on its own until another mod registers a gauge on it.
-
Gauge — a named (
ResourceLocation), team-scoped, floating-point value with a threshold. -
Source — a
ResourceLocationidentifying why a contribution happened (e.g.mymod:source_something). The gauge only ever sees the ID, never any logic behind it. - Threshold rule — a gauge is "at threshold" once its level reaches a configured amount and at least a configured number of distinct sources have contributed at least once. Both conditions must hold; sources are never un-recorded once contributed (only the level itself goes up/down).
- Confluence Lib never knows why a source contributes or what happens once a threshold is crossed — that's entirely up to the mod that registered the gauge.
Do this once, typically in your mod's FMLCommonSetupEvent:
import fr.protosrv.confluencelib.api.GaugeDefinition;
import net.minecraft.resources.ResourceLocation;
public static final ResourceLocation GAUGE_ID =
ResourceLocation.fromNamespaceAndPath("mymod", "corruption");
public static void registerGauge() {
GaugeDefinition.builder(GAUGE_ID)
.threshold(100f) // total amount required
.minDistinctSources(2) // at least 2 different sources must have contributed
.decayPerDay(0f) // optional passive decay, disabled by default
.register();
}GaugeDefinition.Builder#register() is a convenience for
ConfluenceAPI.get().registerGauge(build()) — use whichever reads better in your code.
Call this from wherever your trigger actually happens (a Forge event listener you already have — Confluence Lib doesn't dictate what those look like):
import fr.protosrv.confluencelib.api.ConfluenceAPI;
import dev.ftb.mods.ftbteams.api.FTBTeamsAPI;
import dev.ftb.mods.ftbteams.api.Team;
public static void onSomethingHappened(ServerPlayer player) {
FTBTeamsAPI.api().getManager().getTeamForPlayer(player).ifPresent(team ->
ConfluenceAPI.get().contribute(team, GAUGE_ID,
ResourceLocation.fromNamespaceAndPath("mymod", "source_something"), 25f));
}Calling contribute with a source ID that has already contributed before still adds to the
level, it just won't increase the distinct-source count a second time.
Symmetric to contribute — for any player action that should lower the gauge (distinct from
passive decay below). Never drops the level under 0.
ConfluenceAPI.get().reduce(team, GAUGE_ID, 40f);import fr.protosrv.confluencelib.api.Gauge;
Gauge gauge = ConfluenceAPI.get().getGauge(team, GAUGE_ID);
gauge.getLevel(); // float
gauge.getContributedSources(); // Set<ResourceLocation>
gauge.isThresholdReached(); // level >= threshold AND distinct sources >= minDistinctSourcesTwo Forge events, posted on MinecraftForge.EVENT_BUS, each exactly once per crossing (not
repeatedly while above/below):
import fr.protosrv.confluencelib.api.GaugeThresholdReachedEvent;
import fr.protosrv.confluencelib.api.GaugeThresholdClearedEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@SubscribeEvent
public static void onReached(GaugeThresholdReachedEvent event) {
if (!event.gaugeId.equals(GAUGE_ID)) return;
// event.team, event.contributedSources available here
}
@SubscribeEvent
public static void onCleared(GaugeThresholdClearedEvent event) {
if (!event.gaugeId.equals(GAUGE_ID)) return;
// event.team available here — gauge dropped back below threshold
// (via reduce(), decay, or resetGauge())
}If the gauge crosses back down and then up again later, GaugeThresholdReachedEvent fires a
second time — there's an internal "already notified" flag per gauge/team that resets whenever
the gauge drops back below threshold, specifically so this can happen.
You don't need these events just to check current state — if you only need "is this team
currently past threshold" at some arbitrary moment (e.g. inside a periodic tick check), just call
getGauge(...).isThresholdReached() directly instead of tracking your own flag from the events.
The events are for reacting to the moment of crossing (a chat message, a sound, spawning
something) — see Cryptic Life Mod's ResonanceThresholdHandler for a real example of that
distinction (events drive a one-time player-facing signal; a separate ticker reads the gauge
directly for continuous gameplay effects).
Zeroes the level, clears every recorded source, and clears the notified flag (posting
GaugeThresholdClearedEvent if it had been past threshold):
ConfluenceAPI.get().resetGauge(team, GAUGE_ID);Set decayPerDay(x) on the GaugeDefinition (defaults to 0f, disabled) to have the gauge lose
x per real Minecraft day automatically, with no player action needed — useful to avoid infinite
accumulation on a long-lived world. Handled by an internal ticker; nothing else to wire up.
Cryptic Life Mod's Resonance gauge is a complete, real reference implementation built on this
API — two sources (source_goat_man_aggression, source_toww_encounter), minDistinctSources(1),
sleep reducing the gauge, and both threshold events driving a discrete player-facing signal. See:
cryptic-life-mod/src/main/java/fr/protosrv/crypticlifemod/resonance/ResonanceSources.javacryptic-life-mod/src/main/java/fr/protosrv/crypticlifemod/resonance/ResonanceThresholdHandler.javacryptic-life-mod/src/main/java/fr/protosrv/crypticlifemod/resonance/ResonanceAggressionTicker.java
-
Register the gauge before anyone contributes to it.
contribute/reduce/getGaugeall throwIllegalArgumentExceptionfor an unregistered gauge ID. -
Gauges are per-team, never per-player. A player with no FTB Team returns
Optional.empty()fromFTBTeamsAPI.api().getManager().getTeamForPlayer(...)— decide what that should mean for your mod (Cryptic Life Mod's/resonancecommand just reports failure). -
Data is stored under a namespaced key in
Team#getExtraData()(confluencelib.<gaugeId>.{level,sources,notified}), so it won't collide with other mods also usinggetExtraData(). -
minDistinctSourceshas no effect once satisfied — sources are never removed from the recorded set, only the level moves. Once a team has touched enough distinct sources at least once, only the level threshold matters from then on.