Change way that finishProgressList is handled at login (#135)
Some checks failed
Build / Build-Server-Jar (push) Has been cancelled

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
This commit is contained in:
Nazrin 2024-10-21 19:07:03 -07:00 committed by GitHub
parent 9138b96a94
commit 3932bdead9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 39 additions and 24 deletions

View File

@ -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);
}
}
}

View File

@ -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);

View File

@ -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<GameMainQuest> activeQuests = getActiveMainQuests();
for (GameMainQuest quest : activeQuests) {
val rewindTarget = quest.getRewindTarget();
var rewindTarget = quest.getRewindTarget();
if (rewindTarget == null) rewindTarget = quest.getHighestActiveQuest();
val finalRewindTarget = rewindTarget;
List<Position> rewindPos = quest.rewind(); // <pos, rotation>
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();
}

View File

@ -101,7 +101,7 @@ public class QuestSystem extends BaseGameSystem {
}
public boolean initialCheckContent(GameQuest quest, int[] curProgress,
List<QuestContentCondition> conditions, LogicType logicType){
List<QuestContentCondition> 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<QuestContentCondition> 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);
}