QuestManager.java 13.4 KB
Newer Older
Melledy's avatar
Melledy committed
1
2
package emu.grasscutter.game.quest;

akatatsu27's avatar
akatatsu27 committed
3
import java.beans.Transient;
Akka's avatar
Akka committed
4
import java.util.*;
Melledy's avatar
Melledy committed
5
import java.util.function.Consumer;
Akka's avatar
Akka committed
6
import java.util.stream.Collectors;
Melledy's avatar
Melledy committed
7

Akka's avatar
Akka committed
8
import emu.grasscutter.Grasscutter;
Melledy's avatar
Melledy committed
9
import emu.grasscutter.data.GameData;
Akka's avatar
Akka committed
10
import emu.grasscutter.data.binout.MainQuestData;
Melledy's avatar
Melledy committed
11
12
import emu.grasscutter.data.excels.QuestData;
import emu.grasscutter.data.excels.QuestData.QuestCondition;
Melledy's avatar
Melledy committed
13
import emu.grasscutter.database.DatabaseHelper;
Melledy's avatar
Melledy committed
14
import emu.grasscutter.game.player.BasePlayerManager;
Melledy's avatar
Melledy committed
15
import emu.grasscutter.game.player.Player;
Akka's avatar
Akka committed
16
import emu.grasscutter.game.quest.enums.ParentQuestState;
Melledy's avatar
Melledy committed
17
import emu.grasscutter.game.quest.enums.QuestTrigger;
18
import emu.grasscutter.game.quest.enums.LogicType;
Melledy's avatar
Melledy committed
19
import emu.grasscutter.game.quest.enums.QuestState;
Akka's avatar
Akka committed
20
import emu.grasscutter.server.packet.send.*;
akatatsu27's avatar
akatatsu27 committed
21
import emu.grasscutter.utils.Position;
Melledy's avatar
Melledy committed
22
23
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
akatatsu27's avatar
akatatsu27 committed
24
25
import jdk.jshell.spi.ExecutionControl;
import lombok.Getter;
Melledy's avatar
Melledy committed
26

Melledy's avatar
Melledy committed
27
public class QuestManager extends BasePlayerManager {
akatatsu27's avatar
akatatsu27 committed
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
	@Getter private final Player player;
    @Getter private Map<Integer,Integer> questGlobalVariables;

    @Getter private final Int2ObjectMap<GameMainQuest> mainQuests;
    @Getter private List<GameQuest> addToQuestListUpdateNotify;
    /*
        On SetPlayerBornDataReq, the server sends FinishedParentQuestNotify, with this exact
        parentQuestList. Captured on Game version 2.7
        Note: quest 40063 is already set to finished, with childQuest 4006406's state set to 3
    */

    private static Set<Integer> newPlayerMainQuests = Set.of(303,318,348,349,350,351,416,500,
        501,502,503,504,505,506,507,508,509,20000,20507,20509,21004,21005,21010,21011,21016,21017,
        21020,21021,21025,40063,70121,70124,70511,71010,71012,71013,71015,71016,71017,71555);

    /*
        On SetPlayerBornDataReq, the server sends ServerCondMeetQuestListUpdateNotify, with this exact
        addQuestIdList. Captured on Game version 2.7
        Total of 161...
     */
    /*
    private static Set<Integer> newPlayerServerCondMeetQuestListUpdateNotify = Set.of(3100101, 7104405, 2201601,
        7100801, 1907002, 7293301, 7193801, 7293401, 7193901, 7091001, 7190501, 7090901, 7190401, 7090801, 7190301,
        7195301, 7294801, 7195201, 7293001, 7094001, 7193501, 7293501, 7194001, 7293701, 7194201, 7194301, 7293801,
        7194901, 7194101, 7195001, 7294501, 7294101, 7194601, 7294301, 7194801, 7091301, 7290301, 2102401, 7216801,
        7190201, 7090701, 7093801, 7193301, 7292801, 7227828, 7093901, 7193401, 7292901, 7093701, 7193201, 7292701,
        7082402, 7093601, 7292601, 7193101, 2102301, 7093501, 7292501, 7193001, 7093401, 7292401, 7192901, 7093301,
        7292301, 7192801, 7294201, 7194701, 2100301, 7093201, 7212402, 7292201, 7192701, 7280001, 7293901, 7194401,
        7093101, 7212302, 7292101, 7192601, 7093001, 7292001, 7192501, 7216001, 7195101, 7294601, 2100900, 7092901,
        7291901, 7192401, 7092801, 7291801, 7192301, 2101501, 7092701, 7291701, 7192201, 7106401, 2100716, 7091801,
        7290801, 7191301, 7293201, 7193701, 7094201, 7294001, 7194501, 2102290, 7227829, 7193601, 7094101, 7091401,
        7290401, 7190901, 7106605, 7291601, 7192101, 7092601, 7291501, 7192001, 7092501, 7291401, 7191901, 7092401,
        7291301, 7191801, 7092301, 7211402, 7291201, 7191701, 7092201, 7291101, 7191601, 7092101, 7291001, 7191501,
        7092001, 7290901, 7191401, 7091901, 7290701, 7191201, 7091701, 7290601, 7191101, 7091601, 7290501, 7191001,
        7091501, 7290201, 7190701, 7091201, 7190601, 7091101, 7190101, 7090601, 7090501, 7090401, 7010701, 7090301,
        7090201, 7010103, 7090101
        );

    */
	public QuestManager(Player player) {
github-actions's avatar
github-actions committed
68
        super(player);
akatatsu27's avatar
akatatsu27 committed
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
		this.player = player;
        this.questGlobalVariables = player.getQuestGlobalVariables();
		this.mainQuests = new Int2ObjectOpenHashMap<>();
        this.addToQuestListUpdateNotify = new ArrayList<>();
	}

