Skip to content

Commit

Permalink
refactor!: Make conditions a native concept for cost modifiers, allow…
Browse files Browse the repository at this point in the history
… multiple conditions
  • Loading branch information
BlayTheNinth committed Dec 25, 2023
1 parent 562a946 commit 8bd4b5e
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ public static class Costs {

@Synced
@ExpectedType(String.class)
@Comment("List of cost modifiers with comma-separated parameters in parentheses. Will be applied in order.")
@Comment("List of cost modifiers with comma-separated parameters in parentheses. Conditions can be defined as comma-separated list in square brackets. Will be applied in order.")
public List<String> costModifiers = List.of(
"scaled_add_xp(distance, 0.01)",
"conditional_multiply_xp(source_is_warp_plate, 0)",
"conditional_multiply_xp(target_is_global, 0)",
"conditional_add_xp(is_interdimensional, 27)",
"[is_not_interdimensional] scaled_add_xp(distance, 0.01)",
"[is_interdimensional] add_xp(27)",
"[source_is_warp_plate] multiply_xp(0)",
"[target_is_global] multiply_xp(0)",
"min_xp(0)",
"max_xp(27)");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,16 @@ public CostContextImpl(IWaystoneTeleportContext context) {
this.context = context;
}

public <T extends Cost, P> void apply(Pair<CostModifier<T, P>, P> modifierAndParameters) {
applyModifier(modifierAndParameters.getFirst(), modifierAndParameters.getSecond());
}

@SuppressWarnings("unchecked")
public <T extends Cost, P> void applyModifier(CostModifier<T, P> modifier, P parameters) {
public <T extends Cost, P> void apply(CostRegistry.ConfiguredCostModifier<T, P> configuredModifier) {
for (final var condition : configuredModifier.conditions()) {
if (!matchesCondition(condition)) {
return;
}
}

final var modifier = configuredModifier.modifier();
final var parameters = configuredModifier.parameters();
var costInstance = (T) costInstances.get(modifier.getCostType());
if (costInstance == null) {
costInstance = CostRegistry.<T>getCostType(modifier.getCostType()).createInstance();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package net.blay09.mods.waystones.cost;

import com.mojang.datafixers.util.Pair;
import net.blay09.mods.waystones.api.IWaystoneTeleportContext;
import net.blay09.mods.waystones.api.WaystoneTypes;
import net.blay09.mods.waystones.api.WaystoneVisibility;
Expand All @@ -12,9 +11,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.*;
import java.util.function.Function;

public class CostRegistry {
Expand All @@ -27,6 +24,9 @@ public class CostRegistry {
private static final Map<ResourceLocation, CostVariableResolver> costVariableResolvers = new HashMap<>();
private static final Map<ResourceLocation, CostConditionResolver> costConditionResolvers = new HashMap<>();

public record ConfiguredCostModifier<T extends Cost, P>(CostModifier<T, P> modifier, List<ResourceLocation> conditions, P parameters) {
}

public record IntParameter(int value) {
}

Expand All @@ -39,9 +39,6 @@ public record IdParameter(ResourceLocation value) {
public record VariableScaledParameter(IdParameter id, FloatParameter scale) {
}

public record ConditionalFloatParameter(IdParameter id, FloatParameter scale) {
}

public static void registerDefaults() {
final var experiencePoints = new ExperiencePointsCostType();
final var levels = new ExperienceLevelCostType();
Expand All @@ -53,22 +50,10 @@ public static void registerDefaults() {
cost.setLevels((int) (cost.getLevels() + parameters.value));
return cost;
});
registerModifier("conditional_add_levels", levels, ConditionalFloatParameter.class, (cost, context, parameters) -> {
if (context.matchesCondition(parameters.id.value)) {
cost.setLevels((int) (cost.getLevels() + parameters.scale.value));
}
return cost;
});
registerModifier("multiply_levels", levels, FloatParameter.class, (cost, context, parameters) -> {
cost.setLevels((int) (cost.getLevels() * parameters.value));
return cost;
});
registerModifier("conditional_multiply_levels", levels, ConditionalFloatParameter.class, (cost, context, parameters) -> {
if (context.matchesCondition(parameters.id.value)) {
cost.setLevels((int) (cost.getLevels() * parameters.scale.value));
}
return cost;
});
registerModifier("scaled_add_levels", levels, VariableScaledParameter.class, (cost, context, parameters) -> {
final var sourceValue = context.getContextValue(parameters.id.value);
cost.setLevels((int) (cost.getLevels() + sourceValue * parameters.scale.value));
Expand All @@ -91,22 +76,10 @@ public static void registerDefaults() {
cost.setPoints(cost.getPoints() + parameters.value);
return cost;
});
registerModifier("conditional_add_xp", experiencePoints, ConditionalFloatParameter.class, (cost, context, parameters) -> {
if (context.matchesCondition(parameters.id.value)) {
cost.setPoints((int) (cost.getPoints() + parameters.scale.value));
}
return cost;
});
registerModifier("multiply_xp", experiencePoints, FloatParameter.class, (cost, context, parameters) -> {
cost.setPoints((int) (cost.getPoints() * parameters.value));
return cost;
});
registerModifier("conditional_multiply_xp", experiencePoints, ConditionalFloatParameter.class, (cost, context, parameters) -> {
if (context.matchesCondition(parameters.id.value)) {
cost.setPoints((int) (cost.getPoints() * parameters.scale.value));
}
return cost;
});
registerModifier("scaled_add_xp", experiencePoints, VariableScaledParameter.class, (cost, context, parameters) -> {
final var sourceValue = context.getContextValue(parameters.id.value);
cost.setPoints((int) (cost.getPoints() + sourceValue * parameters.scale.value));
Expand All @@ -125,7 +98,6 @@ public static void registerDefaults() {
registerSerializer(FloatParameter.class, it -> new FloatParameter(Float.parseFloat(it)));
registerSerializer(IdParameter.class, it -> new IdParameter(waystonesResourceLocation(it)));
registerDefaultSerializer(VariableScaledParameter.class);
registerDefaultSerializer(ConditionalFloatParameter.class);

registerConditionResolver("is_interdimensional", IWaystoneTeleportContext::isDimensionalTeleport);
registerConditionResolver("source_is_warp_plate",
Expand Down Expand Up @@ -175,23 +147,41 @@ public static void register(CostConditionResolver costConditionResolver) {
costConditionResolvers.put(costConditionResolver.getId(), costConditionResolver);
}

public static <T extends Cost, P> Optional<Pair<CostModifier<T, P>, P>> deserializeModifier(String modifier) {
final var openParen = modifier.indexOf('(');
final var closeParen = modifier.indexOf(')');
if (openParen == -1 || closeParen == -1) {
public static <T extends Cost, P> Optional<ConfiguredCostModifier<T, P>> deserializeModifier(String modifier) {
// format: [commaSeparatedConditions] modifierId(parameter1, parameter2, ...)
final var conditionStart = modifier.indexOf('[');
final var conditionEnd = modifier.indexOf(']');
final List<ResourceLocation> conditions = new ArrayList<>();
if (conditionStart != -1 && conditionEnd != -1) {
final var conditionString = modifier.substring(conditionStart + 1, conditionEnd);
for (final var condition : conditionString.split(",")) {
final var conditionId = waystonesResourceLocation(condition.trim());
final var costCondition = CostRegistry.getConditionResolver(conditionId);
if (costCondition == null) {
logger.error("Failed to process waystone cost: Unknown condition {}", conditionId);
return Optional.empty();
}
conditions.add(conditionId);
}
}

final var parameterStart = modifier.indexOf('(');
final var parameterEnd = modifier.indexOf(')');
if (parameterStart == -1 || parameterEnd == -1) {
return Optional.empty();
}

final var modifierId = waystonesResourceLocation(modifier.substring(0, openParen));
final var parameterString = modifier.substring(openParen + 1, closeParen);
final var modifierStart = conditionEnd != -1 ? conditionEnd + 1 : 0;
final var modifierId = waystonesResourceLocation(modifier.substring(modifierStart, parameterStart).trim());
final var parameterString = modifier.substring(parameterStart + 1, parameterEnd);
final var costModifier = CostRegistry.<T, P>getCostModifier(modifierId);
if (costModifier == null) {
return Optional.empty();
}

try {
final var parameters = deserializeParameter(costModifier.getParameterType(), parameterString);
return Optional.of(Pair.of(costModifier, parameters));
return Optional.of(new ConfiguredCostModifier<T, P>(costModifier, conditions, parameters));
} catch (Exception e) {
logger.error("Failed to process waystone cost", e);
return Optional.empty();
Expand Down

0 comments on commit 8bd4b5e

Please sign in to comment.