Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public class ActivityConfiguration {
private volatile Map<String, String> professionActivities = Map.of();

private volatile Map<String, String> stationActivities = Map.of();
private volatile Map<String, Integer> stationActionAmounts = Map.of();

private volatile DayOfWeek resetDay;
private volatile int resetHour;
Expand Down Expand Up @@ -257,6 +258,7 @@ private void loadActivities(ConfigurationSection section) {
craftPaths = List.of();
professionActivities = Map.of();
stationActivities = Map.of();
stationActionAmounts = Map.of();
guaranteedActivities = List.of();
return;
}
Expand All @@ -266,6 +268,7 @@ private void loadActivities(ConfigurationSection section) {
List<Map.Entry<String, String>> paths = new ArrayList<>();
Map<String, String> professions = new LinkedHashMap<>();
Map<String, String> stations = new LinkedHashMap<>();
Map<String, Integer> stationAmounts = new LinkedHashMap<>();
List<String> guaranteed = new ArrayList<>();
for (String id : section.getKeys(false)) {
ConfigurationSection entry = section.getConfigurationSection(id);
Expand Down Expand Up @@ -318,7 +321,7 @@ private void loadActivities(ConfigurationSection section) {
}
}

loadStation(stations, entry, id);
loadStation(stations, stationAmounts, entry, id);

if (flag(entry, id, "daily-guaranteed", false)) {
guaranteed.add(id);
Expand All @@ -337,10 +340,12 @@ private void loadActivities(ConfigurationSection section) {
craftPaths = List.copyOf(paths);
professionActivities = professions;
stationActivities = stations;
stationActionAmounts = stationAmounts;
guaranteedActivities = List.copyOf(guaranteed);
}

private void loadStation(Map<String, String> stations, ConfigurationSection entry, String id) {
private void loadStation(Map<String, String> stations, Map<String, Integer> amounts,
ConfigurationSection entry, String id) {
String station = entry.getString("station");
if (station == null) {
return;
Expand Down Expand Up @@ -376,10 +381,35 @@ private void loadStation(Map<String, String> stations, ConfigurationSection entr
}

String previous = stations.put(stationKey, id);
amounts.remove(stationKey);
if (previous != null) {
plugin.getLogger().warning("Activities '" + previous + "' and '" + id
+ "' both track station '" + stationKey + "' - only '" + id + "' will be fed.");
}
ConfigurationSection alternatives = entry.getConfigurationSection("station-actions");
if (alternatives == null) {
return;
}
for (String recipe : alternatives.getKeys(false)) {
String key = stationKey(recipe);
Object raw = alternatives.get(recipe);
double value = raw instanceof Number number ? number.doubleValue() : Double.NaN;
if (key.isEmpty() || key.startsWith("/") || key.endsWith("/") || !key.contains("/")
|| key.equals(stationKey) || !Double.isFinite(value) || value < 1
|| value > Integer.MAX_VALUE || Math.rint(value) != value) {
plugin.getLogger().warning("Activity '" + id + "' has invalid station-actions entry '"
+ Utils.safeForLog(recipe) + "' - expected a different <station>/<recipe>"
+ " with a positive whole-number amount within the int range.");
continue;
}
int amount = (int) value;
String displaced = stations.put(key, id);
if (displaced != null) {
plugin.getLogger().warning("Activities '" + displaced + "' and '" + id
+ "' both track station '" + key + "' - only '" + id + "' will be fed.");
}
amounts.put(key, amount);
}
}

private static String stationKey(String station) {
Expand Down Expand Up @@ -1094,17 +1124,25 @@ public String craftActivity(ItemStack crafted) {
}

public Optional<String> stationActivity(String stationId, String recipeId) {
return stationAction(stationId, recipeId).map(StationActionCredit::activityId);
}

public record StationActionCredit(String activityId, int amount) {}

public Optional<StationActionCredit> stationAction(String stationId, String recipeId) {
if (stationId == null || stationId.isBlank()) {
return Optional.empty();
}
String station = normalizeStationPart(stationId);
if (recipeId != null && !recipeId.isBlank()) {
String specific = stationActivities.get(station + "/" + normalizeStationPart(recipeId));
String key = station + "/" + normalizeStationPart(recipeId);
String specific = stationActivities.get(key);
if (specific != null) {
return Optional.of(specific);
return Optional.of(new StationActionCredit(specific, stationActionAmounts.getOrDefault(key, 1)));
}
}
return Optional.ofNullable(stationActivities.get(station));
return Optional.ofNullable(stationActivities.get(station))
.map(id -> new StationActionCredit(id, 1));
}

public String professionActivity(String professionId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public void onUseCraftingStation(PlayerUseCraftingStationEvent event) {
return;
}

manager.getConfiguration().stationActivity(station.getId(), recipe.getId())
.ifPresent(activityId -> manager.recordAction(player.getUniqueId(), activityId, 1));
manager.getConfiguration().stationAction(station.getId(), recipe.getId())
.ifPresent(credit -> manager.recordAction(player.getUniqueId(), credit.activityId(), credit.amount()));
}
}
7 changes: 6 additions & 1 deletion src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,12 @@ reset:
# is counted when the craft actually completes - instantly, or when a queued
# craft is claimed - so queueing and cancelling count nothing. A recipe with
# 'output-item: false' still counts, and one craft counts as one action
# however big the output stack is. An
# regardless of output stack size unless station-actions sets another amount. An
# activity with both 'station' and 'craft'/'profession' is a config error:
# the extra 'station' is reported at load and ignored.
# station-actions: optional recipe aliases for a station activity. Each
# <station>/<recipe> key gives the number of actions credited by one craft.
# The primary station recipe still gives one action. Use this for bulk recipes.
# click-commands: optional. Console commands run when the player clicks this
# activity's task in /activity AFTER it has already been revealed - the
# first click on a hidden task only reveals it, every later click runs
Expand Down Expand Up @@ -280,6 +283,8 @@ activities:
points: 1
daily-cap: 1
station: ingot-station/coal
station-actions:
ingot-station/coal-64: 16
# Tool station
tool_iron_pickaxe:
display: "#e6ca40&lForge Iron Pickaxes"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,35 @@ void specificRecipeOnlyMatchesThatRecipe() {
assertEquals(Optional.empty(), config.stationActivity("forge", "coal"));
}

@Test
void bulkCoalRecipeCreditsSixteenActionsWhileSmallRecipeCreditsOne() {
ActivityConfiguration config = configFor(
" coal:\n points: 1\n every: 16\n station: ingot-station/coal\n"
+ " station-actions:\n ingot-station/coal-64: 16\n");

assertEquals(Optional.of(new ActivityConfiguration.StationActionCredit("coal", 1)),
config.stationAction("ingot-station", "coal"));
assertEquals(Optional.of(new ActivityConfiguration.StationActionCredit("coal", 16)),
config.stationAction("ingot-station", "coal-64"));
assertEquals(Optional.empty(), config.stationAction("ingot-station", "coke"));
}

@Test
void invalidBulkAmountsDoNotCreditActions() {
ActivityConfiguration config = configFor(
" coal:\n points: 1\n station: ingot-station/coal\n station-actions:\n"
+ " ingot-station/fractional: 16.9\n"
+ " ingot-station/zero: 0\n"
+ " ingot-station/overflow: 2147483648\n"
+ " ingot-station/text: sixteen\n");

assertEquals(Optional.of(new ActivityConfiguration.StationActionCredit("coal", 1)),
config.stationAction("ingot-station", "coal"));
for (String recipe : java.util.List.of("fractional", "zero", "overflow", "text")) {
assertEquals(Optional.empty(), config.stationAction("ingot-station", recipe));
}
}

@Test
void specificRecipeBeatsWholeStation() {
ActivityConfiguration config = configFor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,4 +252,31 @@ void collectingCommandRewardFishingRodUpdatesTheRevealedTask() {
org.junit.jupiter.api.Assertions.assertEquals(1, manager.tasks(uuid).points());
}

@Test
void bulkCoalCraftCompletesSixteenActionQuestInOneCraft() {
var def = new ActivityDef("ingot_coal", "Make Coal", Material.COAL, null, 16, 1, 1);
var manager = net.tfminecraft.activitytf.managers.TestManagers.manager(def);
net.tfminecraft.activitytf.managers.TestManagers.bukkit();
net.tfminecraft.activitytf.managers.TestManagers.storeLoaded(manager);
net.tfminecraft.activitytf.managers.TestManagers.guarantee(manager, def.id());
setField(manager.getConfiguration(), ActivityConfiguration.class, "stationActivities",
Map.of("ingot-station/coal", "ingot_coal", "ingot-station/coal-64", "ingot_coal"));
setField(manager.getConfiguration(), ActivityConfiguration.class, "stationActionAmounts",
Map.of("ingot-station/coal-64", 16));
UUID uuid = UUID.randomUUID();
UUID smallUuid = UUID.randomUUID();
manager.reveal(uuid, 0);
manager.reveal(smallUuid, 0);
var listener = new MmoItemsStationListener(manager);
var player = stubPlayer(uuid);

listener.onUseCraftingStation(event(stubPlayer(smallUuid), station("ingot-station"), recipe("coal"), null));
assertEquals(1, manager.tasks(smallUuid).count(def.id()));
assertEquals(0, manager.tasks(smallUuid).points());

listener.onUseCraftingStation(event(player, station("ingot-station"), recipe("coal-64"), null));
assertEquals(16, manager.tasks(uuid).count(def.id()));
assertEquals(1, manager.tasks(uuid).points());
}

}