    public void onNewPlayerCreate() {

        List<GameMainQuest> newQuests = this.addMultMainQuests(newPlayerMainQuests);
        //getPlayer().sendPacket(new PacketServerCondMeetQuestListUpdateNotify(newPlayerServerCondMeetQuestListUpdateNotify));
        getPlayer().sendPacket(new PacketFinishedParentQuestUpdateNotify(newQuests));


    }

    public void onLogin() {

        List<GameMainQuest> activeQuests = getActiveMainQuests();
        for(GameMainQuest quest : activeQuests) {
            List<Position> rewindPos = quest.rewind(); // <pos, rotation>
            if(rewindPos != null) {
                getPlayer().getPosition().set(rewindPos.get(0));
                getPlayer().getRotation().set(rewindPos.get(1));
            }
        }
    }

    private List<GameMainQuest> addMultMainQuests(Set<Integer> mainQuestIds) {
        List<GameMainQuest> newQuests = new ArrayList<>();
        for(Integer id : mainQuestIds) {
            getMainQuests().put(id.intValue(),new GameMainQuest(this.player, id));
            getMainQuestById(id).save();
            newQuests.add(getMainQuestById(id));
        }
        return newQuests;
github-actions's avatar
github-actions committed
104
105
    }

akatatsu27's avatar
akatatsu27 committed
106
107
108
109
110
    /*
        Looking through mainQuests 72201-72208 and 72174, we can infer that a questGlobalVar's default value is 0
    */
    public Integer getQuestGlobalVarValue(Integer variable) {
        return this.questGlobalVariables.getOrDefault(variable,0);
github-actions's avatar
github-actions committed
111
112
    }

akatatsu27's avatar
akatatsu27 committed
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
    public void setQuestGlobalVarValue(Integer variable, Integer value) {
        Integer previousValue = this.questGlobalVariables.put(variable,value);
        Grasscutter.getLogger().debug("Changed questGlobalVar {} value from {} to {}", variable, previousValue==null ? 0: previousValue, value);
    }
    public void incQuestGlobalVarValue(Integer variable, Integer inc) {
        //
        Integer previousValue = this.questGlobalVariables.getOrDefault(variable,0);
        this.questGlobalVariables.put(variable,previousValue + inc);
        Grasscutter.getLogger().debug("Incremented questGlobalVar {} value from {} to {}", variable, previousValue, previousValue + inc);
    }
    //In MainQuest 998, dec is passed as a positive integer
    public void decQuestGlobalVarValue(Integer variable, Integer dec) {
        //
        Integer previousValue = this.questGlobalVariables.getOrDefault(variable,0);
        this.questGlobalVariables.put(variable,previousValue - dec);
        Grasscutter.getLogger().debug("Decremented questGlobalVar {} value from {} to {}", variable, previousValue, previousValue - dec);
github-actions's avatar
github-actions committed
129
130
    }

akatatsu27's avatar
akatatsu27 committed
131
132
133
134
	public GameMainQuest getMainQuestById(int mainQuestId) {
		return getMainQuests().get(mainQuestId);
	}

github-actions's avatar
github-actions committed
135
136
137
138
139
140
    public GameQuest getQuestById(int questId) {
        QuestData questConfig = GameData.getQuestDataMap().get(questId);
        if (questConfig == null) {
            return null;
        }

akatatsu27's avatar
akatatsu27 committed
141
		GameMainQuest mainQuest = getMainQuests().get(questConfig.getMainId());
github-actions's avatar
github-actions committed
142
143
144
145
146
147
148
149

        if (mainQuest == null) {
            return null;
        }

        return mainQuest.getChildQuests().get(questId);
    }

akatatsu27's avatar
akatatsu27 committed
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
	public void forEachQuest(Consumer<GameQuest> callback) {
		for (GameMainQuest mainQuest : getMainQuests().values()) {
			for (GameQuest quest : mainQuest.getChildQuests().values()) {
				callback.accept(quest);
			}
		}
	}

