From 12146ff09cd82ac4991c18614053cff8257eb21e Mon Sep 17 00:00:00 2001 From: Akka <104902222+Akka0@users.noreply.github.com> Date: Sun, 26 Jun 2022 20:16:50 +0800 Subject: [PATCH] implement the music game --- .../java/emu/grasscutter/data/GameData.java | 1 + .../data/excels/ActivityWatcherData.java | 4 + .../data/excels/MusicGameBasicData.java | 21 ++++ .../grasscutter/database/DatabaseHelper.java | 10 ++ .../grasscutter/database/DatabaseManager.java | 7 +- .../game/activity/ActivityHandler.java | 27 +++-- .../game/activity/ActivityManager.java | 103 ++++++++++------- ...cherType.java => ActivityWatcherType.java} | 2 +- .../game/activity/DefaultActivityHandler.java | 17 +++ .../game/activity/DefaultWatcher.java | 2 +- .../{ActivityType.java => GameActivity.java} | 6 +- .../game/activity/PlayerActivityData.java | 46 +++++++- .../musicgame/MusicGameActivityHandler.java | 76 +++++++++++- .../activity/musicgame/MusicGameBeatmap.java | 109 ++++++++++++++++++ .../musicgame/MusicGamePlayerData.java | 76 ++++++++++++ .../musicgame/MusicGameScoreTrigger.java | 4 +- .../grasscutter/game/props/ActivityType.java | 38 ++++++ .../grasscutter/net/packet/PacketOpcodes.java | 6 + .../HandlerActivityTakeWatcherRewardReq.java | 25 ++++ .../HandlerMusicGameCreateBeatmapReq.java | 47 ++++++++ .../recv/HandlerMusicGameGetBeatmapReq.java | 31 +++++ .../HandlerMusicGameSearchBeatmapReq.java | 28 +++++ .../recv/HandlerMusicGameSettleReq.java | 41 ++++++- .../packet/recv/HandlerMusicGameStartReq.java | 4 +- .../PacketActivityTakeWatcherRewardRsp.java | 20 ++++ .../packet/send/PacketGetActivityInfoRsp.java | 2 +- .../send/PacketMusicGameCreateBeatmapRsp.java | 20 ++++ .../send/PacketMusicGameGetBeatmapRsp.java | 27 +++++ .../send/PacketMusicGameSearchBeatmapRsp.java | 34 ++++++ .../packet/send/PacketMusicGameSettleRsp.java | 15 +-- .../packet/send/PacketMusicGameStartRsp.java | 5 +- .../defaults/data/ActivityConfig.json | 6 +- 32 files changed, 780 insertions(+), 80 deletions(-) create mode 100644 src/main/java/emu/grasscutter/data/excels/MusicGameBasicData.java rename src/main/java/emu/grasscutter/game/activity/{WatcherType.java => ActivityWatcherType.java} (89%) create mode 100644 src/main/java/emu/grasscutter/game/activity/DefaultActivityHandler.java rename src/main/java/emu/grasscutter/game/activity/{ActivityType.java => GameActivity.java} (71%) create mode 100644 src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameBeatmap.java create mode 100644 src/main/java/emu/grasscutter/game/activity/musicgame/MusicGamePlayerData.java create mode 100644 src/main/java/emu/grasscutter/game/props/ActivityType.java create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerActivityTakeWatcherRewardReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameCreateBeatmapReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameGetBeatmapReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameSearchBeatmapReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketActivityTakeWatcherRewardRsp.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameCreateBeatmapRsp.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameGetBeatmapRsp.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameSearchBeatmapRsp.java diff --git a/src/main/java/emu/grasscutter/data/GameData.java b/src/main/java/emu/grasscutter/data/GameData.java index 780564cbd..da95b1bcc 100644 --- a/src/main/java/emu/grasscutter/data/GameData.java +++ b/src/main/java/emu/grasscutter/data/GameData.java @@ -101,6 +101,7 @@ 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<>(); // Cache private static Map> fetters = new HashMap<>(); diff --git a/src/main/java/emu/grasscutter/data/excels/ActivityWatcherData.java b/src/main/java/emu/grasscutter/data/excels/ActivityWatcherData.java index e784693f9..4ff176fa5 100644 --- a/src/main/java/emu/grasscutter/data/excels/ActivityWatcherData.java +++ b/src/main/java/emu/grasscutter/data/excels/ActivityWatcherData.java @@ -2,6 +2,7 @@ package emu.grasscutter.data.excels; import emu.grasscutter.data.GameResource; import emu.grasscutter.data.ResourceType; +import emu.grasscutter.game.props.WatcherTriggerType; import lombok.AccessLevel; import lombok.Getter; import lombok.experimental.FieldDefaults; @@ -24,6 +25,7 @@ public class ActivityWatcherData extends GameResource { @Override public void onLoad() { triggerConfig.paramList = triggerConfig.paramList.stream().filter(x -> !x.isBlank()).toList(); + triggerConfig.watcherTriggerType = WatcherTriggerType.getTypeByName(triggerConfig.triggerType); } @Getter @@ -31,6 +33,8 @@ public class ActivityWatcherData extends GameResource { public static class WatcherTrigger{ String triggerType; List paramList; + + transient WatcherTriggerType watcherTriggerType; } } diff --git a/src/main/java/emu/grasscutter/data/excels/MusicGameBasicData.java b/src/main/java/emu/grasscutter/data/excels/MusicGameBasicData.java new file mode 100644 index 000000000..d73d74ce9 --- /dev/null +++ b/src/main/java/emu/grasscutter/data/excels/MusicGameBasicData.java @@ -0,0 +1,21 @@ +package emu.grasscutter.data.excels; + +import emu.grasscutter.data.GameResource; +import emu.grasscutter.data.ResourceType; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.FieldDefaults; + +@ResourceType(name = "MusicGameBasicConfigData.json") +@Getter +@FieldDefaults(level = AccessLevel.PRIVATE) +public class MusicGameBasicData extends GameResource { + int id; + int musicID; + int musicLevel; + + @Override + public int getId() { + return this.id; + } +} diff --git a/src/main/java/emu/grasscutter/database/DatabaseHelper.java b/src/main/java/emu/grasscutter/database/DatabaseHelper.java index 55afc4354..1178ddc47 100644 --- a/src/main/java/emu/grasscutter/database/DatabaseHelper.java +++ b/src/main/java/emu/grasscutter/database/DatabaseHelper.java @@ -11,6 +11,7 @@ import emu.grasscutter.GameConstants; import emu.grasscutter.Grasscutter; import emu.grasscutter.game.Account; import emu.grasscutter.game.activity.PlayerActivityData; +import emu.grasscutter.game.activity.musicgame.MusicGameBeatmap; import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.battlepass.BattlePassManager; import emu.grasscutter.game.friends.Friendship; @@ -337,4 +338,13 @@ public final class DatabaseHelper { public static void savePlayerActivityData(PlayerActivityData playerActivityData) { DatabaseManager.getGameDatastore().save(playerActivityData); } + public static MusicGameBeatmap getMusicGameBeatmap(long musicShareId) { + return DatabaseManager.getGameDatastore().find(MusicGameBeatmap.class) + .filter(Filters.eq("musicShareId", musicShareId)) + .first(); + } + + public static void saveMusicGameBeatmap(MusicGameBeatmap musicGameBeatmap) { + DatabaseManager.getGameDatastore().save(musicGameBeatmap); + } } diff --git a/src/main/java/emu/grasscutter/database/DatabaseManager.java b/src/main/java/emu/grasscutter/database/DatabaseManager.java index 19618c27b..d0c322864 100644 --- a/src/main/java/emu/grasscutter/database/DatabaseManager.java +++ b/src/main/java/emu/grasscutter/database/DatabaseManager.java @@ -14,6 +14,7 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter.ServerRunMode; import emu.grasscutter.game.Account; import emu.grasscutter.game.activity.PlayerActivityData; +import emu.grasscutter.game.activity.musicgame.MusicGameBeatmap; import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.battlepass.BattlePassManager; import emu.grasscutter.game.friends.Friendship; @@ -33,12 +34,14 @@ public final class DatabaseManager { private static final Class[] mappedClasses = new Class[] { DatabaseCounter.class, Account.class, Player.class, Avatar.class, GameItem.class, Friendship.class, - GachaRecord.class, Mail.class, GameMainQuest.class, GameHome.class, BattlePassManager.class, PlayerActivityData.class + GachaRecord.class, Mail.class, GameMainQuest.class, GameHome.class, BattlePassManager.class, + PlayerActivityData.class, MusicGameBeatmap.class }; + public static Datastore getGameDatastore() { return gameDatastore; } - + public static MongoDatabase getGameDatabase() { return getGameDatastore().getDatabase(); } diff --git a/src/main/java/emu/grasscutter/game/activity/ActivityHandler.java b/src/main/java/emu/grasscutter/game/activity/ActivityHandler.java index 386533d5c..5a8709cd6 100644 --- a/src/main/java/emu/grasscutter/game/activity/ActivityHandler.java +++ b/src/main/java/emu/grasscutter/game/activity/ActivityHandler.java @@ -26,12 +26,15 @@ public abstract class ActivityHandler { ActivityData activityData; Map> watchersMap = new HashMap<>(); - public void initWatchers(HashMap> activityWatcherTypeMap){ + abstract public void onProtoBuild(PlayerActivityData playerActivityData, ActivityInfoOuterClass.ActivityInfo.Builder activityInfo); + abstract public void onInitPlayerActivityData(PlayerActivityData playerActivityData); + + public void initWatchers(Map> activityWatcherTypeMap){ activityData = GameData.getActivityDataMap().get(activityConfigItem.getActivityId()); // add watcher to map by id activityData.getWatcherDataList().forEach(watcherData -> { - var watcherType = activityWatcherTypeMap.get(watcherData.getTriggerConfig().getTriggerType()); + var watcherType = activityWatcherTypeMap.get(watcherData.getTriggerConfig().getWatcherTriggerType()); ActivityWatcher watcher; if(watcherType != null){ watcher = (ActivityWatcher) watcherType.newInstance(); @@ -42,8 +45,8 @@ public abstract class ActivityHandler { watcher.setWatcherId(watcherData.getId()); watcher.setActivityHandler(this); watcher.setActivityWatcherData(watcherData); - watchersMap.computeIfAbsent(WatcherTriggerType.getTypeByName(watcherData.getTriggerConfig().getTriggerType()), k -> new ArrayList<>()); - watchersMap.get(WatcherTriggerType.getTypeByName(watcherData.getTriggerConfig().getTriggerType())).add(watcher); + watchersMap.computeIfAbsent(watcherData.getTriggerConfig().getWatcherTriggerType(), k -> new ArrayList<>()); + watchersMap.get(watcherData.getTriggerConfig().getWatcherTriggerType()).add(watcher); }); } @@ -55,16 +58,19 @@ public abstract class ActivityHandler { } public PlayerActivityData initPlayerActivityData(Player player){ - return PlayerActivityData.of() + PlayerActivityData playerActivityData = PlayerActivityData.of() .activityId(activityConfigItem.getActivityId()) .uid(player.getUid()) .watcherInfoMap(initWatchersDataForPlayer()) .build(); + + onInitPlayerActivityData(playerActivityData); + return playerActivityData; } - - public void buildProto(PlayerActivityData playerActivityData, ActivityInfoOuterClass.ActivityInfo.Builder activityInfo){ - activityInfo.setActivityId(activityConfigItem.getActivityId()) + public ActivityInfoOuterClass.ActivityInfo toProto(PlayerActivityData playerActivityData){ + var proto = ActivityInfoOuterClass.ActivityInfo.newBuilder(); + proto.setActivityId(activityConfigItem.getActivityId()) .setActivityType(activityConfigItem.getActivityType()) .setScheduleId(activityConfigItem.getScheduleId()) .setBeginTime(DateHelper.getUnixTime(activityConfigItem.getBeginTime())) @@ -73,9 +79,12 @@ public abstract class ActivityHandler { .addAllMeetCondList(activityConfigItem.getMeetCondList()); if (playerActivityData != null){ - activityInfo.addAllWatcherInfoList(playerActivityData.getAllWatcherInfoList()); + proto.addAllWatcherInfoList(playerActivityData.getAllWatcherInfoList()); } + onProtoBuild(playerActivityData, proto); + + return proto.build(); } } diff --git a/src/main/java/emu/grasscutter/game/activity/ActivityManager.java b/src/main/java/emu/grasscutter/game/activity/ActivityManager.java index b8b4db168..b511a2629 100644 --- a/src/main/java/emu/grasscutter/game/activity/ActivityManager.java +++ b/src/main/java/emu/grasscutter/game/activity/ActivityManager.java @@ -6,6 +6,7 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.data.DataLoader; import emu.grasscutter.data.GameData; import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.ActivityType; import emu.grasscutter.game.props.WatcherTriggerType; import emu.grasscutter.net.proto.ActivityInfoOuterClass; import emu.grasscutter.server.packet.send.PacketActivityScheduleInfoNotify; @@ -25,41 +26,22 @@ public class ActivityManager { static { activityConfigItemMap = new HashMap<>(); - loadActivityConfigData(); } - public ActivityManager(Player player){ - this.player = player; - - playerActivityDataMap = new ConcurrentHashMap<>(); - // load data for player - activityConfigItemMap.values().forEach(item -> { - var data = PlayerActivityData.getByPlayer(player, item.getActivityId()); - if(data == null){ - data = item.getActivityHandler().initPlayerActivityData(player); - data.save(); - } - data.setPlayer(player); - playerActivityDataMap.put(item.getActivityId(), data); - }); - - player.sendPacket(new PacketActivityScheduleInfoNotify(activityConfigItemMap.values())); - } - private static void loadActivityConfigData() { // scan activity type handler & watcher type - var activityHandlerTypeMap = new HashMap>(); - var activityWatcherTypeMap = new HashMap>(); + var activityHandlerTypeMap = new HashMap>(); + var activityWatcherTypeMap = new HashMap>(); var reflections = new Reflections(ActivityManager.class.getPackage().getName()); reflections.getSubTypesOf(ActivityHandler.class).forEach(item -> { - var typeName = item.getAnnotation(ActivityType.class); + var typeName = item.getAnnotation(GameActivity.class); activityHandlerTypeMap.put(typeName.value(), ConstructorAccess.get(item)); }); reflections.getSubTypesOf(ActivityWatcher.class).forEach(item -> { - var typeName = item.getAnnotation(WatcherType.class); - activityWatcherTypeMap.put(typeName.value().name(), ConstructorAccess.get(item)); + var typeName = item.getAnnotation(ActivityWatcherType.class); + activityWatcherTypeMap.put(typeName.value(), ConstructorAccess.get(item)); }); try(InputStream is = DataLoader.load("ActivityConfig.json"); InputStreamReader isr = new InputStreamReader(is)) { @@ -74,39 +56,49 @@ public class ActivityManager { Grasscutter.getLogger().warn("activity {} not exist.", item.getActivityId()); return; } - var activityHandlerType = activityHandlerTypeMap.get(activityData.getActivityType()); + var activityHandlerType = activityHandlerTypeMap.get(ActivityType.getTypeByName(activityData.getActivityType())); + ActivityHandler activityHandler; if(activityHandlerType != null) { - var activityHandler = (ActivityHandler) activityHandlerType.newInstance(); - activityHandler.setActivityConfigItem(item); - activityHandler.initWatchers(activityWatcherTypeMap); - item.setActivityHandler(activityHandler); + activityHandler = (ActivityHandler) activityHandlerType.newInstance(); + }else{ + activityHandler = new DefaultActivityHandler(); } + activityHandler.setActivityConfigItem(item); + activityHandler.initWatchers(activityWatcherTypeMap); + item.setActivityHandler(activityHandler); activityConfigItemMap.putIfAbsent(item.getActivityId(), item); }); - Grasscutter.getLogger().error("Enable {} activities.", activityConfigItemMap.size()); + Grasscutter.getLogger().info("Enable {} activities.", activityConfigItemMap.size()); } catch (Exception e) { - Grasscutter.getLogger().error("Unable to load chest reward config.", e); + Grasscutter.getLogger().error("Unable to load activities config.", e); } } - public ActivityInfoOuterClass.ActivityInfo getInfoProto(int activityId){ - var activityHandler = activityConfigItemMap.get(activityId).getActivityHandler(); - var activityData = playerActivityDataMap.get(activityId); + public ActivityManager(Player player){ + this.player = player; - var proto = ActivityInfoOuterClass.ActivityInfo.newBuilder(); - activityHandler.buildProto(activityData, proto); + playerActivityDataMap = new ConcurrentHashMap<>(); + // load data for player + activityConfigItemMap.values().forEach(item -> { + var data = PlayerActivityData.getByPlayer(player, item.getActivityId()); + if(data == null){ + data = item.getActivityHandler().initPlayerActivityData(player); + data.save(); + } + data.setPlayer(player); + data.setActivityHandler(item.getActivityHandler()); + playerActivityDataMap.put(item.getActivityId(), data); + }); - return proto.build(); + player.sendPacket(new PacketActivityScheduleInfoNotify(activityConfigItemMap.values())); } /** * trigger activity watcher - * @param watcherTriggerType - * @param params */ public void triggerWatcher(WatcherTriggerType watcherTriggerType, String... params) { var watchers = activityConfigItemMap.values().stream() @@ -122,4 +114,37 @@ public class ActivityManager { playerActivityDataMap.get(watcher.getActivityHandler().getActivityConfigItem().getActivityId()), params)); } + + public ActivityInfoOuterClass.ActivityInfo getInfoProtoByActivityId(int activityId){ + var activityHandler = activityConfigItemMap.get(activityId).getActivityHandler(); + var activityData = playerActivityDataMap.get(activityId); + + return activityHandler.toProto(activityData); + } + + public Optional getActivityHandler(ActivityType type){ + return activityConfigItemMap.values().stream() + .map(ActivityConfigItem::getActivityHandler) + .filter(x -> type == x.getClass().getAnnotation(GameActivity.class).value()) + .findFirst(); + } + + public Optional getActivityHandlerAs(ActivityType type, Class clazz){ + return getActivityHandler(type).map(x -> (T)x); + } + + public Optional getActivityIdByActivityType(ActivityType type){ + return getActivityHandler(type) + .map(ActivityHandler::getActivityConfigItem) + .map(ActivityConfigItem::getActivityId); + } + public Optional getPlayerActivityDataByActivityType(ActivityType type){ + return getActivityIdByActivityType(type) + .map(playerActivityDataMap::get); + } + public Optional getInfoProtoByActivityType(ActivityType type){ + return getActivityIdByActivityType(type) + .map(this::getInfoProtoByActivityId); + } + } diff --git a/src/main/java/emu/grasscutter/game/activity/WatcherType.java b/src/main/java/emu/grasscutter/game/activity/ActivityWatcherType.java similarity index 89% rename from src/main/java/emu/grasscutter/game/activity/WatcherType.java rename to src/main/java/emu/grasscutter/game/activity/ActivityWatcherType.java index 7d1f9a261..4c68e11f5 100644 --- a/src/main/java/emu/grasscutter/game/activity/WatcherType.java +++ b/src/main/java/emu/grasscutter/game/activity/ActivityWatcherType.java @@ -9,6 +9,6 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) -public @interface WatcherType { +public @interface ActivityWatcherType { WatcherTriggerType value(); } diff --git a/src/main/java/emu/grasscutter/game/activity/DefaultActivityHandler.java b/src/main/java/emu/grasscutter/game/activity/DefaultActivityHandler.java new file mode 100644 index 000000000..693878328 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/activity/DefaultActivityHandler.java @@ -0,0 +1,17 @@ +package emu.grasscutter.game.activity; + +import emu.grasscutter.game.props.ActivityType; +import emu.grasscutter.net.proto.ActivityInfoOuterClass; + +@GameActivity(ActivityType.NONE) +public class DefaultActivityHandler extends ActivityHandler{ + @Override + public void onProtoBuild(PlayerActivityData playerActivityData, ActivityInfoOuterClass.ActivityInfo.Builder activityInfo) { + + } + + @Override + public void onInitPlayerActivityData(PlayerActivityData playerActivityData) { + + } +} diff --git a/src/main/java/emu/grasscutter/game/activity/DefaultWatcher.java b/src/main/java/emu/grasscutter/game/activity/DefaultWatcher.java index 8c6e2464f..bd4c93fe6 100644 --- a/src/main/java/emu/grasscutter/game/activity/DefaultWatcher.java +++ b/src/main/java/emu/grasscutter/game/activity/DefaultWatcher.java @@ -2,7 +2,7 @@ package emu.grasscutter.game.activity; import emu.grasscutter.game.props.WatcherTriggerType; -@WatcherType(WatcherTriggerType.TRIGGER_NONE) +@ActivityWatcherType(WatcherTriggerType.TRIGGER_NONE) public class DefaultWatcher extends ActivityWatcher{ @Override protected boolean isMeet(String... param) { diff --git a/src/main/java/emu/grasscutter/game/activity/ActivityType.java b/src/main/java/emu/grasscutter/game/activity/GameActivity.java similarity index 71% rename from src/main/java/emu/grasscutter/game/activity/ActivityType.java rename to src/main/java/emu/grasscutter/game/activity/GameActivity.java index da57637e7..7d70a653d 100644 --- a/src/main/java/emu/grasscutter/game/activity/ActivityType.java +++ b/src/main/java/emu/grasscutter/game/activity/GameActivity.java @@ -1,5 +1,7 @@ package emu.grasscutter.game.activity; +import emu.grasscutter.game.props.ActivityType; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -7,6 +9,6 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) -public @interface ActivityType { - String value(); +public @interface GameActivity { + ActivityType value(); } diff --git a/src/main/java/emu/grasscutter/game/activity/PlayerActivityData.java b/src/main/java/emu/grasscutter/game/activity/PlayerActivityData.java index 4a251a621..3a4b207f3 100644 --- a/src/main/java/emu/grasscutter/game/activity/PlayerActivityData.java +++ b/src/main/java/emu/grasscutter/game/activity/PlayerActivityData.java @@ -3,8 +3,14 @@ package emu.grasscutter.game.activity; import dev.morphia.annotations.Entity; import dev.morphia.annotations.Id; import dev.morphia.annotations.Transient; +import emu.grasscutter.Grasscutter; +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.common.ItemParamData; +import emu.grasscutter.data.excels.ActivityWatcherData; import emu.grasscutter.database.DatabaseHelper; +import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.net.proto.ActivityWatcherInfoOuterClass; import emu.grasscutter.server.packet.send.PacketActivityUpdateWatcherNotify; import lombok.AccessLevel; @@ -12,8 +18,10 @@ import lombok.Builder; import lombok.Data; import lombok.experimental.FieldDefaults; +import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; @Entity("activities") @Data @@ -25,9 +33,12 @@ public class PlayerActivityData { int uid; int activityId; Map watcherInfoMap; + /** + * the detail data of each type of activity (Json format) + */ String detail; @Transient Player player; - + @Transient ActivityHandler activityHandler; public void save(){ DatabaseHelper.savePlayerActivityData(this); } @@ -56,6 +67,35 @@ public class PlayerActivityData { .toList(); } + public void setDetail(Object detail){ + this.detail = Grasscutter.getGsonFactory().toJson(detail); + } + + public void takeWatcherReward(int watcherId) { + var watcher = watcherInfoMap.get(watcherId); + if(watcher == null || watcher.isTakenReward()){ + return; + } + + var reward = Optional.of(watcher) + .map(WatcherInfo::getMetadata) + .map(ActivityWatcherData::getRewardID) + .map(id -> GameData.getRewardDataMap().get(id.intValue())); + + if(reward.isEmpty()){ + return; + } + + List rewards = new ArrayList<>(); + for (ItemParamData param : reward.get().getRewardItemList()) { + rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1))); + } + + player.getInventory().addItems(rewards, ActionReason.ActivityWatcher); + watcher.setTakenReward(true); + save(); + } + @Entity @Data @FieldDefaults(level = AccessLevel.PRIVATE) @@ -66,6 +106,10 @@ public class PlayerActivityData { int curProgress; boolean isTakenReward; + public ActivityWatcherData getMetadata(){ + return GameData.getActivityWatcherDataMap().get(watcherId); + } + public static WatcherInfo init(ActivityWatcher watcher){ return WatcherInfo.of() .watcherId(watcher.getWatcherId()) diff --git a/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameActivityHandler.java b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameActivityHandler.java index c3d5ad53a..0dcb0ae55 100644 --- a/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameActivityHandler.java +++ b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameActivityHandler.java @@ -1,17 +1,85 @@ package emu.grasscutter.game.activity.musicgame; +import emu.grasscutter.Grasscutter; import emu.grasscutter.game.activity.ActivityHandler; -import emu.grasscutter.game.activity.ActivityType; +import emu.grasscutter.game.activity.GameActivity; import emu.grasscutter.game.activity.PlayerActivityData; +import emu.grasscutter.game.props.ActivityType; import emu.grasscutter.net.proto.ActivityInfoOuterClass; +import emu.grasscutter.net.proto.MusicBriefInfoOuterClass; +import emu.grasscutter.net.proto.MusicGameActivityDetailInfoOuterClass; -@ActivityType("NEW_ACTIVITY_MUSIC_GAME") +import java.util.stream.Collectors; + +@GameActivity(ActivityType.NEW_ACTIVITY_MUSIC_GAME) public class MusicGameActivityHandler extends ActivityHandler { @Override - public void buildProto(PlayerActivityData playerActivityData, ActivityInfoOuterClass.ActivityInfo.Builder activityInfo) { - super.buildProto(playerActivityData, activityInfo); + public void onInitPlayerActivityData(PlayerActivityData playerActivityData) { + var musicGamePlayerData = MusicGamePlayerData.create(); + playerActivityData.setDetail(musicGamePlayerData); + } + @Override + public void onProtoBuild(PlayerActivityData playerActivityData, ActivityInfoOuterClass.ActivityInfo.Builder activityInfo) { + MusicGamePlayerData musicGamePlayerData = getMusicGameRecord(playerActivityData); + + activityInfo.setMusicGameInfo(MusicGameActivityDetailInfoOuterClass.MusicGameActivityDetailInfo.newBuilder() + .putAllMusicGameRecordMap( + musicGamePlayerData.getMusicGameRecord().values().stream() + .collect(Collectors.toMap(MusicGamePlayerData.MusicGameRecord::getMusicId, MusicGamePlayerData.MusicGameRecord::toProto))) + + .addAllPersonCustomBeatmap(musicGamePlayerData.getPersonalCustomBeatmapRecord().values().stream() + .map(MusicGamePlayerData.CustomBeatmapRecord::toProto) + .map(MusicBriefInfoOuterClass.MusicBriefInfo.Builder::build) + .toList()) + + .addAllPersonCustomBeatmap(musicGamePlayerData.getOthersCustomBeatmapRecord().values().stream() + .map(MusicGamePlayerData.CustomBeatmapRecord::toProto) + .map(MusicBriefInfoOuterClass.MusicBriefInfo.Builder::build) + .toList()) + .build()); + } + + public MusicGamePlayerData getMusicGameRecord(PlayerActivityData playerActivityData){ + if(playerActivityData.getDetail() == null || playerActivityData.getDetail().isBlank()){ + onInitPlayerActivityData(playerActivityData); + playerActivityData.save(); + } + + return Grasscutter.getGsonFactory().fromJson(playerActivityData.getDetail(), + MusicGamePlayerData.class); + } + + public boolean setMusicGameRecord(PlayerActivityData playerActivityData, MusicGamePlayerData.MusicGameRecord newRecord){ + var musicGamePlayerData = getMusicGameRecord(playerActivityData); + var saveRecord = musicGamePlayerData.getMusicGameRecord().get(newRecord.getMusicId()); + + saveRecord.setMaxCombo(Math.max(newRecord.getMaxCombo(), saveRecord.getMaxCombo())); + saveRecord.setMaxScore(Math.max(newRecord.getMaxScore(), saveRecord.getMaxScore())); + + playerActivityData.setDetail(musicGamePlayerData); + playerActivityData.save(); + + return newRecord.getMaxScore() > saveRecord.getMaxScore(); + } + public void setMusicGameCustomBeatmapRecord(PlayerActivityData playerActivityData, MusicGamePlayerData.CustomBeatmapRecord newRecord){ + var musicGamePlayerData = getMusicGameRecord(playerActivityData); + musicGamePlayerData.getOthersCustomBeatmapRecord().put(newRecord.getMusicShareId(), newRecord); + + playerActivityData.setDetail(musicGamePlayerData); + playerActivityData.save(); + } + + public void addPersonalBeatmap(PlayerActivityData playerActivityData, MusicGameBeatmap musicGameBeatmap) { + var musicGamePlayerData = getMusicGameRecord(playerActivityData); + musicGamePlayerData.getPersonalCustomBeatmapRecord().put(musicGameBeatmap.getMusicShareId(), + MusicGamePlayerData.CustomBeatmapRecord.of() + .musicShareId(musicGameBeatmap.getMusicShareId()) + .build()); + + playerActivityData.setDetail(musicGamePlayerData); + playerActivityData.save(); } } diff --git a/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameBeatmap.java b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameBeatmap.java new file mode 100644 index 000000000..0a5baaf39 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameBeatmap.java @@ -0,0 +1,109 @@ +package emu.grasscutter.game.activity.musicgame; + +import dev.morphia.annotations.Entity; +import dev.morphia.annotations.Id; +import emu.grasscutter.database.DatabaseHelper; +import emu.grasscutter.net.proto.MusicBeatmapListOuterClass; +import emu.grasscutter.net.proto.MusicBeatmapNoteOuterClass; +import emu.grasscutter.net.proto.MusicBeatmapOuterClass; +import emu.grasscutter.net.proto.MusicBriefInfoOuterClass; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +import java.util.List; +import java.util.Random; + +@Entity("music_game_beatmaps") +@Data +@FieldDefaults(level = AccessLevel.PRIVATE) +@Builder(builderMethodName = "of") +public class MusicGameBeatmap { + + @Id + long musicShareId; + int authorUid; + int musicId; + int musicNoteCount; + int savePosition; + int maxScore; + int createTime; + + List> beatmap; + + public static MusicGameBeatmap getByShareId(long musicShareId){ + return DatabaseHelper.getMusicGameBeatmap(musicShareId); + } + + public void save(){ + if(musicShareId == 0){ + musicShareId = new Random().nextLong(100000000000000L,999999999999999L); + } + DatabaseHelper.saveMusicGameBeatmap(this); + } + + public static List> parse(List beatmapItemListList) { + return beatmapItemListList.stream() + .map(item -> item.getBeatmapNoteListList().stream() + .map(BeatmapNote::parse) + .toList()) + .toList(); + } + + public MusicBeatmapOuterClass.MusicBeatmap toProto(){ + return MusicBeatmapOuterClass.MusicBeatmap.newBuilder() + .setMusicId(musicId) + .addAllBeatmapItemList(beatmap.stream() + .map(this::musicBeatmapListToProto) + .toList()) + .build(); + } + + public MusicBriefInfoOuterClass.MusicBriefInfo.Builder toBriefProto(){ + var player = DatabaseHelper.getPlayerByUid(authorUid); + + return MusicBriefInfoOuterClass.MusicBriefInfo.newBuilder() + .setCanShare(true) + .setMusicId(musicId) + .setMusicNoteCount(musicNoteCount) + .setMusicShareId(musicShareId) + .setMaxScore(maxScore) + .setCreateTime(createTime) + .setShareTime(createTime) + .setAuthorNickname(player.getNickname()) + .setVersion(1) + ; + } + + private MusicBeatmapListOuterClass.MusicBeatmapList musicBeatmapListToProto(List beatmapNoteList){ + return MusicBeatmapListOuterClass.MusicBeatmapList.newBuilder() + .addAllBeatmapNoteList(beatmapNoteList.stream() + .map(BeatmapNote::toProto) + .toList()) + .build(); + } + + @Data + @FieldDefaults(level = AccessLevel.PRIVATE) + @Builder(builderMethodName = "of") + @Entity + public static class BeatmapNote{ + int startTime; + int endTime; + + public static BeatmapNote parse(MusicBeatmapNoteOuterClass.MusicBeatmapNote note){ + return BeatmapNote.of() + .startTime(note.getStartTime()) + .endTime(note.getEndTime()) + .build(); + } + + public MusicBeatmapNoteOuterClass.MusicBeatmapNote toProto(){ + return MusicBeatmapNoteOuterClass.MusicBeatmapNote.newBuilder() + .setStartTime(startTime) + .setEndTime(endTime) + .build(); + } + } +} diff --git a/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGamePlayerData.java b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGamePlayerData.java new file mode 100644 index 000000000..1492d93f9 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGamePlayerData.java @@ -0,0 +1,76 @@ +package emu.grasscutter.game.activity.musicgame; + +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.excels.MusicGameBasicData; +import emu.grasscutter.net.proto.MusicBriefInfoOuterClass; +import emu.grasscutter.net.proto.MusicGameRecordOuterClass; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +@Data +@FieldDefaults(level = AccessLevel.PRIVATE) +@Builder(builderMethodName = "of") +public class MusicGamePlayerData { + Map musicGameRecord; + Map personalCustomBeatmapRecord; + Map othersCustomBeatmapRecord; + + public static MusicGamePlayerData create(){ + return MusicGamePlayerData.of() + .musicGameRecord(GameData.getMusicGameBasicDataMap().values().stream() + .collect(Collectors.toMap(MusicGameBasicData::getId, MusicGamePlayerData.MusicGameRecord::create))) + .personalCustomBeatmapRecord(new HashMap<>()) + .othersCustomBeatmapRecord(new HashMap<>()) + .build(); + } + + @Data + @FieldDefaults(level = AccessLevel.PRIVATE) + @Builder(builderMethodName = "of") + public static class MusicGameRecord { + int musicId; + int maxCombo; + int maxScore; + + public static MusicGameRecord create(MusicGameBasicData musicGameBasicData){ + return MusicGameRecord.of() + .musicId(musicGameBasicData.getId()) + .build(); + } + + public MusicGameRecordOuterClass.MusicGameRecord toProto(){ + return MusicGameRecordOuterClass.MusicGameRecord.newBuilder() + .setIsUnlock(true) + .setMaxCombo(maxCombo) + .setMaxScore(maxScore) + .build(); + } + } + + @Data + @FieldDefaults(level = AccessLevel.PRIVATE) + @Builder(builderMethodName = "of") + public static class CustomBeatmapRecord { + long musicShareId; + int score; + boolean settle; + + public MusicBriefInfoOuterClass.MusicBriefInfo.Builder toProto(){ + var musicGameBeatmap = MusicGameBeatmap.getByShareId(musicShareId); + + return musicGameBeatmap.toBriefProto() + .setScore(score) + .setSettle(settle) + ; + } + + } +} + + diff --git a/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameScoreTrigger.java b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameScoreTrigger.java index 8ee92027f..34cfbe257 100644 --- a/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameScoreTrigger.java +++ b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameScoreTrigger.java @@ -1,10 +1,10 @@ package emu.grasscutter.game.activity.musicgame; import emu.grasscutter.game.activity.ActivityWatcher; -import emu.grasscutter.game.activity.WatcherType; +import emu.grasscutter.game.activity.ActivityWatcherType; import emu.grasscutter.game.props.WatcherTriggerType; -@WatcherType(WatcherTriggerType.TRIGGER_FLEUR_FAIR_MUSIC_GAME_REACH_SCORE) +@ActivityWatcherType(WatcherTriggerType.TRIGGER_FLEUR_FAIR_MUSIC_GAME_REACH_SCORE) public class MusicGameScoreTrigger extends ActivityWatcher { @Override protected boolean isMeet(String... param) { diff --git a/src/main/java/emu/grasscutter/game/props/ActivityType.java b/src/main/java/emu/grasscutter/game/props/ActivityType.java new file mode 100644 index 000000000..b91538cbb --- /dev/null +++ b/src/main/java/emu/grasscutter/game/props/ActivityType.java @@ -0,0 +1,38 @@ +package emu.grasscutter.game.props; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +@Getter +@AllArgsConstructor +public enum ActivityType { + NONE(0), + NEW_ACTIVITY_MUSIC_GAME(2202), + + ; + + 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); + }); + } + + public static ActivityType getTypeByValue(int value) { + return map.getOrDefault(value, NONE); + } + + public static ActivityType getTypeByName(String name) { + return stringMap.getOrDefault(name, NONE); + } +} diff --git a/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java b/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java index af37f7a05..9582b6fe0 100644 --- a/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java +++ b/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java @@ -899,6 +899,12 @@ public class PacketOpcodes { public static final int MultistagePlayInfoNotify = 5309; public static final int MultistagePlaySettleNotify = 5314; public static final int MultistagePlayStageEndNotify = 5340; + public static final int MusicGameCreateBeatmapReq = 6326; + public static final int MusicGameCreateBeatmapRsp = 6347; + public static final int MusicGameGetBeatmapReq = 6318; + public static final int MusicGameGetBeatmapRsp = 6309; + public static final int MusicGameSearchBeatmapReq = 6343; + public static final int MusicGameSearchBeatmapRsp = 6304; public static final int MusicGameSettleReq = 8745; public static final int MusicGameSettleRsp = 8288; public static final int MusicGameStartReq = 8927; diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerActivityTakeWatcherRewardReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerActivityTakeWatcherRewardReq.java new file mode 100644 index 000000000..3ea3b75e2 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerActivityTakeWatcherRewardReq.java @@ -0,0 +1,25 @@ +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.ActivityTakeWatcherRewardReqOuterClass; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketActivityTakeWatcherRewardRsp; + +import java.util.Optional; + +@Opcodes(PacketOpcodes.ActivityTakeWatcherRewardReq) +public class HandlerActivityTakeWatcherRewardReq extends PacketHandler { + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + var req = ActivityTakeWatcherRewardReqOuterClass.ActivityTakeWatcherRewardReq.parseFrom(payload); + + Optional.ofNullable(session.getPlayer().getActivityManager().getPlayerActivityDataMap().get(req.getActivityId())) + .ifPresent(x -> x.takeWatcherReward(req.getWatcherId())); + + session.send(new PacketActivityTakeWatcherRewardRsp(req.getActivityId(), req.getWatcherId())); + } + +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameCreateBeatmapReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameCreateBeatmapReq.java new file mode 100644 index 000000000..b3ac7ef84 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameCreateBeatmapReq.java @@ -0,0 +1,47 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.game.activity.musicgame.MusicGameActivityHandler; +import emu.grasscutter.game.activity.musicgame.MusicGameBeatmap; +import emu.grasscutter.game.props.ActivityType; +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.MusicGameCreateBeatmapReqOuterClass; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketActivityInfoNotify; +import emu.grasscutter.server.packet.send.PacketMusicGameCreateBeatmapRsp; +import emu.grasscutter.utils.Utils; + +@Opcodes(PacketOpcodes.MusicGameCreateBeatmapReq) +public class HandlerMusicGameCreateBeatmapReq extends PacketHandler { + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + var req = MusicGameCreateBeatmapReqOuterClass.MusicGameCreateBeatmapReq.parseFrom(payload); + + var musicGameBeatmap = MusicGameBeatmap.of() + .musicId(req.getMusicBriefInfo().getMusicId()) + .musicNoteCount(req.getMusicBriefInfo().getMusicNoteCount()) + .savePosition(req.getMusicBriefInfo().getSavePosition()) + .maxScore(req.getMusicBriefInfo().getMaxScore()) + .authorUid(session.getPlayer().getUid()) + .beatmap(MusicGameBeatmap.parse(req.getMusicRecord().getBeatmapItemListList())) + .createTime(Utils.getCurrentSeconds()) + .build(); + + // TODO avoid player save too much to make server down + musicGameBeatmap.save(); + + var playerData = session.getPlayer().getActivityManager().getPlayerActivityDataByActivityType(ActivityType.NEW_ACTIVITY_MUSIC_GAME); + if(playerData.isEmpty()){ + return; + } + + var handler = (MusicGameActivityHandler) playerData.get().getActivityHandler(); + handler.addPersonalBeatmap(playerData.get(), musicGameBeatmap); + + session.send(new PacketActivityInfoNotify(handler.toProto(playerData.get()))); + session.send(new PacketMusicGameCreateBeatmapRsp(musicGameBeatmap.getMusicShareId(), req.getUnknownEnum1())); + } + +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameGetBeatmapReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameGetBeatmapReq.java new file mode 100644 index 000000000..8d18c3525 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameGetBeatmapReq.java @@ -0,0 +1,31 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.game.activity.musicgame.MusicGameBeatmap; +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.MusicGameGetBeatmapReqOuterClass; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketMusicGameGetBeatmapRsp; + +@Opcodes(PacketOpcodes.MusicGameGetBeatmapReq) +public class HandlerMusicGameGetBeatmapReq extends PacketHandler { + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + var req = MusicGameGetBeatmapReqOuterClass.MusicGameGetBeatmapReq.parseFrom(payload); + + var musicGameBeatmap = MusicGameBeatmap.getByShareId(req.getMusicShareId()); + + if(musicGameBeatmap == null){ + return; + } + + session.send(new PacketMusicGameGetBeatmapRsp( + musicGameBeatmap.toBriefProto().build(), + musicGameBeatmap.toProto(), + req + )); + } + +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameSearchBeatmapReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameSearchBeatmapReq.java new file mode 100644 index 000000000..82c6f45f1 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameSearchBeatmapReq.java @@ -0,0 +1,28 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.game.activity.musicgame.MusicGameBeatmap; +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.MusicGameSearchBeatmapReqOuterClass; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketMusicGameSearchBeatmapRsp; + +@Opcodes(PacketOpcodes.MusicGameSearchBeatmapReq) +public class HandlerMusicGameSearchBeatmapReq extends PacketHandler { + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + var req = MusicGameSearchBeatmapReqOuterClass.MusicGameSearchBeatmapReq.parseFrom(payload); + + var musicGameBeatmap = MusicGameBeatmap.getByShareId(req.getMusicShareId()); + + if(musicGameBeatmap == null){ + session.send(new PacketMusicGameSearchBeatmapRsp(11153, req.getUnknownEnum1())); + return; + } + + session.send(new PacketMusicGameSearchBeatmapRsp(musicGameBeatmap.toBriefProto().build(), req.getUnknownEnum1())); + } + +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameSettleReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameSettleReq.java index e4e83950f..b73a867e5 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameSettleReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameSettleReq.java @@ -1,11 +1,15 @@ package emu.grasscutter.server.packet.recv; +import emu.grasscutter.game.activity.musicgame.MusicGameActivityHandler; +import emu.grasscutter.game.activity.musicgame.MusicGamePlayerData; +import emu.grasscutter.game.props.ActivityType; import emu.grasscutter.game.props.WatcherTriggerType; import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.MusicGameSettleReqOuterClass; import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketActivityInfoNotify; import emu.grasscutter.server.packet.send.PacketMusicGameSettleRsp; @Opcodes(PacketOpcodes.MusicGameSettleReq) @@ -15,15 +19,40 @@ public class HandlerMusicGameSettleReq extends PacketHandler { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { var req = MusicGameSettleReqOuterClass.MusicGameSettleReq.parseFrom(payload); - session.getPlayer().getActivityManager().triggerWatcher( - WatcherTriggerType.TRIGGER_FLEUR_FAIR_MUSIC_GAME_REACH_SCORE, - String.valueOf(req.getMusicBasicId()), - String.valueOf(req.getScore()) + var playerData = session.getPlayer().getActivityManager().getPlayerActivityDataByActivityType(ActivityType.NEW_ACTIVITY_MUSIC_GAME); + if(playerData.isEmpty()){ + return; + } + var handler = (MusicGameActivityHandler) playerData.get().getActivityHandler(); + boolean isNewRecord = false; + // check if custom beatmap + if(req.getMusicShareId() == 0){ + session.getPlayer().getActivityManager().triggerWatcher( + WatcherTriggerType.TRIGGER_FLEUR_FAIR_MUSIC_GAME_REACH_SCORE, + String.valueOf(req.getMusicBasicId()), + String.valueOf(req.getScore()) ); + isNewRecord = handler.setMusicGameRecord(playerData.get(), + MusicGamePlayerData.MusicGameRecord.of() + .musicId(req.getMusicBasicId()) + .maxCombo(req.getMaxCombo()) + .maxScore(req.getScore()) + .build()); - //session.send(new PacketMusicGameSettleRsp(req.getMusicBasicId())); - session.send(new PacketMusicGameSettleRsp(req.getMusicBasicId())); + // update activity info + session.send(new PacketActivityInfoNotify(handler.toProto(playerData.get()))); + }else{ + handler.setMusicGameCustomBeatmapRecord(playerData.get(), + MusicGamePlayerData.CustomBeatmapRecord.of() + .musicShareId(req.getMusicShareId()) + .score(req.getMaxCombo()) + .settle(req.getSuccess()) + .build()); + } + + + session.send(new PacketMusicGameSettleRsp(req.getMusicBasicId(), req.getMusicShareId(), isNewRecord)); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameStartReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameStartReq.java index a7bb22cf8..a5f92f53a 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameStartReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameStartReq.java @@ -9,12 +9,12 @@ import emu.grasscutter.server.packet.send.PacketMusicGameStartRsp; @Opcodes(PacketOpcodes.MusicGameStartReq) public class HandlerMusicGameStartReq extends PacketHandler { - + @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { var req = MusicGameStartReqOuterClass.MusicGameStartReq.parseFrom(payload); - session.send(new PacketMusicGameStartRsp(req.getMusicBasicId())); + session.send(new PacketMusicGameStartRsp(req.getMusicBasicId(), req.getMusicShareId())); } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketActivityTakeWatcherRewardRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketActivityTakeWatcherRewardRsp.java new file mode 100644 index 000000000..5968198e4 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketActivityTakeWatcherRewardRsp.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.ActivityTakeWatcherRewardRspOuterClass; + +public class PacketActivityTakeWatcherRewardRsp extends BasePacket { + + public PacketActivityTakeWatcherRewardRsp(int activityId, int watcherId) { + super(PacketOpcodes.ActivityTakeWatcherRewardRsp); + + var proto = ActivityTakeWatcherRewardRspOuterClass.ActivityTakeWatcherRewardRsp.newBuilder(); + + proto.setActivityId(activityId) + .setWatcherId(watcherId); + + this.setData(proto); + } + +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetActivityInfoRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetActivityInfoRsp.java index 36e35dcb4..d0172bfcd 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetActivityInfoRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetActivityInfoRsp.java @@ -14,7 +14,7 @@ public class PacketGetActivityInfoRsp extends BasePacket { var proto = GetActivityInfoRsp.newBuilder(); activityIdList.stream() - .map(activityManager::getInfoProto) + .map(activityManager::getInfoProtoByActivityId) .forEach(proto::addActivityInfoList); this.setData(proto); diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameCreateBeatmapRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameCreateBeatmapRsp.java new file mode 100644 index 000000000..401ff44cc --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameCreateBeatmapRsp.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.MusicGameCreateBeatmapRspOuterClass; +import emu.grasscutter.net.proto.MusicGameUnknown1EnumOuterClass; + +public class PacketMusicGameCreateBeatmapRsp extends BasePacket { + + public PacketMusicGameCreateBeatmapRsp(long musicShareId, MusicGameUnknown1EnumOuterClass.MusicGameUnknown1Enum unknownEnum1) { + super(PacketOpcodes.MusicGameCreateBeatmapRsp); + + var proto = MusicGameCreateBeatmapRspOuterClass.MusicGameCreateBeatmapRsp.newBuilder(); + + proto.setMusicShareId(musicShareId) + .setUnknownEnum1(unknownEnum1); + + this.setData(proto); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameGetBeatmapRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameGetBeatmapRsp.java new file mode 100644 index 000000000..35cbdfb3c --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameGetBeatmapRsp.java @@ -0,0 +1,27 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.MusicBeatmapOuterClass; +import emu.grasscutter.net.proto.MusicBriefInfoOuterClass; +import emu.grasscutter.net.proto.MusicGameGetBeatmapReqOuterClass; +import emu.grasscutter.net.proto.MusicGameGetBeatmapRspOuterClass; + +public class PacketMusicGameGetBeatmapRsp extends BasePacket { + + public PacketMusicGameGetBeatmapRsp(MusicBriefInfoOuterClass.MusicBriefInfo briefInfo, MusicBeatmapOuterClass.MusicBeatmap musicRecord, MusicGameGetBeatmapReqOuterClass.MusicGameGetBeatmapReq req) { + super(PacketOpcodes.MusicGameGetBeatmapRsp); + + var proto = MusicGameGetBeatmapRspOuterClass.MusicGameGetBeatmapRsp.newBuilder(); + + proto.setMusicBriefInfo(briefInfo) + .setMusicShareId(briefInfo.getMusicShareId()) + .setMusicRecord(musicRecord) + .setUnknownEnum1(req.getUnknownEnum1()) + .setReqType(req.getReqType()) + ; + + + this.setData(proto); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameSearchBeatmapRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameSearchBeatmapRsp.java new file mode 100644 index 000000000..e5dc218ff --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameSearchBeatmapRsp.java @@ -0,0 +1,34 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.MusicBriefInfoOuterClass; +import emu.grasscutter.net.proto.MusicGameSearchBeatmapRspOuterClass; +import emu.grasscutter.net.proto.MusicGameUnknown1EnumOuterClass; + +public class PacketMusicGameSearchBeatmapRsp extends BasePacket { + + public PacketMusicGameSearchBeatmapRsp(int ret, MusicGameUnknown1EnumOuterClass.MusicGameUnknown1Enum unknownEnum1) { + super(PacketOpcodes.MusicGameSearchBeatmapRsp); + + var proto = MusicGameSearchBeatmapRspOuterClass.MusicGameSearchBeatmapRsp.newBuilder(); + + proto.setRetcode(ret) + .setUnknownEnum1(unknownEnum1); + + this.setData(proto); + } + + public PacketMusicGameSearchBeatmapRsp(MusicBriefInfoOuterClass.MusicBriefInfo briefInfo, MusicGameUnknown1EnumOuterClass.MusicGameUnknown1Enum unknownEnum1) { + super(PacketOpcodes.MusicGameSearchBeatmapRsp); + + var proto = MusicGameSearchBeatmapRspOuterClass.MusicGameSearchBeatmapRsp.newBuilder(); + + proto.setMusicBriefInfo(briefInfo) + .setUnknownEnum1(unknownEnum1); + + this.setData(proto); + } + + +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameSettleRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameSettleRsp.java index c64e44f71..6651f8c06 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameSettleRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameSettleRsp.java @@ -6,14 +6,15 @@ import emu.grasscutter.net.proto.MusicGameSettleRspOuterClass; public class PacketMusicGameSettleRsp extends BasePacket { - public PacketMusicGameSettleRsp(int musicBasicId) { - super(PacketOpcodes.MusicGameSettleRsp); + public PacketMusicGameSettleRsp(int musicBasicId, long musicShareId, boolean isNewRecord) { + super(PacketOpcodes.MusicGameSettleRsp); - var proto = MusicGameSettleRspOuterClass.MusicGameSettleRsp.newBuilder(); + var proto = MusicGameSettleRspOuterClass.MusicGameSettleRsp.newBuilder(); - proto.setMusicBasicId(musicBasicId) - .setIsNewRecord(true); + proto.setMusicBasicId(musicBasicId) + .setMusicShareId(musicShareId) + .setIsNewRecord(isNewRecord); - this.setData(proto); - } + this.setData(proto); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameStartRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameStartRsp.java index 2dce1ba7c..86e11442c 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameStartRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameStartRsp.java @@ -6,12 +6,13 @@ import emu.grasscutter.net.proto.MusicGameStartRspOuterClass; public class PacketMusicGameStartRsp extends BasePacket { - public PacketMusicGameStartRsp(int musicBasicId) { + public PacketMusicGameStartRsp(int musicBasicId, long musicShareId) { super(PacketOpcodes.MusicGameStartRsp); var proto = MusicGameStartRspOuterClass.MusicGameStartRsp.newBuilder(); - proto.setMusicBasicId(musicBasicId); + proto.setMusicBasicId(musicBasicId) + .setMusicShareId(musicShareId); this.setData(proto); } diff --git a/src/main/resources/defaults/data/ActivityConfig.json b/src/main/resources/defaults/data/ActivityConfig.json index 75314fdb9..6291aea43 100644 --- a/src/main/resources/defaults/data/ActivityConfig.json +++ b/src/main/resources/defaults/data/ActivityConfig.json @@ -2,6 +2,7 @@ { "activityId" : 5072, "activityType" : 2202, + "scheduleId": 5072001, "meetCondList" : [ 5072001, 5072002, @@ -9,7 +10,10 @@ 5072004, 5072005, 5072006, - 5072007 + 5072007, + 5072008, + 5072009, + 5072013 ], "beginTime" : "2022-05-01T00:00:00+08:00", "endTime" : "2023-05-01T00:00:00+08:00"