Merge pull request #21 from BiosNod/questsFixes

Auto finish all hidden child quests + QuestListUpdateNotify queue deprecated
This commit is contained in:
Alexander Hartmann 2022-10-26 21:53:27 +02:00 committed by GitHub
commit 279557416d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 27 deletions

View File

@ -125,9 +125,36 @@ public class GameMainQuest {
}
public void finish() {
// Avoid recursion from child finish() in GameQuest
// when auto finishing all child quests with QUEST_STATE_UNFINISHED (below)
if (this.isFinished) {
Grasscutter.getLogger().debug("Skip main quest finishing because it's already finished");
return;
}
this.isFinished = true;
this.state = ParentQuestState.PARENT_QUEST_STATE_FINISHED;
/*
We also need to check for unfinished childQuests in this MainQuest
force them to complete and send a packet about this to the user,
because at some points there are special "invisible" child quests that control
some situations.
For example, subQuest 35312 is responsible for the event of leaving the territory
of the island with a statue and automatically returns the character back,
quest 35311 completes the main quest line 353 and starts 35501 from
new MainQuest 355 but if 35312 is not completed after the completion
of the main quest 353 - the character will not be able to leave place
(return again and again)
*/
this
.getChildQuests()
.values()
.stream()
.filter(p -> p.state != QuestState.QUEST_STATE_FINISHED)
.forEach(GameQuest::finish);
this.getOwner().getSession().send(new PacketFinishedParentQuestUpdateNotify(this));
this.getOwner().getSession().send(new PacketCodexDataUpdateNotify(this));
@ -304,11 +331,8 @@ public class GameMainQuest {
boolean shouldAccept = LogicType.calculate(subQuestWithCond.getQuestData().getAcceptCondComb(), accept);
if (shouldAccept) {
if (shouldAccept)
subQuestWithCond.start();
getQuestManager().getAddToQuestListUpdateNotify().add(subQuestWithCond);
}
}
this.save();
} catch (Exception e) {
@ -340,10 +364,8 @@ public class GameMainQuest {
boolean shouldFail = LogicType.calculate(subQuestWithCond.getQuestData().getFailCondComb(), subQuestWithCond.getFailProgressList());
if (shouldFail) {
if (shouldFail)
subQuestWithCond.fail();
getQuestManager().getAddToQuestListUpdateNotify().add(subQuestWithCond);
}
}
} catch (Exception e) {
@ -375,10 +397,8 @@ public class GameMainQuest {
boolean shouldFinish = LogicType.calculate(subQuestWithCond.getQuestData().getFinishCondComb(), subQuestWithCond.getFinishProgressList());
if (shouldFinish) {
if (shouldFinish)
subQuestWithCond.finish();
getQuestManager().getAddToQuestListUpdateNotify().add(subQuestWithCond);
}
}
} catch (Exception e) {
Grasscutter.getLogger().debug("An error occurred while trying to finish quest.", e);

View File

@ -35,7 +35,7 @@ public class GameQuest {
@Getter private int subQuestId;
@Getter private int mainQuestId;
@Getter @Setter
private QuestState state;
public QuestState state;
@Getter @Setter private int startTime;
@Getter @Setter private int acceptTime;
@ -156,6 +156,8 @@ public class GameQuest {
this.state = QuestState.QUEST_STATE_FINISHED;
this.finishTime = Utils.getCurrentSeconds();
getOwner().sendPacket(new PacketQuestListUpdateNotify(this));
if (getQuestData().finishParent()) {
// This quest finishes the questline - the main quest will also save the quest to db, so we don't have to call save() here
getMainQuest().finish();
@ -183,13 +185,17 @@ public class GameQuest {
this.state = QuestState.QUEST_STATE_FAILED;
this.finishTime = Utils.getCurrentSeconds();
getOwner().sendPacket(new PacketQuestListUpdateNotify(this));
//Some subQuests have conditions that subQuests fail (even from different MainQuests)
getOwner().getQuestManager().queueEvent(QuestTrigger.QUEST_CONTENT_QUEST_STATE_EQUAL, this.subQuestId, this.state.getValue(),0,0,0);
getOwner().getQuestManager().queueEvent(QuestTrigger.QUEST_COND_STATE_EQUAL, this.subQuestId, this.state.getValue(),0,0,0);
getQuestData().getFailExec().forEach(e -> getOwner().getServer().getQuestSystem().triggerExec(this, e, e.getParam()));
Grasscutter.getLogger().debug("Quest {} is failed", subQuestId);
}
// Return true if it did the rewind
public boolean rewind(boolean notifyDelete) {
getMainQuest().getChildQuests().values().stream().filter(p -> p.getQuestData().getOrder() > this.getQuestData().getOrder()).forEach(q -> {

View File

@ -27,7 +27,6 @@ public class QuestManager extends BasePlayerManager {
@Getter private final Player player;
@Getter private final Int2ObjectMap<GameMainQuest> mainQuests;
@Getter private List<GameQuest> addToQuestListUpdateNotify;
public static final ExecutorService eventExecutor;
static {
eventExecutor = new ThreadPoolExecutor(4, 4,
@ -78,7 +77,6 @@ public class QuestManager extends BasePlayerManager {
super(player);
this.player = player;
this.mainQuests = new Int2ObjectOpenHashMap<>();
this.addToQuestListUpdateNotify = new ArrayList<>();
}
public void onPlayerBorn() {
@ -208,6 +206,7 @@ public class QuestManager extends BasePlayerManager {
public GameQuest addQuest(int questId) {
QuestData questConfig = GameData.getQuestDataMap().get(questId);
if (questConfig == null) {
return null;
}
@ -225,19 +224,11 @@ public class QuestManager extends BasePlayerManager {
// Forcefully start
quest.start();
// Save main quest
mainQuest.save();
// Send packet
getPlayer().sendPacket(new PacketQuestListUpdateNotify(mainQuest.getChildQuests().values().stream()
.filter(p -> p.getState() != QuestState.QUEST_STATE_UNSTARTED)
.toList()));
checkQuestAlreadyFullfilled(quest);
return quest;
}
public void startMainQuest(int mainQuestId) {
var mainQuestData = GameData.getMainQuestDataMap().get(mainQuestId);
@ -351,11 +342,6 @@ public class QuestManager extends BasePlayerManager {
default:
Grasscutter.getLogger().error("Unhandled QuestTrigger {}", condType);
}
if (this.addToQuestListUpdateNotify.size() != 0) {
this.getPlayer().getSession().send(new PacketQuestListUpdateNotify(this.addToQuestListUpdateNotify));
this.addToQuestListUpdateNotify.clear();
}
}
/**