	public void forEachMainQuest(Consumer<GameMainQuest> callback) {
		for (GameMainQuest mainQuest : getMainQuests().values()) {
			callback.accept(mainQuest);
		}
	}

	// TODO
	public void forEachActiveQuest(Consumer<GameQuest> callback) {
		for (GameMainQuest mainQuest : getMainQuests().values()) {
			for (GameQuest quest : mainQuest.getChildQuests().values()) {
				if (quest.getState() != QuestState.QUEST_STATE_FINISHED) {
					callback.accept(quest);
				}
			}
		}
	}

	public GameMainQuest addMainQuest(QuestData questConfig) {
		GameMainQuest mainQuest = new GameMainQuest(getPlayer(), questConfig.getMainId());
		getMainQuests().put(mainQuest.getParentQuestId(), mainQuest);
github-actions's avatar
github-actions committed
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200

        getPlayer().sendPacket(new PacketFinishedParentQuestUpdateNotify(mainQuest));

        return mainQuest;
    }

    public GameQuest addQuest(int questId) {
        QuestData questConfig = GameData.getQuestDataMap().get(questId);
        if (questConfig == null) {
            return null;
        }

        // Main quest
        GameMainQuest mainQuest = this.getMainQuestById(questConfig.getMainId());

        // Create main quest if it doesnt exist
        if (mainQuest == null) {
            mainQuest = addMainQuest(questConfig);
        }

        // Sub quest
        GameQuest quest = mainQuest.getChildQuestById(questId);

akatatsu27's avatar
akatatsu27 committed
201
202
		// Forcefully start
		quest.start();
github-actions's avatar
github-actions committed
203
204
205
206

        // Save main quest
        mainQuest.save();

akatatsu27's avatar
akatatsu27 committed
207
208
209
210
		// Send packet
		getPlayer().sendPacket(new PacketQuestListUpdateNotify(mainQuest.getChildQuests().values().stream()
            .filter(p -> p.getState() != QuestState.QUEST_STATE_UNSTARTED)
            .toList()));
github-actions's avatar
github-actions committed
211
212
213
214

        return quest;
    }
    public void startMainQuest(int mainQuestId) {
Akka's avatar
Akka committed
215
216
        var mainQuestData = GameData.getMainQuestDataMap().get(mainQuestId);

github-actions's avatar
github-actions committed
217
        if (mainQuestData == null) {
Akka's avatar
Akka committed
218
219
220
221
222
223
224
225
226
227
228
229
            return;
        }

        Arrays.stream(mainQuestData.getSubQuests())
            .min(Comparator.comparingInt(MainQuestData.SubQuestData::getOrder))
            .map(MainQuestData.SubQuestData::getSubId)
            .ifPresent(this::addQuest);
    }
    public void triggerEvent(QuestTrigger condType, int... params) {
        triggerEvent(condType, "", params);
    }

akatatsu27's avatar
akatatsu27 committed
230
231
    //TODO
	public void triggerEvent(QuestTrigger condType, String paramStr, int... params) {
Akka's avatar
Akka committed
232
        Grasscutter.getLogger().debug("Trigger Event {}, {}, {}", condType, paramStr, params);
akatatsu27's avatar
akatatsu27 committed
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
        List<GameMainQuest> checkMainQuests = this.getMainQuests().values().stream()
            .filter(i -> i.getState() != ParentQuestState.PARENT_QUEST_STATE_FINISHED)
            .toList();
        switch(condType){
            //accept Conds
            case QUEST_COND_STATE_EQUAL:
            case QUEST_COND_STATE_NOT_EQUAL:
            case QUEST_COND_COMPLETE_TALK:
            case QUEST_COND_LUA_NOTIFY:
            case QUEST_COND_QUEST_VAR_EQUAL:
            case QUEST_COND_QUEST_VAR_GREATER:
            case QUEST_COND_QUEST_VAR_LESS:
            case QUEST_COND_PLAYER_LEVEL_EQUAL_GREATER:
            case QUEST_COND_QUEST_GLOBAL_VAR_EQUAL:
            case QUEST_COND_QUEST_GLOBAL_VAR_GREATER:
            case QUEST_COND_QUEST_GLOBAL_VAR_LESS:
                for (GameMainQuest mainquest : checkMainQuests) {
                    mainquest.tryAcceptSubQuests(condType, paramStr, params);
github-actions's avatar
github-actions committed
251
                }
akatatsu27's avatar
akatatsu27 committed
252
                break;
Akka's avatar
Akka committed
253

akatatsu27's avatar
akatatsu27 committed
254
255
256
257
            //fail Conds
            case QUEST_CONTENT_NOT_FINISH_PLOT:
                for (GameMainQuest mainquest : checkMainQuests) {
                    mainquest.tryFailSubQuests(condType, paramStr, params);
github-actions's avatar
github-actions committed
258
                }
akatatsu27's avatar
akatatsu27 committed
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
                break;
            //finish Conds
            case QUEST_CONTENT_COMPLETE_TALK:
            case QUEST_CONTENT_FINISH_PLOT:
            case QUEST_CONTENT_COMPLETE_ANY_TALK:
            case QUEST_CONTENT_LUA_NOTIFY:
            case QUEST_CONTENT_QUEST_VAR_EQUAL:
            case QUEST_CONTENT_QUEST_VAR_GREATER:
            case QUEST_CONTENT_QUEST_VAR_LESS:
            case QUEST_CONTENT_ENTER_DUNGEON:
            case QUEST_CONTENT_ENTER_ROOM:
            case QUEST_CONTENT_INTERACT_GADGET:
            case QUEST_CONTENT_TRIGGER_FIRE:
            case QUEST_CONTENT_UNLOCK_TRANS_POINT:
                for (GameMainQuest mainQuest : checkMainQuests) {
                    mainQuest.tryFinishSubQuests(condType, paramStr, params);
github-actions's avatar
github-actions committed
275
                }
akatatsu27's avatar
akatatsu27 committed
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
                break;

            //finish Or Fail Conds
            case QUEST_CONTENT_GAME_TIME_TICK:
            case QUEST_CONTENT_QUEST_STATE_EQUAL:
            case QUEST_CONTENT_ADD_QUEST_PROGRESS:
            case QUEST_CONTENT_LEAVE_SCENE:
                for (GameMainQuest mainQuest : checkMainQuests) {
                    mainQuest.tryFailSubQuests(condType, paramStr, params);
                    mainQuest.tryFinishSubQuests(condType, paramStr, params);
                }
                break;
            //QUEST_EXEC are handled directly by each subQuest

            //Unused
            case QUEST_CONTENT_QUEST_STATE_NOT_EQUAL:
            case QUEST_COND_PLAYER_CHOOSE_MALE:
            default:
                Grasscutter.getLogger().error("Unhandled QuestTrigger {}", condType);
github-actions's avatar
github-actions committed
295
        }
akatatsu27's avatar
akatatsu27 committed
296
297
298
299
300
301
        if(this.addToQuestListUpdateNotify.size() != 0){
            this.getPlayer().getSession().send(new PacketQuestListUpdateNotify(this.addToQuestListUpdateNotify));
            this.addToQuestListUpdateNotify.clear();
        }

	}
Melledy's avatar
Melledy committed
302

Akka's avatar
Akka committed
303
    public List<QuestGroupSuite> getSceneGroupSuite(int sceneId) {
akatatsu27's avatar
akatatsu27 committed
304
        return getMainQuests().values().stream()
Akka's avatar
Akka committed
305
306
307
308
309
310
311
            .filter(i -> i.getState() != ParentQuestState.PARENT_QUEST_STATE_FINISHED)
            .map(GameMainQuest::getQuestGroupSuites)
            .filter(Objects::nonNull)
            .flatMap(Collection::stream)
            .filter(i -> i.getScene() == sceneId)
            .toList();
    }
github-actions's avatar
github-actions committed
312
313
314
315
316
317
    public void loadFromDatabase() {
        List<GameMainQuest> quests = DatabaseHelper.getAllQuests(getPlayer());

        for (GameMainQuest mainQuest : quests) {
            mainQuest.setOwner(this.getPlayer());

akatatsu27's avatar
akatatsu27 committed
318
319
320
321
			for (GameQuest quest : mainQuest.getChildQuests().values()) {
				quest.setMainQuest(mainQuest);
				quest.setConfig(GameData.getQuestDataMap().get(quest.getSubQuestId()));
			}
github-actions's avatar
github-actions committed
322

akatatsu27's avatar
akatatsu27 committed
323
324
325
326
327
328
			this.getMainQuests().put(mainQuest.getParentQuestId(), mainQuest);
		}
	}

    public List<GameMainQuest> getActiveMainQuests() {
        return getMainQuests().values().stream().filter(p -> !p.isFinished()).toList();
github-actions's avatar
github-actions committed
329
    }
Melledy's avatar
Melledy committed
330
}