diff --git a/src/main/java/emu/grasscutter/data/GameData.java b/src/main/java/emu/grasscutter/data/GameData.java index 59b7c4944..780564cbd 100644 --- a/src/main/java/emu/grasscutter/data/GameData.java +++ b/src/main/java/emu/grasscutter/data/GameData.java @@ -15,6 +15,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; +import lombok.Getter; public class GameData { // BinOutputs @@ -98,6 +99,9 @@ public class GameData { private static final Int2ObjectMap battlePassMissionDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap battlePassRewardDataMap = new Int2ObjectOpenHashMap<>(); + @Getter private static final Int2ObjectMap activityDataMap = new Int2ObjectOpenHashMap<>(); + @Getter private static final Int2ObjectMap activityWatcherDataMap = new Int2ObjectOpenHashMap<>(); + // Cache private static Map> fetters = new HashMap<>(); private static Map> shopGoods = new HashMap<>(); diff --git a/src/main/java/emu/grasscutter/data/excels/ActivityData.java b/src/main/java/emu/grasscutter/data/excels/ActivityData.java new file mode 100644 index 000000000..74b569673 --- /dev/null +++ b/src/main/java/emu/grasscutter/data/excels/ActivityData.java @@ -0,0 +1,34 @@ +package emu.grasscutter.data.excels; + +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.GameResource; +import emu.grasscutter.data.ResourceType; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.FieldDefaults; + +import java.util.List; +import java.util.Objects; + +@ResourceType(name = "NewActivityExcelConfigData.json", loadPriority = ResourceType.LoadPriority.LOW) +@Getter +@FieldDefaults(level = AccessLevel.PRIVATE) +public class ActivityData extends GameResource { + int activityId; + String activityType; + List condGroupId; + List watcherId; + List watcherDataList; + + @Override + public int getId() { + return this.activityId; + } + @Override + public void onLoad() { + this.watcherDataList = watcherId.stream().map(item -> GameData.getActivityWatcherDataMap().get(item.intValue())) + .filter(Objects::nonNull) + .toList(); + } + +} diff --git a/src/main/java/emu/grasscutter/data/excels/ActivityWatcherData.java b/src/main/java/emu/grasscutter/data/excels/ActivityWatcherData.java new file mode 100644 index 000000000..e784693f9 --- /dev/null +++ b/src/main/java/emu/grasscutter/data/excels/ActivityWatcherData.java @@ -0,0 +1,36 @@ +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; + +import java.util.List; + +@ResourceType(name = "NewActivityWatcherConfigData.json", loadPriority = ResourceType.LoadPriority.HIGH) +@Getter +@FieldDefaults(level = AccessLevel.PRIVATE) +public class ActivityWatcherData extends GameResource { + int id; + int rewardID; + int progress; + WatcherTrigger triggerConfig; + + @Override + public int getId() { + return this.id; + } + @Override + public void onLoad() { + triggerConfig.paramList = triggerConfig.paramList.stream().filter(x -> !x.isBlank()).toList(); + } + + @Getter + @FieldDefaults(level = AccessLevel.PRIVATE) + public static class WatcherTrigger{ + String triggerType; + List paramList; + } + +} diff --git a/src/main/java/emu/grasscutter/database/DatabaseHelper.java b/src/main/java/emu/grasscutter/database/DatabaseHelper.java index d4592b005..55afc4354 100644 --- a/src/main/java/emu/grasscutter/database/DatabaseHelper.java +++ b/src/main/java/emu/grasscutter/database/DatabaseHelper.java @@ -10,6 +10,7 @@ import dev.morphia.query.experimental.filters.Filters; import emu.grasscutter.GameConstants; import emu.grasscutter.Grasscutter; import emu.grasscutter.game.Account; +import emu.grasscutter.game.activity.PlayerActivityData; import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.battlepass.BattlePassManager; import emu.grasscutter.game.friends.Friendship; @@ -326,4 +327,14 @@ public final class DatabaseHelper { public static void saveBattlePass(BattlePassManager manager) { DatabaseManager.getGameDatastore().save(manager); } + + public static PlayerActivityData getPlayerActivityData(int uid, int activityId) { + return DatabaseManager.getGameDatastore().find(PlayerActivityData.class) + .filter(Filters.and(Filters.eq("uid", uid),Filters.eq("activityId", activityId))) + .first(); + } + + public static void savePlayerActivityData(PlayerActivityData playerActivityData) { + DatabaseManager.getGameDatastore().save(playerActivityData); + } } diff --git a/src/main/java/emu/grasscutter/database/DatabaseManager.java b/src/main/java/emu/grasscutter/database/DatabaseManager.java index 565d76815..19618c27b 100644 --- a/src/main/java/emu/grasscutter/database/DatabaseManager.java +++ b/src/main/java/emu/grasscutter/database/DatabaseManager.java @@ -13,6 +13,7 @@ import dev.morphia.query.experimental.filters.Filters; import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter.ServerRunMode; import emu.grasscutter.game.Account; +import emu.grasscutter.game.activity.PlayerActivityData; import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.battlepass.BattlePassManager; import emu.grasscutter.game.friends.Friendship; @@ -29,12 +30,11 @@ import static emu.grasscutter.Configuration.*; public final class DatabaseManager { private static Datastore gameDatastore; private static Datastore dispatchDatastore; - + 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 + DatabaseCounter.class, Account.class, Player.class, Avatar.class, GameItem.class, Friendship.class, + GachaRecord.class, Mail.class, GameMainQuest.class, GameHome.class, BattlePassManager.class, PlayerActivityData.class }; - public static Datastore getGameDatastore() { return gameDatastore; } diff --git a/src/main/java/emu/grasscutter/game/activity/ActivityConfigItem.java b/src/main/java/emu/grasscutter/game/activity/ActivityConfigItem.java new file mode 100644 index 000000000..a8f17cdc8 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/activity/ActivityConfigItem.java @@ -0,0 +1,21 @@ +package emu.grasscutter.game.activity; + +import lombok.AccessLevel; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +import java.util.Date; +import java.util.List; + +@Data +@FieldDefaults(level = AccessLevel.PRIVATE) +public class ActivityConfigItem { + int activityId; + int activityType; + int scheduleId; + List meetCondList; + Date beginTime; + Date endTime; + + transient ActivityHandler activityHandler; +} diff --git a/src/main/java/emu/grasscutter/game/activity/ActivityHandler.java b/src/main/java/emu/grasscutter/game/activity/ActivityHandler.java new file mode 100644 index 000000000..386533d5c --- /dev/null +++ b/src/main/java/emu/grasscutter/game/activity/ActivityHandler.java @@ -0,0 +1,81 @@ +package emu.grasscutter.game.activity; + +import com.esotericsoftware.reflectasm.ConstructorAccess; +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.excels.ActivityData; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.WatcherTriggerType; +import emu.grasscutter.net.proto.ActivityInfoOuterClass; +import emu.grasscutter.utils.DateHelper; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.FieldDefaults; + +import java.util.*; +import java.util.stream.Collectors; + +@Getter +@Setter +@FieldDefaults(level = AccessLevel.PRIVATE) +public abstract class ActivityHandler { + /** + * Must set before initWatchers + */ + ActivityConfigItem activityConfigItem; + ActivityData activityData; + Map> watchersMap = new HashMap<>(); + + public void initWatchers(HashMap> activityWatcherTypeMap){ + activityData = GameData.getActivityDataMap().get(activityConfigItem.getActivityId()); + + // add watcher to map by id + activityData.getWatcherDataList().forEach(watcherData -> { + var watcherType = activityWatcherTypeMap.get(watcherData.getTriggerConfig().getTriggerType()); + ActivityWatcher watcher; + if(watcherType != null){ + watcher = (ActivityWatcher) watcherType.newInstance(); + }else{ + watcher = new DefaultWatcher(); + } + + 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); + }); + } + + private Map initWatchersDataForPlayer(){ + return watchersMap.values().stream() + .flatMap(Collection::stream) + .map(PlayerActivityData.WatcherInfo::init) + .collect(Collectors.toMap(PlayerActivityData.WatcherInfo::getWatcherId, y -> y)); + } + + public PlayerActivityData initPlayerActivityData(Player player){ + return PlayerActivityData.of() + .activityId(activityConfigItem.getActivityId()) + .uid(player.getUid()) + .watcherInfoMap(initWatchersDataForPlayer()) + .build(); + } + + + public void buildProto(PlayerActivityData playerActivityData, ActivityInfoOuterClass.ActivityInfo.Builder activityInfo){ + activityInfo.setActivityId(activityConfigItem.getActivityId()) + .setActivityType(activityConfigItem.getActivityType()) + .setScheduleId(activityConfigItem.getScheduleId()) + .setBeginTime(DateHelper.getUnixTime(activityConfigItem.getBeginTime())) + .setFirstDayStartTime(DateHelper.getUnixTime(activityConfigItem.getBeginTime())) + .setEndTime(DateHelper.getUnixTime(activityConfigItem.getEndTime())) + .addAllMeetCondList(activityConfigItem.getMeetCondList()); + + if (playerActivityData != null){ + activityInfo.addAllWatcherInfoList(playerActivityData.getAllWatcherInfoList()); + } + + } + +} diff --git a/src/main/java/emu/grasscutter/game/activity/ActivityManager.java b/src/main/java/emu/grasscutter/game/activity/ActivityManager.java new file mode 100644 index 000000000..b8b4db168 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/activity/ActivityManager.java @@ -0,0 +1,125 @@ +package emu.grasscutter.game.activity; + +import com.esotericsoftware.reflectasm.ConstructorAccess; +import com.google.gson.reflect.TypeToken; +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.WatcherTriggerType; +import emu.grasscutter.net.proto.ActivityInfoOuterClass; +import emu.grasscutter.server.packet.send.PacketActivityScheduleInfoNotify; +import lombok.Getter; +import org.reflections.Reflections; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +@Getter +public class ActivityManager { + private static final Map activityConfigItemMap; + private final Player player; + private final Map playerActivityDataMap; + + 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 reflections = new Reflections(ActivityManager.class.getPackage().getName()); + + reflections.getSubTypesOf(ActivityHandler.class).forEach(item -> { + var typeName = item.getAnnotation(ActivityType.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)); + }); + + try(InputStream is = DataLoader.load("ActivityConfig.json"); InputStreamReader isr = new InputStreamReader(is)) { + List activities = Grasscutter.getGsonFactory().fromJson( + isr, + TypeToken.getParameterized(List.class, ActivityConfigItem.class).getType()); + + + activities.forEach(item -> { + var activityData = GameData.getActivityDataMap().get(item.getActivityId()); + if(activityData == null){ + Grasscutter.getLogger().warn("activity {} not exist.", item.getActivityId()); + return; + } + var activityHandlerType = activityHandlerTypeMap.get(activityData.getActivityType()); + + if(activityHandlerType != null) { + var activityHandler = (ActivityHandler) activityHandlerType.newInstance(); + activityHandler.setActivityConfigItem(item); + activityHandler.initWatchers(activityWatcherTypeMap); + item.setActivityHandler(activityHandler); + } + + activityConfigItemMap.putIfAbsent(item.getActivityId(), item); + }); + + Grasscutter.getLogger().error("Enable {} activities.", activityConfigItemMap.size()); + } catch (Exception e) { + Grasscutter.getLogger().error("Unable to load chest reward config.", e); + } + + } + + public ActivityInfoOuterClass.ActivityInfo getInfoProto(int activityId){ + var activityHandler = activityConfigItemMap.get(activityId).getActivityHandler(); + var activityData = playerActivityDataMap.get(activityId); + + var proto = ActivityInfoOuterClass.ActivityInfo.newBuilder(); + activityHandler.buildProto(activityData, proto); + + return proto.build(); + } + + /** + * trigger activity watcher + * @param watcherTriggerType + * @param params + */ + public void triggerWatcher(WatcherTriggerType watcherTriggerType, String... params) { + var watchers = activityConfigItemMap.values().stream() + .map(ActivityConfigItem::getActivityHandler) + .filter(Objects::nonNull) + .map(ActivityHandler::getWatchersMap) + .map(map -> map.get(watcherTriggerType)) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .toList(); + + watchers.forEach(watcher -> watcher.trigger( + playerActivityDataMap.get(watcher.getActivityHandler().getActivityConfigItem().getActivityId()), + params)); + } +} diff --git a/src/main/java/emu/grasscutter/game/activity/ActivityType.java b/src/main/java/emu/grasscutter/game/activity/ActivityType.java new file mode 100644 index 000000000..da57637e7 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/activity/ActivityType.java @@ -0,0 +1,12 @@ +package emu.grasscutter.game.activity; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface ActivityType { + String value(); +} diff --git a/src/main/java/emu/grasscutter/game/activity/ActivityWatcher.java b/src/main/java/emu/grasscutter/game/activity/ActivityWatcher.java new file mode 100644 index 000000000..eeb864207 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/activity/ActivityWatcher.java @@ -0,0 +1,26 @@ +package emu.grasscutter.game.activity; + +import emu.grasscutter.data.excels.ActivityWatcherData; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.FieldDefaults; + +@Getter +@Setter +@FieldDefaults(level = AccessLevel.PRIVATE) +public abstract class ActivityWatcher { + int watcherId; + ActivityWatcherData activityWatcherData; + ActivityHandler activityHandler; + + protected abstract boolean isMeet(String... param); + + public void trigger(PlayerActivityData playerActivityData, String... param){ + if(isMeet(param)){ + playerActivityData.addWatcherProgress(watcherId); + playerActivityData.save(); + } + } + +} diff --git a/src/main/java/emu/grasscutter/game/activity/DefaultWatcher.java b/src/main/java/emu/grasscutter/game/activity/DefaultWatcher.java new file mode 100644 index 000000000..8c6e2464f --- /dev/null +++ b/src/main/java/emu/grasscutter/game/activity/DefaultWatcher.java @@ -0,0 +1,11 @@ +package emu.grasscutter.game.activity; + +import emu.grasscutter.game.props.WatcherTriggerType; + +@WatcherType(WatcherTriggerType.TRIGGER_NONE) +public class DefaultWatcher extends ActivityWatcher{ + @Override + protected boolean isMeet(String... param) { + return false; + } +} diff --git a/src/main/java/emu/grasscutter/game/activity/PlayerActivityData.java b/src/main/java/emu/grasscutter/game/activity/PlayerActivityData.java new file mode 100644 index 000000000..4a251a621 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/activity/PlayerActivityData.java @@ -0,0 +1,86 @@ +package emu.grasscutter.game.activity; + +import dev.morphia.annotations.Entity; +import dev.morphia.annotations.Id; +import dev.morphia.annotations.Transient; +import emu.grasscutter.database.DatabaseHelper; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.net.proto.ActivityWatcherInfoOuterClass; +import emu.grasscutter.server.packet.send.PacketActivityUpdateWatcherNotify; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +import java.util.List; +import java.util.Map; + +@Entity("activities") +@Data +@FieldDefaults(level = AccessLevel.PRIVATE) +@Builder(builderMethodName = "of") +public class PlayerActivityData { + @Id + String id; + int uid; + int activityId; + Map watcherInfoMap; + String detail; + @Transient Player player; + + public void save(){ + DatabaseHelper.savePlayerActivityData(this); + } + + public static PlayerActivityData getByPlayer(Player player, int activityId){ + return DatabaseHelper.getPlayerActivityData(player.getUid(), activityId); + } + + public synchronized void addWatcherProgress(int watcherId){ + var watcherInfo = watcherInfoMap.get(watcherId); + if(watcherInfo == null){ + return; + } + + if(watcherInfo.curProgress >= watcherInfo.totalProgress){ + return; + } + + watcherInfo.curProgress++; + getPlayer().sendPacket(new PacketActivityUpdateWatcherNotify(activityId, watcherInfo)); + } + + public List getAllWatcherInfoList() { + return watcherInfoMap.values().stream() + .map(WatcherInfo::toProto) + .toList(); + } + + @Entity + @Data + @FieldDefaults(level = AccessLevel.PRIVATE) + @Builder(builderMethodName = "of") + public static class WatcherInfo{ + int watcherId; + int totalProgress; + int curProgress; + boolean isTakenReward; + + public static WatcherInfo init(ActivityWatcher watcher){ + return WatcherInfo.of() + .watcherId(watcher.getWatcherId()) + .totalProgress(watcher.getActivityWatcherData().getProgress()) + .isTakenReward(false) + .build(); + } + + public ActivityWatcherInfoOuterClass.ActivityWatcherInfo toProto(){ + return ActivityWatcherInfoOuterClass.ActivityWatcherInfo.newBuilder() + .setWatcherId(watcherId) + .setCurProgress(curProgress) + .setTotalProgress(totalProgress) + .setIsTakenReward(isTakenReward) + .build(); + } + } +} diff --git a/src/main/java/emu/grasscutter/game/activity/WatcherType.java b/src/main/java/emu/grasscutter/game/activity/WatcherType.java new file mode 100644 index 000000000..7d1f9a261 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/activity/WatcherType.java @@ -0,0 +1,14 @@ +package emu.grasscutter.game.activity; + +import emu.grasscutter.game.props.WatcherTriggerType; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface WatcherType { + WatcherTriggerType value(); +} diff --git a/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameActivityHandler.java b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameActivityHandler.java new file mode 100644 index 000000000..c3d5ad53a --- /dev/null +++ b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameActivityHandler.java @@ -0,0 +1,17 @@ +package emu.grasscutter.game.activity.musicgame; + +import emu.grasscutter.game.activity.ActivityHandler; +import emu.grasscutter.game.activity.ActivityType; +import emu.grasscutter.game.activity.PlayerActivityData; +import emu.grasscutter.net.proto.ActivityInfoOuterClass; + +@ActivityType("NEW_ACTIVITY_MUSIC_GAME") +public class MusicGameActivityHandler extends ActivityHandler { + + @Override + public void buildProto(PlayerActivityData playerActivityData, ActivityInfoOuterClass.ActivityInfo.Builder activityInfo) { + super.buildProto(playerActivityData, activityInfo); + + + } +} diff --git a/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameScoreTrigger.java b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameScoreTrigger.java new file mode 100644 index 000000000..8ee92027f --- /dev/null +++ b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameScoreTrigger.java @@ -0,0 +1,23 @@ +package emu.grasscutter.game.activity.musicgame; + +import emu.grasscutter.game.activity.ActivityWatcher; +import emu.grasscutter.game.activity.WatcherType; +import emu.grasscutter.game.props.WatcherTriggerType; + +@WatcherType(WatcherTriggerType.TRIGGER_FLEUR_FAIR_MUSIC_GAME_REACH_SCORE) +public class MusicGameScoreTrigger extends ActivityWatcher { + @Override + protected boolean isMeet(String... param) { + if(param.length != 2){ + return false; + } + var paramList = getActivityWatcherData().getTriggerConfig().getParamList(); + if(!paramList.get(0).equals(param[0])){ + return false; + } + + var score = Integer.parseInt(param[1]); + var target = Integer.parseInt(paramList.get(1)); + return score >= target; + } +} diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index e01b0abcc..59c001948 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -11,6 +11,7 @@ import emu.grasscutter.database.DatabaseManager; import emu.grasscutter.game.Account; import emu.grasscutter.game.CoopRequest; import emu.grasscutter.game.ability.AbilityManager; +import emu.grasscutter.game.activity.ActivityManager; import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.avatar.AvatarProfileData; import emu.grasscutter.game.avatar.AvatarStorage; @@ -183,6 +184,7 @@ public class Player { @Transient private GameHome home; @Transient private FurnitureManager furnitureManager; @Transient private BattlePassManager battlePassManager; + @Getter @Transient private ActivityManager activityManager; @Transient private CollectionManager collectionManager; private CollectionRecordStore collectionRecordStore; @@ -1508,11 +1510,13 @@ public class Player { // Battle Pass trigger this.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_LOGIN); - + this.furnitureManager.onLogin(); // Home home = GameHome.getByUid(getUid()); home.onOwnerLogin(this); + // Activity + activityManager = new ActivityManager(this); session.send(new PacketPlayerEnterSceneNotify(this)); // Enter game world session.send(new PacketPlayerLevelRewardUpdateNotify(rewardedLevels)); diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetActivityInfoReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetActivityInfoReq.java index bf2cf7491..8ecad3514 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetActivityInfoReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetActivityInfoReq.java @@ -3,13 +3,20 @@ package emu.grasscutter.server.packet.recv; import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.net.proto.GetActivityInfoReqOuterClass; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.packet.send.PacketGetActivityInfoRsp; +import java.util.HashSet; + @Opcodes(PacketOpcodes.GetActivityInfoReq) public class HandlerGetActivityInfoReq extends PacketHandler { @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - session.send(new PacketGetActivityInfoRsp()); + var req = GetActivityInfoReqOuterClass.GetActivityInfoReq.parseFrom(payload); + + session.send(new PacketGetActivityInfoRsp( + new HashSet<>(req.getActivityIdListList()), + session.getPlayer().getActivityManager())); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameSettleReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameSettleReq.java new file mode 100644 index 000000000..e4e83950f --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameSettleReq.java @@ -0,0 +1,29 @@ +package emu.grasscutter.server.packet.recv; + +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.PacketMusicGameSettleRsp; + +@Opcodes(PacketOpcodes.MusicGameSettleReq) +public class HandlerMusicGameSettleReq extends PacketHandler { + + @Override + 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()) + ); + + + //session.send(new PacketMusicGameSettleRsp(req.getMusicBasicId())); + session.send(new PacketMusicGameSettleRsp(req.getMusicBasicId())); + } + +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameStartReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameStartReq.java new file mode 100644 index 000000000..a7bb22cf8 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerMusicGameStartReq.java @@ -0,0 +1,20 @@ +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.MusicGameStartReqOuterClass; +import emu.grasscutter.server.game.GameSession; +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())); + } + +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketActivityInfoNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketActivityInfoNotify.java new file mode 100644 index 000000000..cf7342ec1 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketActivityInfoNotify.java @@ -0,0 +1,19 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.ActivityInfoNotifyOuterClass; +import emu.grasscutter.net.proto.ActivityInfoOuterClass; + +public class PacketActivityInfoNotify extends BasePacket { + + public PacketActivityInfoNotify(ActivityInfoOuterClass.ActivityInfo activityInfo) { + super(PacketOpcodes.ActivityInfoNotify); + + var proto = ActivityInfoNotifyOuterClass.ActivityInfoNotify.newBuilder(); + + proto.setActivityInfo(activityInfo); + + this.setData(proto); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketActivityScheduleInfoNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketActivityScheduleInfoNotify.java new file mode 100644 index 000000000..f7048ffb3 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketActivityScheduleInfoNotify.java @@ -0,0 +1,31 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.game.activity.ActivityConfigItem; +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.ActivityScheduleInfoNotifyOuterClass; +import emu.grasscutter.net.proto.ActivityScheduleInfoOuterClass; +import emu.grasscutter.utils.DateHelper; + +import java.util.Collection; + +public class PacketActivityScheduleInfoNotify extends BasePacket { + + public PacketActivityScheduleInfoNotify(Collection activityConfigItemList) { + super(PacketOpcodes.ActivityScheduleInfoNotify); + + var proto = ActivityScheduleInfoNotifyOuterClass.ActivityScheduleInfoNotify.newBuilder(); + + activityConfigItemList.forEach(item -> { + proto.addActivityScheduleList(ActivityScheduleInfoOuterClass.ActivityScheduleInfo.newBuilder() + .setActivityId(item.getActivityId()) + .setScheduleId(item.getScheduleId()) + .setIsOpen(true) + .setBeginTime(DateHelper.getUnixTime(item.getBeginTime())) + .setEndTime(DateHelper.getUnixTime(item.getEndTime())) + .build()); + }); + + this.setData(proto); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketActivityUpdateWatcherNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketActivityUpdateWatcherNotify.java new file mode 100644 index 000000000..68ced92ad --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketActivityUpdateWatcherNotify.java @@ -0,0 +1,20 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.game.activity.PlayerActivityData; +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.ActivityUpdateWatcherNotifyOuterClass; + +public class PacketActivityUpdateWatcherNotify extends BasePacket { + + public PacketActivityUpdateWatcherNotify(int activityId, PlayerActivityData.WatcherInfo watcherInfo) { + super(PacketOpcodes.ActivityUpdateWatcherNotify); + + var proto = ActivityUpdateWatcherNotifyOuterClass.ActivityUpdateWatcherNotify.newBuilder(); + + proto.setActivityId(activityId) + .setWatcherInfo(watcherInfo.toProto()); + + 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 1808391c6..36e35dcb4 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetActivityInfoRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetActivityInfoRsp.java @@ -1,15 +1,22 @@ package emu.grasscutter.server.packet.send; +import emu.grasscutter.game.activity.ActivityManager; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.GetActivityInfoRspOuterClass.GetActivityInfoRsp; +import java.util.Set; + public class PacketGetActivityInfoRsp extends BasePacket { - public PacketGetActivityInfoRsp() { + public PacketGetActivityInfoRsp(Set activityIdList, ActivityManager activityManager) { super(PacketOpcodes.GetActivityInfoRsp); - - GetActivityInfoRsp proto = GetActivityInfoRsp.newBuilder().build(); - + + var proto = GetActivityInfoRsp.newBuilder(); + + activityIdList.stream() + .map(activityManager::getInfoProto) + .forEach(proto::addActivityInfoList); + 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 new file mode 100644 index 000000000..c64e44f71 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameSettleRsp.java @@ -0,0 +1,19 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.MusicGameSettleRspOuterClass; + +public class PacketMusicGameSettleRsp extends BasePacket { + + public PacketMusicGameSettleRsp(int musicBasicId) { + super(PacketOpcodes.MusicGameSettleRsp); + + var proto = MusicGameSettleRspOuterClass.MusicGameSettleRsp.newBuilder(); + + proto.setMusicBasicId(musicBasicId) + .setIsNewRecord(true); + + 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 new file mode 100644 index 000000000..2dce1ba7c --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketMusicGameStartRsp.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.MusicGameStartRspOuterClass; + +public class PacketMusicGameStartRsp extends BasePacket { + + public PacketMusicGameStartRsp(int musicBasicId) { + super(PacketOpcodes.MusicGameStartRsp); + + var proto = MusicGameStartRspOuterClass.MusicGameStartRsp.newBuilder(); + + proto.setMusicBasicId(musicBasicId); + + this.setData(proto); + } +} diff --git a/src/main/resources/defaults/data/ActivityConfig.json b/src/main/resources/defaults/data/ActivityConfig.json new file mode 100644 index 000000000..75314fdb9 --- /dev/null +++ b/src/main/resources/defaults/data/ActivityConfig.json @@ -0,0 +1,17 @@ +[ + { + "activityId" : 5072, + "activityType" : 2202, + "meetCondList" : [ + 5072001, + 5072002, + 5072003, + 5072004, + 5072005, + 5072006, + 5072007 + ], + "beginTime" : "2022-05-01T00:00:00+08:00", + "endTime" : "2023-05-01T00:00:00+08:00" + } +] \ No newline at end of file