From a788828a9999cb038edbbcc790037bfde390eb84 Mon Sep 17 00:00:00 2001 From: Akka <104902222+Akka0@users.noreply.github.com> Date: Tue, 5 Jul 2022 20:41:07 +0800 Subject: [PATCH] quest fix & personal line impl --- proto/AddQuestContentProgressReq.proto | 13 +++ proto/AddQuestContentProgressRsp.proto | 11 ++ proto/ChapterState.proto | 10 ++ proto/ChapterStateNotify.proto | 25 +++++ proto/EvtEntityRenderersChangedNotify.proto | 17 +++ proto/LockedPersonallineData.proto | 17 +++ proto/PersonalLineAllDataReq.proto | 10 ++ proto/PersonalLineAllDataRsp.proto | 17 +++ proto/QueryFilter.proto | 8 ++ proto/QueryPathReq.proto | 28 +++++ proto/QueryPathRsp.proto | 21 ++++ proto/UnlockPersonalLineReq.proto | 11 ++ proto/UnlockPersonalLineRsp.proto | 15 +++ proto/Vector3Int.proto | 9 ++ .../java/emu/grasscutter/data/GameData.java | 2 + .../data/binout/MainQuestData.java | 11 +- .../grasscutter/data/excels/ChapterData.java | 37 ++++++ .../data/excels/PersonalLineData.java | 28 +++++ .../grasscutter/data/excels/QuestData.java | 105 +++++++++--------- .../grasscutter/game/inventory/Inventory.java | 8 +- .../emu/grasscutter/game/player/Player.java | 14 ++- .../game/props/PlayerProperty.java | 2 +- .../grasscutter/game/quest/GameMainQuest.java | 47 +++++--- .../emu/grasscutter/game/quest/GameQuest.java | 90 ++++++++++----- .../game/quest/QuestGroupSuite.java | 17 +++ .../grasscutter/game/quest/QuestManager.java | 70 ++++++++---- .../game/quest/ServerQuestHandler.java | 67 +++++------ .../game/quest/conditions/BaseCondition.java | 4 +- .../quest/conditions/ConditionLuaNotify.java | 17 +++ .../ConditionPlayerLevelEqualGreater.java | 4 +- .../quest/conditions/ConditionStateEqual.java | 10 +- .../game/quest/content/BaseContent.java | 4 +- .../content/ContentAddQuestProgress.java | 17 +++ .../quest/content/ContentCompleteTalk.java | 4 +- .../quest/content/ContentEnterDungeon.java | 4 +- .../game/quest/content/ContentEnterRoom.java | 17 +++ .../game/quest/content/ContentFinishPlot.java | 4 +- .../quest/content/ContentGameTimeTick.java | 23 ++++ .../quest/content/ContentInteractGadget.java | 17 +++ .../game/quest/content/ContentLuaNotify.java | 17 +++ .../quest/content/ContentQuestStateEqual.java | 23 ++++ .../game/quest/enums/QuestTrigger.java | 35 +++++- .../game/quest/exec/ExecAddQuestProgress.java | 24 ++++ .../game/quest/exec/ExecNotifyGroupLua.java | 34 ++++++ .../quest/exec/ExecRefreshGroupSuite.java | 39 +++++++ .../game/quest/handlers/QuestBaseHandler.java | 6 +- .../game/quest/handlers/QuestExecHandler.java | 10 ++ .../emu/grasscutter/game/world/Scene.java | 19 ++++ .../emu/grasscutter/scripts/ScriptLib.java | 5 + .../HandlerAddQuestContentProgressReq.java | 23 ++++ .../packet/recv/HandlerChangeGameTimeReq.java | 8 +- .../packet/recv/HandlerEnterSceneDoneReq.java | 6 + ...andlerEvtEntityRenderersChangedNotify.java | 30 +++++ .../packet/recv/HandlerGadgetInteractReq.java | 6 +- .../recv/HandlerPersonalLineAllDataReq.java | 17 +++ .../packet/recv/HandlerPostEnterSceneReq.java | 8 +- .../packet/recv/HandlerQueryPathReq.java | 11 +- .../recv/HandlerUnlockPersonalLineReq.java | 28 +++++ .../PacketAddQuestContentProgressRsp.java | 19 ++++ .../packet/send/PacketChapterStateNotify.java | 20 ++++ ...PacketEvtEntityRenderersChangedNotify.java | 14 +++ .../packet/send/PacketGroupSuiteNotify.java | 22 ++++ .../send/PacketPersonalLineAllDataRsp.java | 35 ++++++ .../packet/send/PacketQueryPathRsp.java | 22 ++++ .../send/PacketUnlockPersonalLineRsp.java | 20 ++++ 65 files changed, 1136 insertions(+), 200 deletions(-) create mode 100644 proto/AddQuestContentProgressReq.proto create mode 100644 proto/AddQuestContentProgressRsp.proto create mode 100644 proto/ChapterState.proto create mode 100644 proto/ChapterStateNotify.proto create mode 100644 proto/EvtEntityRenderersChangedNotify.proto create mode 100644 proto/LockedPersonallineData.proto create mode 100644 proto/PersonalLineAllDataReq.proto create mode 100644 proto/PersonalLineAllDataRsp.proto create mode 100644 proto/QueryFilter.proto create mode 100644 proto/QueryPathReq.proto create mode 100644 proto/QueryPathRsp.proto create mode 100644 proto/UnlockPersonalLineReq.proto create mode 100644 proto/UnlockPersonalLineRsp.proto create mode 100644 proto/Vector3Int.proto create mode 100644 src/main/java/emu/grasscutter/data/excels/ChapterData.java create mode 100644 src/main/java/emu/grasscutter/data/excels/PersonalLineData.java create mode 100644 src/main/java/emu/grasscutter/game/quest/QuestGroupSuite.java create mode 100644 src/main/java/emu/grasscutter/game/quest/conditions/ConditionLuaNotify.java create mode 100644 src/main/java/emu/grasscutter/game/quest/content/ContentAddQuestProgress.java create mode 100644 src/main/java/emu/grasscutter/game/quest/content/ContentEnterRoom.java create mode 100644 src/main/java/emu/grasscutter/game/quest/content/ContentGameTimeTick.java create mode 100644 src/main/java/emu/grasscutter/game/quest/content/ContentInteractGadget.java create mode 100644 src/main/java/emu/grasscutter/game/quest/content/ContentLuaNotify.java create mode 100644 src/main/java/emu/grasscutter/game/quest/content/ContentQuestStateEqual.java create mode 100644 src/main/java/emu/grasscutter/game/quest/exec/ExecAddQuestProgress.java create mode 100644 src/main/java/emu/grasscutter/game/quest/exec/ExecNotifyGroupLua.java create mode 100644 src/main/java/emu/grasscutter/game/quest/exec/ExecRefreshGroupSuite.java create mode 100644 src/main/java/emu/grasscutter/game/quest/handlers/QuestExecHandler.java create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerAddQuestContentProgressReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtEntityRenderersChangedNotify.java create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerPersonalLineAllDataReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerUnlockPersonalLineReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketAddQuestContentProgressRsp.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketChapterStateNotify.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketEvtEntityRenderersChangedNotify.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketPersonalLineAllDataRsp.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketQueryPathRsp.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketUnlockPersonalLineRsp.java diff --git a/proto/AddQuestContentProgressReq.proto b/proto/AddQuestContentProgressReq.proto new file mode 100644 index 000000000..7dc73118c --- /dev/null +++ b/proto/AddQuestContentProgressReq.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +option java_package = "emu.grasscutter.net.proto"; + +// CmdId: 417 +// EnetChannelId: 0 +// EnetIsReliable: true +// IsAllowClient: true +message AddQuestContentProgressReq { + uint32 content_type = 9; + uint32 param = 13; + uint32 add_progress = 11; +} diff --git a/proto/AddQuestContentProgressRsp.proto b/proto/AddQuestContentProgressRsp.proto new file mode 100644 index 000000000..fdfc27f33 --- /dev/null +++ b/proto/AddQuestContentProgressRsp.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +option java_package = "emu.grasscutter.net.proto"; + +// CmdId: 485 +// EnetChannelId: 0 +// EnetIsReliable: true +message AddQuestContentProgressRsp { + int32 retcode = 10; + uint32 content_type = 7; +} diff --git a/proto/ChapterState.proto b/proto/ChapterState.proto new file mode 100644 index 000000000..d0a23ddf8 --- /dev/null +++ b/proto/ChapterState.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; + +option java_package = "emu.grasscutter.net.proto"; + +enum ChapterState { + CHAPTER_STATE_INVALID = 0; + CHAPTER_STATE_UNABLE_TO_BEGIN = 1; + CHAPTER_STATE_BEGIN = 2; + CHAPTER_STATE_END = 3; +} diff --git a/proto/ChapterStateNotify.proto b/proto/ChapterStateNotify.proto new file mode 100644 index 000000000..0838691d2 --- /dev/null +++ b/proto/ChapterStateNotify.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; + +option java_package = "emu.grasscutter.net.proto"; + +import "ChapterState.proto"; + +// CmdId: 498 +// EnetChannelId: 0 +// EnetIsReliable: true +message ChapterStateNotify { + uint32 chapter_id = 1; + ChapterState chapter_state = 12; + NeedPlayerLevel need_player_level = 10; + NeedBeginTime need_begin_time = 14; + + message NeedPlayerLevel { + bool is_limit = 1; + uint32 config_need_player_level = 2; + } + + message NeedBeginTime { + bool is_limit = 1; + uint32 config_need_begin_time = 2; + } +} diff --git a/proto/EvtEntityRenderersChangedNotify.proto b/proto/EvtEntityRenderersChangedNotify.proto new file mode 100644 index 000000000..5c8a5da04 --- /dev/null +++ b/proto/EvtEntityRenderersChangedNotify.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +option java_package = "emu.grasscutter.net.proto"; + +import "EntityRendererChangedInfo.proto"; +import "ForwardType.proto"; + +// CmdId: 354 +// EnetChannelId: 0 +// EnetIsReliable: true +// IsAllowClient: true +message EvtEntityRenderersChangedNotify { + ForwardType forward_type = 2; + uint32 entity_id = 7; + bool is_server_cache = 15; + EntityRendererChangedInfo renderer_changed_info = 3; +} diff --git a/proto/LockedPersonallineData.proto b/proto/LockedPersonallineData.proto new file mode 100644 index 000000000..5ca8be3cd --- /dev/null +++ b/proto/LockedPersonallineData.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +option java_package = "emu.grasscutter.net.proto"; + +message LockedPersonallineData { + uint32 personal_line_id = 1; + LockReason lock_reason = 2; + oneof param { + uint32 chapter_id = 3; + uint32 level = 4; + } + + enum LockReason { + LOCK_REASON_LEVEL = 0; + LOCK_REASON_QUEST = 1; + } +} diff --git a/proto/PersonalLineAllDataReq.proto b/proto/PersonalLineAllDataReq.proto new file mode 100644 index 000000000..9365a3379 --- /dev/null +++ b/proto/PersonalLineAllDataReq.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; + +option java_package = "emu.grasscutter.net.proto"; + +// CmdId: 446 +// EnetChannelId: 0 +// EnetIsReliable: true +// IsAllowClient: true +message PersonalLineAllDataReq { +} diff --git a/proto/PersonalLineAllDataRsp.proto b/proto/PersonalLineAllDataRsp.proto new file mode 100644 index 000000000..eee4ad918 --- /dev/null +++ b/proto/PersonalLineAllDataRsp.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +option java_package = "emu.grasscutter.net.proto"; + +import "LockedPersonallineData.proto"; + +// CmdId: 433 +// EnetChannelId: 0 +// EnetIsReliable: true +message PersonalLineAllDataRsp { + int32 retcode = 1; + uint32 cur_finished_daily_task_count = 4; + uint32 legendary_key_count = 3; + repeated uint32 ongoing_personal_line_list = 13; + repeated uint32 can_be_unlocked_personal_line_list = 12; + repeated LockedPersonallineData locked_personal_line_list = 14; +} diff --git a/proto/QueryFilter.proto b/proto/QueryFilter.proto new file mode 100644 index 000000000..76a6c14f5 --- /dev/null +++ b/proto/QueryFilter.proto @@ -0,0 +1,8 @@ +syntax = "proto3"; + +option java_package = "emu.grasscutter.net.proto"; + +message QueryFilter { + int32 type_id = 1; + int32 area_mask = 2; +} diff --git a/proto/QueryPathReq.proto b/proto/QueryPathReq.proto new file mode 100644 index 000000000..e7c96c95e --- /dev/null +++ b/proto/QueryPathReq.proto @@ -0,0 +1,28 @@ +syntax = "proto3"; + +option java_package = "emu.grasscutter.net.proto"; + +import "QueryFilter.proto"; +import "Vector.proto"; +import "Vector3Int.proto"; + +// CmdId: 2309 +// EnetChannelId: 0 +// EnetIsReliable: true +// IsAllowClient: true +message QueryPathReq { + OptionType query_type = 9; + int32 query_id = 4; + uint32 scene_id = 8; + Vector source_pos = 14; + repeated Vector destination_pos = 11; + QueryFilter filter = 5; + Vector3Int destination_extend = 7; + Vector3Int source_extend = 15; + + enum OptionType { + OPTION_TYPE_NONE = 0; + OPTION_TYPE_NORMAL = 1; + OPTION_TYPE_FIRST_CAN_GO = 2; + } +} diff --git a/proto/QueryPathRsp.proto b/proto/QueryPathRsp.proto new file mode 100644 index 000000000..aba4e9329 --- /dev/null +++ b/proto/QueryPathRsp.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +option java_package = "emu.grasscutter.net.proto"; + +import "Vector.proto"; + +// CmdId: 2331 +// EnetChannelId: 0 +// EnetIsReliable: true +message QueryPathRsp { + int32 retcode = 14; + int32 query_id = 2; + PathStatusType query_status = 5; + repeated Vector corners = 12; + + enum PathStatusType { + PATH_STATUS_TYPE_FAIL = 0; + PATH_STATUS_TYPE_SUCC = 1; + PATH_STATUS_TYPE_PARTIAL = 2; + } +} diff --git a/proto/UnlockPersonalLineReq.proto b/proto/UnlockPersonalLineReq.proto new file mode 100644 index 000000000..582d5dc92 --- /dev/null +++ b/proto/UnlockPersonalLineReq.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +option java_package = "emu.grasscutter.net.proto"; + +// CmdId: 476 +// EnetChannelId: 0 +// EnetIsReliable: true +// IsAllowClient: true +message UnlockPersonalLineReq { + uint32 personal_line_id = 8; +} diff --git a/proto/UnlockPersonalLineRsp.proto b/proto/UnlockPersonalLineRsp.proto new file mode 100644 index 000000000..bddeb520e --- /dev/null +++ b/proto/UnlockPersonalLineRsp.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +option java_package = "emu.grasscutter.net.proto"; + +// CmdId: 472 +// EnetChannelId: 0 +// EnetIsReliable: true +message UnlockPersonalLineRsp { + int32 retcode = 7; + uint32 personal_line_id = 8; + oneof param { + uint32 level = 1; + uint32 chapter_id = 15; + } +} diff --git a/proto/Vector3Int.proto b/proto/Vector3Int.proto new file mode 100644 index 000000000..1cd44230a --- /dev/null +++ b/proto/Vector3Int.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +option java_package = "emu.grasscutter.net.proto"; + +message Vector3Int { + int32 x = 1; + int32 y = 2; + int32 z = 3; +} diff --git a/src/main/java/emu/grasscutter/data/GameData.java b/src/main/java/emu/grasscutter/data/GameData.java index 89bf06df1..dd2d60a6b 100644 --- a/src/main/java/emu/grasscutter/data/GameData.java +++ b/src/main/java/emu/grasscutter/data/GameData.java @@ -104,6 +104,8 @@ public class GameData { @Getter private static final Int2ObjectMap activityDataMap = new Int2ObjectOpenHashMap<>(); @Getter private static final Int2ObjectMap activityWatcherDataMap = new Int2ObjectOpenHashMap<>(); @Getter private static final Int2ObjectMap musicGameBasicDataMap = new Int2ObjectOpenHashMap<>(); + @Getter private static final Int2ObjectMap personalLineDataMap = new Int2ObjectOpenHashMap<>(); + @Getter private static final Int2ObjectMap chapterDataMap = new Int2ObjectOpenHashMap<>(); // Cache private static Map> fetters = new HashMap<>(); diff --git a/src/main/java/emu/grasscutter/data/binout/MainQuestData.java b/src/main/java/emu/grasscutter/data/binout/MainQuestData.java index 96075bd61..eda72e8a5 100644 --- a/src/main/java/emu/grasscutter/data/binout/MainQuestData.java +++ b/src/main/java/emu/grasscutter/data/binout/MainQuestData.java @@ -1,8 +1,7 @@ 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 lombok.Data; public class MainQuestData { private int id; @@ -42,12 +41,10 @@ public class MainQuestData { public SubQuestData[] getSubQuests() { return subQuests; } - + + @Data public static class SubQuestData { private int subId; - - public int getSubId() { - return subId; - } + private int order; } } diff --git a/src/main/java/emu/grasscutter/data/excels/ChapterData.java b/src/main/java/emu/grasscutter/data/excels/ChapterData.java new file mode 100644 index 000000000..e8436d5a2 --- /dev/null +++ b/src/main/java/emu/grasscutter/data/excels/ChapterData.java @@ -0,0 +1,37 @@ +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 beginQuestChapterMap = new HashMap<>(); + public static final Map endQuestChapterMap = new HashMap<>(); + + @Override + public int getId() { + return this.id; + } + + @Override + public void onLoad() { + beginQuestChapterMap.put(beginQuestId, this); + beginQuestChapterMap.put(endQuestId, this); + } +} diff --git a/src/main/java/emu/grasscutter/data/excels/PersonalLineData.java b/src/main/java/emu/grasscutter/data/excels/PersonalLineData.java new file mode 100644 index 000000000..f7b956898 --- /dev/null +++ b/src/main/java/emu/grasscutter/data/excels/PersonalLineData.java @@ -0,0 +1,28 @@ +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 preQuestId; + int startQuestId; + int chapterId; + + @Override + public int getId() { + return this.id; + } + +} diff --git a/src/main/java/emu/grasscutter/data/excels/QuestData.java b/src/main/java/emu/grasscutter/data/excels/QuestData.java index 7866eeb45..a0f34fc62 100644 --- a/src/main/java/emu/grasscutter/data/excels/QuestData.java +++ b/src/main/java/emu/grasscutter/data/excels/QuestData.java @@ -3,31 +3,36 @@ package emu.grasscutter.data.excels; import java.util.Arrays; import java.util.List; +import com.google.gson.annotations.SerializedName; import emu.grasscutter.data.GameResource; import emu.grasscutter.data.ResourceType; import emu.grasscutter.game.quest.enums.LogicType; 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") +@Getter +@ToString public class QuestData extends GameResource { private int subId; private int mainId; private int order; private long descTextMapHash; - + private boolean finishParent; private boolean isRewind; - + private LogicType acceptCondComb; - private QuestCondition[] acceptConditons; private LogicType finishCondComb; - private QuestCondition[] finishConditons; private LogicType failCondComb; - private QuestCondition[] failConditons; - - private List acceptCond; - private List finishCond; - private List failCond; + + private List acceptCond; + private List finishCond; + private List failCond; private List beginExec; private List finishExec; private List failExec; @@ -60,67 +65,57 @@ public class QuestData extends GameResource { return acceptCondComb; } - public QuestCondition[] getAcceptCond() { - return acceptConditons; + public List getAcceptCond() { + return acceptCond; } public LogicType getFinishCondComb() { return finishCondComb; } - public QuestCondition[] getFinishCond() { - return finishConditons; + public List getFinishCond() { + return finishCond; } public LogicType getFailCondComb() { return failCondComb; } - public QuestCondition[] getFailCond() { - return failConditons; + public List getFailCond() { + return failCond; } public void onLoad() { - this.acceptConditons = acceptCond.stream().filter(p -> p._type != null).map(QuestCondition::new).toArray(QuestCondition[]::new); - acceptCond = null; - this.finishConditons = finishCond.stream().filter(p -> p._type != null).map(QuestCondition::new).toArray(QuestCondition[]::new); - finishCond = null; - this.failConditons = failCond.stream().filter(p -> p._type != null).map(QuestCondition::new).toArray(QuestCondition[]::new); - failCond = null; - } - - public class QuestParam { - QuestTrigger _type; - int[] _param; - String _count; - } - - public class QuestExecParam { - QuestTrigger _type; - String[] _param; - String _count; - } - - public static class QuestCondition { - private QuestTrigger type; - private int[] param; - 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; - } + this.acceptCond = acceptCond.stream().filter(p -> p.type != null).toList(); + this.finishCond = finishCond.stream().filter(p -> p.type != null).toList(); + this.failCond = failCond.stream().filter(p -> p.type != null).toList(); + + this.beginExec = beginExec.stream().filter(p -> p.type != null).toList(); + this.finishExec = finishExec.stream().filter(p -> p.type != null).toList(); + this.failExec = failExec.stream().filter(p -> p.type != null).toList(); + } + + @Data + @FieldDefaults(level = AccessLevel.PRIVATE) + public class QuestExecParam { + @SerializedName("_type") + QuestTrigger type; + @SerializedName("_param") + String[] param; + @SerializedName("_count") + String count; + } + + @Data + public static class QuestCondition { + @SerializedName("_type") + private QuestTrigger type; + @SerializedName("_param") + private int[] param; + @SerializedName("_param_str") + private String paramStr; + @SerializedName("_count") + private String count; - public String getCount() { - return count; - } } } diff --git a/src/main/java/emu/grasscutter/game/inventory/Inventory.java b/src/main/java/emu/grasscutter/game/inventory/Inventory.java index 2f412fbad..a40a6ac5a 100644 --- a/src/main/java/emu/grasscutter/game/inventory/Inventory.java +++ b/src/main/java/emu/grasscutter/game/inventory/Inventory.java @@ -271,6 +271,8 @@ public class Inventory implements Iterable { this.player.getServer().getInventoryManager().upgradeAvatarFetterLevel(this.player, this.player.getTeamManager().getCurrentAvatarEntity().getAvatar(), count); case 106 -> // Resin this.player.getResinManager().addResin(count); + case 107 -> // Legendary Key + this.player.addLegendaryKey(count); case 201 -> // Primogem this.player.setPrimogems(this.player.getPrimogems() + count); case 202 -> // Mora @@ -292,6 +294,8 @@ public class Inventory implements Iterable { return this.player.getCrystals(); case 106: // 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 return this.player.getHomeCoin(); default: @@ -334,13 +338,15 @@ public class Inventory implements Iterable { player.setCrystals(player.getCrystals() - (cost.getCount() * quantity)); case 106 -> // Resin player.getResinManager().useResin(cost.getCount() * quantity); + case 107 -> // LegendaryKey + player.useLegendaryKey(cost.getCount() * quantity); case 204 -> // Home Coin player.setHomeCoin(player.getHomeCoin() - (cost.getCount() * quantity)); default -> removeItem(getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(cost.getId()), cost.getCount() * quantity); } } - + if (reason != null) { // Do we need these? // getPlayer().sendPacket(new PacketItemAddHintNotify(changedItems, reason)); } diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 245742691..ec101ea83 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -4,10 +4,10 @@ import dev.morphia.annotations.*; import emu.grasscutter.GameConstants; import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; +import emu.grasscutter.data.excels.PersonalLineData; import emu.grasscutter.data.excels.PlayerLevelData; import emu.grasscutter.data.excels.WeatherData; import emu.grasscutter.database.DatabaseHelper; -import emu.grasscutter.database.DatabaseManager; import emu.grasscutter.game.Account; import emu.grasscutter.game.CoopRequest; import emu.grasscutter.game.ability.AbilityManager; @@ -1597,7 +1597,17 @@ public class Player { 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); private final int value; diff --git a/src/main/java/emu/grasscutter/game/props/PlayerProperty.java b/src/main/java/emu/grasscutter/game/props/PlayerProperty.java index 30f3ce14f..4106a4b98 100644 --- a/src/main/java/emu/grasscutter/game/props/PlayerProperty.java +++ b/src/main/java/emu/grasscutter/game/props/PlayerProperty.java @@ -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_PLAYER_MCOIN (10025), // Genesis Crystal (-inf, +inf) see 10015 PROP_PLAYER_WAIT_SUB_MCOIN (10026), - PROP_PLAYER_LEGENDARY_KEY (10027), + PROP_PLAYER_LEGENDARY_KEY (10027,0), PROP_IS_HAS_FIRST_SHARE (10028), PROP_PLAYER_FORGE_POINT (10029, 0, 300_000), PROP_CUR_CLIMATE_METER (10035), diff --git a/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java b/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java index 4dc31a5ae..9117be4c1 100644 --- a/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java +++ b/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java @@ -1,7 +1,6 @@ package emu.grasscutter.game.quest; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import emu.grasscutter.server.packet.send.PacketCodexDataUpdateNotify; import org.bson.types.ObjectId; @@ -31,20 +30,21 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @Entity(value = "quests", useDiscriminator = false) public class GameMainQuest { @Id private ObjectId id; - + @Indexed private int ownerUid; @Transient private Player owner; - + private Map childQuests; - + private int parentQuestId; private int[] questVars; private ParentQuestState state; private boolean isFinished; - + List questGroupSuites; + @Deprecated // Morphia only. Do not use. public GameMainQuest() {} - + public GameMainQuest(Player player, int parentQuestId) { this.owner = player; this.ownerUid = player.getUid(); @@ -52,12 +52,13 @@ public class GameMainQuest { this.childQuests = new HashMap<>(); this.questVars = new int[5]; this.state = ParentQuestState.PARENT_QUEST_STATE_NONE; + this.questGroupSuites = new ArrayList<>(); } public int getParentQuestId() { return parentQuestId; } - + public int getOwnerUid() { return ownerUid; } @@ -74,7 +75,7 @@ public class GameMainQuest { public Map getChildQuests() { return childQuests; } - + public GameQuest getChildQuestById(int id) { return this.getChildQuests().get(id); } @@ -91,26 +92,36 @@ public class GameMainQuest { return isFinished; } - public void finish() { + public List getQuestGroupSuites() { + return questGroupSuites; + } + + public void finish() { this.isFinished = true; this.state = ParentQuestState.PARENT_QUEST_STATE_FINISHED; - + this.getOwner().getSession().send(new PacketFinishedParentQuestUpdateNotify(this)); this.getOwner().getSession().send(new PacketCodexDataUpdateNotify(this)); - + this.save(); - + // Add rewards MainQuestData mainQuestData = GameData.getMainQuestDataMap().get(this.getParentQuestId()); for (int rewardId : mainQuestData.getRewardIdList()) { RewardData rewardData = GameData.getRewardDataMap().get(rewardId); - + if (rewardData == null) { continue; } - + 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() { @@ -122,16 +133,16 @@ public class GameMainQuest { .setParentQuestId(getParentQuestId()) .setIsFinished(isFinished()) .setParentQuestState(getState().getValue()); - + for (GameQuest quest : this.getChildQuests().values()) { ChildQuest childQuest = ChildQuest.newBuilder() .setQuestId(quest.getQuestId()) .setState(quest.getState().getValue()) .build(); - + proto.addChildQuestList(childQuest); } - + if (getQuestVars() != null) { for (int i : getQuestVars()) { proto.addQuestVar(i); diff --git a/src/main/java/emu/grasscutter/game/quest/GameQuest.java b/src/main/java/emu/grasscutter/game/quest/GameQuest.java index 57d8655fb..7d1fe5ade 100644 --- a/src/main/java/emu/grasscutter/game/quest/GameQuest.java +++ b/src/main/java/emu/grasscutter/game/quest/GameQuest.java @@ -6,13 +6,16 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; import emu.grasscutter.data.binout.MainQuestData; 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.QuestCondition; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.quest.enums.LogicType; 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.server.packet.send.PacketCodexDataUpdateNotify; +import emu.grasscutter.server.packet.send.PacketChapterStateNotify; import emu.grasscutter.server.packet.send.PacketQuestListUpdateNotify; import emu.grasscutter.server.packet.send.PacketQuestProgressUpdateNotify; import emu.grasscutter.utils.Utils; @@ -21,21 +24,21 @@ import emu.grasscutter.utils.Utils; public class GameQuest { @Transient private GameMainQuest mainQuest; @Transient private QuestData questData; - + private int questId; private int mainQuestId; private QuestState state; - + private int startTime; private int acceptTime; private int finishTime; - + private int[] finishProgressList; private int[] failProgressList; - + @Deprecated // Morphia only. Do not use. public GameQuest() {} - + public GameQuest(GameMainQuest mainQuest, QuestData questData) { this.mainQuest = mainQuest; this.questId = questData.getId(); @@ -44,18 +47,31 @@ public class GameQuest { this.acceptTime = Utils.getCurrentSeconds(); this.startTime = this.acceptTime; this.state = QuestState.QUEST_STATE_UNFINISHED; - - if (questData.getFinishCond() != null && questData.getAcceptCond().length != 0) { - this.finishProgressList = new int[questData.getFinishCond().length]; + + if (questData.getFinishCond() != null && questData.getAcceptCond().size() != 0) { + this.finishProgressList = new int[questData.getFinishCond().size()]; } - if (questData.getFailCond() != null && questData.getFailCond().length != 0) { - this.failProgressList = new int[questData.getFailCond().length]; + if (questData.getFailCond() != null && questData.getFailCond().size() != 0) { + this.failProgressList = new int[questData.getFailCond().size()]; } - + 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() { return mainQuest; } @@ -63,7 +79,7 @@ public class GameQuest { public void setMainQuest(GameMainQuest mainQuest) { this.mainQuest = mainQuest; } - + public Player getOwner() { return getMainQuest().getOwner(); } @@ -116,11 +132,11 @@ public class GameQuest { public void setFinishTime(int finishTime) { this.finishTime = finishTime; } - + public int[] getFinishProgressList() { return finishProgressList; } - + public void setFinishProgress(int index, int value) { finishProgressList[index] = value; } @@ -128,7 +144,7 @@ public class GameQuest { public int[] getFailProgressList() { return failProgressList; } - + public void setFailProgress(int index, int value) { failProgressList[index] = value; } @@ -136,16 +152,16 @@ public class GameQuest { public void finish() { this.state = QuestState.QUEST_STATE_FINISHED; this.finishTime = Utils.getCurrentSeconds(); - + if (this.getFinishProgressList() != null) { for (int i = 0 ; i < getFinishProgressList().length; i++) { getFinishProgressList()[i] = 1; } } - + this.getOwner().getSession().send(new PacketQuestProgressUpdateNotify(this)); this.getOwner().getSession().send(new PacketQuestListUpdateNotify(this)); - + 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.getMainQuest().finish(); @@ -154,8 +170,21 @@ public class GameQuest { this.tryAcceptQuestLine(); 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() { try { MainQuestData questConfig = GameData.getMainQuestDataMap().get(this.getMainQuestId()); @@ -167,16 +196,17 @@ public class GameQuest { QuestData questData = GameData.getQuestDataMap().get(subQuest.getSubId()); if (questData == null || questData.getAcceptCond() == null - || questData.getAcceptCond().length == 0) { + || questData.getAcceptCond().size() == 0) { continue; } - int[] accept = new int[questData.getAcceptCond().length]; + int[] accept = new int[questData.getAcceptCond().size()]; // TODO - for (int i = 0; i < questData.getAcceptCond().length; i++) { - QuestCondition condition = questData.getAcceptCond()[i]; + for (int i = 0; i < questData.getAcceptCond().size(); i++) { + QuestCondition condition = questData.getAcceptCond().get(i); boolean result = getOwner().getServer().getQuestHandler().triggerCondition(this, condition, + condition.getParamStr(), condition.getParam()); accept[i] = result ? 1 : 0; @@ -195,11 +225,11 @@ public class GameQuest { return false; } - + public void save() { getMainQuest().save(); } - + public Quest toProto() { Quest.Builder proto = Quest.newBuilder() .setQuestId(this.getQuestId()) @@ -208,19 +238,19 @@ public class GameQuest { .setStartTime(this.getStartTime()) .setStartGameTime(438) .setAcceptTime(this.getAcceptTime()); - + if (this.getFinishProgressList() != null) { for (int i : this.getFinishProgressList()) { proto.addFinishProgressList(i); } } - + if (this.getFailProgressList() != null) { for (int i : this.getFailProgressList()) { proto.addFailProgressList(i); } } - + return proto.build(); } } diff --git a/src/main/java/emu/grasscutter/game/quest/QuestGroupSuite.java b/src/main/java/emu/grasscutter/game/quest/QuestGroupSuite.java new file mode 100644 index 000000000..9865f6d1e --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/QuestGroupSuite.java @@ -0,0 +1,17 @@ +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; +} diff --git a/src/main/java/emu/grasscutter/game/quest/QuestManager.java b/src/main/java/emu/grasscutter/game/quest/QuestManager.java index 838cb301f..d98586991 100644 --- a/src/main/java/emu/grasscutter/game/quest/QuestManager.java +++ b/src/main/java/emu/grasscutter/game/quest/QuestManager.java @@ -1,29 +1,28 @@ package emu.grasscutter.game.quest; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.function.Consumer; +import java.util.stream.Collectors; +import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; +import emu.grasscutter.data.binout.MainQuestData; import emu.grasscutter.data.excels.QuestData; import emu.grasscutter.data.excels.QuestData.QuestCondition; import emu.grasscutter.database.DatabaseHelper; 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.LogicType; import emu.grasscutter.game.quest.enums.QuestState; -import emu.grasscutter.server.packet.send.PacketFinishedParentQuestUpdateNotify; -import emu.grasscutter.server.packet.send.PacketQuestListUpdateNotify; -import emu.grasscutter.server.packet.send.PacketQuestProgressUpdateNotify; -import emu.grasscutter.server.packet.send.PacketServerCondMeetQuestListUpdateNotify; +import emu.grasscutter.server.packet.send.*; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; public class QuestManager { private final Player player; private final Int2ObjectMap quests; - + public QuestManager(Player player) { this.player = player; this.quests = new Int2ObjectOpenHashMap<>(); @@ -122,40 +121,56 @@ public class QuestManager { return quest; } - - public void triggerEvent(QuestTrigger condType, int... params) { + public void startMainQuest(int mainQuestId){ + 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 changedQuests = new HashSet<>(); - + this.forEachActiveQuest(quest -> { QuestData data = quest.getData(); - - for (int i = 0; i < data.getFinishCond().length; i++) { - if (quest.getFinishProgressList() == null + + for (int i = 0; i < data.getFinishCond().size(); i++) { + if (quest.getFinishProgressList() == null || quest.getFinishProgressList().length == 0 || quest.getFinishProgressList()[i] == 1) { continue; } - - QuestCondition condition = data.getFinishCond()[i]; - + + QuestCondition condition = data.getFinishCond().get(i); + if (condition.getType() != condType) { continue; } - - boolean result = getPlayer().getServer().getQuestHandler().triggerContent(quest, condition, params); - + + boolean result = getPlayer().getServer().getQuestHandler().triggerContent(quest, condition, paramStr, params); + if (result) { quest.getFinishProgressList()[i] = 1; - + changedQuests.add(quest); } } }); - + for (GameQuest quest : changedQuests) { LogicType logicType = quest.getData().getFailCondComb(); int[] progress = quest.getFinishProgressList(); - + // Handle logical comb boolean finish = LogicType.calculate(logicType, progress); @@ -169,6 +184,15 @@ public class QuestManager { } } + public List 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() { List quests = DatabaseHelper.getAllQuests(getPlayer()); diff --git a/src/main/java/emu/grasscutter/game/quest/ServerQuestHandler.java b/src/main/java/emu/grasscutter/game/quest/ServerQuestHandler.java index b48194dd9..19c779470 100644 --- a/src/main/java/emu/grasscutter/game/quest/ServerQuestHandler.java +++ b/src/main/java/emu/grasscutter/game/quest/ServerQuestHandler.java @@ -2,10 +2,12 @@ package emu.grasscutter.game.quest; import java.util.Set; +import emu.grasscutter.data.excels.QuestData; +import emu.grasscutter.game.quest.handlers.QuestExecHandler; import org.reflections.Reflections; 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 it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -14,32 +16,32 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; public class ServerQuestHandler { private final Int2ObjectMap condHandlers; private final Int2ObjectMap contHandlers; - private final Int2ObjectMap execHandlers; - + private final Int2ObjectMap execHandlers; + public ServerQuestHandler() { - this.condHandlers = new Int2ObjectOpenHashMap<>(); + this.condHandlers = new Int2ObjectOpenHashMap<>(); this.contHandlers = new Int2ObjectOpenHashMap<>(); this.execHandlers = new Int2ObjectOpenHashMap<>(); - + this.registerHandlers(); } public void registerHandlers() { - this.registerHandlers(this.condHandlers, "emu.grasscutter.game.quest.conditions"); - this.registerHandlers(this.contHandlers, "emu.grasscutter.game.quest.content"); - this.registerHandlers(this.execHandlers, "emu.grasscutter.game.quest.exec"); + this.registerHandlers(this.condHandlers, "emu.grasscutter.game.quest.conditions", QuestBaseHandler.class); + this.registerHandlers(this.contHandlers, "emu.grasscutter.game.quest.content", QuestBaseHandler.class); + this.registerHandlers(this.execHandlers, "emu.grasscutter.game.quest.exec", QuestExecHandler.class); } - - public void registerHandlers(Int2ObjectMap map, String packageName) { + + public void registerHandlers(Int2ObjectMap map, String packageName, Class clazz) { Reflections reflections = new Reflections(packageName); - Set handlerClasses = reflections.getSubTypesOf(QuestBaseHandler.class); - - for (Object obj : handlerClasses) { - this.registerPacketHandler(map, (Class) obj); + var handlerClasses = reflections.getSubTypesOf(clazz); + + for (var obj : handlerClasses) { + this.registerPacketHandler(map, obj); } } - public void registerPacketHandler(Int2ObjectMap map, Class handlerClass) { + public void registerPacketHandler(Int2ObjectMap map, Class handlerClass) { try { QuestValue opcode = handlerClass.getAnnotation(QuestValue.class); @@ -47,43 +49,44 @@ public class ServerQuestHandler { return; } - QuestBaseHandler packetHandler = (QuestBaseHandler) handlerClass.newInstance(); - - map.put(opcode.value().getValue(), packetHandler); + map.put(opcode.value().getValue(), handlerClass.newInstance()); } catch (Exception e) { e.printStackTrace(); } } - + // 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()); if (handler == null || quest.getData() == null) { + Grasscutter.getLogger().debug("Could not trigger condition {} at {}", condition.getType().getValue(), quest.getData()); 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()); if (handler == null || quest.getData() == null) { + Grasscutter.getLogger().debug("Could not trigger content {} at {}", condition.getType().getValue(), quest.getData()); return false; } - - return handler.execute(quest, condition, params); + + return handler.execute(quest, condition, paramStr, params); } - - public boolean triggerExec(GameQuest quest, QuestCondition condition, int... params) { - QuestBaseHandler handler = execHandlers.get(condition.getType().getValue()); + + public boolean triggerExec(GameQuest quest, QuestExecParam execParam, String... params) { + QuestExecHandler handler = execHandlers.get(execParam.getType().getValue()); if (handler == null || quest.getData() == null) { + Grasscutter.getLogger().debug("Could not trigger exec {} at {}", execParam.getType().getValue(), quest.getData()); return false; } - - return handler.execute(quest, condition, params); + + return handler.execute(quest, execParam, params); } } diff --git a/src/main/java/emu/grasscutter/game/quest/conditions/BaseCondition.java b/src/main/java/emu/grasscutter/game/quest/conditions/BaseCondition.java index 86df72b34..e3efe6ed6 100644 --- a/src/main/java/emu/grasscutter/game/quest/conditions/BaseCondition.java +++ b/src/main/java/emu/grasscutter/game/quest/conditions/BaseCondition.java @@ -10,9 +10,9 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler; public class BaseCondition extends QuestBaseHandler { @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 return false; } - + } diff --git a/src/main/java/emu/grasscutter/game/quest/conditions/ConditionLuaNotify.java b/src/main/java/emu/grasscutter/game/quest/conditions/ConditionLuaNotify.java new file mode 100644 index 000000000..8d3fd541b --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/conditions/ConditionLuaNotify.java @@ -0,0 +1,17 @@ +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); + } + +} diff --git a/src/main/java/emu/grasscutter/game/quest/conditions/ConditionPlayerLevelEqualGreater.java b/src/main/java/emu/grasscutter/game/quest/conditions/ConditionPlayerLevelEqualGreater.java index e15ce8ed7..cb19e8878 100644 --- a/src/main/java/emu/grasscutter/game/quest/conditions/ConditionPlayerLevelEqualGreater.java +++ b/src/main/java/emu/grasscutter/game/quest/conditions/ConditionPlayerLevelEqualGreater.java @@ -10,8 +10,8 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler; public class ConditionPlayerLevelEqualGreater extends QuestBaseHandler { @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]; } - + } diff --git a/src/main/java/emu/grasscutter/game/quest/conditions/ConditionStateEqual.java b/src/main/java/emu/grasscutter/game/quest/conditions/ConditionStateEqual.java index bcf90145b..c993eebb7 100644 --- a/src/main/java/emu/grasscutter/game/quest/conditions/ConditionStateEqual.java +++ b/src/main/java/emu/grasscutter/game/quest/conditions/ConditionStateEqual.java @@ -10,14 +10,14 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler; public class ConditionStateEqual extends QuestBaseHandler { @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]); - + if (checkQuest != null) { return checkQuest.getState().getValue() == params[1]; } - - return false; + + return false; } - + } diff --git a/src/main/java/emu/grasscutter/game/quest/content/BaseContent.java b/src/main/java/emu/grasscutter/game/quest/content/BaseContent.java index e2c7abdc8..f0db20a51 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/BaseContent.java +++ b/src/main/java/emu/grasscutter/game/quest/content/BaseContent.java @@ -10,9 +10,9 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler; public class BaseContent extends QuestBaseHandler { @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 return false; } - + } diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentAddQuestProgress.java b/src/main/java/emu/grasscutter/game/quest/content/ContentAddQuestProgress.java new file mode 100644 index 000000000..a49d067f4 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentAddQuestProgress.java @@ -0,0 +1,17 @@ +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]; + } + +} diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteTalk.java b/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteTalk.java index 3c17bccde..76819f47c 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteTalk.java +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteTalk.java @@ -10,8 +10,8 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler; public class ContentCompleteTalk extends QuestBaseHandler { @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]; } - + } diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentEnterDungeon.java b/src/main/java/emu/grasscutter/game/quest/content/ContentEnterDungeon.java index e331f48e0..4dc291606 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/ContentEnterDungeon.java +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentEnterDungeon.java @@ -10,8 +10,8 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler; public class ContentEnterDungeon extends QuestBaseHandler { @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]; } - + } diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentEnterRoom.java b/src/main/java/emu/grasscutter/game/quest/content/ContentEnterRoom.java new file mode 100644 index 000000000..e140eb3cb --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentEnterRoom.java @@ -0,0 +1,17 @@ +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_ENTER_ROOM) +public class ContentEnterRoom extends QuestBaseHandler { + + @Override + public boolean execute(GameQuest quest, QuestCondition condition, String paramStr, int... params) { + return condition.getParam()[0] == params[0]; + } + +} diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentFinishPlot.java b/src/main/java/emu/grasscutter/game/quest/content/ContentFinishPlot.java index 305808112..f3040b18c 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/ContentFinishPlot.java +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentFinishPlot.java @@ -10,8 +10,8 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler; public class ContentFinishPlot extends QuestBaseHandler { @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]; } - + } diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentGameTimeTick.java b/src/main/java/emu/grasscutter/game/quest/content/ContentGameTimeTick.java new file mode 100644 index 000000000..f28f5718c --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentGameTimeTick.java @@ -0,0 +1,23 @@ +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_GAME_TIME_TICK) +public class ContentGameTimeTick extends QuestBaseHandler { + + @Override + public boolean execute(GameQuest quest, QuestCondition condition, String paramStr, int... params) { + var range = condition.getParamStr().split(","); + var min = Math.min(Integer.parseInt(range[0]), Integer.parseInt(range[1])); + var max = Math.max(Integer.parseInt(range[0]), Integer.parseInt(range[1])); + + // params[0] is clock, params[1] is day + return params[0] >= min && params[0] <= max && + params[1] >= condition.getParam()[0]; + } + +} diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentInteractGadget.java b/src/main/java/emu/grasscutter/game/quest/content/ContentInteractGadget.java new file mode 100644 index 000000000..975a7f224 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentInteractGadget.java @@ -0,0 +1,17 @@ +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_INTERACT_GADGET) +public class ContentInteractGadget extends QuestBaseHandler { + + @Override + public boolean execute(GameQuest quest, QuestCondition condition, String paramStr, int... params) { + return params[0] == condition.getParam()[0]; + } + +} diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentLuaNotify.java b/src/main/java/emu/grasscutter/game/quest/content/ContentLuaNotify.java new file mode 100644 index 000000000..f8ca181da --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentLuaNotify.java @@ -0,0 +1,17 @@ +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_LUA_NOTIFY) +public class ContentLuaNotify extends QuestBaseHandler { + + @Override + public boolean execute(GameQuest quest, QuestCondition condition, String paramStr, int... params) { + return condition.getParamStr().equals(paramStr); + } + +} diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentQuestStateEqual.java b/src/main/java/emu/grasscutter/game/quest/content/ContentQuestStateEqual.java new file mode 100644 index 000000000..511e7e19a --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentQuestStateEqual.java @@ -0,0 +1,23 @@ +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_QUEST_STATE_EQUAL) +public class ContentQuestStateEqual extends QuestBaseHandler { + + @Override + public boolean execute(GameQuest quest, QuestCondition condition, String paramStr, int... params) { + GameQuest checkQuest = quest.getOwner().getQuestManager().getQuestById(params[0]); + + if (checkQuest != null) { + return checkQuest.getState().getValue() == params[1]; + } + + return false; + } + +} diff --git a/src/main/java/emu/grasscutter/game/quest/enums/QuestTrigger.java b/src/main/java/emu/grasscutter/game/quest/enums/QuestTrigger.java index def3a399d..c9c3eb880 100644 --- a/src/main/java/emu/grasscutter/game/quest/enums/QuestTrigger.java +++ b/src/main/java/emu/grasscutter/game/quest/enums/QuestTrigger.java @@ -1,5 +1,12 @@ package emu.grasscutter.game.quest.enums; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + public enum QuestTrigger { QUEST_COND_NONE (0), QUEST_COND_STATE_EQUAL (1), @@ -79,7 +86,7 @@ public enum QuestTrigger { QUEST_COND_NEW_HOMEWORLD_SHOP_ITEM (75), QUEST_COND_SCENE_POINT_UNLOCK (76), QUEST_COND_SCENE_LEVEL_TAG_EQ (77), - + QUEST_CONTENT_NONE (0), QUEST_CONTENT_KILL_MONSTER (1), QUEST_CONTENT_COMPLETE_TALK (2), @@ -153,7 +160,7 @@ public enum QuestTrigger { QUEST_CONTENT_IRODORI_FINISH_FLOWER_COMBINATION (151), QUEST_CONTENT_IRODORI_POETRY_REACH_MIN_PROGRESS (152), QUEST_CONTENT_IRODORI_POETRY_FINISH_FILL_POETRY (153), - + QUEST_EXEC_NONE (0), QUEST_EXEC_DEL_PACK_ITEM (1), QUEST_EXEC_UNLOCK_POINT (2), @@ -222,9 +229,9 @@ public enum QuestTrigger { QUEST_EXEC_LOCK_PLAYER_WORLD_SCENE (66), QUEST_EXEC_FAIL_MAINCOOP (67), QUEST_EXEC_MODIFY_WEATHER_AREA (68); - + private final int value; - + QuestTrigger(int id) { this.value = id; } @@ -232,4 +239,24 @@ public enum QuestTrigger { public int getValue() { return value; } + + private static final Int2ObjectMap contentMap = new Int2ObjectOpenHashMap<>(); + private static final Map contentStringMap = new HashMap<>(); + + static { + Stream.of(values()) + .filter(e -> e.name().startsWith("QUEST_CONTENT_")) + .forEach(e -> { + contentMap.put(e.getValue(), e); + contentStringMap.put(e.name(), e); + }); + } + + public static QuestTrigger getContentTriggerByValue(int value) { + return contentMap.getOrDefault(value, QUEST_CONTENT_NONE); + } + + public static QuestTrigger getContentTriggerByName(String name) { + return contentStringMap.getOrDefault(name, QUEST_CONTENT_NONE); + } } diff --git a/src/main/java/emu/grasscutter/game/quest/exec/ExecAddQuestProgress.java b/src/main/java/emu/grasscutter/game/quest/exec/ExecAddQuestProgress.java new file mode 100644 index 000000000..57d1f5450 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/exec/ExecAddQuestProgress.java @@ -0,0 +1,24 @@ +package emu.grasscutter.game.quest.exec; + +import emu.grasscutter.data.excels.QuestData; +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.QuestExecHandler; + +import java.util.Arrays; + +@QuestValue(QuestTrigger.QUEST_EXEC_ADD_QUEST_PROGRESS) +public class ExecAddQuestProgress extends QuestExecHandler { + @Override + public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) { + var param = Arrays.stream(paramStr) + .filter(i -> !i.isBlank()) + .mapToInt(Integer::parseInt) + .toArray(); + + quest.getOwner().getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_ADD_QUEST_PROGRESS, param); + + return true; + } +} diff --git a/src/main/java/emu/grasscutter/game/quest/exec/ExecNotifyGroupLua.java b/src/main/java/emu/grasscutter/game/quest/exec/ExecNotifyGroupLua.java new file mode 100644 index 000000000..df674fc4b --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/exec/ExecNotifyGroupLua.java @@ -0,0 +1,34 @@ +package emu.grasscutter.game.quest.exec; + +import emu.grasscutter.data.excels.QuestData; +import emu.grasscutter.game.quest.GameQuest; +import emu.grasscutter.game.quest.QuestGroupSuite; +import emu.grasscutter.game.quest.QuestValue; +import emu.grasscutter.game.quest.enums.QuestState; +import emu.grasscutter.game.quest.enums.QuestTrigger; +import emu.grasscutter.game.quest.handlers.QuestExecHandler; +import emu.grasscutter.scripts.constants.EventType; +import emu.grasscutter.scripts.data.ScriptArgs; +import emu.grasscutter.server.packet.send.PacketGroupSuiteNotify; + +@QuestValue(QuestTrigger.QUEST_EXEC_NOTIFY_GROUP_LUA) +public class ExecNotifyGroupLua extends QuestExecHandler { + + @Override + public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) { + var sceneId = Integer.parseInt(paramStr[0]); + var groupId = Integer.parseInt(paramStr[1]); + + var scriptManager = quest.getOwner().getScene().getScriptManager(); + + if(quest.getOwner().getScene().getId() == sceneId){ + scriptManager.callEvent( + quest.getState() == QuestState.QUEST_STATE_FINISHED ? + EventType.EVENT_QUEST_FINISH : EventType.EVENT_QUEST_START + , new ScriptArgs()); + } + + return true; + } + +} diff --git a/src/main/java/emu/grasscutter/game/quest/exec/ExecRefreshGroupSuite.java b/src/main/java/emu/grasscutter/game/quest/exec/ExecRefreshGroupSuite.java new file mode 100644 index 000000000..c14e3c34d --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/exec/ExecRefreshGroupSuite.java @@ -0,0 +1,39 @@ +package emu.grasscutter.game.quest.exec; + +import emu.grasscutter.data.excels.QuestData; +import emu.grasscutter.game.quest.GameQuest; +import emu.grasscutter.game.quest.QuestGroupSuite; +import emu.grasscutter.game.quest.QuestValue; +import emu.grasscutter.game.quest.enums.QuestTrigger; +import emu.grasscutter.game.quest.handlers.QuestExecHandler; +import emu.grasscutter.server.packet.send.PacketGroupSuiteNotify; + +import java.util.Arrays; + +@QuestValue(QuestTrigger.QUEST_EXEC_REFRESH_GROUP_SUITE) +public class ExecRefreshGroupSuite extends QuestExecHandler { + + @Override + public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) { + var sceneId = Integer.parseInt(paramStr[0]); + var groupId = Integer.parseInt(paramStr[1].split(",")[0]); + var suiteId = Integer.parseInt(paramStr[1].split(",")[1]); + + var scriptManager = quest.getOwner().getScene().getScriptManager(); + + quest.getMainQuest().getQuestGroupSuites().add(QuestGroupSuite.of() + .scene(sceneId) + .group(groupId) + .suite(suiteId) + .build()); + + // refresh immediately if player is in this scene + if(quest.getOwner().getScene().getId() == sceneId){ + scriptManager.refreshGroup(scriptManager.getGroupById(groupId), suiteId); + quest.getOwner().sendPacket(new PacketGroupSuiteNotify(groupId, suiteId)); + } + + return true; + } + +} diff --git a/src/main/java/emu/grasscutter/game/quest/handlers/QuestBaseHandler.java b/src/main/java/emu/grasscutter/game/quest/handlers/QuestBaseHandler.java index 815906f81..077029016 100644 --- a/src/main/java/emu/grasscutter/game/quest/handlers/QuestBaseHandler.java +++ b/src/main/java/emu/grasscutter/game/quest/handlers/QuestBaseHandler.java @@ -4,7 +4,7 @@ import emu.grasscutter.data.excels.QuestData.QuestCondition; import emu.grasscutter.game.quest.GameQuest; public abstract class QuestBaseHandler { - - public abstract boolean execute(GameQuest quest, QuestCondition condition, int... params); - + + public abstract boolean execute(GameQuest quest, QuestCondition condition, String paramStr, int... params); + } diff --git a/src/main/java/emu/grasscutter/game/quest/handlers/QuestExecHandler.java b/src/main/java/emu/grasscutter/game/quest/handlers/QuestExecHandler.java new file mode 100644 index 000000000..378a59614 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/handlers/QuestExecHandler.java @@ -0,0 +1,10 @@ +package emu.grasscutter.game.quest.handlers; + +import emu.grasscutter.data.excels.QuestData; +import emu.grasscutter.game.quest.GameQuest; + +public abstract class QuestExecHandler { + + public abstract boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr); + +} diff --git a/src/main/java/emu/grasscutter/game/world/Scene.java b/src/main/java/emu/grasscutter/game/world/Scene.java index ce4d9eaf3..82f534e5e 100644 --- a/src/main/java/emu/grasscutter/game/world/Scene.java +++ b/src/main/java/emu/grasscutter/game/world/Scene.java @@ -13,6 +13,7 @@ import emu.grasscutter.game.props.ClimateType; import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.LifeState; import emu.grasscutter.game.props.SceneType; +import emu.grasscutter.game.quest.QuestGroupSuite; import emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry; import emu.grasscutter.game.dungeons.challenge.WorldChallenge; import emu.grasscutter.net.packet.BasePacket; @@ -798,4 +799,22 @@ public class Scene { } return npcList; } + + public void loadGroupForQuest(List sceneGroupSuite) { + if(!scriptManager.isInit()){ + return; + } + + sceneGroupSuite.forEach(i -> { + var group = scriptManager.getGroupById(i.getGroup()); + if(group == null){ + return; + } + var suite = group.getSuiteByIndex(i.getSuite()); + if(suite == null){ + return; + } + scriptManager.addGroupSuite(group, suite); + }); + } } diff --git a/src/main/java/emu/grasscutter/scripts/ScriptLib.java b/src/main/java/emu/grasscutter/scripts/ScriptLib.java index 39ee908b5..946ec04e4 100644 --- a/src/main/java/emu/grasscutter/scripts/ScriptLib.java +++ b/src/main/java/emu/grasscutter/scripts/ScriptLib.java @@ -482,6 +482,11 @@ public class ScriptLib { logger.debug("[LUA] Call AddQuestProgress with {}", var1); + for(var player : getSceneScriptManager().getScene().getPlayers()){ + player.getQuestManager().triggerEvent(QuestTrigger.QUEST_COND_LUA_NOTIFY, var1); + player.getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_LUA_NOTIFY, var1); + } + return 0; } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerAddQuestContentProgressReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerAddQuestContentProgressReq.java new file mode 100644 index 000000000..03bae4ac5 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerAddQuestContentProgressReq.java @@ -0,0 +1,23 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.game.quest.enums.QuestTrigger; +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.AddQuestContentProgressReqOuterClass; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketAddQuestContentProgressRsp; + +@Opcodes(PacketOpcodes.AddQuestContentProgressReq) +public class HandlerAddQuestContentProgressReq extends PacketHandler { + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + var req = AddQuestContentProgressReqOuterClass.AddQuestContentProgressReq.parseFrom(payload); + + session.getPlayer().getQuestManager().triggerEvent(QuestTrigger.getContentTriggerByValue(req.getContentType()), req.getParam()); + + session.send(new PacketAddQuestContentProgressRsp(req.getContentType())); + } + +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerChangeGameTimeReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerChangeGameTimeReq.java index dbd80ccff..17d66e60e 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerChangeGameTimeReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerChangeGameTimeReq.java @@ -1,5 +1,6 @@ package emu.grasscutter.server.packet.recv; +import emu.grasscutter.game.quest.enums.QuestTrigger; import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.ChangeGameTimeReqOuterClass.ChangeGameTimeReq; @@ -9,12 +10,15 @@ import emu.grasscutter.server.packet.send.PacketChangeGameTimeRsp; @Opcodes(PacketOpcodes.ChangeGameTimeReq) public class HandlerChangeGameTimeReq extends PacketHandler { - + @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { ChangeGameTimeReq req = ChangeGameTimeReq.parseFrom(payload); - + session.getPlayer().getScene().changeTime(req.getGameTime()); + session.getPlayer().getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_GAME_TIME_TICK, + req.getGameTime() / 60 , // hours + req.getExtraDays()); //days session.getPlayer().sendPacket(new PacketChangeGameTimeRsp(session.getPlayer())); } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerEnterSceneDoneReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEnterSceneDoneReq.java index be2d4ac6b..b9b8c8657 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerEnterSceneDoneReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEnterSceneDoneReq.java @@ -32,6 +32,12 @@ public class HandlerEnterSceneDoneReq extends PacketHandler { // spawn NPC session.getPlayer().getScene().loadNpcForPlayerEnter(session.getPlayer()); + + // notify client to load the npc for quest + var questGroupSuites = session.getPlayer().getQuestManager().getSceneGroupSuite(session.getPlayer().getSceneId()); + session.getPlayer().getScene().loadGroupForQuest(questGroupSuites); + session.send(new PacketGroupSuiteNotify(questGroupSuites)); + // Reset timer for sending player locations session.getPlayer().resetSendPlayerLocTime(); } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtEntityRenderersChangedNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtEntityRenderersChangedNotify.java new file mode 100644 index 000000000..091bc00d4 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtEntityRenderersChangedNotify.java @@ -0,0 +1,30 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.EvtEntityRenderersChangedNotifyOuterClass; +import emu.grasscutter.net.proto.ForwardTypeOuterClass; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketEvtEntityRenderersChangedNotify; +import emu.grasscutter.server.packet.send.PacketWorldPlayerLocationNotify; + +@Opcodes(PacketOpcodes.EvtEntityRenderersChangedNotify) +public class HandlerEvtEntityRenderersChangedNotify extends PacketHandler { + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + var req = EvtEntityRenderersChangedNotifyOuterClass.EvtEntityRenderersChangedNotify.parseFrom(payload); + + switch (req.getForwardType()) { + case FORWARD_TYPE_TO_ALL -> + session.getPlayer().getScene().broadcastPacket(new PacketEvtEntityRenderersChangedNotify(req)); + case FORWARD_TYPE_TO_ALL_EXCEPT_CUR -> + session.getPlayer().getScene().broadcastPacketToOthers(session.getPlayer(), new PacketEvtEntityRenderersChangedNotify(req)); + case FORWARD_TYPE_TO_HOST -> + session.getPlayer().getScene().getWorld().getHost().sendPacket(new PacketEvtEntityRenderersChangedNotify(req)); + } + + } + +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGadgetInteractReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGadgetInteractReq.java index 9fa116977..9dadef7bb 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGadgetInteractReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGadgetInteractReq.java @@ -1,5 +1,6 @@ package emu.grasscutter.server.packet.recv; +import emu.grasscutter.game.quest.enums.QuestTrigger; import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq; @@ -8,11 +9,12 @@ import emu.grasscutter.server.game.GameSession; @Opcodes(PacketOpcodes.GadgetInteractReq) public class HandlerGadgetInteractReq extends PacketHandler { - + @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { GadgetInteractReq req = GadgetInteractReq.parseFrom(payload); - + + session.getPlayer().getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_INTERACT_GADGET, req.getGadgetId()); session.getPlayer().interactWith(req.getGadgetEntityId(), req); } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPersonalLineAllDataReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPersonalLineAllDataReq.java new file mode 100644 index 000000000..5552e63f2 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPersonalLineAllDataReq.java @@ -0,0 +1,17 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketPersonalLineAllDataRsp; + +@Opcodes(PacketOpcodes.PersonalLineAllDataReq) +public class HandlerPersonalLineAllDataReq extends PacketHandler { + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + session.send(new PacketPersonalLineAllDataRsp(session.getPlayer().getQuestManager().getQuests().values())); + } + +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPostEnterSceneReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPostEnterSceneReq.java index 9c74946b7..746f8c1da 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPostEnterSceneReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPostEnterSceneReq.java @@ -1,5 +1,7 @@ package emu.grasscutter.server.packet.recv; +import emu.grasscutter.game.props.SceneType; +import emu.grasscutter.game.quest.enums.QuestTrigger; import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketHandler; @@ -8,9 +10,13 @@ import emu.grasscutter.server.packet.send.PacketPostEnterSceneRsp; @Opcodes(PacketOpcodes.PostEnterSceneReq) public class HandlerPostEnterSceneReq extends PacketHandler { - + @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + if(session.getPlayer().getScene().getSceneType() == SceneType.SCENE_ROOM){ + session.getPlayer().getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_ENTER_ROOM, session.getPlayer().getSceneId()); + } + session.send(new PacketPostEnterSceneRsp(session.getPlayer())); } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerQueryPathReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerQueryPathReq.java index aa8492b25..1184d5b17 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerQueryPathReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerQueryPathReq.java @@ -3,14 +3,21 @@ package emu.grasscutter.server.packet.recv; import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.net.proto.QueryPathReqOuterClass; import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketQueryPathRsp; @Opcodes(PacketOpcodes.QueryPathReq) public class HandlerQueryPathReq extends PacketHandler { - + @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - // Auto template + var req = QueryPathReqOuterClass.QueryPathReq.parseFrom(payload); + + /** + * It is not the actual work + */ + session.send(new PacketQueryPathRsp(req)); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnlockPersonalLineReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnlockPersonalLineReq.java new file mode 100644 index 000000000..480ebe4fc --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnlockPersonalLineReq.java @@ -0,0 +1,28 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.data.GameData; +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.UnlockPersonalLineReqOuterClass; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketUnlockPersonalLineRsp; + +@Opcodes(PacketOpcodes.UnlockPersonalLineReq) +public class HandlerUnlockPersonalLineReq extends PacketHandler { + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + var req = UnlockPersonalLineReqOuterClass.UnlockPersonalLineReq.parseFrom(payload); + var data = GameData.getPersonalLineDataMap().get(req.getPersonalLineId()); + if(data == null){ + return; + } + + session.getPlayer().getQuestManager().addQuest(data.getStartQuestId()); + session.getPlayer().useLegendaryKey(1); + + session.send(new PacketUnlockPersonalLineRsp(data.getId(), 1, data.getChapterId())); + } + +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketAddQuestContentProgressRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketAddQuestContentProgressRsp.java new file mode 100644 index 000000000..c803c0464 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketAddQuestContentProgressRsp.java @@ -0,0 +1,19 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.AddQuestContentProgressRspOuterClass; + +public class PacketAddQuestContentProgressRsp extends BasePacket { + + public PacketAddQuestContentProgressRsp(int contentType) { + super(PacketOpcodes.AddQuestContentProgressRsp); + + var proto = AddQuestContentProgressRspOuterClass.AddQuestContentProgressRsp.newBuilder(); + + proto.setContentType(contentType); + + this.setData(proto); + + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketChapterStateNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketChapterStateNotify.java new file mode 100644 index 000000000..4d60be2ce --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketChapterStateNotify.java @@ -0,0 +1,20 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.ChapterStateNotifyOuterClass; +import emu.grasscutter.net.proto.ChapterStateOuterClass; + +public class PacketChapterStateNotify extends BasePacket { + + public PacketChapterStateNotify(int id, ChapterStateOuterClass.ChapterState state) { + super(PacketOpcodes.ChapterStateNotify); + + var proto = ChapterStateNotifyOuterClass.ChapterStateNotify.newBuilder(); + + proto.setChapterId(id) + .setChapterState(state); + + this.setData(proto); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketEvtEntityRenderersChangedNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketEvtEntityRenderersChangedNotify.java new file mode 100644 index 000000000..4df5c4848 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketEvtEntityRenderersChangedNotify.java @@ -0,0 +1,14 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.EvtEntityRenderersChangedNotifyOuterClass; + +public class PacketEvtEntityRenderersChangedNotify extends BasePacket { + + public PacketEvtEntityRenderersChangedNotify(EvtEntityRenderersChangedNotifyOuterClass.EvtEntityRenderersChangedNotify req) { + super(PacketOpcodes.EvtEntityRenderersChangedNotify, true); + + this.setData(req); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGroupSuiteNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGroupSuiteNotify.java index 5a79b2ef1..58adfdf0f 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGroupSuiteNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGroupSuiteNotify.java @@ -1,10 +1,12 @@ package emu.grasscutter.server.packet.send; import emu.grasscutter.data.binout.SceneNpcBornEntry; +import emu.grasscutter.game.quest.QuestGroupSuite; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.GroupSuiteNotifyOuterClass; +import java.util.Collection; import java.util.List; public class PacketGroupSuiteNotify extends BasePacket { @@ -27,4 +29,24 @@ public class PacketGroupSuiteNotify extends BasePacket { this.setData(proto); } + + public PacketGroupSuiteNotify(int groupId, int suiteId) { + super(PacketOpcodes.GroupSuiteNotify); + + var proto = GroupSuiteNotifyOuterClass.GroupSuiteNotify.newBuilder(); + + proto.putGroupMap(groupId, suiteId); + + this.setData(proto); + } + + public PacketGroupSuiteNotify(Collection questGroupSuites) { + super(PacketOpcodes.GroupSuiteNotify); + + var proto = GroupSuiteNotifyOuterClass.GroupSuiteNotify.newBuilder(); + + questGroupSuites.forEach(i -> proto.putGroupMap(i.getGroup(), i.getSuite())); + + this.setData(proto); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPersonalLineAllDataRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPersonalLineAllDataRsp.java new file mode 100644 index 000000000..6074c1cf1 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPersonalLineAllDataRsp.java @@ -0,0 +1,35 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.data.GameData; +import emu.grasscutter.game.quest.GameMainQuest; +import emu.grasscutter.game.quest.GameQuest; +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.PersonalLineAllDataRspOuterClass; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class PacketPersonalLineAllDataRsp extends BasePacket { + + public PacketPersonalLineAllDataRsp(Collection gameMainQuestList) { + super(PacketOpcodes.PersonalLineAllDataRsp); + + var proto = PersonalLineAllDataRspOuterClass.PersonalLineAllDataRsp.newBuilder(); + + var questList = gameMainQuestList.stream() + .map(GameMainQuest::getChildQuests) + .map(Map::values) + .flatMap(Collection::stream) + .map(GameQuest::getQuestId) + .collect(Collectors.toSet()); + + GameData.getPersonalLineDataMap().values().stream() + .filter(i -> !questList.contains(i.getStartQuestId())) + .forEach(i -> proto.addCanBeUnlockedPersonalLineList(i.getId())); + + this.setData(proto); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketQueryPathRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketQueryPathRsp.java new file mode 100644 index 000000000..6e95b5ec9 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketQueryPathRsp.java @@ -0,0 +1,22 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.QueryPathReqOuterClass; +import emu.grasscutter.net.proto.QueryPathRspOuterClass; + +public class PacketQueryPathRsp extends BasePacket { + + public PacketQueryPathRsp(QueryPathReqOuterClass.QueryPathReq req) { + super(PacketOpcodes.QueryPathRsp); + + var proto = QueryPathRspOuterClass.QueryPathRsp.newBuilder(); + + proto.addCorners(req.getSourcePos()) + .addCorners(req.getDestinationPos(0)) + .setQueryId(req.getQueryId()) + .setQueryStatus(QueryPathRspOuterClass.QueryPathRsp.PathStatusType.PATH_STATUS_TYPE_SUCC); + + this.setData(proto); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketUnlockPersonalLineRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketUnlockPersonalLineRsp.java new file mode 100644 index 000000000..e25523e87 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketUnlockPersonalLineRsp.java @@ -0,0 +1,20 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.UnlockPersonalLineRspOuterClass; + +public class PacketUnlockPersonalLineRsp extends BasePacket { + + public PacketUnlockPersonalLineRsp(int id, int level, int chapterId) { + super(PacketOpcodes.UnlockPersonalLineRsp); + + var proto = UnlockPersonalLineRspOuterClass.UnlockPersonalLineRsp.newBuilder(); + + proto.setPersonalLineId(id) + .setLevel(level) + .setChapterId(chapterId); + + this.setData(proto); + } +}