From 3932bdead9f28dfce676cd3d46febf902a632812 Mon Sep 17 00:00:00 2001 From: Nazrin Date: Mon, 21 Oct 2024 19:07:03 -0700 Subject: [PATCH] Change way that finishProgressList is handled at login (#135) Quests that have isRewind=False cannot be rewindTargets checkAndUpdateContent saves the quest if Content changed Don't modify finishProgressList if it's from a login --- .../grasscutter/game/quest/GameMainQuest.java | 17 ++++++--- .../emu/grasscutter/game/quest/GameQuest.java | 2 +- .../grasscutter/game/quest/QuestManager.java | 36 +++++++++++-------- .../grasscutter/game/quest/QuestSystem.java | 8 +++-- 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java b/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java index 118a8584..6c3deaaf 100644 --- a/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java +++ b/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java @@ -4,6 +4,7 @@ import dev.morphia.annotations.Entity; import dev.morphia.annotations.Id; import dev.morphia.annotations.Indexed; import dev.morphia.annotations.Transient; +import emu.grasscutter.Grasscutter; import emu.grasscutter.Loggers; import emu.grasscutter.data.GameData; import emu.grasscutter.data.binout.ScriptSceneData; @@ -254,7 +255,7 @@ public class GameMainQuest { return null; } - public GameQuest getRewindTarget(){ + public GameQuest getHighestActiveQuest() { var activeQuests = getChildQuests().values().stream() .filter(p -> (p.getState() == QuestState.QUEST_STATE_UNFINISHED || p.getState() == QuestState.QUEST_STATE_FINISHED)).toList(); var highestActiveQuest = activeQuests.stream() @@ -266,7 +267,7 @@ public class GameMainQuest { var firstUnstarted = getChildQuests().values().stream() .filter(q -> q.getQuestData() != null && q.getState().getValue() != QuestState.QUEST_STATE_FINISHED.getValue()) .min(Comparator.comparingInt(a -> a.getQuestData().getOrder())); - if(firstUnstarted.isEmpty()){ + if (firstUnstarted.isEmpty()) { // all quests are probably finished, do don't rewind and maybe also set the mainquest to finished? return null; } @@ -274,14 +275,20 @@ public class GameMainQuest { //todo maybe try to accept quests if there is no active quest and no rewind target? //tryAcceptSubQuests(QuestTrigger.QUEST_COND_NONE, "", 0); } + return highestActiveQuest; + } + + public GameQuest getRewindTarget(){ + var highestActiveQuest = getHighestActiveQuest(); var highestOrder = highestActiveQuest.getQuestData().getOrder(); var rewindTarget = getChildQuests().values().stream() .filter(q -> q.getQuestData() != null) .filter(q -> q.getQuestData().isRewind() && q.getQuestData().getOrder() <= highestOrder) .max(Comparator.comparingInt(a -> a.getQuestData().getOrder())) - .orElse(highestActiveQuest); + .orElse(null); + Grasscutter.getLogger().trace("For quest {}, the rewindTarget is {}", this.getParentQuestId(), rewindTarget); return rewindTarget; } @@ -354,10 +361,10 @@ public class GameMainQuest { return true; } - public void checkProgress(){ + public void checkProgress(boolean shouldReset) { for (var quest : getChildQuests().values()){ if(quest.getState() == QuestState.QUEST_STATE_UNFINISHED) { - questManager.checkQuestAlreadyFullfilled(quest); + questManager.checkQuestAlreadyFulfilled(quest, shouldReset); } } } diff --git a/src/main/java/emu/grasscutter/game/quest/GameQuest.java b/src/main/java/emu/grasscutter/game/quest/GameQuest.java index 92f4015b..f9969c2a 100644 --- a/src/main/java/emu/grasscutter/game/quest/GameQuest.java +++ b/src/main/java/emu/grasscutter/game/quest/GameQuest.java @@ -101,7 +101,7 @@ public class GameQuest { triggerStateEvents(); getQuestData().getBeginExec().forEach(e -> getOwner().getServer().getQuestSystem().triggerExec(this, e, e.getParam())); - getOwner().getQuestManager().checkQuestAlreadyFullfilled(this); + getOwner().getQuestManager().checkQuestAlreadyFulfilled(this, true); getOwner().getDungeonEntryManager().checkQuestForDungeonEntryUpdate(this); Grasscutter.getLogger().debug("Quest {} is started", subQuestId); diff --git a/src/main/java/emu/grasscutter/game/quest/QuestManager.java b/src/main/java/emu/grasscutter/game/quest/QuestManager.java index b6cd5bae..79b018bc 100644 --- a/src/main/java/emu/grasscutter/game/quest/QuestManager.java +++ b/src/main/java/emu/grasscutter/game/quest/QuestManager.java @@ -1,20 +1,18 @@ package emu.grasscutter.game.quest; -import java.util.*; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; import emu.grasscutter.data.common.quest.SubQuestData; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; -import emu.grasscutter.game.quest.enums.*; +import emu.grasscutter.game.quest.enums.LogicType; +import emu.grasscutter.game.quest.enums.ParentQuestState; +import emu.grasscutter.game.quest.enums.QuestCond; +import emu.grasscutter.game.quest.enums.QuestContent; import emu.grasscutter.game.world.World; -import emu.grasscutter.server.packet.send.*; +import emu.grasscutter.server.packet.send.PacketFinishedParentQuestUpdateNotify; +import emu.grasscutter.server.packet.send.PacketQuestGlobalVarNotify; import emu.grasscutter.utils.Position; import io.netty.util.concurrent.FastThreadLocalThread; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; @@ -24,6 +22,12 @@ import lombok.val; import org.anime_game_servers.core.gi.enums.QuestState; import javax.annotation.Nonnull; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; public class QuestManager extends BasePlayerManager { @@ -106,18 +110,20 @@ public class QuestManager extends BasePlayerManager { public void onLogin() { List activeQuests = getActiveMainQuests(); for (GameMainQuest quest : activeQuests) { - val rewindTarget = quest.getRewindTarget(); + var rewindTarget = quest.getRewindTarget(); + if (rewindTarget == null) rewindTarget = quest.getHighestActiveQuest(); + val finalRewindTarget = rewindTarget; List rewindPos = quest.rewind(); // if (rewindPos != null) { getPlayer().getPosition().set(rewindPos.get(0)); getPlayer().getRotation().set(rewindPos.get(1)); } //execute all the beginExec before the rewind target on UNFINISHED quests on login only - quest.getChildQuests().values().stream().filter(p -> p.getQuestData().getOrder() < rewindTarget.getQuestData().getOrder() + quest.getChildQuests().values().stream().filter(p -> p.getQuestData().getOrder() < finalRewindTarget.getQuestData().getOrder() && p.getState().getValue() == QuestState.QUEST_STATE_UNFINISHED.getValue()).forEach(q -> { q.getQuestData().getBeginExec().forEach(e -> getPlayer().getServer().getQuestSystem().triggerExec(q, e, e.getParam())); }); - quest.checkProgress(); + quest.checkProgress(false); } player.getActivityManager().triggerActivityConditions(); } @@ -301,7 +307,7 @@ public class QuestManager extends BasePlayerManager { // Forcefully start quest.start(); - checkQuestAlreadyFullfilled(quest); + checkQuestAlreadyFulfilled(quest, true); return quest; } @@ -406,7 +412,7 @@ public class QuestManager extends BasePlayerManager { * TODO move content checks to use static informations where possible to allow direct already fulfilled checking * @param quest */ - public void checkQuestAlreadyFullfilled(GameQuest quest){ + public void checkQuestAlreadyFulfilled(GameQuest quest, boolean shouldReset) { Grasscutter.getGameServer().getScheduler().scheduleDelayedTask(() -> { val questSystem = getPlayer().getServer().getQuestSystem(); val questData = quest.getQuestData(); @@ -415,13 +421,13 @@ public class QuestManager extends BasePlayerManager { return; } - val shouldFinish = questSystem.initialCheckContent(quest, quest.getFinishProgressList(), questData.getFinishCond(), questData.getFinishCondComb()); + val shouldFinish = questSystem.initialCheckContent(quest, quest.getFinishProgressList(), questData.getFinishCond(), questData.getFinishCondComb(), shouldReset); if (shouldFinish) { quest.finish(false); return; } if(!questData.getFailCond().isEmpty()) { - val shouldFail = questSystem.initialCheckContent(quest, quest.getFailProgressList(), questData.getFailCond(), questData.getFailCondComb()); + val shouldFail = questSystem.initialCheckContent(quest, quest.getFailProgressList(), questData.getFailCond(), questData.getFailCondComb(), shouldReset); if (shouldFail) { quest.fail(); } diff --git a/src/main/java/emu/grasscutter/game/quest/QuestSystem.java b/src/main/java/emu/grasscutter/game/quest/QuestSystem.java index 7777969e..b8050452 100644 --- a/src/main/java/emu/grasscutter/game/quest/QuestSystem.java +++ b/src/main/java/emu/grasscutter/game/quest/QuestSystem.java @@ -101,7 +101,7 @@ public class QuestSystem extends BaseGameSystem { } public boolean initialCheckContent(GameQuest quest, int[] curProgress, - List conditions, LogicType logicType){ + List conditions, LogicType logicType, boolean shouldReset) { val owner = quest.getOwner(); var changed = false; int[] finished = new int[conditions.size()]; @@ -112,17 +112,18 @@ public class QuestSystem extends BaseGameSystem { val startingProgress = curProgress[i]; int result = handler.initialCheck(quest, quest.getQuestData(), condition); - curProgress[i] = result; + if (shouldReset) curProgress[i] = result; if (startingProgress != result) { changed = true; } finished[i] = handler.checkProgress(quest, condition, result) ? 1 : 0; } - if(changed) { + if (changed) { owner.getSession().send(new PacketQuestProgressUpdateNotify(quest)); } return LogicType.calculate(logicType, finished); } + public boolean checkAndUpdateContent(GameQuest quest, int[] curProgress, List conditions, LogicType logicType, QuestContent condType, String paramStr, int... params){ @@ -146,6 +147,7 @@ public class QuestSystem extends BaseGameSystem { } if(changed) { owner.getSession().send(new PacketQuestProgressUpdateNotify(quest)); + quest.save(); } return LogicType.calculate(logicType, finished); }