From 5eb1d34b14e22bd445545fa1f522b3508c764c02 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Fri, 24 Jun 2022 01:12:52 -0700 Subject: [PATCH] Implement battle pass triggers/rewards --- .../java/emu/grasscutter/GameConstants.java | 4 + .../command/commands/SetBPLevelCommand.java | 3 +- .../java/emu/grasscutter/data/GameData.java | 12 +- .../data/excels/BattlePassMissionData.java | 69 ++++ .../BattlePassMissionExcelConfigData.java | 29 -- ...figData.java => BattlePassRewardData.java} | 4 +- .../grasscutter/database/DatabaseHelper.java | 1 + .../game/battlepass/BattlePassManager.java | 252 ++++++++++++- .../game/battlepass/BattlePassMission.java | 70 ++++ .../battlepass/BattlePassMissionManager.java | 78 ++++ .../game/battlepass/BattlePassReward.java | 52 +++ .../dungeons/challenge/DungeonChallenge.java | 3 + .../game/entity/EntityMonster.java | 3 + .../grasscutter/game/gacha/GachaManager.java | 6 +- .../grasscutter/game/inventory/Inventory.java | 10 +- .../game/managers/ResinManager.java | 6 +- .../game/managers/forging/ForgingManager.java | 4 + .../emu/grasscutter/game/player/Player.java | 5 + .../props/BattlePassMissionRefreshType.java | 18 + .../game/props/BattlePassMissionStatus.java | 26 ++ .../game/props/WatcherTriggerType.java | 337 ++++++++++++++++++ .../grasscutter/server/game/GameServer.java | 8 + .../recv/HandlerBuyBattlePassLevelReq.java | 22 ++ .../recv/HandlerSetBattlePassViewedReq.java | 19 + .../HandlerTakeBattlePassMissionPointReq.java | 12 +- .../recv/HandlerTakeBattlePassRewardReq.java | 12 +- .../send/PacketBattlePassAllDataNotify.java | 62 +--- ...cketBattlePassCurScheduleUpdateNotify.java | 28 +- .../PacketBattlePassMissionUpdateNotify.java | 42 +-- .../send/PacketBuyBattlePassLevelRsp.java | 18 + .../send/PacketSetBattlePassViewedRsp.java | 18 + .../send/PacketTakeBattlePassRewardRsp.java | 43 +-- 32 files changed, 1079 insertions(+), 197 deletions(-) create mode 100644 src/main/java/emu/grasscutter/data/excels/BattlePassMissionData.java delete mode 100644 src/main/java/emu/grasscutter/data/excels/BattlePassMissionExcelConfigData.java rename src/main/java/emu/grasscutter/data/excels/{BattlePassRewardExcelConfigData.java => BattlePassRewardData.java} (87%) create mode 100644 src/main/java/emu/grasscutter/game/battlepass/BattlePassMission.java create mode 100644 src/main/java/emu/grasscutter/game/battlepass/BattlePassMissionManager.java create mode 100644 src/main/java/emu/grasscutter/game/battlepass/BattlePassReward.java create mode 100644 src/main/java/emu/grasscutter/game/props/BattlePassMissionRefreshType.java create mode 100644 src/main/java/emu/grasscutter/game/props/BattlePassMissionStatus.java create mode 100644 src/main/java/emu/grasscutter/game/props/WatcherTriggerType.java create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerBuyBattlePassLevelReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerSetBattlePassViewedReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketBuyBattlePassLevelRsp.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketSetBattlePassViewedRsp.java diff --git a/src/main/java/emu/grasscutter/GameConstants.java b/src/main/java/emu/grasscutter/GameConstants.java index 5e50e3fd6..088ad8555 100644 --- a/src/main/java/emu/grasscutter/GameConstants.java +++ b/src/main/java/emu/grasscutter/GameConstants.java @@ -18,6 +18,10 @@ public final class GameConstants { public static final int SERVER_CONSOLE_UID = 99; // The UID of the server console's "player". + public static final int BATTLE_PASS_MAX_LEVEL = 50; + public static final int BATTLE_PASS_POINT_PER_LEVEL = 1000; + public static final int BATTLE_PASS_LEVEL_PRICE = 150; + // Default entity ability hashes. public static final String[] DEFAULT_ABILITY_STRINGS = { "Avatar_DefaultAbility_VisionReplaceDieInvincible", "Avatar_DefaultAbility_AvartarInShaderChange", "Avatar_SprintBS_Invincible", diff --git a/src/main/java/emu/grasscutter/command/commands/SetBPLevelCommand.java b/src/main/java/emu/grasscutter/command/commands/SetBPLevelCommand.java index 2da2567dd..47c9ee88e 100644 --- a/src/main/java/emu/grasscutter/command/commands/SetBPLevelCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/SetBPLevelCommand.java @@ -17,7 +17,6 @@ public final class SetBPLevelCommand implements CommandHandler { int level = Integer.parseInt(args.get(0)); - sender.getBattlePassManager().addPoint(level); - sender.getBattlePassManager().updateAwardTakenLevel(0); + sender.getBattlePassManager().addPoints(level); } } diff --git a/src/main/java/emu/grasscutter/data/GameData.java b/src/main/java/emu/grasscutter/data/GameData.java index 9ed0390cc..59b7c4944 100644 --- a/src/main/java/emu/grasscutter/data/GameData.java +++ b/src/main/java/emu/grasscutter/data/GameData.java @@ -95,8 +95,8 @@ public class GameData { private static final Int2ObjectMap investigationMonsterDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap cityDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap weatherDataMap = new Int2ObjectOpenHashMap<>(); - private static final Int2ObjectMap battlePassMissionExcelConfigDataMap = new Int2ObjectOpenHashMap<>(); - private static final Int2ObjectMap battlePassRewardExcelConfigDataMap = new Int2ObjectOpenHashMap<>(); + private static final Int2ObjectMap battlePassMissionDataMap = new Int2ObjectOpenHashMap<>(); + private static final Int2ObjectMap battlePassRewardDataMap = new Int2ObjectOpenHashMap<>(); // Cache private static Map> fetters = new HashMap<>(); @@ -424,11 +424,11 @@ public class GameData { return weatherDataMap; } - public static Int2ObjectMap getBattlePassMissionExcelConfigDataMap() { - return battlePassMissionExcelConfigDataMap; + public static Int2ObjectMap getBattlePassMissionDataMap() { + return battlePassMissionDataMap; } - public static Int2ObjectMap getBattlePassRewardExcelConfigDataMap() { - return battlePassRewardExcelConfigDataMap; + public static Int2ObjectMap getBattlePassRewardDataMap() { + return battlePassRewardDataMap; } } diff --git a/src/main/java/emu/grasscutter/data/excels/BattlePassMissionData.java b/src/main/java/emu/grasscutter/data/excels/BattlePassMissionData.java new file mode 100644 index 000000000..d51c2e6eb --- /dev/null +++ b/src/main/java/emu/grasscutter/data/excels/BattlePassMissionData.java @@ -0,0 +1,69 @@ +package emu.grasscutter.data.excels; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +import emu.grasscutter.data.GameResource; +import emu.grasscutter.data.ResourceType; +import emu.grasscutter.game.props.BattlePassMissionRefreshType; +import emu.grasscutter.game.props.WatcherTriggerType; +import emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.MissionStatus; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.FieldDefaults; + +@ResourceType(name = {"BattlePassMissionExcelConfigData.json"}) +@Getter +public class BattlePassMissionData extends GameResource { + private int addPoint; + private int id; + private int scheduleId; + private int progress; + private TriggerConfig triggerConfig; + private BattlePassMissionRefreshType refreshType; + + private transient Set mainParams; + + @Override + public int getId() { + return this.id; + } + + public WatcherTriggerType getTriggerType() { + return this.getTriggerConfig().getTriggerType(); + } + + public boolean isValidRefreshType() { + return getRefreshType() == null || + getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE || + getScheduleId() == 2701; + } + + @Override + public void onLoad() { + if (this.getTriggerConfig() != null && getTriggerConfig().getParamList()[0].length() > 0) { + this.mainParams = Arrays.stream(getTriggerConfig().getParamList()[0].split("[:;,]")).map(Integer::parseInt).collect(Collectors.toSet()); + } + } + + @Getter + public static class TriggerConfig { + private WatcherTriggerType triggerType; + private String[] paramList; + } + + public emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission toProto() { + var protoBuilder = emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.newBuilder(); + + protoBuilder + .setMissionId(getId()) + .setTotalProgress(this.getProgress()) + .setRewardBattlePassPoint(this.getAddPoint()) + .setMissionStatus(MissionStatus.MISSION_STATUS_UNFINISHED) + .setMissionType(this.getRefreshType() == null ? 0 : this.getRefreshType().getValue()); + + return protoBuilder.build(); + } +} diff --git a/src/main/java/emu/grasscutter/data/excels/BattlePassMissionExcelConfigData.java b/src/main/java/emu/grasscutter/data/excels/BattlePassMissionExcelConfigData.java deleted file mode 100644 index 10ecd963b..000000000 --- a/src/main/java/emu/grasscutter/data/excels/BattlePassMissionExcelConfigData.java +++ /dev/null @@ -1,29 +0,0 @@ -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; - -@ResourceType(name = {"BattlePassMissionExcelConfigData.json"}) -@FieldDefaults(level = AccessLevel.PRIVATE) -@Getter -@Setter -public class BattlePassMissionExcelConfigData extends GameResource { - - private int addPoint; - private int id; - private int progress; - private String refreshType; - - @Override - public void onLoad() { - } - - @Override - public int getId() { - return this.id; - } -} diff --git a/src/main/java/emu/grasscutter/data/excels/BattlePassRewardExcelConfigData.java b/src/main/java/emu/grasscutter/data/excels/BattlePassRewardData.java similarity index 87% rename from src/main/java/emu/grasscutter/data/excels/BattlePassRewardExcelConfigData.java rename to src/main/java/emu/grasscutter/data/excels/BattlePassRewardData.java index ca7f6277a..95ca24a80 100644 --- a/src/main/java/emu/grasscutter/data/excels/BattlePassRewardExcelConfigData.java +++ b/src/main/java/emu/grasscutter/data/excels/BattlePassRewardData.java @@ -9,8 +9,7 @@ import java.util.List; @ResourceType(name = "BattlePassRewardExcelConfigData.json") @Getter -@Setter -public class BattlePassRewardExcelConfigData extends GameResource { +public class BattlePassRewardData extends GameResource { private int indexId; private int level; private List freeRewardIdList; @@ -23,5 +22,6 @@ public class BattlePassRewardExcelConfigData extends GameResource { @Override public void onLoad() { + } } diff --git a/src/main/java/emu/grasscutter/database/DatabaseHelper.java b/src/main/java/emu/grasscutter/database/DatabaseHelper.java index 2696860c9..d4592b005 100644 --- a/src/main/java/emu/grasscutter/database/DatabaseHelper.java +++ b/src/main/java/emu/grasscutter/database/DatabaseHelper.java @@ -131,6 +131,7 @@ public final class DatabaseHelper { DatabaseManager.getGameDatabase().getCollection("gachas").deleteMany(eq("ownerId", player.getUid())); DatabaseManager.getGameDatabase().getCollection("items").deleteMany(eq("ownerId", player.getUid())); DatabaseManager.getGameDatabase().getCollection("quests").deleteMany(eq("ownerUid", player.getUid())); + DatabaseManager.getGameDatabase().getCollection("battlepass").deleteMany(eq("ownerUid", player.getUid())); // Delete friendships. // Here, we need to make sure to not only delete the deleted account's friendships, diff --git a/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java b/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java index 0bc22a71b..adee62b89 100644 --- a/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java +++ b/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java @@ -1,14 +1,34 @@ package emu.grasscutter.game.battlepass; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import org.bson.types.ObjectId; import dev.morphia.annotations.Entity; import dev.morphia.annotations.Id; import dev.morphia.annotations.Indexed; import dev.morphia.annotations.Transient; +import emu.grasscutter.GameConstants; +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.common.ItemParamData; +import emu.grasscutter.data.excels.BattlePassRewardData; +import emu.grasscutter.data.excels.RewardData; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.ActionReason; +import emu.grasscutter.game.props.BattlePassMissionStatus; +import emu.grasscutter.game.props.WatcherTriggerType; +import emu.grasscutter.net.proto.BattlePassCycleOuterClass.BattlePassCycle; +import emu.grasscutter.net.proto.BattlePassRewardTagOuterClass.BattlePassRewardTag; +import emu.grasscutter.net.proto.BattlePassUnlockStatusOuterClass.BattlePassUnlockStatus; +import emu.grasscutter.net.proto.BattlePassRewardTakeOptionOuterClass.BattlePassRewardTakeOption; +import emu.grasscutter.net.proto.BattlePassScheduleOuterClass.BattlePassSchedule; import emu.grasscutter.server.packet.send.PacketBattlePassCurScheduleUpdateNotify; +import emu.grasscutter.server.packet.send.PacketBattlePassMissionUpdateNotify; +import emu.grasscutter.server.packet.send.PacketTakeBattlePassRewardRsp; @Entity(value = "battlepass", useDiscriminator = false) public class BattlePassManager { @@ -17,7 +37,13 @@ public class BattlePassManager { @Indexed private int ownerUid; private int point; - private int awardTakenLevel; + private int level; + + private boolean viewed; + private boolean paid; + + private Map missions; + private Map takenRewards; @Deprecated // Morphia only public BattlePassManager() {} @@ -40,25 +66,215 @@ public class BattlePassManager { } public int getPoint() { - return point; - } - - public int getAwardTakenLevel() { - return awardTakenLevel; - } - - public void addPoint(int point){ - this.point += point; - player.getSession().send(new PacketBattlePassCurScheduleUpdateNotify(player.getSession().getPlayer())); - this.save(); - } - - public void updateAwardTakenLevel(int level){ - this.awardTakenLevel = level; - player.getSession().send(new PacketBattlePassCurScheduleUpdateNotify(player.getSession().getPlayer())); - this.save(); + return this.point; } + public int getLevel() { + return this.level; + } + + public boolean isViewed() { + return viewed; + } + + public void updateViewed() { + this.viewed = true; + } + + public boolean isPaid() { + return paid; + } + + public void addPoints(int point){ + this.addPointsDirectly(point); + + player.getSession().send(new PacketBattlePassCurScheduleUpdateNotify(player.getSession().getPlayer())); + this.save(); + } + + public void addPointsDirectly(int point) { + this.point += point; + + if (this.point >= GameConstants.BATTLE_PASS_POINT_PER_LEVEL && this.getLevel() < GameConstants.BATTLE_PASS_MAX_LEVEL) { + int levelups = (int) Math.floor((float) this.point / GameConstants.BATTLE_PASS_POINT_PER_LEVEL); + + // Make sure player cant go above max BP level + levelups = Math.min(levelups, GameConstants.BATTLE_PASS_MAX_LEVEL - levelups); + + // Set new points after level up + this.point = this.point - (levelups * GameConstants.BATTLE_PASS_POINT_PER_LEVEL); + this.level += levelups; + } + } + + public Map getMissions() { + if (this.missions == null) this.missions = new HashMap<>(); + return this.missions; + } + + // Will return a new empty mission if the mission id is not found + public BattlePassMission loadMissionById(int id) { + return getMissions().computeIfAbsent(id, i -> new BattlePassMission(i)); + } + + public boolean hasMission(int id) { + return getMissions().containsKey(id); + } + + public Map getTakenRewards() { + if (this.takenRewards == null) this.takenRewards = new HashMap<>(); + return this.takenRewards; + } + + // Mission triggers + public void triggerMission(WatcherTriggerType triggerType) { + getPlayer().getServer().getBattlePassMissionManager().triggerMission(getPlayer(), triggerType); + } + + public void triggerMission(WatcherTriggerType triggerType, int param, int progress) { + getPlayer().getServer().getBattlePassMissionManager().triggerMission(getPlayer(), triggerType, param, progress); + } + + // Handlers + public void takeMissionPoint(List missionIdList) { + // Obvious exploit check + if (missionIdList.size() > GameData.getBattlePassMissionDataMap().size()) { + return; + } + + List updatedMissions = new ArrayList<>(missionIdList.size()); + + for (int id : missionIdList) { + // Skip if we dont have this mission + if (!this.hasMission(id)) { + continue; + } + + BattlePassMission mission = this.loadMissionById(id); + + if (mission.getData() == null) { + this.getMissions().remove(mission.getId()); + continue; + } + + // Take reward + if (mission.getStatus() == BattlePassMissionStatus.MISSION_STATUS_FINISHED) { + this.addPointsDirectly(mission.getData().getAddPoint()); + mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_POINT_TAKEN); + + updatedMissions.add(mission); + } + } + + if (updatedMissions.size() > 0) { + // Save to db + this.save(); + + // Packet + getPlayer().sendPacket(new PacketBattlePassMissionUpdateNotify(updatedMissions)); + getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer())); + } + } + + public void takeReward(List takeOptionList) { + List rewardList = new ArrayList<>(); + + for (BattlePassRewardTakeOption option : takeOptionList) { + // Duplicate check + if (option.getTag().getRewardId() == 0 || getTakenRewards().containsKey(option.getTag().getRewardId())) { + continue; + } + + // Level check + if (option.getTag().getLevel() > this.getLevel()) { + continue; + } + + BattlePassRewardData rewardData = GameData.getBattlePassRewardDataMap().get(option.getTag().getLevel()); + + // Sanity check with excel data + if (rewardData.getFreeRewardIdList().contains(option.getTag().getRewardId())) { + rewardList.add(option.getTag()); + } else if (this.isPaid() && rewardData.getPaidRewardIdList().contains(option.getTag().getRewardId())) { + rewardList.add(option.getTag()); + } + } + + // Get rewards + List rewardItems = null; + + if (rewardList.size() > 0) { + rewardItems = new ArrayList<>(); + + for (BattlePassRewardTag tag : rewardList) { + RewardData reward = GameData.getRewardDataMap().get(tag.getRewardId()); + + if (reward == null) continue; + + BattlePassReward bpReward = new BattlePassReward(tag.getLevel(), tag.getRewardId(), tag.getUnlockStatus() == BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID); + this.getTakenRewards().put(bpReward.getRewardId(), bpReward); + + rewardItems.addAll(reward.getRewardItemList()); + } + + // Save to db + this.save(); + + // Add items and send battle pass schedule packet + getPlayer().getInventory().addItemParamDatas(rewardItems); + getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer())); + } + + getPlayer().sendPacket(new PacketTakeBattlePassRewardRsp(takeOptionList, rewardItems)); + } + + public int buyLevels(int buyLevel) { + int boughtLevels = Math.min(buyLevel, GameConstants.BATTLE_PASS_MAX_LEVEL - buyLevel); + + if (boughtLevels > 0) { + int price = GameConstants.BATTLE_PASS_LEVEL_PRICE * boughtLevels; + + if (getPlayer().getPrimogems() < price) { + return 0; + } + + this.level += boughtLevels; + this.save(); + + getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer())); + } + + return boughtLevels; + } + + public void resetDailyMissions() { + // TODO + } + + public void resetWeeklyMissions() { + // TODO + } + + // + public BattlePassSchedule getScheduleProto() { + BattlePassSchedule.Builder schedule = BattlePassSchedule.newBuilder() + .setScheduleId(2700) + .setLevel(this.getLevel()) + .setPoint(this.getPoint()) + .setBeginTime(0) + .setEndTime(2059483200) + .setIsViewed(this.isViewed()) + .setUnlockStatus(this.isPaid() ? BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID : BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE) + .setCurCyclePoints(0) + .setCurCycle(BattlePassCycle.newBuilder().setBeginTime(0).setEndTime(2059483200).setCycleIdx(3)); + + for (BattlePassReward reward : getTakenRewards().values()) { + schedule.addRewardTakenList(reward.toProto()); + } + + return schedule.build(); + } + public void save() { DatabaseHelper.saveBattlePass(this); } diff --git a/src/main/java/emu/grasscutter/game/battlepass/BattlePassMission.java b/src/main/java/emu/grasscutter/game/battlepass/BattlePassMission.java new file mode 100644 index 000000000..be870b911 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/battlepass/BattlePassMission.java @@ -0,0 +1,70 @@ +package emu.grasscutter.game.battlepass; + +import dev.morphia.annotations.Entity; +import dev.morphia.annotations.Transient; +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.excels.BattlePassMissionData; +import emu.grasscutter.game.props.BattlePassMissionStatus; + +@Entity +public class BattlePassMission { + private int id; + private int progress; + private BattlePassMissionStatus status; + + @Transient + private BattlePassMissionData data; + + @Deprecated // Morphia only + public BattlePassMission() {} + + public BattlePassMission(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + public BattlePassMissionData getData() { + if (this.data == null) { + this.data = GameData.getBattlePassMissionDataMap().get(getId()); + } + return this.data; + } + + public int getProgress() { + return progress; + } + + public void addProgress(int addProgress, int maxProgress) { + this.progress = Math.min(addProgress + this.progress, maxProgress); + } + + public BattlePassMissionStatus getStatus() { + if (status == null) status = BattlePassMissionStatus.MISSION_STATUS_UNFINISHED; + return status; + } + + public void setStatus(BattlePassMissionStatus status) { + this.status = status; + } + + public boolean isFinshed() { + return getStatus().getValue() >= 2; + } + + public emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission toProto() { + var protoBuilder = emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.newBuilder(); + + protoBuilder + .setMissionId(getId()) + .setCurProgress(getProgress()) + .setTotalProgress(getData().getProgress()) + .setRewardBattlePassPoint(getData().getAddPoint()) + .setMissionStatus(getStatus().getMissionStatus()) + .setMissionType(getData().getRefreshType() == null ? 0 : getData().getRefreshType().getValue()); + + return protoBuilder.build(); + } +} diff --git a/src/main/java/emu/grasscutter/game/battlepass/BattlePassMissionManager.java b/src/main/java/emu/grasscutter/game/battlepass/BattlePassMissionManager.java new file mode 100644 index 000000000..d45c4d978 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/battlepass/BattlePassMissionManager.java @@ -0,0 +1,78 @@ +package emu.grasscutter.game.battlepass; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.excels.BattlePassMissionData; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.BattlePassMissionRefreshType; +import emu.grasscutter.game.props.BattlePassMissionStatus; +import emu.grasscutter.game.props.WatcherTriggerType; +import emu.grasscutter.server.game.GameServer; +import emu.grasscutter.server.packet.send.PacketBattlePassMissionUpdateNotify; + +public class BattlePassMissionManager { + private final GameServer server; + private final Map> cachedTriggers; + + // BP Mission manager for the server, contains cached triggers so we dont have to load it for each player + public BattlePassMissionManager(GameServer server) { + this.server = server; + this.cachedTriggers = new HashMap<>(); + + for (BattlePassMissionData missionData : GameData.getBattlePassMissionDataMap().values()) { + if (missionData.isValidRefreshType()) { + List triggerList = getTriggers().computeIfAbsent(missionData.getTriggerType(), e -> new ArrayList<>()); + triggerList.add(missionData); + } + } + } + + public GameServer getServer() { + return server; + } + + private Map> getTriggers() { + return cachedTriggers; + } + + public void triggerMission(Player player, WatcherTriggerType triggerType) { + triggerMission(player, triggerType, 0, 1); + } + + public void triggerMission(Player player, WatcherTriggerType triggerType, int param, int progress) { + List triggerList = getTriggers().get(triggerType); + + if (triggerList == null || triggerList.isEmpty()) return; + + for (BattlePassMissionData data : triggerList) { + // Skip params check if param == 0 + if (param != 0) { + if (!data.getMainParams().contains(param)) { + continue; + } + } + + // Get mission from player, if it doesnt exist, then we make one + BattlePassMission mission = player.getBattlePassManager().loadMissionById(data.getId()); + + if (mission.isFinshed()) continue; + + // Add progress + mission.addProgress(progress, data.getProgress()); + + if (mission.getProgress() >= data.getProgress()) { + mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_FINISHED); + } + + // Save to db + player.getBattlePassManager().save(); + + // Packet + player.sendPacket(new PacketBattlePassMissionUpdateNotify(mission)); + } + } +} diff --git a/src/main/java/emu/grasscutter/game/battlepass/BattlePassReward.java b/src/main/java/emu/grasscutter/game/battlepass/BattlePassReward.java new file mode 100644 index 000000000..5d05ab84b --- /dev/null +++ b/src/main/java/emu/grasscutter/game/battlepass/BattlePassReward.java @@ -0,0 +1,52 @@ +package emu.grasscutter.game.battlepass; + +import dev.morphia.annotations.Entity; +import dev.morphia.annotations.Transient; +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.excels.BattlePassMissionData; +import emu.grasscutter.data.excels.BattlePassRewardData; +import emu.grasscutter.game.props.BattlePassMissionStatus; +import emu.grasscutter.net.proto.BattlePassRewardTagOuterClass.BattlePassRewardTag; +import emu.grasscutter.net.proto.BattlePassUnlockStatusOuterClass.BattlePassUnlockStatus; + +@Entity +public class BattlePassReward { + private int level; + private int rewardId; + private boolean paid; + + @Transient + private BattlePassMissionData data; + + @Deprecated // Morphia only + public BattlePassReward() {} + + public BattlePassReward(int level, int rewardId, boolean paid) { + this.level = level; + this.rewardId = rewardId; + this.paid = paid; + } + + public int getLevel() { + return level; + } + + public int getRewardId() { + return rewardId; + } + + public boolean isPaid() { + return paid; + } + + public BattlePassRewardTag toProto() { + var protoBuilder = BattlePassRewardTag.newBuilder(); + + protoBuilder + .setLevel(this.getLevel()) + .setRewardId(this.getRewardId()) + .setUnlockStatus(this.isPaid() ? BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID : BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE); + + return protoBuilder.build(); + } +} diff --git a/src/main/java/emu/grasscutter/game/dungeons/challenge/DungeonChallenge.java b/src/main/java/emu/grasscutter/game/dungeons/challenge/DungeonChallenge.java index 1333fc96e..6836f44c8 100644 --- a/src/main/java/emu/grasscutter/game/dungeons/challenge/DungeonChallenge.java +++ b/src/main/java/emu/grasscutter/game/dungeons/challenge/DungeonChallenge.java @@ -11,6 +11,7 @@ import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.inventory.ItemType; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ActionReason; +import emu.grasscutter.game.props.WatcherTriggerType; import emu.grasscutter.game.world.Scene; import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq; import emu.grasscutter.scripts.constants.EventType; @@ -98,6 +99,8 @@ public class DungeonChallenge extends WorldChallenge { getScene().getDungeonSettleObservers().forEach(o -> o.onDungeonSettle(getScene())); getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE, new ScriptArgs(this.isSuccess() ? 1 : 0)); + // Battle pass trigger + this.getScene().getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON)); } } diff --git a/src/main/java/emu/grasscutter/game/entity/EntityMonster.java b/src/main/java/emu/grasscutter/game/entity/EntityMonster.java index 99ab3ea0e..b8c47e3db 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityMonster.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityMonster.java @@ -8,6 +8,7 @@ import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.EntityIdType; import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.PlayerProperty; +import emu.grasscutter.game.props.WatcherTriggerType; import emu.grasscutter.game.world.Scene; import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo; import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair; @@ -154,6 +155,8 @@ public class EntityMonster extends GameEntity { getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_DIE, new ScriptArgs().setParam1(this.getConfigId())); } } + // Battle Pass trigger + getScene().getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_MONSTER_DIE, this.getMonsterId(), 1)); } public void recalcStats() { diff --git a/src/main/java/emu/grasscutter/game/gacha/GachaManager.java b/src/main/java/emu/grasscutter/game/gacha/GachaManager.java index 10cc5dae3..c7fff96e5 100644 --- a/src/main/java/emu/grasscutter/game/gacha/GachaManager.java +++ b/src/main/java/emu/grasscutter/game/gacha/GachaManager.java @@ -27,6 +27,7 @@ import emu.grasscutter.game.inventory.Inventory; import emu.grasscutter.game.inventory.ItemType; import emu.grasscutter.game.inventory.MaterialType; import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.WatcherTriggerType; import emu.grasscutter.net.proto.GachaItemOuterClass.GachaItem; import emu.grasscutter.net.proto.GachaTransferItemOuterClass.GachaTransferItem; import emu.grasscutter.net.proto.GetGachaInfoRspOuterClass.GetGachaInfoRsp; @@ -372,9 +373,12 @@ public class GachaManager { if (starglitter > 0) { inventory.addItem(starglitterId, starglitter); } - + // Packets player.sendPacket(new PacketDoGachaRsp(banner, list, gachaInfo)); + + // Battle Pass trigger + player.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_GACHA_NUM, 0, times); } private synchronized void startWatcher(GameServer server) { diff --git a/src/main/java/emu/grasscutter/game/inventory/Inventory.java b/src/main/java/emu/grasscutter/game/inventory/Inventory.java index b22217bd9..13f201c01 100644 --- a/src/main/java/emu/grasscutter/game/inventory/Inventory.java +++ b/src/main/java/emu/grasscutter/game/inventory/Inventory.java @@ -18,6 +18,7 @@ import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.PlayerProperty; +import emu.grasscutter.game.props.WatcherTriggerType; import emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam; import emu.grasscutter.server.packet.send.PacketAvatarEquipChangeNotify; import emu.grasscutter.server.packet.send.PacketItemAddHintNotify; @@ -95,6 +96,7 @@ public class Inventory implements Iterable { GameItem result = putItem(item); if (result != null) { + getPlayer().getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_OBTAIN_MATERIAL_NUM, result.getItemId(), result.getCount()); getPlayer().sendPacket(new PacketStoreItemChangeNotify(result)); return true; } @@ -131,7 +133,9 @@ public class Inventory implements Iterable { for (GameItem item : items) { GameItem result = putItem(item); + if (result != null) { + getPlayer().getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_OBTAIN_MATERIAL_NUM, result.getItemId(), result.getCount()); changedItems.add(result); } } @@ -368,7 +372,7 @@ public class Inventory implements Iterable { if (count <= 0 || item == null) { return false; } - + if (item.getItemData().isEquip()) { item.setCount(0); } else { @@ -389,6 +393,10 @@ public class Inventory implements Iterable { getPlayer().sendPacket(new PacketStoreItemChangeNotify(item)); } + // Battle pass trigger + int removeCount = Math.min(count, item.getCount()); + getPlayer().getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_COST_MATERIAL, item.getItemId(), removeCount); + // Update in db item.save(); diff --git a/src/main/java/emu/grasscutter/game/managers/ResinManager.java b/src/main/java/emu/grasscutter/game/managers/ResinManager.java index cefd0ede8..e55809f41 100644 --- a/src/main/java/emu/grasscutter/game/managers/ResinManager.java +++ b/src/main/java/emu/grasscutter/game/managers/ResinManager.java @@ -2,6 +2,7 @@ package emu.grasscutter.game.managers; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.PlayerProperty; +import emu.grasscutter.game.props.WatcherTriggerType; import emu.grasscutter.server.packet.send.PacketPlayerPropNotify; import emu.grasscutter.server.packet.send.PacketResinChangeNotify; import emu.grasscutter.utils.Utils; @@ -45,7 +46,10 @@ public class ResinManager { // Send packets. this.player.sendPacket(new PacketPlayerPropNotify(this.player, PlayerProperty.PROP_PLAYER_RESIN)); this.player.sendPacket(new PacketResinChangeNotify(this.player)); - + + // Battle Pass trigger + this.player.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_COST_MATERIAL, 106, amount); // Resin item id = 106 + return true; } diff --git a/src/main/java/emu/grasscutter/game/managers/forging/ForgingManager.java b/src/main/java/emu/grasscutter/game/managers/forging/ForgingManager.java index b9908e248..4edb6bf33 100644 --- a/src/main/java/emu/grasscutter/game/managers/forging/ForgingManager.java +++ b/src/main/java/emu/grasscutter/game/managers/forging/ForgingManager.java @@ -16,6 +16,7 @@ import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.inventory.ItemType; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ActionReason; +import emu.grasscutter.game.props.WatcherTriggerType; import emu.grasscutter.net.proto.ForgeStartReqOuterClass; import emu.grasscutter.net.proto.ForgeQueueDataOuterClass.ForgeQueueData; import emu.grasscutter.net.proto.ForgeQueueManipulateReqOuterClass.ForgeQueueManipulateReq; @@ -195,6 +196,9 @@ public class ForgingManager { GameItem addItem = new GameItem(resultItemData, data.getResultItemCount() * finished); this.player.getInventory().addItem(addItem); + + // Battle pass trigger handler + this.player.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_DO_FORGE, 0, finished); // Replace active forge with a new one for the unfinished items, if there are any. if (unfinished > 0) { diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index f52f6d6be..f883d27a6 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -42,6 +42,7 @@ import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.ClimateType; import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.props.SceneType; +import emu.grasscutter.game.props.WatcherTriggerType; import emu.grasscutter.game.quest.QuestManager; import emu.grasscutter.game.shop.ShopLimit; import emu.grasscutter.game.tower.TowerData; @@ -1268,6 +1269,7 @@ public class Player { public void loadBattlePassManager() { if (this.battlePassManager != null) return; this.battlePassManager = DatabaseHelper.loadBattlePass(this); + this.battlePassManager.getMissions().values().removeIf(mission -> mission.getData() == null); } public AbilityManager getAbilityManager() { @@ -1425,6 +1427,9 @@ public class Player { getTodayMoonCard(); // The timer works at 0:0, some users log in after that, use this method to check if they have received a reward today or not. If not, send the reward. + // Battle Pass trigger + this.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_LOGIN); + this.furnitureManager.onLogin(); // Home home = GameHome.getByUid(getUid()); diff --git a/src/main/java/emu/grasscutter/game/props/BattlePassMissionRefreshType.java b/src/main/java/emu/grasscutter/game/props/BattlePassMissionRefreshType.java new file mode 100644 index 000000000..b07f20ea2 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/props/BattlePassMissionRefreshType.java @@ -0,0 +1,18 @@ +package emu.grasscutter.game.props; + +public enum BattlePassMissionRefreshType { + BATTLE_PASS_MISSION_REFRESH_DAILY (0), + BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE (1), // Weekly + BATTLE_PASS_MISSION_REFRESH_SCHEDULE (2), // Per BP + BATTLE_PASS_MISSION_REFRESH_CYCLE (1); // Event? + + private final int value; + + BattlePassMissionRefreshType(int value) { + this.value = value; + } + + public int getValue() { + return value; + } +} diff --git a/src/main/java/emu/grasscutter/game/props/BattlePassMissionStatus.java b/src/main/java/emu/grasscutter/game/props/BattlePassMissionStatus.java new file mode 100644 index 000000000..7f2dabc90 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/props/BattlePassMissionStatus.java @@ -0,0 +1,26 @@ +package emu.grasscutter.game.props; + +import emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.MissionStatus; + +public enum BattlePassMissionStatus { + MISSION_STATUS_INVALID (0, MissionStatus.MISSION_STATUS_INVALID), + MISSION_STATUS_UNFINISHED (1, MissionStatus.MISSION_STATUS_UNFINISHED), + MISSION_STATUS_FINISHED (2, MissionStatus.MISSION_STATUS_FINISHED), + MISSION_STATUS_POINT_TAKEN (3, MissionStatus.MISSION_STATUS_POINT_TAKEN); + + private final int value; + private final MissionStatus missionStatus; + + BattlePassMissionStatus(int value, MissionStatus missionStatus) { + this.value = value; + this.missionStatus = missionStatus; // In case proto enum values change later + } + + public int getValue() { + return value; + } + + public MissionStatus getMissionStatus() { + return missionStatus; + } +} diff --git a/src/main/java/emu/grasscutter/game/props/WatcherTriggerType.java b/src/main/java/emu/grasscutter/game/props/WatcherTriggerType.java new file mode 100644 index 000000000..d9be1d8e2 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/props/WatcherTriggerType.java @@ -0,0 +1,337 @@ +package emu.grasscutter.game.props; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + +public enum WatcherTriggerType { + TRIGGER_NONE (0), + TRIGGER_COMBAT_CONFIG_COMMON (1), + TRIGGER_ELEMENT_VIEW (2), + TRIGGER_ENTER_AIRFLOW (5), + TRIGGER_NEW_MONSTER (6), + TRIGGER_NEW_AFFIX (8), + TRIGGER_CHANGE_INPUT_DEVICE_TYPE (9), + TRIGGER_PAIMON_ANGRY_VOICE_EASTER_EGG (10), + TRIGGER_WIND_CRYSTAL (11), + TRIGGER_ELEMENT_BALL (101), + TRIGGER_WORLD_LEVEL_UP (102), + TRIGGER_DUNGEON_ENTRY_TO_BE_EXPLORED (103), + TRIGGER_UNLOCK_GATE_TEMPLE (104), + TRIGGER_UNLOCK_AREA (105), + TRIGGER_UNLOCK_TRANS_POINT (106), + TRIGGER_OPEN_CHEST_WITH_GADGET_ID (107), + TRIGGER_CITY_LEVEL_UP (108), + TRIGGER_MONSTER_DIE (109), + TRIGGER_PLATFORM_START_MOVE (110), + TRIGGER_GROUP_NOTIFY (111), + TRIGGER_ELEMENT_TYPE_CHANGE (112), + TRIGGER_GADGET_INTERACTABLE (113), + TRIGGER_COLLECT_SET_OF_READINGS (114), + TRIGGER_TELEPORT_WITH_CERTAIN_PORTAL (115), + TRIGGER_WORLD_GATHER (116), + TRIGGER_TAKE_GENERAL_REWARD (117), + TRIGGER_BATTLE_FOR_MONSTER_DIE_OR (118), + TRIGGER_BATTLE_FOR_MONSTER_DIE_AND (119), + TRIGGER_OPEN_WORLD_CHEST (120), + TRIGGER_ENTER_CLIMATE_AREA (121), + TRIGGER_UNLOCK_SCENE_POINT (122), + TRIGGER_INTERACT_GADGET_WITH_INTERACT_ID (123), + TRIGGER_OBTAIN_AVATAR (201), + TRIGGER_PLAYER_LEVEL (202), + TRIGGER_AVATAR_UPGRADE (203), + TRIGGER_AVATAR_PROMOTE (204), + TRIGGER_WEAPON_UPGRADE (205), + TRIGGER_WEAPON_PROMOTE (206), + TRIGGER_RELIQUARY_UPGRADE (207), + TRIGGER_WEAR_RELIQUARY (208), + TRIGGER_UPGRADE_TALENT (209), + TRIGGER_UNLOCK_RECIPE (210), + TRIGGER_RELIQUARY_SET_NUM (211), + TRIGGER_OBTAIN_MATERIAL_NUM (212), + TRIGGER_OBTAIN_RELIQUARY_NUM (213), + TRIGGER_GACHA_NUM (214), + TRIGGER_ANY_RELIQUARY_UPGRADE (215), + TRIGGER_FETTER_LEVEL_AVATAR_NUM (216), + TRIGGER_SKILLED_AT_RECIPE (217), + TRIGGER_RELIQUARY_UPGRADE_EQUAL_RANK_LEVEL (218), + TRIGGER_SPECIFIED_WEAPON_UPGRADE (219), + TRIGGER_SPECIFIED_WEAPON_AWAKEN (220), + TRIGGER_UNLOCK_SPECIFIC_RECIPE_OR (221), + TRIGGER_POSSESS_MATERIAL_NUM (222), + TRIGGER_EXHIBITION_ACCUMULABLE_VALUE (223), + TRIGGER_EXHIBITION_REPLACEABLE_VALUE_SETTLE_NUM (224), + TRIGGER_ANY_WEAPON_UPGRADE_NUM (225), + TRIGGER_ANY_RELIQUARY_UPGRADE_NUM (226), + TRIGGER_ACTIVITY_SCORE_EXCEED_VALUE (227), + TRIGGER_UNLOCK_SPECIFIC_FORGE_OR (228), + TRIGGER_UNLOCK_SPECIFIC_ANIMAL_CODEX (229), + TRIGGER_OBTAIN_ITEM_NUM (230), + TRIGGER_CAPTURE_ANIMAL (231), + TRIGGER_DAILY_TASK (301), + TRIGGER_RAND_TASK (302), + TRIGGER_AVATAR_EXPEDITION (303), + TRIGGER_FINISH_TOWER_LEVEL (304), + TRIGGER_WORLD_BOSS_REWARD (306), + TRIGGER_FINISH_DUNGEON (307), + TRIGGER_START_AVATAR_EXPEDITION (308), + TRIGGER_OPEN_BLOSSOM_CHEST (309), + TRIGGER_FINISH_BLOSSOM_PROGRESS (310), + TRIGGER_DONE_TOWER_GADGET_UNHURT (311), + TRIGGER_DONE_TOWER_STARS (312), + TRIGGER_DONE_TOWER_UNHURT (313), + TRIGGER_STEAL_FOOD_TIMES (314), + TRIGGER_DONE_DUNGEON_WITH_SAME_ELEMENT_AVATARS (315), + TRIGGER_GROUP_FLIGHT_CHALLENGE_REACH_POINTS (316), + TRIGGER_FINISH_DAILY_DELIVERY_NUM (317), + TRIGGER_TOWER_STARS_NUM (318), + TRIGGER_FINISH_SPECIFED_TYPE_BLOSSOM_NUM (319), + TRIGGER_FINISH_SPECIFED_TYPE_BLOSSOM_CLIMATE_METER (320), + TRIGGER_FINISH_BLOSSOM_GROUP_VARIABLE_GT (321), + TRIGGER_EFFIGY_CHALLENGE_SCORE (322), + TRIGGER_FINISH_ROUTINE (323), + TRIGGER_ACTIVITY_EXPEDITION_FINISH (324), + TRIGGER_ACTIVITY_CHANNELLER_SLAB_FINISH_ALL_CAMP (325), + TRIGGER_ACTIVITY_CHANNELLER_SLAB_FINISH_ALL_ONEOFF_DUNGEON (326), + TRIGGER_ACTIVITY_CHANNELLER_SLAB_LOOP_DUNGEON_TOTAL_SCORE (327), + TRIGGER_GROUP_SUMMER_TIME_SPRINT_BOAT_REACH_POINTS (328), + TRIGGER_WEEKLY_BOSS_KILL (329), + TRIGGER_BOUNCE_CONJURING_FINISH_COUNT (330), + TRIGGER_BOUNCE_CONJURING_SCORE (331), + TRIGGER_GROUP_VARIABLE_SET_VALUE_TO (332), + TRIGGER_KILL_GADGETS_BY_SPECIFIC_SKILL (333), + TRIGGER_KILL_MONSTERS_WITHOUT_VEHICLE (334), + TRIGGER_KILL_MONSTER_IN_AREA (335), + TRIGGER_ENTER_VEHICLE (336), + TRIGGER_VEHICLE_DURATION (337), + TRIGGER_VEHICLE_FRIENDS (338), + TRIGGER_VEHICLE_KILLED_BY_MONSTER (339), + TRIGGER_VEHICLE_DASH (340), + TRIGGER_DO_COOK (401), + TRIGGER_DO_FORGE (402), + TRIGGER_DO_COMPOUND (403), + TRIGGER_DO_COMBINE (404), + TRIGGER_BUY_SHOP_GOODS (405), + TRIGGER_FORGE_WEAPON (406), + TRIGGER_MP_PLAY_BATTLE_WIN (421), + TRIGGER_KILL_GROUP_MONSTER (422), + TRIGGER_CRUCIBLE_ELEMENT_SCORE (423), + TRIGGER_MP_DUNGEON_TIMES (424), + TRIGGER_MP_KILL_MONSTER_NUM (425), + TRIGGER_CRUCIBLE_MAX_BALL (426), + TRIGGER_CRUCIBLE_MAX_SCORE (427), + TRIGGER_CRUCIBLE_SUBMIT_BALL (428), + TRIGGER_CRUCIBLE_WORLD_LEVEL_SCORE (429), + TRIGGER_MP_PLAY_GROUP_STATISTIC (430), + TRIGGER_KILL_GROUP_SPECIFIC_MONSTER (431), + TRIGGER_REACH_MP_PLAY_SCORE (432), + TRIGGER_REACH_MP_PLAY_RECORD (433), + TRIGGER_TREASURE_MAP_DONE_REGION (434), + TRIGGER_SEA_LAMP_MINI_QUEST (435), + TRIGGER_FINISH_FIND_HILICHURL_LEVEL (436), + TRIGGER_COMBINE_ITEM (437), + TRIGGER_FINISH_CHALLENGE_IN_DURATION (438), + TRIGGER_FINISH_CHALLENGE_LEFT_TIME (439), + TRIGGER_MP_KILL_MONSTER_ID_NUM (440), + TRIGGER_LOGIN (501), + TRIGGER_COST_MATERIAL (502), + TRIGGER_DELIVER_ITEM_TO_SALESMAN (503), + TRIGGER_USE_ITEM (504), + TRIGGER_ACCUMULATE_DAILY_LOGIN (505), + TRIGGER_FINISH_CHALLENGE (601), + TRIGGER_MECHANICUS_UNLOCK_GEAR (602), + TRIGGER_MECHANICUS_LEVELUP_GEAR (603), + TRIGGER_MECHANICUS_DIFFICULT (604), + TRIGGER_MECHANICUS_DIFFICULT_SCORE (605), + TRIGGER_MECHANICUS_KILL_MONSTER (606), + TRIGGER_MECHANICUS_BUILDING_POINT (607), + TRIGGER_MECHANICUS_DIFFICULT_EQ (608), + TRIGGER_MECHANICUS_BATTLE_END (609), + TRIGGER_MECHANICUS_BATTLE_END_EXCAPED_LESS_THAN (610), + TRIGGER_MECHANICUS_BATTLE_END_POINTS_MORE_THAN (611), + TRIGGER_MECHANICUS_BATTLE_END_GEAR_MORE_THAN (612), + TRIGGER_MECHANICUS_BATTLE_END_PURE_GEAR_DAMAGE (613), + TRIGGER_MECHANICUS_BATTLE_END_CARD_PICK_MORE_THAN (614), + TRIGGER_MECHANICUS_BATTLE_END_CARD_TARGET_MORE_THAN (615), + TRIGGER_MECHANICUS_BATTLE_END_BUILD_GEAR_MORE_THAN (616), + TRIGGER_MECHANICUS_BATTLE_END_GEAR_KILL_MORE_THAN (617), + TRIGGER_MECHANICUS_BATTLE_END_ROUND_MORE_THAN (618), + TRIGGER_MECHANICUS_BATTLE_END_ROUND (619), + TRIGGER_MECHANICUS_BATTLE_FIN_CHALLENGE_MORE_THAN (620), + TRIGGER_MECHANICUS_BATTLE_WATCHER_FINISH_COUNT (621), + TRIGGER_MECHANICUS_BATTLE_INTERACT_COUNT (622), + TRIGGER_MECHANICUS_BATTLE_DIFFICULT_ESCAPE (623), + TRIGGER_MECHANICUS_BATTLE_DIFFICULT_GEAR_NUM (624), + TRIGGER_MECHANICUS_BATTLE_DIFFICULT_GEAR_ID_NUM (625), + TRIGGER_FLEUR_FAIR_DUNGEON_FINISH_IN_LIMIT_TIME (626), + TRIGGER_FLEUR_FAIR_DUNGEON_FINISH_KEEP_ENERGY (627), + TRIGGER_FLEUR_FAIR_DUNGEON_FINISH_WITH_GROUP_VARIABLE (628), + TRIGGER_FLEUR_FAIR_DUNGEON_FINISH_WITH_BUFF_NUM (629), + TRIGGER_FLEUR_FAIR_DUNGEON_MISSION_FINISH (630), + TRIGGER_FINISH_DUNGEON_AND_CHALLENGE_REMAIN_TIME_GREATER_THAN (631), + TRIGGER_FINISH_DUNGEON_WITH_MIST_TRIAL_STAT (632), + TRIGGER_DUNGEON_MIST_TRIAL_STAT (633), + TRIGGER_DUNGEON_ELEMENT_REACTION_NUM (634), + TRIGGER_LEVEL_AVATAR_FINISH_DUNGEON_COUNT (635), + TRIGGER_CHESS_REACH_LEVEL (636), + TRIGGER_CHESS_DUNGEON_ADD_SCORE (637), + TRIGGER_CHESS_DUNGEON_SUCC_WITH_ESCAPED_MONSTERS_LESS_THAN (638), + TRIGGER_CHESS_DUNGEON_SUCC_WITH_TOWER_COUNT_LESS_OR_EQUAL (639), + TRIGGER_CHESS_DUNGEON_SUCC_WITH_CARD_COUNT_LESS_OR_EQUAL (640), + TRIGGER_CHESS_DUNGEON_SUCC_WITH_CARD_COUNT_GREATER_THAN (641), + TRIGGER_CHESS_KILL_MONSTERS (642), + TRIGGER_CHESS_COST_BUILDING_POINTS (643), + TRIGGER_SUMO_STAGE_SCORE_REACH (644), + TRIGGER_SUMO_TOTAL_MAX_SCORE_REACH (645), + TRIGGER_ROGUE_DESTROY_GADGET_NUM (646), + TRIGGER_ROGUE_KILL_MONSTER_NUM (647), + TRIGGER_ROGUE_FINISH_WITHOUT_USING_SPRING_CELL (649), + TRIGGER_ROGUE_FINISH_ALL_CHALLENGE_CELL (650), + TRIGGER_ROGUE_FINISH_WITH_AVATAR_ELEMENT_TYPE_NUM_LESS_THAN (651), + TRIGGER_ROGUE_FINISH_WITH_AVATAR_NUM_LESS_THAN (652), + TRIGGER_ROGUE_FINISH_NO_AVATAR_DEAD (653), + TRIGGER_ROGUE_SHIKIGAMI_UPGRADE (654), + TRIGGER_ROGUE_CURSE_NUM (655), + TRIGGER_ROGUE_SELECT_CARD_NUM (656), + TRIGGER_FINISH_QUEST_AND (700), + TRIGGER_FINISH_QUEST_OR (701), + TRIGGER_DAILY_TASK_VAR_EQUAL (702), + TRIGGER_QUEST_GLOBAL_VAR_EQUAL (703), + TRIGGER_TALK_NUM (704), + TRIGGER_FINISH_PARENT_QUEST_AND (705), + TRIGGER_FINISH_PARENT_QUEST_OR (706), + TRIGGER_ELEMENT_REACTION_TIMELIMIT_NUM (800), + TRIGGER_ELEMENT_REACTION_TIMELIMIT_KILL_NUM (801), + TRIGGER_ELEMENT_REACTION_TIMELIMIT_DAMAGE_NUM (802), + TRIGGER_ABILITY_STATE_PASS_TIME (803), + TRIGGER_MAX_CRITICAL_DAMAGE (804), + TRIGGER_FULL_SATIATION_TEAM_AVATAR_NUM (805), + TRIGGER_KILLED_BY_CERTAIN_MONSTER (806), + TRIGGER_CUR_AVATAR_HURT (807), + TRIGGER_CUR_AVATAR_ABILITY_STATE (808), + TRIGGER_USE_ENERGY_SKILL_NUM_TIMELIMIT (809), + TRIGGER_SHIELD_SOURCE_NUM (810), + TRIGGER_CUR_AVATAR_HURT_BY_SPECIFIC_ABILITY (811), + TRIGGER_KILLED_BY_SPECIFIC_ABILITY (812), + TRIGGER_MAX_DASH_TIME (900), + TRIGGER_MAX_FLY_TIME (901), + TRIGGER_MAX_FLY_MAP_DISTANCE (902), + TRIGGER_SIT_DOWN_IN_POINT (903), + TRIGGER_DASH (904), + TRIGGER_CLIMB (905), + TRIGGER_FLY (906), + TRIGGER_CITY_REPUTATION_LEVEL (930), + TRIGGER_CITY_REPUTATION_FINISH_REQUEST (931), + TRIGGER_HUNTING_FINISH_NUM (932), + TRIGGER_HUNTING_FAIL_NUM (933), + TRIGGER_OFFERING_LEVEL (934), + TRIGGER_MIRACLE_RING_DELIVER_ITEM (935), + TRIGGER_MIRACLE_RING_TAKE_REWARD (936), + TRIGGER_BLESSING_EXCHANGE_PIC_NUM (937), + TRIGGER_BLESSING_REDEEM_REWARD_NUM (938), + TRIGGER_GALLERY_BALLOON_REACH_SCORE (939), + TRIGGER_GALLERY_FALL_REACH_SCORE (940), + TRIGGER_FLEUR_FAIR_MUSIC_GAME_REACH_SCORE (941), + TRIGGER_MAIN_COOP_SAVE_POINT_AND (942), + TRIGGER_MAIN_COOP_SAVE_POINT_OR (943), + TRIGGER_MAIN_COOP_VAR_EQUAL (944), + TRIGGER_FINISH_ALL_ARENA_CHALLENGE_WATCHER_IN_SCHEDULE (945), + TRIGGER_GALLERY_BUOYANT_COMBAT_REACH_SCORE (946), + TRIGGER_BUOYANT_COMBAT_REACH_NEW_SCORE_LEVEL (947), + TRIGGER_PLACE_MIRACLE_RING (948), + TRIGGER_LUNA_RITE_SEARCH (949), + TRIGGER_GALLERY_FISH_REACH_SCORE (950), + TRIGGER_GALLERY_TRIATHLON_REACH_SCORE (951), + TRIGGER_WINTER_CAMP_SNOWMAN_COMPLEIET (952), + TRIGGER_CREATE_CUSTOM_DUNGEON (953), + TRIGGER_PUBLISH_CUSTOM_DUNGEON (954), + TRIGGER_PLAY_OTHER_CUSTOM_DUNGEON (955), + TRIGGER_FINISH_CUSTOM_DUNGEON_OFFICIAL (956), + TRIGGER_CUSTOM_DUNGEON_OFFICIAL_COIN (957), + TRIGGER_OBTAIN_WOOD_TYPE (1000), + TRIGGER_OBTAIN_WOOD_COUNT (1001), + TRIGGER_UNLOCK_FURNITURE_COUNT (1002), + TRIGGER_FURNITURE_MAKE (1003), + TRIGGER_HOME_LEVEL (1004), + TRIGGER_HOME_COIN (1005), + TRIGGER_HOME_COMFORT_LEVEL (1006), + TRIGGER_HOME_LIMITED_SHOP_BUY (1007), + TRIGGER_FURNITURE_SUITE_TYPE (1008), + TRIGGER_ARRANGEMENT_FURNITURE_COUNT (1009), + TRIGGER_ENTER_SELF_HOME (1010), + TRIGGER_HOME_MODULE_COMFORT_VALUE (1011), + TRIGGER_HOME_ENTER_ROOM (1012), + TRIGGER_HOME_AVATAR_IN (1013), + TRIGGER_HOME_AVATAR_REWARD_EVENT_COUNT (1014), + TRIGGER_HOME_AVATAR_TALK_FINISH_COUNT (1015), + TRIGGER_HOME_AVATAR_REWARD_EVENT_ALL_COUNT (1016), + TRIGGER_HOME_AVATAR_TALK_FINISH_ALL_COUNT (1017), + TRIGGER_HOME_AVATAR_FETTER_GET (1018), + TRIGGER_HOME_AVATAR_IN_COUNT (1019), + TRIGGER_HOME_DO_PLANT (1020), + TRIGGER_ARRANGEMENT_FURNITURE (1021), + TRIGGER_HOME_GATHER_COUNT (1022), + TRIGGER_HOME_FIELD_GATHER_COUNT (1023), + TRIGGER_HOME_UNLOCK_BGM_COUNT (1024), + TRIGGER_FISHING_SUCC_NUM (1100), + TRIGGER_FISHING_KEEP_BONUS (1101), + TRIGGER_EMPTY_FISH_POOL (1102), + TRIGGER_FISHING_FAIL_NUM (1103), + TRIGGER_SHOCK_FISH_NUM (1104), + TRIGGER_PLANT_FLOWER_SET_WISH (1105), + TRIGGER_PLANT_FLOWER_GIVE_FLOWER (1106), + TRIGGER_PLANT_FLOWER_OBTAIN_FLOWER_TYPE (1107), + TRIGGER_PLANT_FLOWER_COMMON_OBTAIN_FLOWER_TYPE (1108), + TRIGGER_FINISH_LANV2_PROJECTION_LEVEL (1111), + TRIGGER_GALLERY_SALVAGE_REACH_SCORE (1112), + TRIGGER_LANV2_FIREWORKS_CHALLENGE_REACH_SCORE (1113), + TRIGGER_POTION_STAGE_LEVEL_PASS_NUM (1115), + TRIGGER_POTION_STAGE_OBTAIN_MEDAL_NUM (1116), + TRIGGER_POTION_STAGE_REACH_TOTAL_SCORE (1117), + TRIGGER_BARTENDER_FINISH_STORY_MODULE (1120), + TRIGGER_BARTENDER_CHALLENGE_MODULE_LEVEL_SCORE (1121), + TRIGGER_BARTENDER_UNLOCK_FORMULA (1122), + TRIGGER_MICHIAE_MATSURI_UNLOCK_CRYSTAL_SKILL_REACH_NUM (1123), + TRIGGER_MICHIAE_MATSURI_FINISH_DARK_CHALLENGE_REACH_NUM (1124), + TRIGGER_CAPTURE_ENV_ANIMAL_REACH_NUM (1125), + TRIGGER_SPICE_MAKE_FORMULA_TIMES (1126), + TRIGGER_SPICE_GIVE_FOOD_TIMES (1127), + TRIGGER_SPICE_MAKE_FORMULA_SUCCESSFUL_TIMES (1128), + TRIGGER_IRODORI_FINISH_FLOWER_THEME (1131), + TRIGGER_IRODORI_FINISH_MASTER_STAGE (1132), + TRIGGER_IRODORI_CHESS_STAGE_REACH_SCORE (1133), + TRIGGER_IRODORI_FINISH_POETRY_THEME (1134), + TRIGGER_PHOTO_FINISH_POS_ID (1135), + TRIGGER_CRYSTAL_LINK_LEVEL_SCORE_REACH (1138), + TRIGGER_CRYSTAL_LINK_TOTAL_MAX_SCORE_REACH (1139); + + private final int value; + private static final Int2ObjectMap map = new Int2ObjectOpenHashMap<>(); + private static final Map stringMap = new HashMap<>(); + + static { + Stream.of(values()).forEach(e -> { + map.put(e.getValue(), e); + stringMap.put(e.name(), e); + }); + } + + private WatcherTriggerType(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static WatcherTriggerType getTypeByValue(int value) { + return map.getOrDefault(value, TRIGGER_NONE); + } + + public static WatcherTriggerType getTypeByName(String name) { + return stringMap.getOrDefault(name, TRIGGER_NONE); + } +} diff --git a/src/main/java/emu/grasscutter/server/game/GameServer.java b/src/main/java/emu/grasscutter/server/game/GameServer.java index 76eedbc51..4ae5c8549 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServer.java +++ b/src/main/java/emu/grasscutter/server/game/GameServer.java @@ -5,6 +5,7 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.command.CommandMap; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.Account; +import emu.grasscutter.game.battlepass.BattlePassMissionManager; import emu.grasscutter.game.combine.CombineManger; import emu.grasscutter.game.drop.DropManager; import emu.grasscutter.game.dungeons.DungeonManager; @@ -61,6 +62,7 @@ public final class GameServer extends KcpServer { private final TaskMap taskMap; private final DropManager dropManager; private final WorldDataManager worldDataManager; + private final BattlePassMissionManager battlePassMissionManager; private final CombineManger combineManger; private final TowerScheduleManager towerScheduleManager; @@ -101,6 +103,8 @@ public final class GameServer extends KcpServer { this.combineManger = new CombineManger(this); this.towerScheduleManager = new TowerScheduleManager(this); this.worldDataManager = new WorldDataManager(this); + this.battlePassMissionManager = new BattlePassMissionManager(this); + // Hook into shutdown event. Runtime.getRuntime().addShutdownHook(new Thread(this::onServerShutdown)); } @@ -173,6 +177,10 @@ public final class GameServer extends KcpServer { return worldDataManager; } + public BattlePassMissionManager getBattlePassMissionManager() { + return battlePassMissionManager; + } + public TaskMap getTaskMap() { return this.taskMap; } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerBuyBattlePassLevelReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerBuyBattlePassLevelReq.java new file mode 100644 index 000000000..abe2aebd8 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerBuyBattlePassLevelReq.java @@ -0,0 +1,22 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.BuyBattlePassLevelReqOuterClass.BuyBattlePassLevelReq; +import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketBuyBattlePassLevelRsp; + +@Opcodes(PacketOpcodes.BuyBattlePassLevelReq) +public class HandlerBuyBattlePassLevelReq extends PacketHandler { + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + BuyBattlePassLevelReq req = BuyBattlePassLevelReq.parseFrom(payload); + + int buyLevel = session.getPlayer().getBattlePassManager().buyLevels(req.getBuyLevel()); + + session.send(new PacketBuyBattlePassLevelRsp(buyLevel)); + } + +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetBattlePassViewedReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetBattlePassViewedReq.java new file mode 100644 index 000000000..4b4723c77 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetBattlePassViewedReq.java @@ -0,0 +1,19 @@ +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.SetBattlePassViewedReqOuterClass.SetBattlePassViewedReq; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketSetBattlePassViewedRsp; + +@Opcodes(PacketOpcodes.SetBattlePassViewedReq) +public class HandlerSetBattlePassViewedReq extends PacketHandler { + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + var req = SetBattlePassViewedReq.parseFrom(payload); + + session.getPlayer().getBattlePassManager().updateViewed(); + session.send(new PacketSetBattlePassViewedRsp(req.getScheduleId())); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerTakeBattlePassMissionPointReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerTakeBattlePassMissionPointReq.java index c7a7e68cd..0288f833e 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerTakeBattlePassMissionPointReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerTakeBattlePassMissionPointReq.java @@ -1,13 +1,10 @@ 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.TakeBattlePassMissionPointReqOuterClass; +import emu.grasscutter.net.proto.TakeBattlePassMissionPointReqOuterClass.TakeBattlePassMissionPointReq; import emu.grasscutter.server.game.GameSession; -import emu.grasscutter.server.packet.send.PacketBattlePassCurScheduleUpdateNotify; -import emu.grasscutter.server.packet.send.PacketBattlePassMissionUpdateNotify; import emu.grasscutter.server.packet.send.PacketTakeBattlePassMissionPointRsp; @Opcodes(PacketOpcodes.TakeBattlePassMissionPointReq) @@ -15,11 +12,10 @@ public class HandlerTakeBattlePassMissionPointReq extends PacketHandler { @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - var req - = TakeBattlePassMissionPointReqOuterClass.TakeBattlePassMissionPointReq.parseFrom(payload); + var req = TakeBattlePassMissionPointReq.parseFrom(payload); + + session.getPlayer().getBattlePassManager().takeMissionPoint(req.getMissionIdListList()); - session.send(new PacketBattlePassMissionUpdateNotify(req.getMissionIdListList() , session)); - session.send(new PacketBattlePassCurScheduleUpdateNotify(session.getPlayer())); session.send(new PacketTakeBattlePassMissionPointRsp()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerTakeBattlePassRewardReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerTakeBattlePassRewardReq.java index 6204d7489..926c08af0 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerTakeBattlePassRewardReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerTakeBattlePassRewardReq.java @@ -3,7 +3,7 @@ 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.TakeBattlePassRewardReqOuterClass; +import emu.grasscutter.net.proto.TakeBattlePassRewardReqOuterClass.TakeBattlePassRewardReq; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.packet.send.PacketTakeBattlePassRewardRsp; @@ -11,14 +11,8 @@ import emu.grasscutter.server.packet.send.PacketTakeBattlePassRewardRsp; public class HandlerTakeBattlePassRewardReq extends PacketHandler { @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - var req - = TakeBattlePassRewardReqOuterClass.TakeBattlePassRewardReq.parseFrom(payload); + var req = TakeBattlePassRewardReq.parseFrom(payload); - //due to the list only have one element, so we can use get(0) - session.send(new PacketTakeBattlePassRewardRsp(req.getTakeOptionListList() , session)); - - //update the awardTakenLevel - req.getTakeOptionListList().forEach(battlePassRewardTakeOption -> - session.getPlayer().getBattlePassManager().updateAwardTakenLevel(battlePassRewardTakeOption.getTag().getLevel())); + session.getPlayer().getBattlePassManager().takeReward(req.getTakeOptionListList()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketBattlePassAllDataNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketBattlePassAllDataNotify.java index dc0ce294c..01ab447b7 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketBattlePassAllDataNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketBattlePassAllDataNotify.java @@ -5,6 +5,7 @@ import emu.grasscutter.game.player.Player; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.*; +import emu.grasscutter.net.proto.BattlePassAllDataNotifyOuterClass.BattlePassAllDataNotify; import java.util.ArrayList; import java.util.List; @@ -13,50 +14,25 @@ public class PacketBattlePassAllDataNotify extends BasePacket { public PacketBattlePassAllDataNotify(Player player) { super(PacketOpcodes.BattlePassAllDataNotify); - var value = player.getBattlePassManager().getPoint(); + var proto = BattlePassAllDataNotify.newBuilder(); + + proto + .setHaveCurSchedule(true) + .setCurSchedule(player.getBattlePassManager().getScheduleProto()); - int level = (int) Math.floor(value / 1000d); - - var point = value - level * 1000; - - List rewardTags = new ArrayList<>(); - - for (int id = 1; id <= player.getBattlePassManager().getAwardTakenLevel(); id++) - rewardTags.add(BattlePassRewardTagOuterClass.BattlePassRewardTag.newBuilder() - .setLevel(id) - .setUnlockStatus(BattlePassUnlockStatusOuterClass.BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE) - .setRewardId(1001000 + id) - .build()); - - - var proto - = BattlePassAllDataNotifyOuterClass.BattlePassAllDataNotify.newBuilder(); - - var missions - = GameData.getBattlePassMissionExcelConfigDataMap(); - - - var curSchedule - = BattlePassScheduleOuterClass.BattlePassSchedule.newBuilder() - .setScheduleId(2700).setLevel(level).setPoint(point).setBeginTime(1653940800).setEndTime(2059483200).addAllRewardTakenList(rewardTags) - .setIsViewed(true).setUnlockStatus(BattlePassUnlockStatusOuterClass.BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE).setCurCyclePoints(0) - .setCurCycle(BattlePassCycleOuterClass.BattlePassCycle.newBuilder().setBeginTime(1653940800).setEndTime(2059483200).setCycleIdx(3).build()); - - proto.setHaveCurSchedule(true).setCurSchedule(curSchedule); - - - //TODO: UNFINISHED YET / Need to add mission data --> Hard work - - for (var mission : missions.values()) - proto.addMissionList(BattlePassMissionOuterClass.BattlePassMission.newBuilder() - .setMissionId(mission.getId()) - .setMissionStatus(BattlePassMissionOuterClass.BattlePassMission.MissionStatus.MISSION_STATUS_UNFINISHED) - .setTotalProgress(mission.getProgress()) - .setMissionType( - mission.getRefreshType() == null ? 0 : - mission.getRefreshType().equals("BATTLE_PASS_MISSION_REFRESH_SCHEDULE") ? 2 : mission.getRefreshType().contains("CYCLE") ? 1 : 0) - .setRewardBattlePassPoint(mission.getAddPoint()) - .build()); + for (var missionData : GameData.getBattlePassMissionDataMap().values()) { + // Dont send invalid refresh types + if (!missionData.isValidRefreshType()) { + continue; + } + + // Check if player has mission in bp manager. If not, then add an empty proto from the mission data + if (player.getBattlePassManager().hasMission(missionData.getId())) { + proto.addMissionList(player.getBattlePassManager().loadMissionById(missionData.getId()).toProto()); + } else { + proto.addMissionList(missionData.toProto()); + } + } setData(proto.build()); } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketBattlePassCurScheduleUpdateNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketBattlePassCurScheduleUpdateNotify.java index 78e22a05d..9e480c121 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketBattlePassCurScheduleUpdateNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketBattlePassCurScheduleUpdateNotify.java @@ -4,36 +4,22 @@ import emu.grasscutter.game.player.Player; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.*; +import emu.grasscutter.net.proto.BattlePassCurScheduleUpdateNotifyOuterClass.BattlePassCurScheduleUpdateNotify; import java.util.ArrayList; import java.util.List; public class PacketBattlePassCurScheduleUpdateNotify extends BasePacket { + public PacketBattlePassCurScheduleUpdateNotify(Player player) { super(PacketOpcodes.BattlePassCurScheduleUpdateNotify); - var value = player.getBattlePassManager().getPoint(); - int level = (int) Math.floor(value / 1000d); - var point = value - level * 1000; + var proto = BattlePassCurScheduleUpdateNotify.newBuilder(); - List rewardTags = new ArrayList<>(); - - for (int id = 1; id <= player.getBattlePassManager().getAwardTakenLevel(); id++) - rewardTags.add(BattlePassRewardTagOuterClass.BattlePassRewardTag.newBuilder() - .setLevel(id) - .setUnlockStatus(BattlePassUnlockStatusOuterClass.BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE) - .setRewardId(1001000 + id) - .build()); - - var curSchedule - = BattlePassScheduleOuterClass.BattlePassSchedule.newBuilder() - .setScheduleId(2700).setLevel(level).setPoint(point).setBeginTime(1653940800).setEndTime(2059483200).addAllRewardTakenList(rewardTags) - .setIsViewed(true).setUnlockStatus(BattlePassUnlockStatusOuterClass.BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE).setCurCyclePoints(0) - .setCurCycle(BattlePassCycleOuterClass.BattlePassCycle.newBuilder().setBeginTime(1653940800).setEndTime(2059483200).setCycleIdx(3).build()); - - var proto = BattlePassCurScheduleUpdateNotifyOuterClass.BattlePassCurScheduleUpdateNotify.newBuilder(); - - proto.setHaveCurSchedule(true).setCurSchedule(curSchedule).build(); + proto + .setHaveCurSchedule(true) + .setCurSchedule(player.getBattlePassManager().getScheduleProto()) + .build(); setData(proto.build()); diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketBattlePassMissionUpdateNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketBattlePassMissionUpdateNotify.java index 06714e27e..0d1404edb 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketBattlePassMissionUpdateNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketBattlePassMissionUpdateNotify.java @@ -1,39 +1,33 @@ package emu.grasscutter.server.packet.send; -import emu.grasscutter.Grasscutter; -import emu.grasscutter.data.GameData; -import emu.grasscutter.data.excels.BattlePassMissionExcelConfigData; +import java.util.Collection; + +import emu.grasscutter.game.battlepass.BattlePassMission; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; -import emu.grasscutter.net.proto.BattlePassMissionOuterClass; -import emu.grasscutter.net.proto.BattlePassMissionUpdateNotifyOuterClass; -import emu.grasscutter.server.game.GameSession; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; - -import java.util.List; -import java.util.Map; +import emu.grasscutter.net.proto.BattlePassMissionUpdateNotifyOuterClass.BattlePassMissionUpdateNotify; public class PacketBattlePassMissionUpdateNotify extends BasePacket { - public PacketBattlePassMissionUpdateNotify(List missionIdList , GameSession session) { + public PacketBattlePassMissionUpdateNotify(BattlePassMission mission) { super(PacketOpcodes.BattlePassMissionUpdateNotify); - var proto - = BattlePassMissionUpdateNotifyOuterClass.BattlePassMissionUpdateNotify.newBuilder(); + var proto = BattlePassMissionUpdateNotify.newBuilder() + .addMissionList(mission.toProto()) + .build(); - Map missionMap - = GameData.getBattlePassMissionExcelConfigDataMap(); + this.setData(proto); + } + + public PacketBattlePassMissionUpdateNotify(Collection missions) { + super(PacketOpcodes.BattlePassMissionUpdateNotify); - missionIdList.forEach(missionId -> proto.addMissionList - (BattlePassMissionOuterClass.BattlePassMission.newBuilder().setMissionId(missionId).setMissionStatus - (BattlePassMissionOuterClass.BattlePassMission.MissionStatus.MISSION_STATUS_POINT_TAKEN) - .setTotalProgress(missionMap.get(missionId).getProgress()).setRewardBattlePassPoint(missionMap.get(missionId).getAddPoint()).build())); - - var point = session.getPlayer().getBattlePassManager().getPoint(); - missionIdList.forEach(missionId - -> session.getPlayer().getBattlePassManager().addPoint(missionMap.get(missionId).getAddPoint())); - Grasscutter.getLogger().info("[PacketBattlePassMissionUpdateNotify] addPoint: {}", session.getPlayer().getBattlePassManager().getPoint() - point); + var proto = BattlePassMissionUpdateNotify.newBuilder(); + missions.forEach(mission -> { + proto.addMissionList(mission.toProto()); + }); + this.setData(proto.build()); } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketBuyBattlePassLevelRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketBuyBattlePassLevelRsp.java new file mode 100644 index 000000000..2649c7e4c --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketBuyBattlePassLevelRsp.java @@ -0,0 +1,18 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.BuyBattlePassLevelRspOuterClass.BuyBattlePassLevelRsp; + +public class PacketBuyBattlePassLevelRsp extends BasePacket { + + public PacketBuyBattlePassLevelRsp(int buyLevel) { + super(PacketOpcodes.BuyBattlePassLevelRsp); + + BuyBattlePassLevelRsp proto = BuyBattlePassLevelRsp.newBuilder() + .setBuyLevel(buyLevel) + .build(); + + this.setData(proto); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketSetBattlePassViewedRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketSetBattlePassViewedRsp.java new file mode 100644 index 000000000..08abf4951 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketSetBattlePassViewedRsp.java @@ -0,0 +1,18 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.SetBattlePassViewedRspOuterClass.SetBattlePassViewedRsp; + +public class PacketSetBattlePassViewedRsp extends BasePacket { + + public PacketSetBattlePassViewedRsp(int scheduleId) { + super(PacketOpcodes.SetBattlePassViewedRsp); + + SetBattlePassViewedRsp proto = SetBattlePassViewedRsp.newBuilder() + .setScheduleId(scheduleId) + .build(); + + this.setData(proto); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketTakeBattlePassRewardRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketTakeBattlePassRewardRsp.java index f38e3fa68..a8ac3a466 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketTakeBattlePassRewardRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketTakeBattlePassRewardRsp.java @@ -1,49 +1,28 @@ package emu.grasscutter.server.packet.send; -import emu.grasscutter.Grasscutter; -import emu.grasscutter.data.GameData; -import emu.grasscutter.data.excels.BattlePassRewardExcelConfigData; -import emu.grasscutter.data.excels.RewardData; +import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; -import emu.grasscutter.net.proto.BattlePassRewardTakeOptionOuterClass; -import emu.grasscutter.net.proto.ItemParamOuterClass; -import emu.grasscutter.net.proto.TakeBattlePassRewardRspOuterClass; +import emu.grasscutter.net.proto.BattlePassRewardTakeOptionOuterClass.BattlePassRewardTakeOption; +import emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam; +import emu.grasscutter.net.proto.TakeBattlePassRewardRspOuterClass.TakeBattlePassRewardRsp; import emu.grasscutter.server.game.GameSession; -import java.util.ArrayList; import java.util.List; -import java.util.Map; public class PacketTakeBattlePassRewardRsp extends BasePacket { - public PacketTakeBattlePassRewardRsp(List takeOptionList , GameSession session) { + public PacketTakeBattlePassRewardRsp(List takeOptionList, List rewardItems) { super(PacketOpcodes.TakeBattlePassRewardRsp); - var proto - = TakeBattlePassRewardRspOuterClass.TakeBattlePassRewardRsp.newBuilder(); - - Map excelConfigDataMap = GameData.getBattlePassRewardExcelConfigDataMap(); - Map rewardDataMap = GameData.getRewardDataMap(); - - List rewardItemList = new ArrayList<>(); - - for (var takeOption : takeOptionList) { - for (int level = session.getPlayer().getBattlePassManager().getAwardTakenLevel() + 1 ; level <= takeOption.getTag().getLevel() ; level++){ - rewardItemList.addAll(excelConfigDataMap.get(level).getFreeRewardIdList()); - rewardItemList.addAll(excelConfigDataMap.get(level).getPaidRewardIdList()); + var proto = TakeBattlePassRewardRsp.newBuilder() + .addAllTakeOptionList(takeOptionList); + + if (rewardItems != null) { + for (ItemParamData param : rewardItems) { + proto.addItemList(ItemParam.newBuilder().setItemId(param.getItemId()).setCount(param.getCount())); } - - for (var rewardItemId : rewardItemList) { - var rewardData = rewardDataMap.get(rewardItemId); - if (rewardData == null) continue; - rewardData.getRewardItemList().forEach(i -> - proto.addItemList(ItemParamOuterClass.ItemParam.newBuilder().setItemId(i.getId()).setCount(i.getCount()).build())); - } - } - proto.addAllTakeOptionList(takeOptionList).build(); - setData(proto); } }