Commit 91000821 authored by Akka's avatar Akka Committed by Luke H-W
Browse files

quest fix & personal line impl

parent 7bae35f5
...@@ -104,6 +104,8 @@ public class GameData { ...@@ -104,6 +104,8 @@ public class GameData {
@Getter private static final Int2ObjectMap<ActivityData> activityDataMap = new Int2ObjectOpenHashMap<>(); @Getter private static final Int2ObjectMap<ActivityData> activityDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<ActivityWatcherData> activityWatcherDataMap = new Int2ObjectOpenHashMap<>(); @Getter private static final Int2ObjectMap<ActivityWatcherData> activityWatcherDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<MusicGameBasicData> musicGameBasicDataMap = new Int2ObjectOpenHashMap<>(); @Getter private static final Int2ObjectMap<MusicGameBasicData> musicGameBasicDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<PersonalLineData> personalLineDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<ChapterData> chapterDataMap = new Int2ObjectOpenHashMap<>();
// Cache // Cache
private static Map<Integer, List<Integer>> fetters = new HashMap<>(); private static Map<Integer, List<Integer>> fetters = new HashMap<>();
......
package emu.grasscutter.data.binout; package emu.grasscutter.data.binout;
import emu.grasscutter.game.quest.enums.LogicType;
import emu.grasscutter.game.quest.enums.QuestTrigger;
import emu.grasscutter.game.quest.enums.QuestType; import emu.grasscutter.game.quest.enums.QuestType;
import lombok.Data;
public class MainQuestData { public class MainQuestData {
private int id; private int id;
...@@ -42,12 +41,10 @@ public class MainQuestData { ...@@ -42,12 +41,10 @@ public class MainQuestData {
public SubQuestData[] getSubQuests() { public SubQuestData[] getSubQuests() {
return subQuests; return subQuests;
} }
@Data
public static class SubQuestData { public static class SubQuestData {
private int subId; private int subId;
private int order;
public int getSubId() {
return subId;
}
} }
} }
package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.FieldDefaults;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ResourceType(name = "ChapterExcelConfigData.json")
@Getter
@Setter
@FieldDefaults(level = AccessLevel.PRIVATE)
public class ChapterData extends GameResource {
int id;
int beginQuestId;
int endQuestId;
int needPlayerLevel;
public static final Map<Integer, ChapterData> beginQuestChapterMap = new HashMap<>();
public static final Map<Integer, ChapterData> endQuestChapterMap = new HashMap<>();
@Override
public int getId() {
return this.id;
}
@Override
public void onLoad() {
beginQuestChapterMap.put(beginQuestId, this);
beginQuestChapterMap.put(endQuestId, this);
}
}
package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.FieldDefaults;
import java.util.List;
@ResourceType(name = "PersonalLineExcelConfigData.json")
@Getter
@Setter
@FieldDefaults(level = AccessLevel.PRIVATE)
public class PersonalLineData extends GameResource {
int id;
int avatarID;
List<Integer> preQuestId;
int startQuestId;
int chapterId;
@Override
public int getId() {
return this.id;
}
}
...@@ -3,31 +3,36 @@ package emu.grasscutter.data.excels; ...@@ -3,31 +3,36 @@ package emu.grasscutter.data.excels;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import com.google.gson.annotations.SerializedName;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.quest.enums.LogicType; import emu.grasscutter.game.quest.enums.LogicType;
import emu.grasscutter.game.quest.enums.QuestTrigger; import emu.grasscutter.game.quest.enums.QuestTrigger;
import lombok.AccessLevel;
import lombok.Data;
import lombok.Getter;
import lombok.ToString;
import lombok.experimental.FieldDefaults;
@ResourceType(name = "QuestExcelConfigData.json") @ResourceType(name = "QuestExcelConfigData.json")
@Getter
@ToString
public class QuestData extends GameResource { public class QuestData extends GameResource {
private int subId; private int subId;
private int mainId; private int mainId;
private int order; private int order;
private long descTextMapHash; private long descTextMapHash;
private boolean finishParent; private boolean finishParent;
private boolean isRewind; private boolean isRewind;
private LogicType acceptCondComb; private LogicType acceptCondComb;
private QuestCondition[] acceptConditons;
private LogicType finishCondComb; private LogicType finishCondComb;
private QuestCondition[] finishConditons;
private LogicType failCondComb; private LogicType failCondComb;
private QuestCondition[] failConditons;
private List<QuestCondition> acceptCond;
private List<QuestParam> acceptCond; private List<QuestCondition> finishCond;
private List<QuestParam> finishCond; private List<QuestCondition> failCond;
private List<QuestParam> failCond;
private List<QuestExecParam> beginExec; private List<QuestExecParam> beginExec;
private List<QuestExecParam> finishExec; private List<QuestExecParam> finishExec;
private List<QuestExecParam> failExec; private List<QuestExecParam> failExec;
...@@ -60,67 +65,57 @@ public class QuestData extends GameResource { ...@@ -60,67 +65,57 @@ public class QuestData extends GameResource {
return acceptCondComb; return acceptCondComb;
} }
public QuestCondition[] getAcceptCond() { public List<QuestCondition> getAcceptCond() {
return acceptConditons; return acceptCond;
} }
public LogicType getFinishCondComb() { public LogicType getFinishCondComb() {
return finishCondComb; return finishCondComb;
} }
public QuestCondition[] getFinishCond() { public List<QuestCondition> getFinishCond() {
return finishConditons; return finishCond;
} }
public LogicType getFailCondComb() { public LogicType getFailCondComb() {
return failCondComb; return failCondComb;
} }
public QuestCondition[] getFailCond() { public List<QuestCondition> getFailCond() {
return failConditons; return failCond;
} }
public void onLoad() { public void onLoad() {
this.acceptConditons = acceptCond.stream().filter(p -> p._type != null).map(QuestCondition::new).toArray(QuestCondition[]::new); this.acceptCond = acceptCond.stream().filter(p -> p.type != null).toList();
acceptCond = null; this.finishCond = finishCond.stream().filter(p -> p.type != null).toList();
this.finishConditons = finishCond.stream().filter(p -> p._type != null).map(QuestCondition::new).toArray(QuestCondition[]::new); this.failCond = failCond.stream().filter(p -> p.type != null).toList();
finishCond = null;
this.failConditons = failCond.stream().filter(p -> p._type != null).map(QuestCondition::new).toArray(QuestCondition[]::new); this.beginExec = beginExec.stream().filter(p -> p.type != null).toList();
failCond = null; this.finishExec = finishExec.stream().filter(p -> p.type != null).toList();
} this.failExec = failExec.stream().filter(p -> p.type != null).toList();
public class QuestParam {
QuestTrigger _type;
int[] _param;
String _count;
} }
@Data
@FieldDefaults(level = AccessLevel.PRIVATE)
public class QuestExecParam { public class QuestExecParam {
QuestTrigger _type; @SerializedName("_type")
String[] _param; QuestTrigger type;
String _count; @SerializedName("_param")
String[] param;
@SerializedName("_count")
String count;
} }
@Data
public static class QuestCondition { public static class QuestCondition {
@SerializedName("_type")
private QuestTrigger type; private QuestTrigger type;
@SerializedName("_param")
private int[] param; private int[] param;
@SerializedName("_param_str")
private String paramStr;
@SerializedName("_count")
private String count; private String count;
public QuestCondition(QuestParam param) {
this.type = param._type;
this.param = param._param;
}
public QuestTrigger getType() {
return type;
}
public int[] getParam() {
return param;
}
public String getCount() {
return count;
}
} }
} }
...@@ -271,6 +271,8 @@ public class Inventory implements Iterable<GameItem> { ...@@ -271,6 +271,8 @@ public class Inventory implements Iterable<GameItem> {
this.player.getServer().getInventoryManager().upgradeAvatarFetterLevel(this.player, this.player.getTeamManager().getCurrentAvatarEntity().getAvatar(), count); this.player.getServer().getInventoryManager().upgradeAvatarFetterLevel(this.player, this.player.getTeamManager().getCurrentAvatarEntity().getAvatar(), count);
case 106 -> // Resin case 106 -> // Resin
this.player.getResinManager().addResin(count); this.player.getResinManager().addResin(count);
case 107 -> // Legendary Key
this.player.addLegendaryKey(count);
case 201 -> // Primogem case 201 -> // Primogem
this.player.setPrimogems(this.player.getPrimogems() + count); this.player.setPrimogems(this.player.getPrimogems() + count);
case 202 -> // Mora case 202 -> // Mora
...@@ -292,6 +294,8 @@ public class Inventory implements Iterable<GameItem> { ...@@ -292,6 +294,8 @@ public class Inventory implements Iterable<GameItem> {
return this.player.getCrystals(); return this.player.getCrystals();
case 106: // Resin case 106: // Resin
return this.player.getProperty(PlayerProperty.PROP_PLAYER_RESIN); return this.player.getProperty(PlayerProperty.PROP_PLAYER_RESIN);
case 107: // Legendary Key
return this.player.getProperty(PlayerProperty.PROP_PLAYER_LEGENDARY_KEY);
case 204: // Home Coin case 204: // Home Coin
return this.player.getHomeCoin(); return this.player.getHomeCoin();
default: default:
...@@ -334,13 +338,15 @@ public class Inventory implements Iterable<GameItem> { ...@@ -334,13 +338,15 @@ public class Inventory implements Iterable<GameItem> {
player.setCrystals(player.getCrystals() - (cost.getCount() * quantity)); player.setCrystals(player.getCrystals() - (cost.getCount() * quantity));
case 106 -> // Resin case 106 -> // Resin
player.getResinManager().useResin(cost.getCount() * quantity); player.getResinManager().useResin(cost.getCount() * quantity);
case 107 -> // LegendaryKey
player.useLegendaryKey(cost.getCount() * quantity);
case 204 -> // Home Coin case 204 -> // Home Coin
player.setHomeCoin(player.getHomeCoin() - (cost.getCount() * quantity)); player.setHomeCoin(player.getHomeCoin() - (cost.getCount() * quantity));
default -> default ->
removeItem(getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(cost.getId()), cost.getCount() * quantity); removeItem(getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(cost.getId()), cost.getCount() * quantity);
} }
} }
if (reason != null) { // Do we need these? if (reason != null) { // Do we need these?
// getPlayer().sendPacket(new PacketItemAddHintNotify(changedItems, reason)); // getPlayer().sendPacket(new PacketItemAddHintNotify(changedItems, reason));
} }
......
...@@ -4,10 +4,10 @@ import dev.morphia.annotations.*; ...@@ -4,10 +4,10 @@ import dev.morphia.annotations.*;
import emu.grasscutter.GameConstants; import emu.grasscutter.GameConstants;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.PersonalLineData;
import emu.grasscutter.data.excels.PlayerLevelData; import emu.grasscutter.data.excels.PlayerLevelData;
import emu.grasscutter.data.excels.WeatherData; import emu.grasscutter.data.excels.WeatherData;
import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.database.DatabaseManager;
import emu.grasscutter.game.Account; import emu.grasscutter.game.Account;
import emu.grasscutter.game.CoopRequest; import emu.grasscutter.game.CoopRequest;
import emu.grasscutter.game.ability.AbilityManager; import emu.grasscutter.game.ability.AbilityManager;
...@@ -1597,7 +1597,17 @@ public class Player { ...@@ -1597,7 +1597,17 @@ public class Player {
getServer().getPlayers().values().removeIf(player1 -> player1 == this); getServer().getPlayers().values().removeIf(player1 -> player1 == this);
} }
public enum SceneLoadState { public int getLegendaryKey() {
return this.getProperty(PlayerProperty.PROP_PLAYER_LEGENDARY_KEY);
}
public synchronized void addLegendaryKey(int count) {
this.setProperty(PlayerProperty.PROP_PLAYER_LEGENDARY_KEY, getLegendaryKey() + count);
}
public synchronized void useLegendaryKey(int count) {
this.setProperty(PlayerProperty.PROP_PLAYER_LEGENDARY_KEY, getLegendaryKey() - count);
}
public enum SceneLoadState {
NONE(0), LOADING(1), INIT(2), LOADED(3); NONE(0), LOADING(1), INIT(2), LOADED(3);
private final int value; private final int value;
......
...@@ -39,7 +39,7 @@ public enum PlayerProperty { ...@@ -39,7 +39,7 @@ public enum PlayerProperty {
PROP_IS_ONLY_MP_WITH_PS_PLAYER (10024, 0, 1), // Is only MP with PlayStation players? [0, 1] PROP_IS_ONLY_MP_WITH_PS_PLAYER (10024, 0, 1), // Is only MP with PlayStation players? [0, 1]
PROP_PLAYER_MCOIN (10025), // Genesis Crystal (-inf, +inf) see 10015 PROP_PLAYER_MCOIN (10025), // Genesis Crystal (-inf, +inf) see 10015
PROP_PLAYER_WAIT_SUB_MCOIN (10026), PROP_PLAYER_WAIT_SUB_MCOIN (10026),
PROP_PLAYER_LEGENDARY_KEY (10027), PROP_PLAYER_LEGENDARY_KEY (10027,0),
PROP_IS_HAS_FIRST_SHARE (10028), PROP_IS_HAS_FIRST_SHARE (10028),
PROP_PLAYER_FORGE_POINT (10029, 0, 300_000), PROP_PLAYER_FORGE_POINT (10029, 0, 300_000),
PROP_CUR_CLIMATE_METER (10035), PROP_CUR_CLIMATE_METER (10035),
......
package emu.grasscutter.game.quest; package emu.grasscutter.game.quest;
import java.util.HashMap; import java.util.*;
import java.util.Map;
import emu.grasscutter.server.packet.send.PacketCodexDataUpdateNotify; import emu.grasscutter.server.packet.send.PacketCodexDataUpdateNotify;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
...@@ -31,20 +30,21 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; ...@@ -31,20 +30,21 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
@Entity(value = "quests", useDiscriminator = false) @Entity(value = "quests", useDiscriminator = false)
public class GameMainQuest { public class GameMainQuest {
@Id private ObjectId id; @Id private ObjectId id;
@Indexed private int ownerUid; @Indexed private int ownerUid;
@Transient private Player owner; @Transient private Player owner;
private Map<Integer, GameQuest> childQuests; private Map<Integer, GameQuest> childQuests;
private int parentQuestId; private int parentQuestId;
private int[] questVars; private int[] questVars;
private ParentQuestState state; private ParentQuestState state;
private boolean isFinished; private boolean isFinished;
List<QuestGroupSuite> questGroupSuites;
@Deprecated // Morphia only. Do not use. @Deprecated // Morphia only. Do not use.
public GameMainQuest() {} public GameMainQuest() {}
public GameMainQuest(Player player, int parentQuestId) { public GameMainQuest(Player player, int parentQuestId) {
this.owner = player; this.owner = player;
this.ownerUid = player.getUid(); this.ownerUid = player.getUid();
...@@ -52,12 +52,13 @@ public class GameMainQuest { ...@@ -52,12 +52,13 @@ public class GameMainQuest {
this.childQuests = new HashMap<>(); this.childQuests = new HashMap<>();
this.questVars = new int[5]; this.questVars = new int[5];
this.state = ParentQuestState.PARENT_QUEST_STATE_NONE; this.state = ParentQuestState.PARENT_QUEST_STATE_NONE;
this.questGroupSuites = new ArrayList<>();
} }
public int getParentQuestId() { public int getParentQuestId() {
return parentQuestId; return parentQuestId;
} }
public int getOwnerUid() { public int getOwnerUid() {
return ownerUid; return ownerUid;
} }
...@@ -74,7 +75,7 @@ public class GameMainQuest { ...@@ -74,7 +75,7 @@ public class GameMainQuest {
public Map<Integer, GameQuest> getChildQuests() { public Map<Integer, GameQuest> getChildQuests() {
return childQuests; return childQuests;
} }
public GameQuest getChildQuestById(int id) { public GameQuest getChildQuestById(int id) {
return this.getChildQuests().get(id); return this.getChildQuests().get(id);
} }
...@@ -91,26 +92,36 @@ public class GameMainQuest { ...@@ -91,26 +92,36 @@ public class GameMainQuest {
return isFinished; return isFinished;
} }
public void finish() { public List<QuestGroupSuite> getQuestGroupSuites() {
return questGroupSuites;
}
public void finish() {
this.isFinished = true; this.isFinished = true;
this.state = ParentQuestState.PARENT_QUEST_STATE_FINISHED; this.state = ParentQuestState.PARENT_QUEST_STATE_FINISHED;
this.getOwner().getSession().send(new PacketFinishedParentQuestUpdateNotify(this)); this.getOwner().getSession().send(new PacketFinishedParentQuestUpdateNotify(this));
this.getOwner().getSession().send(new PacketCodexDataUpdateNotify(this)); this.getOwner().getSession().send(new PacketCodexDataUpdateNotify(this));
this.save(); this.save();
// Add rewards // Add rewards
MainQuestData mainQuestData = GameData.getMainQuestDataMap().get(this.getParentQuestId()); MainQuestData mainQuestData = GameData.getMainQuestDataMap().get(this.getParentQuestId());
for (int rewardId : mainQuestData.getRewardIdList()) { for (int rewardId : mainQuestData.getRewardIdList()) {
RewardData rewardData = GameData.getRewardDataMap().get(rewardId); RewardData rewardData = GameData.getRewardDataMap().get(rewardId);
if (rewardData == null) { if (rewardData == null) {
continue; continue;
} }
getOwner().getInventory().addItemParamDatas(rewardData.getRewardItemList(), ActionReason.QuestReward); getOwner().getInventory().addItemParamDatas(rewardData.getRewardItemList(), ActionReason.QuestReward);
} }
// handoff main quest
if(mainQuestData.getSuggestTrackMainQuestList() != null){
Arrays.stream(mainQuestData.getSuggestTrackMainQuestList())
.forEach(getOwner().getQuestManager()::startMainQuest);
}
} }
public void save() { public void save() {
...@@ -122,16 +133,16 @@ public class GameMainQuest { ...@@ -122,16 +133,16 @@ public class GameMainQuest {
.setParentQuestId(getParentQuestId()) .setParentQuestId(getParentQuestId())
.setIsFinished(isFinished()) .setIsFinished(isFinished())
.setParentQuestState(getState().getValue()); .setParentQuestState(getState().getValue());
for (GameQuest quest : this.getChildQuests().values()) { for (GameQuest quest : this.getChildQuests().values()) {
ChildQuest childQuest = ChildQuest.newBuilder() ChildQuest childQuest = ChildQuest.newBuilder()
.setQuestId(quest.getQuestId()) .setQuestId(quest.getQuestId())
.setState(quest.getState().getValue()) .setState(quest.getState().getValue())
.build(); .build();
proto.addChildQuestList(childQuest); proto.addChildQuestList(childQuest);
} }
if (getQuestVars() != null) { if (getQuestVars() != null) {
for (int i : getQuestVars()) { for (int i : getQuestVars()) {
proto.addQuestVar(i); proto.addQuestVar(i);
......
...@@ -6,13 +6,16 @@ import emu.grasscutter.Grasscutter; ...@@ -6,13 +6,16 @@ import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.binout.MainQuestData; import emu.grasscutter.data.binout.MainQuestData;
import emu.grasscutter.data.binout.MainQuestData.SubQuestData; import emu.grasscutter.data.binout.MainQuestData.SubQuestData;
import emu.grasscutter.data.excels.ChapterData;
import emu.grasscutter.data.excels.QuestData; import emu.grasscutter.data.excels.QuestData;
import emu.grasscutter.data.excels.QuestData.QuestCondition; import emu.grasscutter.data.excels.QuestData.QuestCondition;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.quest.enums.LogicType; import emu.grasscutter.game.quest.enums.LogicType;
import emu.grasscutter.game.quest.enums.QuestState; import emu.grasscutter.game.quest.enums.QuestState;
import emu.grasscutter.game.quest.enums.QuestTrigger;
import emu.grasscutter.net.proto.ChapterStateOuterClass;
import emu.grasscutter.net.proto.QuestOuterClass.Quest; import emu.grasscutter.net.proto.QuestOuterClass.Quest;
import emu.grasscutter.server.packet.send.PacketCodexDataUpdateNotify; import emu.grasscutter.server.packet.send.PacketChapterStateNotify;
import emu.grasscutter.server.packet.send.PacketQuestListUpdateNotify; import emu.grasscutter.server.packet.send.PacketQuestListUpdateNotify;
import emu.grasscutter.server.packet.send.PacketQuestProgressUpdateNotify; import emu.grasscutter.server.packet.send.PacketQuestProgressUpdateNotify;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
...@@ -21,21 +24,21 @@ import emu.grasscutter.utils.Utils; ...@@ -21,21 +24,21 @@ import emu.grasscutter.utils.Utils;
public class GameQuest { public class GameQuest {
@Transient private GameMainQuest mainQuest; @Transient private GameMainQuest mainQuest;
@Transient private QuestData questData; @Transient private QuestData questData;
private int questId; private int questId;
private int mainQuestId; private int mainQuestId;
private QuestState state; private QuestState state;
private int startTime; private int startTime;
private int acceptTime; private int acceptTime;
private int finishTime; private int finishTime;
private int[] finishProgressList; private int[] finishProgressList;
private int[] failProgressList; private int[] failProgressList;
@Deprecated // Morphia only. Do not use. @Deprecated // Morphia only. Do not use.
public GameQuest() {} public GameQuest() {}
public GameQuest(GameMainQuest mainQuest, QuestData questData) { public GameQuest(GameMainQuest mainQuest, QuestData questData) {
this.mainQuest = mainQuest; this.mainQuest = mainQuest;
this.questId = questData.getId(); this.questId = questData.getId();
...@@ -44,18 +47,31 @@ public class GameQuest { ...@@ -44,18 +47,31 @@ public class GameQuest {
this.acceptTime = Utils.getCurrentSeconds(); this.acceptTime = Utils.getCurrentSeconds();
this.startTime = this.acceptTime; this.startTime = this.acceptTime;
this.state = QuestState.QUEST_STATE_UNFINISHED; this.state = QuestState.QUEST_STATE_UNFINISHED;
if (questData.getFinishCond() != null && questData.getAcceptCond().length != 0) { if (questData.getFinishCond() != null && questData.getAcceptCond().size() != 0) {
this.finishProgressList = new int[questData.getFinishCond().length]; this.finishProgressList = new int[questData.getFinishCond().size()];
} }
if (questData.getFailCond() != null && questData.getFailCond().length != 0) { if (questData.getFailCond() != null && questData.getFailCond().size() != 0) {
this.failProgressList = new int[questData.getFailCond().length]; this.failProgressList = new int[questData.getFailCond().size()];
} }
this.mainQuest.getChildQuests().put(this.questId, this); this.mainQuest.getChildQuests().put(this.questId, this);
this.getData().getBeginExec().forEach(e -> getOwner().getServer().getQuestHandler().triggerExec(this, e, e.getParam()));
this.getOwner().getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_QUEST_STATE_EQUAL, this.questId, this.state.getValue());
if (ChapterData.beginQuestChapterMap.containsKey(questId)){
mainQuest.getOwner().sendPacket(new PacketChapterStateNotify(
ChapterData.beginQuestChapterMap.get(questId).getId(),
ChapterStateOuterClass.ChapterState.CHAPTER_STATE_BEGIN
));
}
Grasscutter.getLogger().debug("Quest {} is started", questId);
} }
public GameMainQuest getMainQuest() { public GameMainQuest getMainQuest() {
return mainQuest; return mainQuest;
} }
...@@ -63,7 +79,7 @@ public class GameQuest { ...@@ -63,7 +79,7 @@ public class GameQuest {
public void setMainQuest(GameMainQuest mainQuest) { public void setMainQuest(GameMainQuest mainQuest) {
this.mainQuest = mainQuest; this.mainQuest = mainQuest;
} }
public Player getOwner() { public Player getOwner() {
return getMainQuest().getOwner(); return getMainQuest().getOwner();
} }
...@@ -116,11 +132,11 @@ public class GameQuest { ...@@ -116,11 +132,11 @@ public class GameQuest {
public void setFinishTime(int finishTime) { public void setFinishTime(int finishTime) {
this.finishTime = finishTime; this.finishTime = finishTime;
} }
public int[] getFinishProgressList() { public int[] getFinishProgressList() {
return finishProgressList; return finishProgressList;
} }
public void setFinishProgress(int index, int value) { public void setFinishProgress(int index, int value) {
finishProgressList[index] = value; finishProgressList[index] = value;
} }
...@@ -128,7 +144,7 @@ public class GameQuest { ...@@ -128,7 +144,7 @@ public class GameQuest {
public int[] getFailProgressList() { public int[] getFailProgressList() {
return failProgressList; return failProgressList;
} }
public void setFailProgress(int index, int value) { public void setFailProgress(int index, int value) {
failProgressList[index] = value; failProgressList[index] = value;
} }
...@@ -136,16 +152,16 @@ public class GameQuest { ...@@ -136,16 +152,16 @@ public class GameQuest {
public void finish() { public void finish() {
this.state = QuestState.QUEST_STATE_FINISHED; this.state = QuestState.QUEST_STATE_FINISHED;
this.finishTime = Utils.getCurrentSeconds(); this.finishTime = Utils.getCurrentSeconds();
if (this.getFinishProgressList() != null) { if (this.getFinishProgressList() != null) {
for (int i = 0 ; i < getFinishProgressList().length; i++) { for (int i = 0 ; i < getFinishProgressList().length; i++) {
getFinishProgressList()[i] = 1; getFinishProgressList()[i] = 1;
} }
} }
this.getOwner().getSession().send(new PacketQuestProgressUpdateNotify(this)); this.getOwner().getSession().send(new PacketQuestProgressUpdateNotify(this));
this.getOwner().getSession().send(new PacketQuestListUpdateNotify(this)); this.getOwner().getSession().send(new PacketQuestListUpdateNotify(this));
if (this.getData().finishParent()) { if (this.getData().finishParent()) {
// This quest finishes the questline - the main quest will also save the quest to db so we dont have to call save() here // This quest finishes the questline - the main quest will also save the quest to db so we dont have to call save() here
this.getMainQuest().finish(); this.getMainQuest().finish();
...@@ -154,8 +170,21 @@ public class GameQuest { ...@@ -154,8 +170,21 @@ public class GameQuest {
this.tryAcceptQuestLine(); this.tryAcceptQuestLine();
this.save(); this.save();
} }
this.getData().getFinishExec().forEach(e -> getOwner().getServer().getQuestHandler().triggerExec(this, e, e.getParam()));
this.getOwner().getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_QUEST_STATE_EQUAL, this.questId, this.state.getValue());
if (ChapterData.endQuestChapterMap.containsKey(questId)){
mainQuest.getOwner().sendPacket(new PacketChapterStateNotify(
ChapterData.endQuestChapterMap.get(questId).getId(),
ChapterStateOuterClass.ChapterState.CHAPTER_STATE_END
));
}
Grasscutter.getLogger().debug("Quest {} is finished", questId);
} }
public boolean tryAcceptQuestLine() { public boolean tryAcceptQuestLine() {
try { try {
MainQuestData questConfig = GameData.getMainQuestDataMap().get(this.getMainQuestId()); MainQuestData questConfig = GameData.getMainQuestDataMap().get(this.getMainQuestId());
...@@ -167,16 +196,17 @@ public class GameQuest { ...@@ -167,16 +196,17 @@ public class GameQuest {
QuestData questData = GameData.getQuestDataMap().get(subQuest.getSubId()); QuestData questData = GameData.getQuestDataMap().get(subQuest.getSubId());
if (questData == null || questData.getAcceptCond() == null if (questData == null || questData.getAcceptCond() == null
|| questData.getAcceptCond().length == 0) { || questData.getAcceptCond().size() == 0) {
continue; continue;
} }
int[] accept = new int[questData.getAcceptCond().length]; int[] accept = new int[questData.getAcceptCond().size()];
// TODO // TODO
for (int i = 0; i < questData.getAcceptCond().length; i++) { for (int i = 0; i < questData.getAcceptCond().size(); i++) {
QuestCondition condition = questData.getAcceptCond()[i]; QuestCondition condition = questData.getAcceptCond().get(i);
boolean result = getOwner().getServer().getQuestHandler().triggerCondition(this, condition, boolean result = getOwner().getServer().getQuestHandler().triggerCondition(this, condition,
condition.getParamStr(),
condition.getParam()); condition.getParam());
accept[i] = result ? 1 : 0; accept[i] = result ? 1 : 0;
...@@ -195,11 +225,11 @@ public class GameQuest { ...@@ -195,11 +225,11 @@ public class GameQuest {
return false; return false;
} }
public void save() { public void save() {
getMainQuest().save(); getMainQuest().save();
} }
public Quest toProto() { public Quest toProto() {
Quest.Builder proto = Quest.newBuilder() Quest.Builder proto = Quest.newBuilder()
.setQuestId(this.getQuestId()) .setQuestId(this.getQuestId())
...@@ -208,19 +238,19 @@ public class GameQuest { ...@@ -208,19 +238,19 @@ public class GameQuest {
.setStartTime(this.getStartTime()) .setStartTime(this.getStartTime())
.setStartGameTime(438) .setStartGameTime(438)
.setAcceptTime(this.getAcceptTime()); .setAcceptTime(this.getAcceptTime());
if (this.getFinishProgressList() != null) { if (this.getFinishProgressList() != null) {
for (int i : this.getFinishProgressList()) { for (int i : this.getFinishProgressList()) {
proto.addFinishProgressList(i); proto.addFinishProgressList(i);
} }
} }
if (this.getFailProgressList() != null) { if (this.getFailProgressList() != null) {
for (int i : this.getFailProgressList()) { for (int i : this.getFailProgressList()) {
proto.addFailProgressList(i); proto.addFailProgressList(i);
} }
} }
return proto.build(); return proto.build();
} }
} }
package emu.grasscutter.game.quest;
import dev.morphia.annotations.Entity;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Data;
import lombok.experimental.FieldDefaults;
@Entity
@Data
@Builder(builderMethodName = "of")
@FieldDefaults(level = AccessLevel.PRIVATE)
public class QuestGroupSuite {
int scene;
int group;
int suite;
}
package emu.grasscutter.game.quest; package emu.grasscutter.game.quest;
import java.util.HashSet; import java.util.*;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.binout.MainQuestData;
import emu.grasscutter.data.excels.QuestData; import emu.grasscutter.data.excels.QuestData;
import emu.grasscutter.data.excels.QuestData.QuestCondition; import emu.grasscutter.data.excels.QuestData.QuestCondition;
import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.quest.enums.ParentQuestState;
import emu.grasscutter.game.quest.enums.QuestTrigger; import emu.grasscutter.game.quest.enums.QuestTrigger;
import emu.grasscutter.game.quest.enums.LogicType; import emu.grasscutter.game.quest.enums.LogicType;
import emu.grasscutter.game.quest.enums.QuestState; import emu.grasscutter.game.quest.enums.QuestState;
import emu.grasscutter.server.packet.send.PacketFinishedParentQuestUpdateNotify; import emu.grasscutter.server.packet.send.*;
import emu.grasscutter.server.packet.send.PacketQuestListUpdateNotify;
import emu.grasscutter.server.packet.send.PacketQuestProgressUpdateNotify;
import emu.grasscutter.server.packet.send.PacketServerCondMeetQuestListUpdateNotify;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class QuestManager { public class QuestManager {
private final Player player; private final Player player;
private final Int2ObjectMap<GameMainQuest> quests; private final Int2ObjectMap<GameMainQuest> quests;
public QuestManager(Player player) { public QuestManager(Player player) {
this.player = player; this.player = player;
this.quests = new Int2ObjectOpenHashMap<>(); this.quests = new Int2ObjectOpenHashMap<>();
...@@ -122,40 +121,56 @@ public class QuestManager { ...@@ -122,40 +121,56 @@ public class QuestManager {
return quest; return quest;
} }
public void startMainQuest(int mainQuestId){
public void triggerEvent(QuestTrigger condType, int... params) { var mainQuestData = GameData.getMainQuestDataMap().get(mainQuestId);
if (mainQuestData == null){
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);
}
public void triggerEvent(QuestTrigger condType, String paramStr, int... params) {
Grasscutter.getLogger().debug("Trigger Event {}, {}, {}", condType, paramStr, params);
Set<GameQuest> changedQuests = new HashSet<>(); Set<GameQuest> changedQuests = new HashSet<>();
this.forEachActiveQuest(quest -> { this.forEachActiveQuest(quest -> {
QuestData data = quest.getData(); QuestData data = quest.getData();
for (int i = 0; i < data.getFinishCond().length; i++) { for (int i = 0; i < data.getFinishCond().size(); i++) {
if (quest.getFinishProgressList() == null if (quest.getFinishProgressList() == null
|| quest.getFinishProgressList().length == 0 || quest.getFinishProgressList().length == 0
|| quest.getFinishProgressList()[i] == 1) { || quest.getFinishProgressList()[i] == 1) {
continue; continue;
} }
QuestCondition condition = data.getFinishCond()[i]; QuestCondition condition = data.getFinishCond().get(i);
if (condition.getType() != condType) { if (condition.getType() != condType) {
continue; continue;
} }
boolean result = getPlayer().getServer().getQuestHandler().triggerContent(quest, condition, params); boolean result = getPlayer().getServer().getQuestHandler().triggerContent(quest, condition, paramStr, params);
if (result) { if (result) {
quest.getFinishProgressList()[i] = 1; quest.getFinishProgressList()[i] = 1;
changedQuests.add(quest); changedQuests.add(quest);
} }
} }
}); });
for (GameQuest quest : changedQuests) { for (GameQuest quest : changedQuests) {
LogicType logicType = quest.getData().getFailCondComb(); LogicType logicType = quest.getData().getFailCondComb();
int[] progress = quest.getFinishProgressList(); int[] progress = quest.getFinishProgressList();
// Handle logical comb // Handle logical comb
boolean finish = LogicType.calculate(logicType, progress); boolean finish = LogicType.calculate(logicType, progress);
...@@ -169,6 +184,15 @@ public class QuestManager { ...@@ -169,6 +184,15 @@ public class QuestManager {
} }
} }
public List<QuestGroupSuite> getSceneGroupSuite(int sceneId) {
return getQuests().values().stream()
.filter(i -> i.getState() != ParentQuestState.PARENT_QUEST_STATE_FINISHED)
.map(GameMainQuest::getQuestGroupSuites)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.filter(i -> i.getScene() == sceneId)
.toList();
}
public void loadFromDatabase() { public void loadFromDatabase() {
List<GameMainQuest> quests = DatabaseHelper.getAllQuests(getPlayer()); List<GameMainQuest> quests = DatabaseHelper.getAllQuests(getPlayer());
......
...@@ -2,10 +2,12 @@ package emu.grasscutter.game.quest; ...@@ -2,10 +2,12 @@ package emu.grasscutter.game.quest;
import java.util.Set; import java.util.Set;
import emu.grasscutter.data.excels.QuestData;
import emu.grasscutter.game.quest.handlers.QuestExecHandler;
import org.reflections.Reflections; import org.reflections.Reflections;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.excels.QuestData.QuestCondition; import emu.grasscutter.data.excels.QuestData.*;
import emu.grasscutter.game.quest.handlers.QuestBaseHandler; import emu.grasscutter.game.quest.handlers.QuestBaseHandler;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
...@@ -14,32 +16,32 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; ...@@ -14,32 +16,32 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class ServerQuestHandler { public class ServerQuestHandler {
private final Int2ObjectMap<QuestBaseHandler> condHandlers; private final Int2ObjectMap<QuestBaseHandler> condHandlers;
private final Int2ObjectMap<QuestBaseHandler> contHandlers; private final Int2ObjectMap<QuestBaseHandler> contHandlers;
private final Int2ObjectMap<QuestBaseHandler> execHandlers; private final Int2ObjectMap<QuestExecHandler> execHandlers;
public ServerQuestHandler() { public ServerQuestHandler() {
this.condHandlers = new Int2ObjectOpenHashMap<>(); this.condHandlers = new Int2ObjectOpenHashMap<>();
this.contHandlers = new Int2ObjectOpenHashMap<>(); this.contHandlers = new Int2ObjectOpenHashMap<>();
this.execHandlers = new Int2ObjectOpenHashMap<>(); this.execHandlers = new Int2ObjectOpenHashMap<>();
this.registerHandlers(); this.registerHandlers();
} }
public void registerHandlers() { public void registerHandlers() {
this.registerHandlers(this.condHandlers, "emu.grasscutter.game.quest.conditions"); this.registerHandlers(this.condHandlers, "emu.grasscutter.game.quest.conditions", QuestBaseHandler.class);
this.registerHandlers(this.contHandlers, "emu.grasscutter.game.quest.content"); this.registerHandlers(this.contHandlers, "emu.grasscutter.game.quest.content", QuestBaseHandler.class);
this.registerHandlers(this.execHandlers, "emu.grasscutter.game.quest.exec"); this.registerHandlers(this.execHandlers, "emu.grasscutter.game.quest.exec", QuestExecHandler.class);
} }
public void registerHandlers(Int2ObjectMap<QuestBaseHandler> map, String packageName) { public <T> void registerHandlers(Int2ObjectMap<T> map, String packageName, Class<T> clazz) {
Reflections reflections = new Reflections(packageName); Reflections reflections = new Reflections(packageName);
Set<?> handlerClasses = reflections.getSubTypesOf(QuestBaseHandler.class); var handlerClasses = reflections.getSubTypesOf(clazz);
for (Object obj : handlerClasses) { for (var obj : handlerClasses) {
this.registerPacketHandler(map, (Class<? extends QuestBaseHandler>) obj); this.registerPacketHandler(map, obj);
} }
} }
public void registerPacketHandler(Int2ObjectMap<QuestBaseHandler> map, Class<? extends QuestBaseHandler> handlerClass) { public <T> void registerPacketHandler(Int2ObjectMap<T> map, Class<? extends T> handlerClass) {
try { try {
QuestValue opcode = handlerClass.getAnnotation(QuestValue.class); QuestValue opcode = handlerClass.getAnnotation(QuestValue.class);
...@@ -47,43 +49,44 @@ public class ServerQuestHandler { ...@@ -47,43 +49,44 @@ public class ServerQuestHandler {
return; return;
} }
QuestBaseHandler packetHandler = (QuestBaseHandler) handlerClass.newInstance(); map.put(opcode.value().getValue(), handlerClass.newInstance());
map.put(opcode.value().getValue(), packetHandler);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
// TODO make cleaner // TODO make cleaner
public boolean triggerCondition(GameQuest quest, QuestCondition condition, int... params) { public boolean triggerCondition(GameQuest quest, QuestCondition condition, String paramStr, int... params) {
QuestBaseHandler handler = condHandlers.get(condition.getType().getValue()); QuestBaseHandler handler = condHandlers.get(condition.getType().getValue());
if (handler == null || quest.getData() == null) { if (handler == null || quest.getData() == null) {
Grasscutter.getLogger().debug("Could not trigger condition {} at {}", condition.getType().getValue(), quest.getData());
return false; return false;
} }
return handler.execute(quest, condition, params); return handler.execute(quest, condition, paramStr, params);
} }
public boolean triggerContent(GameQuest quest, QuestCondition condition, int... params) { public boolean triggerContent(GameQuest quest, QuestCondition condition, String paramStr, int... params) {
QuestBaseHandler handler = contHandlers.get(condition.getType().getValue()); QuestBaseHandler handler = contHandlers.get(condition.getType().getValue());
if (handler == null || quest.getData() == null) { if (handler == null || quest.getData() == null) {
Grasscutter.getLogger().debug("Could not trigger content {} at {}", condition.getType().getValue(), quest.getData());
return false; return false;
} }
return handler.execute(quest, condition, params); return handler.execute(quest, condition, paramStr, params);
} }
public boolean triggerExec(GameQuest quest, QuestCondition condition, int... params) { public boolean triggerExec(GameQuest quest, QuestExecParam execParam, String... params) {
QuestBaseHandler handler = execHandlers.get(condition.getType().getValue()); QuestExecHandler handler = execHandlers.get(execParam.getType().getValue());
if (handler == null || quest.getData() == null) { if (handler == null || quest.getData() == null) {
Grasscutter.getLogger().debug("Could not trigger exec {} at {}", execParam.getType().getValue(), quest.getData());
return false; return false;
} }
return handler.execute(quest, condition, params); return handler.execute(quest, execParam, params);
} }
} }
...@@ -10,9 +10,9 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler; ...@@ -10,9 +10,9 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler;
public class BaseCondition extends QuestBaseHandler { public class BaseCondition extends QuestBaseHandler {
@Override @Override
public boolean execute(GameQuest quest, QuestCondition condition, int... params) { public boolean execute(GameQuest quest, QuestCondition condition, String paramStr, int... params) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return false; return false;
} }
} }
package emu.grasscutter.game.quest.conditions;
import emu.grasscutter.data.excels.QuestData.QuestCondition;
import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.QuestValue;
import emu.grasscutter.game.quest.enums.QuestTrigger;
import emu.grasscutter.game.quest.handlers.QuestBaseHandler;
@QuestValue(QuestTrigger.QUEST_COND_LUA_NOTIFY)
public class ConditionLuaNotify extends QuestBaseHandler {
@Override
public boolean execute(GameQuest quest, QuestCondition condition, String paramStr, int... params) {
return condition.getParam()[0] == Integer.parseInt(paramStr);
}
}
...@@ -10,8 +10,8 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler; ...@@ -10,8 +10,8 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler;
public class ConditionPlayerLevelEqualGreater extends QuestBaseHandler { public class ConditionPlayerLevelEqualGreater extends QuestBaseHandler {
@Override @Override
public boolean execute(GameQuest quest, QuestCondition condition, int... params) { public boolean execute(GameQuest quest, QuestCondition condition, String paramStr, int... params) {
return quest.getOwner().getLevel() >= params[0]; return quest.getOwner().getLevel() >= params[0];
} }
} }
...@@ -10,14 +10,14 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler; ...@@ -10,14 +10,14 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler;
public class ConditionStateEqual extends QuestBaseHandler { public class ConditionStateEqual extends QuestBaseHandler {
@Override @Override
public boolean execute(GameQuest quest, QuestCondition condition, int... params) { public boolean execute(GameQuest quest, QuestCondition condition, String paramStr, int... params) {
GameQuest checkQuest = quest.getOwner().getQuestManager().getQuestById(params[0]); GameQuest checkQuest = quest.getOwner().getQuestManager().getQuestById(params[0]);
if (checkQuest != null) { if (checkQuest != null) {
return checkQuest.getState().getValue() == params[1]; return checkQuest.getState().getValue() == params[1];
} }
return false; return false;
} }
} }
...@@ -10,9 +10,9 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler; ...@@ -10,9 +10,9 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler;
public class BaseContent extends QuestBaseHandler { public class BaseContent extends QuestBaseHandler {
@Override @Override
public boolean execute(GameQuest quest, QuestCondition condition, int... params) { public boolean execute(GameQuest quest, QuestCondition condition, String paramStr, int... params) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return false; return false;
} }
} }
package emu.grasscutter.game.quest.content;
import emu.grasscutter.data.excels.QuestData.QuestCondition;
import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.QuestValue;
import emu.grasscutter.game.quest.enums.QuestTrigger;
import emu.grasscutter.game.quest.handlers.QuestBaseHandler;
@QuestValue(QuestTrigger.QUEST_CONTENT_ADD_QUEST_PROGRESS)
public class ContentAddQuestProgress extends QuestBaseHandler {
@Override
public boolean execute(GameQuest quest, QuestCondition condition, String paramStr, int... params) {
return condition.getParam()[0] == params[0];
}
}
...@@ -10,8 +10,8 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler; ...@@ -10,8 +10,8 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler;
public class ContentCompleteTalk extends QuestBaseHandler { public class ContentCompleteTalk extends QuestBaseHandler {
@Override @Override
public boolean execute(GameQuest quest, QuestCondition condition, int... params) { public boolean execute(GameQuest quest, QuestCondition condition, String paramStr, int... params) {
return condition.getParam()[0] == params[0]; return condition.getParam()[0] == params[0];
} }
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment