diff --git a/src/main/java/emu/grasscutter/command/commands/SetPropCommand.java b/src/main/java/emu/grasscutter/command/commands/SetPropCommand.java index a66a7cf74..078cb0978 100644 --- a/src/main/java/emu/grasscutter/command/commands/SetPropCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/SetPropCommand.java @@ -1,15 +1,19 @@ package emu.grasscutter.command.commands; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import emu.grasscutter.command.Command; import emu.grasscutter.command.CommandHandler; +import emu.grasscutter.data.GameData; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.tower.TowerLevelRecord; import emu.grasscutter.server.packet.send.PacketOpenStateChangeNotify; +import emu.grasscutter.server.packet.send.PacketSceneAreaUnlockNotify; +import emu.grasscutter.server.packet.send.PacketScenePointUnlockNotify; @Command(label = "setProp", aliases = {"prop"}, usage = {" "}, permission = "player.setprop", permissionTargeted = "player.setprop.others") public final class SetPropCommand implements CommandHandler { @@ -22,7 +26,8 @@ public final class SetPropCommand implements CommandHandler { NO_STAMINA, UNLIMITED_ENERGY, SET_OPENSTATE, - UNSET_OPENSTATE + UNSET_OPENSTATE, + UNLOCKMAP } static class Prop { @@ -101,6 +106,10 @@ public final class SetPropCommand implements CommandHandler { Prop unsetopenstate = new Prop("unsetopenstate", PseudoProp.UNSET_OPENSTATE); this.props.put("unsetopenstate", unsetopenstate); this.props.put("uo", unsetopenstate); + + Prop unlockmap = new Prop("unlockmap", PseudoProp.UNLOCKMAP); + this.props.put("unlockmap", unlockmap); + this.props.put("um", unlockmap); } @Override @@ -139,6 +148,7 @@ public final class SetPropCommand implements CommandHandler { case GOD_MODE, NO_STAMINA, UNLIMITED_ENERGY -> this.setBool(sender, targetPlayer, prop.pseudoProp, value); case SET_OPENSTATE -> this.setOpenState(targetPlayer, value, 1); case UNSET_OPENSTATE -> this.setOpenState(targetPlayer, value, 0); + case UNLOCKMAP -> unlockMap(targetPlayer); default -> targetPlayer.setProperty(prop.prop, value); }; @@ -220,4 +230,26 @@ public final class SetPropCommand implements CommandHandler { targetPlayer.sendPacket(new PacketOpenStateChangeNotify(state, value)); return true; } + + private boolean unlockMap(Player targetPlayer) { + // Unlock. + targetPlayer.setUnlockedScenePoints(new HashMap<>()); + targetPlayer.setUnlockedSceneAreas(new HashMap<>()); + for (int sceneId : GameData.getScenePointsPerScene().keySet()) { + // Unlock trans points. + targetPlayer.getUnlockedScenePoints().put(sceneId, new ArrayList<>()); + targetPlayer.getUnlockedScenePoints().get(sceneId).addAll(GameData.getScenePointsPerScene().get(sceneId)); + + // Unlock map areas. Unfortunately, there is no readily available source for them in excels or bins. + targetPlayer.getUnlockedSceneAreas().put(sceneId, new ArrayList<>()); + targetPlayer.getUnlockedSceneAreas().get(sceneId).addAll(List.of(1,2,3,4,5,6,7,8,9,10,11,12,13,14,17,18,19,20,21,22,23,24,25,29,100,101,102,103,200,210,300,400,401,402,403)); + } + + // Send notify. + int playerScene = targetPlayer.getSceneId(); + targetPlayer.sendPacket(new PacketScenePointUnlockNotify(playerScene, targetPlayer.getUnlockedScenePoints().get(playerScene))); + targetPlayer.sendPacket(new PacketSceneAreaUnlockNotify(playerScene, targetPlayer.getUnlockedSceneAreas().get(playerScene))); + + return true; + } } diff --git a/src/main/java/emu/grasscutter/command/commands/UnlockAllCommand.java b/src/main/java/emu/grasscutter/command/commands/UnlockAllCommand.java index 6ba2088a5..95cb1f599 100644 --- a/src/main/java/emu/grasscutter/command/commands/UnlockAllCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/UnlockAllCommand.java @@ -4,7 +4,7 @@ import emu.grasscutter.command.Command; import emu.grasscutter.command.CommandHandler; import emu.grasscutter.data.GameData; import emu.grasscutter.game.player.Player; -import emu.grasscutter.game.player.PlayerOpenStateManager; +import emu.grasscutter.game.player.PlayerProgressManager; import emu.grasscutter.server.packet.send.PacketOpenStateChangeNotify; import java.util.HashMap; @@ -22,12 +22,12 @@ public final class UnlockAllCommand implements CommandHandler { for (var state : GameData.getOpenStateList()) { // Don't unlock blacklisted open states. - if (PlayerOpenStateManager.BLACKLIST_OPEN_STATES.contains(state.getId())) { + if (PlayerProgressManager.BLACKLIST_OPEN_STATES.contains(state.getId())) { continue; } - if (targetPlayer.getOpenStateManager().getOpenState(state.getId()) == 0) { - targetPlayer.getOpenStateManager().getOpenStateMap().put(state.getId(), 1); + if (targetPlayer.getProgressManager().getOpenState(state.getId()) == 0) { + targetPlayer.getOpenStates().put(state.getId(), 1); changed.put(state.getId(), 1); } } diff --git a/src/main/java/emu/grasscutter/data/GameData.java b/src/main/java/emu/grasscutter/data/GameData.java index 0a86451d3..e56140b83 100644 --- a/src/main/java/emu/grasscutter/data/GameData.java +++ b/src/main/java/emu/grasscutter/data/GameData.java @@ -112,6 +112,7 @@ public class GameData { @Getter private static final Int2ObjectMap chapterDataMap = new Int2ObjectOpenHashMap<>(); @Getter private static final Int2ObjectMap triggerExcelConfigDataMap = new Int2ObjectOpenHashMap<>(); @Getter private static final Map scriptSceneDataMap = new HashMap<>(); + @Getter private static final Map> scenePointsPerScene = new HashMap<>(); @Getter private static final Int2ObjectMap openStateDataMap = new Int2ObjectOpenHashMap<>(); diff --git a/src/main/java/emu/grasscutter/data/ResourceLoader.java b/src/main/java/emu/grasscutter/data/ResourceLoader.java index ed66cc821..5ceb756fd 100644 --- a/src/main/java/emu/grasscutter/data/ResourceLoader.java +++ b/src/main/java/emu/grasscutter/data/ResourceLoader.java @@ -142,7 +142,8 @@ public class ResourceLoader { List scenePointList = new ArrayList<>(); for (File file : Objects.requireNonNull(folder.listFiles())) { - ScenePointConfig config; Integer sceneId; + ScenePointConfig config; + Integer sceneId; Matcher matcher = pattern.matcher(file.getName()); if (matcher.find()) { @@ -173,8 +174,10 @@ public class ResourceLoader { pointData.updateDailyDungeon(); } + GameData.getScenePointsPerScene().put(sceneId, new ArrayList<>()); for (ScenePointEntry entry : scenePointList) { GameData.getScenePointEntries().put(entry.getName(), entry); + GameData.getScenePointsPerScene().get(sceneId).add(entry.getPointData().getId()); } } } diff --git a/src/main/java/emu/grasscutter/data/binout/MainQuestData.java b/src/main/java/emu/grasscutter/data/binout/MainQuestData.java index 6fa65b975..dd05a2663 100644 --- a/src/main/java/emu/grasscutter/data/binout/MainQuestData.java +++ b/src/main/java/emu/grasscutter/data/binout/MainQuestData.java @@ -66,5 +66,11 @@ public class MainQuestData { public static class TalkData { private int id; private String heroTalk; + + public TalkData() {} + public TalkData(int id, String heroTalk) { + this.id = id; + this.heroTalk = heroTalk; + } } } diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 59bc6b5b6..8ea9100c3 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -56,6 +56,7 @@ import emu.grasscutter.net.proto.MpSettingTypeOuterClass.MpSettingType; import emu.grasscutter.net.proto.OnlinePlayerInfoOuterClass.OnlinePlayerInfo; import emu.grasscutter.net.proto.PlayerLocationInfoOuterClass.PlayerLocationInfo; import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture; +import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason; import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail; import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType; import emu.grasscutter.scripts.data.SceneRegion; @@ -122,6 +123,9 @@ public class Player { @Getter private Map unlockedRecipies; @Getter private List activeForges; @Getter private Map questGlobalVariables; + @Getter private Map openStates; + @Getter @Setter private Map> unlockedSceneAreas; + @Getter @Setter private Map> unlockedScenePoints; @Transient private long nextGuid = 0; @Transient private int peerId; @@ -151,13 +155,13 @@ public class Player { @Getter private transient CookingManager cookingManager; @Getter private transient ActivityManager activityManager; @Getter private transient PlayerBuffManager buffManager; + @Getter private transient PlayerProgressManager progressManager; // Manager data (Save-able to the database) private PlayerProfile playerProfile; private TeamManager teamManager; private TowerData towerData; private PlayerGachaInfo gachaInfo; - private PlayerOpenStateManager openStateManager; private PlayerCollectionRecords collectionRecordStore; private ArrayList shopLimit; @@ -221,6 +225,9 @@ public class Player { this.unlockedFurnitureSuite = new HashSet<>(); this.activeForges = new ArrayList<>(); this.unlockedRecipies = new HashMap<>(); + this.openStates = new HashMap<>(); + this.unlockedSceneAreas = new HashMap<>(); + this.unlockedScenePoints = new HashMap<>(); this.sceneState = SceneLoadState.NONE; this.attackResults = new LinkedBlockingQueue<>(); @@ -233,7 +240,7 @@ public class Player { this.rewardedLevels = new HashSet<>(); this.moonCardGetTimes = new HashSet<>(); this.codex = new PlayerCodex(this); - this.openStateManager = new PlayerOpenStateManager(this); + this.progressManager = new PlayerProgressManager(this); this.shopLimit = new ArrayList<>(); this.expeditionInfo = new HashMap<>(); this.messageHandler = null; @@ -243,6 +250,7 @@ public class Player { this.energyManager = new EnergyManager(this); this.resinManager = new ResinManager(this); this.forgingManager = new ForgingManager(this); + this.progressManager = new PlayerProgressManager(this); this.furnitureManager = new FurnitureManager(this); this.cookingManager = new CookingManager(this); } @@ -276,6 +284,7 @@ public class Player { this.resinManager = new ResinManager(this); this.deforestationManager = new DeforestationManager(this); this.forgingManager = new ForgingManager(this); + this.progressManager = new PlayerProgressManager(this); this.furnitureManager = new FurnitureManager(this); this.cookingManager = new CookingManager(this); } @@ -436,7 +445,7 @@ public class Player { this.updateProfile(); // Handle open state unlocks from level-up. - this.getOpenStateManager().tryUnlockOpenStates(); + this.getProgressManager().tryUnlockOpenStates(); return true; } @@ -1191,13 +1200,6 @@ public class Player { return mapMarks; } - public PlayerOpenStateManager getOpenStateManager() { - if (this.openStateManager == null) { - this.openStateManager = new PlayerOpenStateManager(this); - } - return openStateManager; - } - public synchronized void onTick() { // Check ping if (this.getLastPingTime() > System.currentTimeMillis() + 60000) { @@ -1297,7 +1299,7 @@ public class Player { @PostLoad private void onLoad() { this.getCodex().setPlayer(this); - this.getOpenStateManager().setPlayer(this); + this.getProgressManager().setPlayer(this); this.getTeamManager().setPlayer(this); } @@ -1356,16 +1358,17 @@ public class Player { // Execute daily reset logic if this is a new day. this.doDailyReset(); - // Rewind active quests, and put the player to a rewind position it finds (if any) of an active quest getQuestManager().onLogin(); - // Packets session.send(new PacketPlayerDataNotify(this)); // Player data session.send(new PacketStoreWeightLimitNotify()); session.send(new PacketPlayerStoreNotify(this)); session.send(new PacketAvatarDataNotify(this)); + + this.getProgressManager().onPlayerLogin(); + session.send(new PacketFinishedParentQuestNotify(this)); session.send(new PacketBattlePassAllDataNotify(this)); session.send(new PacketQuestListNotify(this)); @@ -1376,7 +1379,6 @@ public class Player { this.forgingManager.sendForgeDataNotify(); this.resinManager.onPlayerLogin(); this.cookingManager.sendCookDataNofity(); - this.getOpenStateManager().onPlayerLogin(); 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. @@ -1513,10 +1515,17 @@ public class Player { int min = this.getPropertyMin(prop); int max = this.getPropertyMax(prop); if (min <= value && value <= max) { + int currentValue = this.properties.get(prop.getId()); this.properties.put(prop.getId(), value); if (sendPacket) { // Update player with packet this.sendPacket(new PacketPlayerPropNotify(this, prop)); + this.sendPacket(new PacketPlayerPropChangeNotify(this, prop, value - currentValue)); + + // Make the Adventure EXP pop-up show on screen. + if (prop == PlayerProperty.PROP_PLAYER_EXP) { + this.sendPacket(new PacketPlayerPropChangeReasonNotify(this, prop, currentValue, value, PropChangeReason.PROP_CHANGE_REASON_PLAYER_ADD_EXP)); + } } return true; } else { diff --git a/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java b/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java deleted file mode 100644 index ddd907016..000000000 --- a/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java +++ /dev/null @@ -1,157 +0,0 @@ -package emu.grasscutter.game.player; - -import dev.morphia.annotations.Entity; -import emu.grasscutter.data.GameData; -import emu.grasscutter.data.excels.OpenStateData; -import emu.grasscutter.data.excels.OpenStateData.OpenStateCondType; -import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode; -import emu.grasscutter.server.packet.send.PacketOpenStateChangeNotify; -import emu.grasscutter.server.packet.send.PacketOpenStateUpdateNotify; -import emu.grasscutter.server.packet.send.PacketSetOpenStateRsp; - -import java.util.*; -import java.util.stream.Collectors; - -@Entity -public class PlayerOpenStateManager extends BasePlayerDataManager { - // Set of open states that are never unlocked, whether they fulfill the conditions or not. - public static final Set BLACKLIST_OPEN_STATES = Set.of( - 48 // blacklist OPEN_STATE_LIMIT_REGION_GLOBAL to make Meledy happy. =D Remove this as soon as quest unlocks are fully implemented. - ); - - // Set of open states that are set per default for all accounts. Can be overwritten by an entry in `map`. - public static final Set DEFAULT_OPEN_STATES = GameData.getOpenStateList().stream() - .filter(s -> - s.isDefaultState() // Actual default-opened states. - || (s.getCond().stream().filter(c -> c.getCondType() == OpenStateCondType.OPEN_STATE_COND_PLAYER_LEVEL).count() == 0) // All states whose unlock we don't handle correctly yet. - || s.getId() == 1 // Always unlock OPEN_STATE_PAIMON, otherwise the player will not have a working chat. - ) - .filter(s -> !BLACKLIST_OPEN_STATES.contains(s.getId())) // Filter out states in the blacklist. - .map(s -> s.getId()) - .collect(Collectors.toSet()); - - // Map of all open states that this player has. - private Map map; - - public PlayerOpenStateManager(Player player) { - super(player); - } - - public synchronized Map getOpenStateMap() { - // If no map currently exists, we create one. - if (this.map == null) { - this.map = new HashMap<>(); - } - - return this.map; - } - - /********** - Direct getters and setters for open states. - **********/ - public int getOpenState(int openState) { - return getOpenStateMap().getOrDefault(openState, 0); - } - - private void setOpenState(int openState, int value, boolean sendNotify) { - int previousValue = this.getOpenStateMap().getOrDefault(openState, 0); - - if (value != previousValue) { - this.getOpenStateMap().put(openState, value); - - if (sendNotify) { - player.getSession().send(new PacketOpenStateChangeNotify(openState, value)); - } - } - } - private void setOpenState(int openState, int value) { - this.setOpenState(openState, value, true); - } - - /********** - Condition checking for setting open states. - **********/ - private boolean areConditionsMet(OpenStateData openState) { - // Check all conditions and test if at least one of them is violated. - for (var condition : openState.getCond()) { - // For level conditions, check if the player has reached the necessary level. - if (condition.getCondType() == OpenStateCondType.OPEN_STATE_COND_PLAYER_LEVEL) { - if (this.player.getLevel() < condition.getParam()) { - return false; - } - } - else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_COND_QUEST) { - // ToDo: Implement. - } - else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_COND_PARENT_QUEST) { - // ToDo: Implement. - } - else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_OFFERING_LEVEL) { - // ToDo: Implement. - } - else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_CITY_REPUTATION_LEVEL) { - // ToDo: Implement. - } - } - - // Done. If we didn't find any violations, all conditions are met. - return true; - } - - /********** - Setting open states from the client (via `SetOpenStateReq`). - **********/ - public void setOpenStateFromClient(int openState, int value) { - // Get the data for this open state. - OpenStateData data = GameData.getOpenStateDataMap().get(openState); - if (data == null) { - this.player.sendPacket(new PacketSetOpenStateRsp(Retcode.RET_FAIL)); - return; - } - - // Make sure that this is an open state that the client is allowed to set, - // and that it doesn't have any further conditions attached. - if (!data.isAllowClientOpen() || !this.areConditionsMet(data)) { - this.player.sendPacket(new PacketSetOpenStateRsp(Retcode.RET_FAIL)); - return; - } - - // Set. - this.setOpenState(openState, value); - this.player.sendPacket(new PacketSetOpenStateRsp(openState, value)); - } - - /********** - Handler for player login. - **********/ - public void onPlayerLogin() { - // Try unlocking open states on player login. This handles accounts where unlock conditions were - // already met before certain open state unlocks were implemented. - this.tryUnlockOpenStates(false); - - // Send notify to the client. - player.getSession().send(new PacketOpenStateUpdateNotify(this)); - } - - /********** - Triggered unlocking of open states (unlock states whose conditions have been met.) - **********/ - public void tryUnlockOpenStates(boolean sendNotify) { - // Get list of open states that are not yet unlocked. - var lockedStates = GameData.getOpenStateList().stream().filter(s -> this.getOpenStateMap().getOrDefault(s, 0) == 0).toList(); - - // Try unlocking all of them. - for (var state : lockedStates) { - // To auto-unlock a state, it has to meet three conditions: - // * it can not be a state that is unlocked by the client, - // * it has to meet all its unlock conditions, and - // * it can not be in the blacklist. - if (!state.isAllowClientOpen() && this.areConditionsMet(state) && !BLACKLIST_OPEN_STATES.contains(state.getId())) { - this.setOpenState(state.getId(), 1, sendNotify); - } - } - } - public void tryUnlockOpenStates() { - this.tryUnlockOpenStates(true); - } -} diff --git a/src/main/java/emu/grasscutter/game/player/PlayerProgressManager.java b/src/main/java/emu/grasscutter/game/player/PlayerProgressManager.java new file mode 100644 index 000000000..9b6dbce56 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/player/PlayerProgressManager.java @@ -0,0 +1,257 @@ +package emu.grasscutter.game.player; + +import dev.morphia.annotations.Entity; +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.binout.ScenePointEntry; +import emu.grasscutter.data.excels.OpenStateData; +import emu.grasscutter.data.excels.OpenStateData.OpenStateCondType; +import emu.grasscutter.game.inventory.GameItem; +import emu.grasscutter.game.props.ActionReason; +import emu.grasscutter.game.props.PlayerProperty; +import emu.grasscutter.game.quest.enums.QuestState; +import emu.grasscutter.game.quest.enums.QuestTrigger; +import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason; +import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode; +import emu.grasscutter.server.packet.send.PacketOpenStateChangeNotify; +import emu.grasscutter.server.packet.send.PacketOpenStateUpdateNotify; +import emu.grasscutter.server.packet.send.PacketSceneAreaUnlockNotify; +import emu.grasscutter.server.packet.send.PacketScenePointUnlockNotify; +import emu.grasscutter.server.packet.send.PacketSetOpenStateRsp; +import emu.grasscutter.server.packet.send.PacketUnlockTransPointRsp; + +import java.util.*; +import java.util.stream.Collectors; + +// @Entity +public class PlayerProgressManager extends BasePlayerDataManager { + public PlayerProgressManager(Player player) { + super(player); + } + + /********** + Handler for player login. + **********/ + public void onPlayerLogin() { + // Try unlocking open states on player login. This handles accounts where unlock conditions were + // already met before certain open state unlocks were implemented. + this.tryUnlockOpenStates(false); + + // Send notify to the client. + player.getSession().send(new PacketOpenStateUpdateNotify(this.player)); + + // Add statue quests if necessary. + this.addStatueQuestsOnLogin(); + + // Auto-unlock the first statue and map area, until we figure out how to make + // that particular statue interactable. + if (!this.player.getUnlockedScenePoints().containsKey(3)) { + this.player.getUnlockedScenePoints().put(3, new ArrayList<>()); + } + if (!this.player.getUnlockedScenePoints().get(3).contains(7)) { + this.player.getUnlockedScenePoints().get(3).add(7); + } + + if (!this.player.getUnlockedSceneAreas().containsKey(3)) { + this.player.getUnlockedSceneAreas().put(3, new ArrayList<>()); + } + if (!this.player.getUnlockedSceneAreas().get(3).contains(1)) { + this.player.getUnlockedSceneAreas().get(3).add(1); + } + } + + /****************************************************************************************************************** + ****************************************************************************************************************** + * OPEN STATES + ****************************************************************************************************************** + *****************************************************************************************************************/ + + // Set of open states that are never unlocked, whether they fulfill the conditions or not. + public static final Set BLACKLIST_OPEN_STATES = Set.of( + 48 // blacklist OPEN_STATE_LIMIT_REGION_GLOBAL to make Meledy happy. =D Remove this as soon as quest unlocks are fully implemented. + ); + + // Set of open states that are set per default for all accounts. Can be overwritten by an entry in `map`. + public static final Set DEFAULT_OPEN_STATES = GameData.getOpenStateList().stream() + .filter(s -> + s.isDefaultState() // Actual default-opened states. + // All states whose unlock we don't handle correctly yet. + || (s.getCond().stream().filter(c -> c.getCondType() == OpenStateCondType.OPEN_STATE_COND_PLAYER_LEVEL).count() == 0) + // Always unlock OPEN_STATE_PAIMON, otherwise the player will not have a working chat. + || s.getId() == 1 + ) + .filter(s -> !BLACKLIST_OPEN_STATES.contains(s.getId())) // Filter out states in the blacklist. + .map(s -> s.getId()) + .collect(Collectors.toSet()); + + /********** + Direct getters and setters for open states. + **********/ + public int getOpenState(int openState) { + return this.player.getOpenStates().getOrDefault(openState, 0); + } + + private void setOpenState(int openState, int value, boolean sendNotify) { + int previousValue = this.player.getOpenStates().getOrDefault(openState, 0); + + if (value != previousValue) { + this.player.getOpenStates().put(openState, value); + + if (sendNotify) { + player.getSession().send(new PacketOpenStateChangeNotify(openState, value)); + } + } + } + private void setOpenState(int openState, int value) { + this.setOpenState(openState, value, true); + } + + /********** + Condition checking for setting open states. + **********/ + private boolean areConditionsMet(OpenStateData openState) { + // Check all conditions and test if at least one of them is violated. + for (var condition : openState.getCond()) { + // For level conditions, check if the player has reached the necessary level. + if (condition.getCondType() == OpenStateCondType.OPEN_STATE_COND_PLAYER_LEVEL) { + if (this.player.getLevel() < condition.getParam()) { + return false; + } + } + else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_COND_QUEST) { + // ToDo: Implement. + } + else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_COND_PARENT_QUEST) { + // ToDo: Implement. + } + else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_OFFERING_LEVEL) { + // ToDo: Implement. + } + else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_CITY_REPUTATION_LEVEL) { + // ToDo: Implement. + } + } + + // Done. If we didn't find any violations, all conditions are met. + return true; + } + + /********** + Setting open states from the client (via `SetOpenStateReq`). + **********/ + public void setOpenStateFromClient(int openState, int value) { + // Get the data for this open state. + OpenStateData data = GameData.getOpenStateDataMap().get(openState); + if (data == null) { + this.player.sendPacket(new PacketSetOpenStateRsp(Retcode.RET_FAIL)); + return; + } + + // Make sure that this is an open state that the client is allowed to set, + // and that it doesn't have any further conditions attached. + if (!data.isAllowClientOpen() || !this.areConditionsMet(data)) { + this.player.sendPacket(new PacketSetOpenStateRsp(Retcode.RET_FAIL)); + return; + } + + // Set. + this.setOpenState(openState, value); + this.player.sendPacket(new PacketSetOpenStateRsp(openState, value)); + } + + /********** + Triggered unlocking of open states (unlock states whose conditions have been met.) + **********/ + public void tryUnlockOpenStates(boolean sendNotify) { + // Get list of open states that are not yet unlocked. + var lockedStates = GameData.getOpenStateList().stream().filter(s -> this.player.getOpenStates().getOrDefault(s, 0) == 0).toList(); + + // Try unlocking all of them. + for (var state : lockedStates) { + // To auto-unlock a state, it has to meet three conditions: + // * it can not be a state that is unlocked by the client, + // * it has to meet all its unlock conditions, and + // * it can not be in the blacklist. + if (!state.isAllowClientOpen() && this.areConditionsMet(state) && !BLACKLIST_OPEN_STATES.contains(state.getId())) { + this.setOpenState(state.getId(), 1, sendNotify); + } + } + } + public void tryUnlockOpenStates() { + this.tryUnlockOpenStates(true); + } + + /****************************************************************************************************************** + ****************************************************************************************************************** + * MAP AREAS AND POINTS + ****************************************************************************************************************** + *****************************************************************************************************************/ + private void addStatueQuestsOnLogin() { + // Get all currently existing subquests for the "unlock all statues" main quest. + var statueMainQuest = GameData.getMainQuestDataMap().get(303); + var statueSubQuests = statueMainQuest.getSubQuests(); + + // Add the main statue quest if it isn't active yet. + var statueGameMainQuest = this.player.getQuestManager().getMainQuestById(303); + if (statueGameMainQuest == null) { + this.player.getQuestManager().addQuest(30302); + statueGameMainQuest = this.player.getQuestManager().getMainQuestById(303); + } + + // Set all subquests to active if they aren't already finished. + for (var subData : statueSubQuests) { + var subGameQuest = statueGameMainQuest.getChildQuestById(subData.getSubId()); + if (subGameQuest != null && subGameQuest.getState() == QuestState.QUEST_STATE_UNSTARTED) { + this.player.getQuestManager().addQuest(subData.getSubId()); + } + } + } + + public void unlockTransPoint(int sceneId, int pointId, boolean isStatue) { + // Check whether the unlocked point exists and whether it is still locked. + String key = sceneId + "_" + pointId; + ScenePointEntry scenePointEntry = GameData.getScenePointEntries().get(key); + + if (scenePointEntry == null || this.player.getUnlockedScenePoints().getOrDefault(sceneId, List.of()).contains(pointId)) { + this.player.sendPacket(new PacketUnlockTransPointRsp(Retcode.RET_FAIL)); + return; + } + + // Add the point to the list of unlocked points for its scene. + if (!this.player.getUnlockedScenePoints().containsKey(sceneId)) { + this.player.getUnlockedScenePoints().put(sceneId, new ArrayList<>()); + } + this.player.getUnlockedScenePoints().get(sceneId).add(pointId); + + // Give primogems and Adventure EXP for unlocking. + var primos = new GameItem(GameData.getItemDataMap().get(201), 5); + this.player.getInventory().addItem(primos, ActionReason.UnlockPointReward); + + var exp = new GameItem(GameData.getItemDataMap().get(102), isStatue ? 50 : 10); + this.player.getInventory().addItem(exp, ActionReason.UnlockPointReward); + + // this.player.sendPacket(new PacketPlayerPropChangeReasonNotify(this.player.getProperty(PlayerProperty.PROP_PLAYER_EXP), PlayerProperty.PROP_PLAYER_EXP, PropChangeReason.PROP_CHANGE_REASON_PLAYER_ADD_EXP)); + + // Fire quest trigger for trans point unlock. + this.player.getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_UNLOCK_TRANS_POINT, sceneId, pointId); + + // Send packet. + this.player.sendPacket(new PacketScenePointUnlockNotify(sceneId, pointId)); + this.player.sendPacket(new PacketUnlockTransPointRsp(Retcode.RET_SUCC)); + } + + public void unlockSceneArea(int sceneId, int areaId) { + // Check whether this area is already unlocked. + if (this.player.getUnlockedSceneAreas().getOrDefault(sceneId, List.of()).contains(areaId)) { + return; + } + + // Add the area to the list of unlocked areas in its scene. + if (!this.player.getUnlockedSceneAreas().containsKey(sceneId)) { + this.player.getUnlockedSceneAreas().put(sceneId, new ArrayList<>()); + } + this.player.getUnlockedSceneAreas().get(sceneId).add(areaId); + + // Send packet. + this.player.sendPacket(new PacketSceneAreaUnlockNotify(sceneId, areaId)); + } +} diff --git a/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java b/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java index 000dad6db..9a3963a49 100644 --- a/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java +++ b/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java @@ -316,7 +316,7 @@ public class GameMainQuest { List finishCond = subQuestWithCond.getQuestData().getFinishCond(); int[] finish = new int[finishCond.size()]; - for (int i = 0; i < subQuestWithCond.getQuestData().getFinishCond().size(); i++) { + for (int i = 0; i < finishCond.size(); i++) { QuestData.QuestCondition condition = finishCond.get(i); boolean result = this.getOwner().getServer().getQuestSystem().triggerContent(subQuestWithCond, condition, paramStr, params); finish[i] = result ? 1 : 0; diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteTalk.java b/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteTalk.java index c87640d8c..36072d22a 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteTalk.java +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteTalk.java @@ -13,9 +13,15 @@ public class ContentCompleteTalk extends QuestBaseHandler { @Override public boolean execute(GameQuest quest, QuestCondition condition, String paramStr, int... params) { - GameMainQuest checkMainQuest = quest.getOwner().getQuestManager().getMainQuestById(params[0]/100); - if (checkMainQuest == null) {return false;} - MainQuestData.TalkData talkData = checkMainQuest.getTalks().get(Integer.valueOf(params[0])); - return talkData == null || condition.getParamStr().contains(paramStr) || checkMainQuest.getChildQuestById(params[0]) != null; + GameMainQuest checkMainQuest = quest.getOwner().getQuestManager().getMainQuestById(params[0] / 100); + if (checkMainQuest == null) { + return false; + } + + MainQuestData.TalkData talkData = checkMainQuest.getTalks().get(condition.getParam()[0]); + return talkData != null; + + // This expression makes zero sense. + // return talkData == null || condition.getParamStr().contains(paramStr) || checkMainQuest.getChildQuestById(params[0]) != null; } } diff --git a/src/main/java/emu/grasscutter/game/quest/exec/ExecUnlockArea.java b/src/main/java/emu/grasscutter/game/quest/exec/ExecUnlockArea.java new file mode 100644 index 000000000..cc958bba9 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/exec/ExecUnlockArea.java @@ -0,0 +1,23 @@ +package emu.grasscutter.game.quest.exec; + +import emu.grasscutter.data.excels.QuestData; +import emu.grasscutter.game.quest.GameQuest; +import emu.grasscutter.game.quest.QuestValue; +import emu.grasscutter.game.quest.enums.QuestTrigger; +import emu.grasscutter.game.quest.handlers.QuestExecHandler; + +import java.util.Arrays; + +@QuestValue(QuestTrigger.QUEST_EXEC_UNLOCK_AREA) +public class ExecUnlockArea extends QuestExecHandler { + @Override + public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) { + // Unlock the trans point for the player. + int sceneId = Integer.parseInt(paramStr[0]); + int areaId = Integer.parseInt(paramStr[1]); + quest.getOwner().getProgressManager().unlockSceneArea(sceneId, areaId); + + // Done. + return true; + } +} diff --git a/src/main/java/emu/grasscutter/game/quest/exec/ExecUnlockPoint.java b/src/main/java/emu/grasscutter/game/quest/exec/ExecUnlockPoint.java new file mode 100644 index 000000000..9e0aec8d2 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/exec/ExecUnlockPoint.java @@ -0,0 +1,23 @@ +package emu.grasscutter.game.quest.exec; + +import emu.grasscutter.data.excels.QuestData; +import emu.grasscutter.game.quest.GameQuest; +import emu.grasscutter.game.quest.QuestValue; +import emu.grasscutter.game.quest.enums.QuestTrigger; +import emu.grasscutter.game.quest.handlers.QuestExecHandler; + +@QuestValue(QuestTrigger.QUEST_EXEC_UNLOCK_POINT) +public class ExecUnlockPoint extends QuestExecHandler { + @Override + public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) { + // Unlock the trans point for the player. + int sceneId = Integer.parseInt(paramStr[0]); + int pointId = Integer.parseInt(paramStr[1]); + boolean isStatue = quest.getMainQuestId() == 303; + + quest.getOwner().getProgressManager().unlockTransPoint(sceneId, pointId, isStatue); + + // Done. + return true; + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetSceneAreaReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetSceneAreaReq.java index ac890623e..fa920d6a5 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetSceneAreaReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetSceneAreaReq.java @@ -14,7 +14,7 @@ public class HandlerGetSceneAreaReq extends PacketHandler { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { GetSceneAreaReq req = GetSceneAreaReq.parseFrom(payload); - session.send(new PacketGetSceneAreaRsp(req.getSceneId())); + session.send(new PacketGetSceneAreaRsp(session.getPlayer(), req.getSceneId())); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetScenePointReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetScenePointReq.java index f4352ba1c..20e8a27f2 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetScenePointReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetScenePointReq.java @@ -14,7 +14,7 @@ public class HandlerGetScenePointReq extends PacketHandler { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { GetScenePointReq req = GetScenePointReq.parseFrom(payload); - session.send(new PacketGetScenePointRsp(req.getSceneId())); + session.send(new PacketGetScenePointRsp(session.getPlayer(), req.getSceneId())); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerNpcTalkReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerNpcTalkReq.java index 933227d86..aef3187b7 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerNpcTalkReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerNpcTalkReq.java @@ -2,6 +2,7 @@ package emu.grasscutter.server.packet.recv; import emu.grasscutter.data.GameData; import emu.grasscutter.data.binout.MainQuestData; +import emu.grasscutter.data.binout.MainQuestData.TalkData; import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.quest.GameMainQuest; import emu.grasscutter.game.quest.enums.ParentQuestState; @@ -15,28 +16,40 @@ import emu.grasscutter.server.packet.send.PacketNpcTalkRsp; @Opcodes(PacketOpcodes.NpcTalkReq) public class HandlerNpcTalkReq extends PacketHandler { + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + NpcTalkReq req = NpcTalkReq.parseFrom(payload); - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - NpcTalkReq req = NpcTalkReq.parseFrom(payload); //Check if mainQuest exists - int talkId = req.getTalkId(); //remove last 2 digits to get a mainQuestId + int talkId = req.getTalkId(); int mainQuestId = talkId/100; MainQuestData mainQuestData = GameData.getMainQuestDataMap().get(mainQuestId); + if(mainQuestData != null) { - MainQuestData.TalkData talk = mainQuestData.getTalks().stream().filter(p -> p.getId() == talkId).toList().get(0); - if(talk != null) { - //talk is finished - session.getPlayer().getQuestManager().getMainQuestById(mainQuestId).getTalks().put(Integer.valueOf(talkId),talk); - session.getPlayer().getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_COMPLETE_ANY_TALK,String.valueOf(req.getTalkId()), 0, 0); - // Why are there 2 quest triggers that do the same thing... - session.getPlayer().getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_COMPLETE_TALK, req.getTalkId(),0); - session.getPlayer().getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_FINISH_PLOT, req.getTalkId(),0); + // This talk is associated with a quest. Handle it. + // If the quest has no talk data defined on it, create one. + TalkData talkForQuest = new TalkData(talkId, ""); + if (mainQuestData.getTalks() != null) { + var talks = mainQuestData.getTalks().stream().filter(p -> p.getId() == talkId).toList(); + + if (talks.size() > 0) { + talkForQuest = talks.get(0); } } + + // Add to the list of done talks for this quest. + var mainQuest = session.getPlayer().getQuestManager().getMainQuestById(mainQuestId); + if (mainQuest != null) { + session.getPlayer().getQuestManager().getMainQuestById(mainQuestId).getTalks().put(talkId, talkForQuest); + } + + // Fire quest triggers. + session.getPlayer().getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_COMPLETE_ANY_TALK, String.valueOf(req.getTalkId()), 0, 0); + session.getPlayer().getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_COMPLETE_TALK, req.getTalkId(), 0); + session.getPlayer().getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_FINISH_PLOT, req.getTalkId(), 0); + } - session.send(new PacketNpcTalkRsp(req.getNpcEntityId(), req.getTalkId(), req.getEntityId())); - } - + session.send(new PacketNpcTalkRsp(req.getNpcEntityId(), req.getTalkId(), req.getEntityId())); + } } \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetOpenStateReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetOpenStateReq.java index 1e5beef1d..6aaefccc2 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetOpenStateReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetOpenStateReq.java @@ -14,6 +14,6 @@ public class HandlerSetOpenStateReq extends PacketHandler { int openState = req.getKey(); int value = req.getValue(); - session.getPlayer().getOpenStateManager().setOpenStateFromClient(openState, value); + session.getPlayer().getProgressManager().setOpenStateFromClient(openState, value); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnlockTransPointReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnlockTransPointReq.java new file mode 100644 index 000000000..4a7336d4d --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnlockTransPointReq.java @@ -0,0 +1,16 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.UnlockTransPointReqOuterClass.UnlockTransPointReq; +import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.server.game.GameSession; + +@Opcodes(PacketOpcodes.UnlockTransPointReq) +public class HandlerUnlockTransPointReq extends PacketHandler { + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + UnlockTransPointReq req = UnlockTransPointReq.parseFrom(payload); + session.getPlayer().getProgressManager().unlockTransPoint(req.getSceneId(), req.getPointId(), false); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetSceneAreaRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetSceneAreaRsp.java index b4d74741d..77750bbb9 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetSceneAreaRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetSceneAreaRsp.java @@ -1,8 +1,8 @@ package emu.grasscutter.server.packet.send; -import java.util.Arrays; -import java.util.stream.Collectors; +import java.util.List; +import emu.grasscutter.game.player.Player; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.CityInfoOuterClass.CityInfo; @@ -10,14 +10,14 @@ import emu.grasscutter.net.proto.GetSceneAreaRspOuterClass.GetSceneAreaRsp; public class PacketGetSceneAreaRsp extends BasePacket { - public PacketGetSceneAreaRsp(int sceneId) { + public PacketGetSceneAreaRsp(Player player, int sceneId) { super(PacketOpcodes.GetSceneAreaRsp); this.buildHeader(0); GetSceneAreaRsp p = GetSceneAreaRsp.newBuilder() .setSceneId(sceneId) - .addAllAreaIdList(Arrays.stream(new int[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,17,18,19,100,101,102,103,200,210,300,400,401,402,403}).boxed().collect(Collectors.toList())) + .addAllAreaIdList(player.getUnlockedSceneAreas().getOrDefault(sceneId, List.of())) .addCityInfoList(CityInfo.newBuilder().setCityId(1).setLevel(1).build()) .addCityInfoList(CityInfo.newBuilder().setCityId(2).setLevel(1).build()) .addCityInfoList(CityInfo.newBuilder().setCityId(3).setLevel(1).build()) diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetScenePointRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetScenePointRsp.java index b4c001831..6f23f65c9 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetScenePointRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetScenePointRsp.java @@ -1,13 +1,16 @@ package emu.grasscutter.server.packet.send; +import java.util.List; + import emu.grasscutter.data.GameData; +import emu.grasscutter.game.player.Player; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.GetScenePointRspOuterClass.GetScenePointRsp; public class PacketGetScenePointRsp extends BasePacket { - public PacketGetScenePointRsp(int sceneId) { + public PacketGetScenePointRsp(Player player, int sceneId) { super(PacketOpcodes.GetScenePointRsp); GetScenePointRsp.Builder p = GetScenePointRsp.newBuilder() @@ -18,7 +21,7 @@ public class PacketGetScenePointRsp extends BasePacket { p.addUnlockedPointList(i); } } else { - p.addAllUnlockedPointList(GameData.getScenePointIdList()); + p.addAllUnlockedPointList(player.getUnlockedScenePoints().getOrDefault(sceneId, List.of())); } for (int i = 1; i < 9; i++) { diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateUpdateNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateUpdateNotify.java index 9a01c090f..12d1bcac7 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateUpdateNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateUpdateNotify.java @@ -2,7 +2,8 @@ package emu.grasscutter.server.packet.send; import emu.grasscutter.data.GameData; import emu.grasscutter.data.excels.OpenStateData; -import emu.grasscutter.game.player.PlayerOpenStateManager; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.player.PlayerProgressManager; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.OpenStateUpdateNotifyOuterClass.OpenStateUpdateNotify; @@ -13,18 +14,18 @@ import emu.grasscutter.net.proto.OpenStateUpdateNotifyOuterClass.OpenStateUpdate */ public class PacketOpenStateUpdateNotify extends BasePacket { - public PacketOpenStateUpdateNotify(PlayerOpenStateManager manager) { + public PacketOpenStateUpdateNotify(Player player) { super(PacketOpcodes.OpenStateUpdateNotify); OpenStateUpdateNotify.Builder proto = OpenStateUpdateNotify.newBuilder(); for (OpenStateData state : GameData.getOpenStateList()) { // If the player has an open state stored in their map, then it would always override any default value - if (manager.getOpenStateMap().containsKey(state.getId())) { - proto.putOpenStateMap(state.getId(), manager.getOpenState(state.getId())); + if (player.getOpenStates().containsKey(state.getId())) { + proto.putOpenStateMap(state.getId(), player.getProgressManager().getOpenState(state.getId())); } // Otherwise, add the state if it is contained in the set of default open states. - else if (PlayerOpenStateManager.DEFAULT_OPEN_STATES.contains(state.getId())) { + else if (PlayerProgressManager.DEFAULT_OPEN_STATES.contains(state.getId())) { proto.putOpenStateMap(state.getId(), 1); } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerPropChangeNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerPropChangeNotify.java new file mode 100644 index 000000000..53810c74b --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerPropChangeNotify.java @@ -0,0 +1,24 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.PlayerProperty; +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.PlayerPropChangeNotifyOuterClass.PlayerPropChangeNotify; +import emu.grasscutter.utils.ProtoHelper; + +public class PacketPlayerPropChangeNotify extends BasePacket { + + public PacketPlayerPropChangeNotify(Player player, PlayerProperty prop, int delta) { + super(PacketOpcodes.PlayerPropChangeNotify); + + this.buildHeader(0); + + PlayerPropChangeNotify proto = PlayerPropChangeNotify.newBuilder() + .setPropType(prop.getId()) + .setPropDelta(delta) + .build(); + + this.setData(proto); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerPropChangeReasonNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerPropChangeReasonNotify.java new file mode 100644 index 000000000..c34ada1de --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerPropChangeReasonNotify.java @@ -0,0 +1,26 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.PlayerProperty; +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.PlayerPropChangeReasonNotifyOuterClass.PlayerPropChangeReasonNotify; +import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason; + +public class PacketPlayerPropChangeReasonNotify extends BasePacket { + + public PacketPlayerPropChangeReasonNotify(Player player, PlayerProperty prop, int oldValue, int newValue, PropChangeReason changeReason) { + super(PacketOpcodes.PlayerPropChangeReasonNotify); + + this.buildHeader(0); + + PlayerPropChangeReasonNotify proto = PlayerPropChangeReasonNotify.newBuilder() + .setPropType(prop.getId()) + .setReason(changeReason) + .setOldValue(oldValue) + .setCurValue(newValue) + .build(); + + this.setData(proto); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketSceneAreaUnlockNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketSceneAreaUnlockNotify.java new file mode 100644 index 000000000..2623aa957 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketSceneAreaUnlockNotify.java @@ -0,0 +1,29 @@ +package emu.grasscutter.server.packet.send; + +import java.util.List; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.SceneAreaUnlockNotifyOuterClass.SceneAreaUnlockNotify; + +public class PacketSceneAreaUnlockNotify extends BasePacket { + public PacketSceneAreaUnlockNotify(int sceneId, int areaId) { + super(PacketOpcodes.SceneAreaUnlockNotify); + + SceneAreaUnlockNotify.Builder p = SceneAreaUnlockNotify.newBuilder() + .setSceneId(sceneId) + .addAreaList(areaId); + + this.setData(p); + } + + public PacketSceneAreaUnlockNotify(int sceneId, List areaIds) { + super(PacketOpcodes.SceneAreaUnlockNotify); + + SceneAreaUnlockNotify.Builder p = SceneAreaUnlockNotify.newBuilder() + .setSceneId(sceneId) + .addAllAreaList(areaIds); + + this.setData(p); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketScenePointUnlockNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketScenePointUnlockNotify.java new file mode 100644 index 000000000..86dcb730c --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketScenePointUnlockNotify.java @@ -0,0 +1,29 @@ +package emu.grasscutter.server.packet.send; + +import java.util.List; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.ScenePointUnlockNotifyOuterClass.ScenePointUnlockNotify; + +public class PacketScenePointUnlockNotify extends BasePacket { + public PacketScenePointUnlockNotify(int sceneId, int pointId) { + super(PacketOpcodes.ScenePointUnlockNotify); + + ScenePointUnlockNotify.Builder p = ScenePointUnlockNotify.newBuilder() + .setSceneId(sceneId) + .addPointList(pointId); + + this.setData(p); + } + + public PacketScenePointUnlockNotify(int sceneId, List pointIds) { + super(PacketOpcodes.ScenePointUnlockNotify); + + ScenePointUnlockNotify.Builder p = ScenePointUnlockNotify.newBuilder() + .setSceneId(sceneId) + .addAllPointList(pointIds); + + this.setData(p); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketUnlockTransPointRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketUnlockTransPointRsp.java new file mode 100644 index 000000000..fe49f92a4 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketUnlockTransPointRsp.java @@ -0,0 +1,19 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.game.avatar.Avatar; +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode; +import emu.grasscutter.net.proto.UnlockTransPointRspOuterClass.UnlockTransPointRsp; + +public class PacketUnlockTransPointRsp extends BasePacket { + public PacketUnlockTransPointRsp(Retcode retcode) { + super(PacketOpcodes.UnlockTransPointRsp); + + UnlockTransPointRsp proto = UnlockTransPointRsp.newBuilder() + .setRetcode(retcode.getNumber()) + .build(); + + this.setData(proto); + } +}