Skip to content

Commit

Permalink
Add caching ability to task types
Browse files Browse the repository at this point in the history
  • Loading branch information
ThatGravyBoat committed Mar 26, 2024
1 parent dafcb95 commit fdc17e2
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 8 deletions.
6 changes: 1 addition & 5 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
- Added JEI and EMI support for clicking on items in the UI (ThatGravyBoat)
- Fix NPE if quest was trying to be reset while never being progressed (ThatGravyBoat)
- Added dependency propagation visibility option (ThatGravyBoat)
- Optimize client quest entry propagation (MsRandom)
- Added loot condition "heracles:completed_quest" for loot tables (ThatGravyBoat)
- Fixed stats task performance in situations where there were many players online (ThatGravyBoat)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package earth.terrarium.heracles.api.tasks;

import earth.terrarium.heracles.api.quests.Quest;

import java.util.Collection;

public interface CacheableQuestTaskType<T extends QuestTask<?, ?, T>, C> extends QuestTaskType<T> {

C cache(Collection<Quest> quests);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,31 @@
import com.mojang.serialization.codecs.RecordCodecBuilder;
import earth.terrarium.heracles.Heracles;
import earth.terrarium.heracles.api.CustomizableQuestElement;
import earth.terrarium.heracles.api.quests.Quest;
import earth.terrarium.heracles.api.quests.QuestIcon;
import earth.terrarium.heracles.api.quests.QuestIcons;
import earth.terrarium.heracles.api.quests.defaults.ItemQuestIcon;
import earth.terrarium.heracles.api.tasks.CacheableQuestTaskType;
import earth.terrarium.heracles.api.tasks.PairQuestTask;
import earth.terrarium.heracles.api.tasks.QuestTask;
import earth.terrarium.heracles.api.tasks.QuestTaskType;
import earth.terrarium.heracles.api.tasks.storage.defaults.IntegerTaskStorage;
import earth.terrarium.heracles.common.handlers.quests.QuestHandler;
import net.minecraft.nbt.NumericTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.stats.Stats;
import org.jetbrains.annotations.ApiStatus;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

public record StatTask(
String id, String title, QuestIcon<?> icon, ResourceLocation stat, int target
) implements PairQuestTask<ResourceLocation, Integer, NumericTag, StatTask>, CustomizableQuestElement {

public static final QuestTaskType<StatTask> TYPE = new Type();
public static final CacheableQuestTaskType<StatTask, Set<ResourceLocation>> TYPE = new Type();

@Override
public NumericTag test(QuestTaskType<?> type, NumericTag progress, ResourceLocation stat, Integer amount) {
Expand Down Expand Up @@ -50,7 +59,7 @@ public QuestTaskType<StatTask> type() {
return TYPE;
}

private static class Type implements QuestTaskType<StatTask> {
private static class Type implements CacheableQuestTaskType<StatTask, Set<ResourceLocation>> {

@Override
public ResourceLocation id() {
Expand All @@ -67,5 +76,24 @@ public Codec<StatTask> codec(String id) {
Codec.INT.fieldOf("target").forGetter(StatTask::target)
).apply(instance, StatTask::new));
}

@Override
public Set<ResourceLocation> cache(Collection<Quest> collection) {
Set<ResourceLocation> stats = new HashSet<>();
for (Quest quest : collection) {
for (QuestTask<?, ?, ?> value : quest.tasks().values()) {
if (value instanceof StatTask task) {
stats.add(task.stat());
}
}
}
return stats;
}
}

@ApiStatus.Internal
public static boolean hasStat(ResourceLocation id) {
Set<ResourceLocation> stats = QuestHandler.getTaskCache(TYPE);
return stats != null && stats.contains(id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@
import com.teamresourceful.resourcefullib.common.utils.Scheduling;
import earth.terrarium.heracles.Heracles;
import earth.terrarium.heracles.api.quests.Quest;
import earth.terrarium.heracles.api.tasks.CacheableQuestTaskType;
import earth.terrarium.heracles.api.tasks.QuestTask;
import earth.terrarium.heracles.api.tasks.QuestTaskType;
import earth.terrarium.heracles.common.utils.ModUtils;
import net.minecraft.core.RegistryAccess;
import net.minecraft.resources.RegistryOps;
import net.minecraft.resources.ResourceLocation;

import java.io.File;
import java.io.Reader;
Expand All @@ -29,6 +33,7 @@ public class QuestHandler {
private static final Map<String, Quest> QUESTS = HashBiMap.create();
private static final Set<String> QUEST_KEYS = Sets.newConcurrentHashSet();
private static final List<String> GROUPS = new ArrayList<>();
private static final Map<ResourceLocation, Object> TASK_CACHES = new HashMap<>();
private static Path lastPath;

private static final Map<String, ScheduledFuture<?>> SAVING_FUTURES = new HashMap<>();
Expand Down Expand Up @@ -59,6 +64,7 @@ public static void load(RegistryAccess access, Path path) {
value.dependencies().removeIf(Predicate.not(QUESTS::containsKey));
}
loadGroups(heraclesPath.resolve("groups.txt").toFile());
updateTaskCache();
}

private static void load(RegistryAccess access, Reader reader, String id, Map<String, Quest> quests) {
Expand Down Expand Up @@ -97,6 +103,7 @@ public static void markDirty(String id) {
return;
}
Quest quest = QUESTS.get(id);
updateTaskCache();
Path questsPath = lastPath.resolve("quests");
File file = new File(questsPath.toFile(), pickQuestPath(quest) + "/" + id + ".json");
JsonElement json = Quest.CODEC.encodeStart(RegistryOps.create(JsonOps.INSTANCE, Heracles.getRegistryAccess()), quest)
Expand Down Expand Up @@ -157,6 +164,7 @@ public static void upload(String id, Quest quest) {

public static void remove(String quest) {
QUESTS.remove(quest);
updateTaskCache();
QUEST_KEYS.remove(quest);
if (SAVING_FUTURES.containsKey(quest)) SAVING_FUTURES.get(quest).cancel(true);
SAVING_FUTURES.remove(quest);
Expand Down Expand Up @@ -197,4 +205,27 @@ public static List<String> groups() {
}
return GROUPS;
}

private static void updateTaskCache() {
TASK_CACHES.clear();
for (Quest quest : QUESTS.values()) {
for (QuestTask<?, ?, ?> task : quest.tasks().values()) {
if (TASK_CACHES.containsKey(task.type().id())) continue;
if (task.type() instanceof CacheableQuestTaskType<?, ?> cacheable) {
Object cache = cacheable.cache(QUESTS.values());
TASK_CACHES.put(cacheable.id(), cache);
} else {
TASK_CACHES.put(task.type().id(), null);
}
}
}
}

public static <T> T getTaskCache(CacheableQuestTaskType<?, T> type) {
return ModUtils.cast(TASK_CACHES.get(type.id()));
}

public static boolean isTaskUsed(QuestTaskType<?> type) {
return TASK_CACHES.containsKey(type.id());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import earth.terrarium.heracles.api.tasks.defaults.XpTask;
import earth.terrarium.heracles.common.handlers.progress.QuestProgressHandler;
import earth.terrarium.heracles.common.handlers.progress.QuestsProgress;
import earth.terrarium.heracles.common.handlers.quests.QuestHandler;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
Expand Down Expand Up @@ -62,6 +63,7 @@ public abstract class ServerPlayerMixin {
)
)
public void heracles$doTick(CallbackInfo ci) {
if (!QuestHandler.isTaskUsed(XpTask.TYPE)) return;
ServerPlayer player = (ServerPlayer) (Object) this;
QuestsProgress progress = QuestProgressHandler.getProgress(server, player.getUUID());
progress.testAndProgressTaskType(player, Pair.of(player, XpTask.Cause.GAINED_XP), XpTask.TYPE);
Expand All @@ -73,7 +75,7 @@ public abstract class ServerPlayerMixin {
)
public void heracles$awardStat(Stat<?> stat, int increment, CallbackInfo ci) {
ServerPlayer player = (ServerPlayer) (Object) this;
if (stat.getValue() instanceof ResourceLocation id) {
if (stat.getValue() instanceof ResourceLocation id && StatTask.hasStat(id)) {
QuestsProgress progress = QuestProgressHandler.getProgress(server, player.getUUID());
progress.testAndProgressTaskType(player, new Pair<>(id, this.stats.getValue(stat)), StatTask.TYPE);
}
Expand Down

0 comments on commit fdc17e2

Please sign in to comment.