-
Notifications
You must be signed in to change notification settings - Fork 0
Level Based Values
Registers custom mathematical formula codecs into the vanilla LevelBasedValue ecosystem. Allows enchantments to scale variables non-linearly or retrieve externally defined configuration values.
| Method | Description |
|---|---|
initialize() |
Injects all custom mathematical codecs into the built-in LevelBasedValue registry (BuiltInRegistries.ENCHANTMENT_LEVEL_BASED_VALUE_TYPE). |
register(String, MapCodec) |
Maps a specific map codec implementation to the LevelBasedValue registry under the mod's namespace. |
Defines a configuration target and an optional fallback. Resolves the active target based on mod load status and handles orphaned configurations. This object utilizes an Either codec, allowing it to be defined either directly as a single ConfigDescription object, or as a dual-target object with primary and fallback configurations.
Type 1: Direct Definition
Define the reference directly using the properties of a ConfigDescription.
Template (Direct)
{
"mod_id": "example_mod",
"category": "combat",
"group": "weapons",
"property": "damage_multiplier"
}Type 2: Fallback Definition Defines a primary target, falling back to a secondary target if the primary mod is not loaded.
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
try_config |
ConfigDescription |
Yes | - | The primary configuration target to attempt loading. |
else_config |
ConfigDescription |
Yes | - | The fallback configuration target if the primary mod is missing. |
Codec
private static final Codec<ConfigReference> TRY_ELSE_CODEC = RecordCodecBuilder.create(instance -> instance.group(
ConfigDescription.CODEC.fieldOf("try_config").forGetter(ConfigReference::target),
ConfigDescription.CODEC.fieldOf("else_config").forGetter(ref -> ref.fallback.orElse(null))
).apply(instance, (tryConfig, elseConfig) -> new ConfigReference(tryConfig, Optional.ofNullable(elseConfig))));
public static final Codec<ConfigReference> CODEC = Codec.either(ConfigDescription.CODEC, TRY_ELSE_CODEC)
.xmap(
either -> either.map(
single -> new ConfigReference(single, Optional.empty()),
tryElse -> tryElse
),
ref -> ref.fallback.isPresent() ? Either.right(ref) : Either.left(ref.target)
);Template (Fallback)
{
"try_config": {
"mod_id": "addon_mod",
"category": "combat",
"group": "weapons",
"property": "damage_multiplier"
},
"else_config": {
"mod_id": "base_mod",
"category": "combat",
"group": "weapons",
"property": "damage_multiplier"
}
}Calculates a total value based on an arithmetic progression where the increment decreases (diminishes) for each subsequent level until a defined minimum value is reached.
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
base |
Float |
Yes | - | The initial value added at the first level. |
decrement |
Float |
Yes | - | The amount by which the value added is reduced for each subsequent level. |
minimum |
Float |
Yes | - | The floor value. The added value per level will never drop below this amount. |
Codec
public static final MapCodec<DiminishingReturnsValue> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
Codec.FLOAT.fieldOf("base").forGetter(DiminishingReturnsValue::base),
Codec.FLOAT.fieldOf("decrement").forGetter(DiminishingReturnsValue::decrement),
Codec.FLOAT.fieldOf("minimum").forGetter(DiminishingReturnsValue::minimum)
).apply(instance, DiminishingReturnsValue::new));Template
{
"type": "enchantment_core:diminishing_returns",
"base": 5.0,
"decrement": 0.5,
"minimum": 1.0
}Calculates a final value using a generalized polynomial function: value = offset + (scale * (level + levelOffset)^power). Allows for custom linear, quadratic, or exponential growth curves.
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
scale |
Float |
No | 1.0 |
The coefficient that multiplies the result of the power calculation. |
power |
Float |
No | 1.0 |
The exponent applied to the level calculation. |
offset |
Float |
No | 0.0 |
A constant value added to the final result. |
level_offset |
Float |
No | 0.0 |
A constant value added to the enchantment level before the power calculation. |
Codec
public static final MapCodec<PolynomialValue> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
Codec.FLOAT.optionalFieldOf("scale", 1.0f).forGetter(PolynomialValue::scale),
Codec.FLOAT.optionalFieldOf("power", 1.0f).forGetter(PolynomialValue::power),
Codec.FLOAT.optionalFieldOf("offset", 0.0f).forGetter(PolynomialValue::offset),
Codec.FLOAT.optionalFieldOf("level_offset", 0.0f).forGetter(PolynomialValue::levelOffset)
).apply(instance, PolynomialValue::new));Template
{
"type": "enchantment_core:polynomial",
"scale": 1.5,
"power": 2.0,
"offset": 0.0,
"level_offset": -1.0
}Calculates the success or failure of a probabilistic event based on an inner chance provider, returning 0.0 for success and 1.0 for failure. Intended for boolean outcome mechanics (like ammo usage).
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
chance |
LevelBasedValue |
Yes | - | An inner value determining the probability (0.0 to 1.0) of a successful outcome. |
Codec
public static final MapCodec<ProbabilisticValue> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
LevelBasedValue.CODEC.fieldOf("chance").forGetter(ProbabilisticValue::chance)
).apply(instance, ProbabilisticValue::new));Template
{
"type": "enchantment_core:probabilistic",
"chance": 0.5
}Calculates the negative additive inverse of the value returned by an inner value provider.
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
value |
LevelBasedValue |
Yes | - | The inner value whose calculated result will be negated. |
Codec
public static final MapCodec<NegateValue> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
LevelBasedValue.CODEC.fieldOf("value").forGetter(NegateValue::input)
).apply(instance, NegateValue::new));Template
{
"type": "enchantment_core:negative",
"value": 5.0
}These codecs dynamically bridge data-driven enchantments with runtime configuration files, updating immediately when a user alters their server/client configs.
A dynamic delegation codec that executes entirely different LevelBasedValue logic branches depending on the stringified output of a configuration property.
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
config |
ConfigDescription |
Yes | - | The target configuration property to read at runtime. |
cases |
Map<String, LevelBasedValue> |
Yes | - | A map of stringified config states mapped to their respective value logic. |
fallback |
LevelBasedValue |
Yes | - | The logic executed if the config property is invalid, missing, or unmatched. |
Codec
public static final MapCodec<ConfigAwareValue> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
ConfigDescription.CODEC.fieldOf("config").forGetter(val -> val.target),
Codec.unboundedMap(Codec.STRING, LevelBasedValue.CODEC).fieldOf("cases").forGetter(val -> val.cases),
LevelBasedValue.CODEC.fieldOf("fallback").forGetter(val -> val.fallback)
).apply(instance, ConfigAwareValue::new));Template
{
"type": "enchantment_core:config_aware",
"config": {
"mod_id": "my_mod",
"category": "balance",
"group": "scaling",
"property": "mode"
},
"cases": {
"linear": { "type": "minecraft:linear", "base": 1.0, "per_level_above_first": 1.0 },
"flat": 5.0
},
"fallback": 1.0
}Fetches a flat float value from the configuration registry.
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
config |
ConfigReference |
Yes | - | The reference path to the configuration property. |
default_value |
Float |
Yes | - | The fallback value if the config is not found or fails to load. |
min |
Float |
No | -MAX_VALUE |
The absolute lowest permitted value bounds. |
max |
Float |
No | MAX_VALUE |
The absolute highest permitted value bounds. |
Codec
public static final MapCodec<ConfigurableConstantValue> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
ConfigReference.CODEC.fieldOf("config").forGetter(ConfigurableConstantValue::reference),
Codec.FLOAT.fieldOf("default_value").forGetter(ConfigurableConstantValue::defaultValue),
Codec.FLOAT.optionalFieldOf("min", -Float.MAX_VALUE).forGetter(ConfigurableConstantValue::min),
Codec.FLOAT.optionalFieldOf("max", Float.MAX_VALUE).forGetter(ConfigurableConstantValue::max)
).apply(instance, ConfigurableConstantValue::new));Template
{
"type": "enchantment_core:configurable_constant",
"config": {
"mod_id": "my_mod",
"category": "combat",
"group": "weapons",
"property": "bonus"
},
"default_value": 2.0,
"min": 0.0,
"max": 10.0
}Wraps a standard LevelBasedValue but bounds the final calculated output between dynamic configurable minimum and maximum thresholds.
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
value |
LevelBasedValue |
Yes | - | The inner logic generating the raw calculation. |
min_config |
ConfigReference |
Yes | - | The config property dictating the clamp floor. |
min_default |
Float |
Yes | - | Fallback default for the minimum bound. |
max_config |
ConfigReference |
Yes | - | The config property dictating the clamp ceiling. |
max_default |
Float |
Yes | - | Fallback default for the maximum bound. |
Codec
public static final MapCodec<ConfigurableClampedValue> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
LevelBasedValue.CODEC.fieldOf("value").forGetter(ConfigurableClampedValue::value),
ConfigReference.CODEC.fieldOf("min_config").forGetter(ConfigurableClampedValue::minReference),
Codec.FLOAT.fieldOf("min_default").forGetter(ConfigurableClampedValue::minDefault),
ConfigReference.CODEC.fieldOf("max_config").forGetter(ConfigurableClampedValue::maxReference),
Codec.FLOAT.fieldOf("max_default").forGetter(ConfigurableClampedValue::maxDefault)
).apply(instance, ConfigurableClampedValue::new));Template
{
"type": "enchantment_core:configurable_clamped",
"value": { "type": "minecraft:linear", "base": 1.0, "per_level_above_first": 2.0 },
"min_config": {
"mod_id": "my_mod",
"category": "limits",
"group": "bounds",
"property": "min_val"
},
"min_default": 1.0,
"max_config": {
"mod_id": "my_mod",
"category": "limits",
"group": "bounds",
"property": "max_val"
},
"max_default": 10.0
}A configurable implementation of the diminishing_returns logic, pulling its structural parameters from external config definitions.
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
base_config |
ConfigReference |
Yes | - | Config reference dictating the starting base value. |
base_default |
Float |
Yes | - | Fallback base value. |
decrement_config |
ConfigReference |
Yes | - | Config reference dictating the per-level decrement amount. |
decrement_default |
Float |
Yes | - | Fallback decrement amount. |
minimum_config |
ConfigReference |
Yes | - | Config reference dictating the lowest allowed addition per level. |
minimum_default |
Float |
Yes | - | Fallback minimum amount. |
Codec
public static final MapCodec<ConfigurableDiminishingReturnsValue> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
ConfigReference.CODEC.fieldOf("base_config").forGetter(ConfigurableDiminishingReturnsValue::baseReference),
Codec.FLOAT.fieldOf("base_default").forGetter(ConfigurableDiminishingReturnsValue::baseDefault),
ConfigReference.CODEC.fieldOf("decrement_config").forGetter(ConfigurableDiminishingReturnsValue::decrementReference),
Codec.FLOAT.fieldOf("decrement_default").forGetter(ConfigurableDiminishingReturnsValue::decrementDefault),
ConfigReference.CODEC.fieldOf("minimum_config").forGetter(ConfigurableDiminishingReturnsValue::minimumReference),
Codec.FLOAT.fieldOf("minimum_default").forGetter(ConfigurableDiminishingReturnsValue::minimumDefault)
).apply(instance, ConfigurableDiminishingReturnsValue::new));Template
{
"type": "enchantment_core:configurable_diminishing_returns",
"base_config": {
"mod_id": "my_mod",
"category": "scaling",
"group": "base",
"property": "val"
},
"base_default": 5.0,
"decrement_config": {
"mod_id": "my_mod",
"category": "scaling",
"group": "decrement",
"property": "val"
},
"decrement_default": 0.5,
"minimum_config": {
"mod_id": "my_mod",
"category": "scaling",
"group": "minimum",
"property": "val"
},
"minimum_default": 1.0
}Returns (level^2) + added_constant, where the added constant is bound to a configuration property.
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
config |
ConfigReference |
Yes | - | The configuration reference dictating the constant added to the squared level. |
default_added |
Float |
Yes | - | Fallback constant added if the config fails to resolve. |
min |
Float |
No | -MAX_VALUE |
Absolute lower bound for the added constant. |
max |
Float |
No | MAX_VALUE |
Absolute upper bound for the added constant. |
Codec
public static final MapCodec<ConfigurableLevelsSquaredValue> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
ConfigReference.CODEC.fieldOf("config").forGetter(ConfigurableLevelsSquaredValue::reference),
Codec.FLOAT.fieldOf("default_added").forGetter(ConfigurableLevelsSquaredValue::defaultValue),
Codec.FLOAT.optionalFieldOf("min", -Float.MAX_VALUE).forGetter(ConfigurableLevelsSquaredValue::min),
Codec.FLOAT.optionalFieldOf("max", Float.MAX_VALUE).forGetter(ConfigurableLevelsSquaredValue::max)
).apply(instance, ConfigurableLevelsSquaredValue::new));Template
{
"type": "enchantment_core:configurable_levels_squared",
"config": {
"mod_id": "my_mod",
"category": "combat",
"group": "weapons",
"property": "squared_offset"
},
"default_added": 0.0,
"min": 0.0,
"max": 10.0
}A linear multiplier (base + per_level * (level - 1)) fully bound to configuration variables with hard limits.
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
base_config |
ConfigReference |
Yes | - | Config reference defining the Level 1 value. |
base_default |
Float |
Yes | - | Fallback default for the base. |
base_min |
Float |
No | -MAX_VALUE |
Absolute lower limit for the base property. |
base_max |
Float |
No | MAX_VALUE |
Absolute upper limit for the base property. |
per_level_config |
ConfigReference |
Yes | - | Config reference defining the scalar added per subsequent level. |
per_level_default |
Float |
Yes | - | Fallback default for the per-level multiplier. |
per_level_min |
Float |
No | -MAX_VALUE |
Absolute lower limit for the per-level multiplier. |
per_level_max |
Float |
No | MAX_VALUE |
Absolute upper limit for the per-level multiplier. |
Codec
public static final MapCodec<ConfigurableLinearValue> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
ConfigReference.CODEC.fieldOf("base_config").forGetter(ConfigurableLinearValue::baseReference),
Codec.FLOAT.fieldOf("base_default").forGetter(ConfigurableLinearValue::baseDefault),
Codec.FLOAT.optionalFieldOf("base_min", -Float.MAX_VALUE).forGetter(ConfigurableLinearValue::baseMin),
Codec.FLOAT.optionalFieldOf("base_max", Float.MAX_VALUE).forGetter(ConfigurableLinearValue::baseMax),
ConfigReference.CODEC.fieldOf("per_level_config").forGetter(ConfigurableLinearValue::perLevelReference),
Codec.FLOAT.fieldOf("per_level_default").forGetter(ConfigurableLinearValue::perLevelDefault),
Codec.FLOAT.optionalFieldOf("per_level_min", -Float.MAX_VALUE).forGetter(ConfigurableLinearValue::perLevelMin),
Codec.FLOAT.optionalFieldOf("per_level_max", Float.MAX_VALUE).forGetter(ConfigurableLinearValue::perLevelMax)
).apply(instance, ConfigurableLinearValue::new));Template
{
"type": "enchantment_core:configurable_linear",
"base_config": {
"mod_id": "my_mod",
"category": "scaling",
"group": "base",
"property": "val"
},
"base_default": 1.0,
"base_min": 0.0,
"base_max": 10.0,
"per_level_config": {
"mod_id": "my_mod",
"category": "scaling",
"group": "per_level",
"property": "val"
},
"per_level_default": 1.0,
"per_level_min": 0.0,
"per_level_max": 5.0
}A configurable implementation of the polynomial value logic.
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
scale_config |
ConfigReference |
Yes | - | Config dictating the final multiplier scale. |
scale_default |
Float |
Yes | - | Fallback default for the scale. |
power_config |
ConfigReference |
Yes | - | Config dictating the level exponent. |
power_default |
Float |
Yes | - | Fallback default for the exponent power. |
offset_config |
ConfigReference |
Yes | - | Config dictating the flat offset added to the result. |
offset_default |
Float |
Yes | - | Fallback default for the offset. |
level_offset_config |
ConfigReference |
Yes | - | Config dictating the offset added to the raw enchantment level. |
level_offset_default |
Float |
Yes | - | Fallback default for the level offset. |
Codec
public static final MapCodec<ConfigurablePolynomialValue> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
ConfigReference.CODEC.fieldOf("scale_config").forGetter(ConfigurablePolynomialValue::scaleReference),
Codec.FLOAT.fieldOf("scale_default").forGetter(ConfigurablePolynomialValue::scaleDefault),
ConfigReference.CODEC.fieldOf("power_config").forGetter(ConfigurablePolynomialValue::powerReference),
Codec.FLOAT.fieldOf("power_default").forGetter(ConfigurablePolynomialValue::powerDefault),
ConfigReference.CODEC.fieldOf("offset_config").forGetter(ConfigurablePolynomialValue::offsetReference),
Codec.FLOAT.fieldOf("offset_default").forGetter(ConfigurablePolynomialValue::offsetDefault),
ConfigReference.CODEC.fieldOf("level_offset_config").forGetter(ConfigurablePolynomialValue::levelOffsetReference),
Codec.FLOAT.fieldOf("level_offset_default").forGetter(ConfigurablePolynomialValue::levelOffsetDefault)
).apply(instance, ConfigurablePolynomialValue::new));Template
{
"type": "enchantment_core:configurable_polynomial",
"scale_config": {
"mod_id": "my_mod",
"category": "poly",
"group": "scale",
"property": "val"
},
"scale_default": 1.0,
"power_config": {
"mod_id": "my_mod",
"category": "poly",
"group": "power",
"property": "val"
},
"power_default": 2.0,
"offset_config": {
"mod_id": "my_mod",
"category": "poly",
"group": "offset",
"property": "val"
},
"offset_default": 0.0,
"level_offset_config": {
"mod_id": "my_mod",
"category": "poly",
"group": "level_offset",
"property": "val"
},
"level_offset_default": -1.0
}Want to learn more about the configuration engine powering Enchantment Core?
Check out Config Understood, the official wiki for Config Overhauled, for a deep dive into dynamic property generation and state synchronization!