From b82567d9d98c9a6374ef7f1f090372ecaf7acb60 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Mon, 31 Jul 2023 15:42:52 -0400 Subject: [PATCH 1/7] Attempt to implement item giving to NPCs (untested) --- .../java/emu/grasscutter/data/GameData.java | 61 +++++++----------- .../data/excels/giving/GivingData.java | 42 +++++++++++++ .../data/excels/giving/GivingGroupData.java | 21 +++++++ .../grasscutter/game/inventory/BagTab.java | 55 ++++++++++++++++ .../grasscutter/game/inventory/Inventory.java | 62 +++++++++++++++++- .../emu/grasscutter/game/player/Player.java | 2 +- .../grasscutter/game/quest/QuestManager.java | 9 ++- .../game/quest/enums/QuestContent.java | 2 +- .../game/quest/enums/QuestExec.java | 4 +- .../game/quest/exec/ExecActiveItemGiving.java | 26 ++++++++ .../quest/exec/ExecDeactivateItemGiving.java | 26 ++++++++ .../packet/recv/HandlerItemGivingReq.java | 63 +++++++++++++++++++ .../packet/send/PacketItemGivingRsp.java | 30 +++++++++ 13 files changed, 354 insertions(+), 49 deletions(-) create mode 100644 src/main/java/emu/grasscutter/data/excels/giving/GivingData.java create mode 100644 src/main/java/emu/grasscutter/data/excels/giving/GivingGroupData.java create mode 100644 src/main/java/emu/grasscutter/game/inventory/BagTab.java create mode 100644 src/main/java/emu/grasscutter/game/quest/exec/ExecActiveItemGiving.java create mode 100644 src/main/java/emu/grasscutter/game/quest/exec/ExecDeactivateItemGiving.java create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerItemGivingReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketItemGivingRsp.java diff --git a/src/main/java/emu/grasscutter/data/GameData.java b/src/main/java/emu/grasscutter/data/GameData.java index 3b99f1f26..a688bf753 100644 --- a/src/main/java/emu/grasscutter/data/GameData.java +++ b/src/main/java/emu/grasscutter/data/GameData.java @@ -4,58 +4,33 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.data.binout.*; import emu.grasscutter.data.binout.config.*; import emu.grasscutter.data.binout.routes.Route; -import emu.grasscutter.data.custom.TrialAvatarActivityCustomData; -import emu.grasscutter.data.custom.TrialAvatarCustomData; +import emu.grasscutter.data.custom.*; import emu.grasscutter.data.excels.*; -import emu.grasscutter.data.excels.achievement.AchievementData; -import emu.grasscutter.data.excels.achievement.AchievementGoalData; -import emu.grasscutter.data.excels.activity.ActivityCondExcelConfigData; -import emu.grasscutter.data.excels.activity.ActivityData; -import emu.grasscutter.data.excels.activity.ActivityShopData; -import emu.grasscutter.data.excels.activity.ActivityWatcherData; +import emu.grasscutter.data.excels.achievement.*; +import emu.grasscutter.data.excels.activity.*; import emu.grasscutter.data.excels.avatar.*; import emu.grasscutter.data.excels.codex.*; import emu.grasscutter.data.excels.dungeon.*; -import emu.grasscutter.data.excels.monster.MonsterCurveData; -import emu.grasscutter.data.excels.monster.MonsterData; -import emu.grasscutter.data.excels.monster.MonsterDescribeData; -import emu.grasscutter.data.excels.monster.MonsterSpecialNameData; -import emu.grasscutter.data.excels.quest.QuestData; -import emu.grasscutter.data.excels.quest.QuestGlobalVarData; -import emu.grasscutter.data.excels.reliquary.ReliquaryAffixData; -import emu.grasscutter.data.excels.reliquary.ReliquaryLevelData; -import emu.grasscutter.data.excels.reliquary.ReliquaryMainPropData; -import emu.grasscutter.data.excels.reliquary.ReliquarySetData; -import emu.grasscutter.data.excels.tower.TowerFloorData; -import emu.grasscutter.data.excels.tower.TowerLevelData; -import emu.grasscutter.data.excels.tower.TowerScheduleData; +import emu.grasscutter.data.excels.giving.*; +import emu.grasscutter.data.excels.monster.*; +import emu.grasscutter.data.excels.quest.*; +import emu.grasscutter.data.excels.reliquary.*; +import emu.grasscutter.data.excels.tower.*; import emu.grasscutter.data.excels.trial.*; -import emu.grasscutter.data.excels.weapon.WeaponCurveData; -import emu.grasscutter.data.excels.weapon.WeaponLevelData; -import emu.grasscutter.data.excels.weapon.WeaponPromoteData; -import emu.grasscutter.data.excels.world.WeatherData; -import emu.grasscutter.data.excels.world.WorldAreaData; -import emu.grasscutter.data.excels.world.WorldLevelData; -import emu.grasscutter.data.server.ActivityCondGroup; -import emu.grasscutter.data.server.DropSubfieldMapping; -import emu.grasscutter.data.server.DropTableExcelConfigData; -import emu.grasscutter.data.server.GadgetMapping; -import emu.grasscutter.data.server.MonsterMapping; -import emu.grasscutter.data.server.SubfieldMapping; +import emu.grasscutter.data.excels.weapon.*; +import emu.grasscutter.data.excels.world.*; +import emu.grasscutter.data.server.*; import emu.grasscutter.game.dungeons.DungeonDropEntry; -import emu.grasscutter.game.quest.QuestEncryptionKey; -import emu.grasscutter.game.quest.RewindData; -import emu.grasscutter.game.quest.TeleportData; +import emu.grasscutter.game.quest.*; import emu.grasscutter.game.quest.enums.QuestCond; import emu.grasscutter.game.world.GroupReplacementData; import emu.grasscutter.utils.Utils; import it.unimi.dsi.fastutil.ints.*; +import lombok.*; + +import javax.annotation.Nullable; import java.lang.reflect.Field; import java.util.*; -import javax.annotation.Nullable; -import lombok.Getter; -import lombok.Setter; -import lombok.val; @SuppressWarnings({"unused", "MismatchedQueryAndUpdateOfCollection"}) public final class GameData { @@ -266,6 +241,12 @@ public final class GameData { @Getter private static final Int2ObjectMap gatherDataMap = new Int2ObjectOpenHashMap<>(); + @Getter + private static final Int2ObjectMap givingDataMap = new Int2ObjectOpenHashMap<>(); + + @Getter + private static final Int2ObjectMap givingGroupDataMap = new Int2ObjectOpenHashMap<>(); + @Getter @Deprecated // This is to prevent people from using this map. This is for the resource loader // only! diff --git a/src/main/java/emu/grasscutter/data/excels/giving/GivingData.java b/src/main/java/emu/grasscutter/data/excels/giving/GivingData.java new file mode 100644 index 000000000..dab20c6d9 --- /dev/null +++ b/src/main/java/emu/grasscutter/data/excels/giving/GivingData.java @@ -0,0 +1,42 @@ +package emu.grasscutter.data.excels.giving; + +import com.google.gson.annotations.SerializedName; +import emu.grasscutter.data.*; +import emu.grasscutter.data.common.ItemParamData; +import emu.grasscutter.game.inventory.BagTab; +import lombok.*; + +import java.util.List; + +@Data +@EqualsAndHashCode(callSuper = false) +@ResourceType(name = "GivingExcelConfigData.json") +public final class GivingData extends GameResource { + @SerializedName(value = "id", alternate = "Id") + private int id; + private int talkId; + private int mistakeTalkId; + + private BagTab tab; + private GiveMethod givingMethod; + + private List exactItems; + private int exactFinishTalkId; + + private List givingGroupIds; + private int givingGroupCount; + + private boolean isRemoveItem; + private GiveType giveType; + + public enum GiveMethod { + @SerializedName("GIVING_METHOD_EXACT") EXACT, + @SerializedName("GIVING_METHOD_GROUP") GROUP, + @SerializedName("GIVING_METHOD_VAGUE_GROUP") GROUP_VAGUE + } + + public enum GiveType { + @SerializedName("GIVING_TYPE_QUEST") QUEST, + @SerializedName("GIVING_TYPE_GROUP") GROUP + } +} diff --git a/src/main/java/emu/grasscutter/data/excels/giving/GivingGroupData.java b/src/main/java/emu/grasscutter/data/excels/giving/GivingGroupData.java new file mode 100644 index 000000000..4c5bb7d1a --- /dev/null +++ b/src/main/java/emu/grasscutter/data/excels/giving/GivingGroupData.java @@ -0,0 +1,21 @@ +package emu.grasscutter.data.excels.giving; + +import com.google.gson.annotations.SerializedName; +import emu.grasscutter.data.*; +import lombok.*; + +import java.util.List; + +@Data +@EqualsAndHashCode(callSuper = false) +@ResourceType(name = "GivingGroupExcelConfigData.json") +public final class GivingGroupData extends GameResource { + @SerializedName(value = "id", alternate = "Id") + private int id; + + @SerializedName(value = "itemIds", alternate = "ItemIds") + private List itemIds; + + private int finishTalkId; + private int mistakeTalkId; +} diff --git a/src/main/java/emu/grasscutter/game/inventory/BagTab.java b/src/main/java/emu/grasscutter/game/inventory/BagTab.java new file mode 100644 index 000000000..a089912f7 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/inventory/BagTab.java @@ -0,0 +1,55 @@ +package emu.grasscutter.game.inventory; + +import it.unimi.dsi.fastutil.ints.*; +import lombok.*; + +import java.util.*; +import java.util.stream.Stream; + +@RequiredArgsConstructor +public enum BagTab { + TAB_NONE(0), + TAB_WEAPON(1), + TAB_EQUIP(2), + TAB_AVATAR(3), + TAB_FOOD(4), + TAB_MATERIAL(5), + TAB_QUEST(6), + TAB_CONSUME(7), + TAB_WIDGET(8), + TAB_HOMEWORLD(9); + + private static final Int2ObjectMap map = new Int2ObjectOpenHashMap<>(); + private static final Map stringMap = new HashMap<>(); + + static { + Stream.of(BagTab.values()) + .forEach( + entry -> { + map.put(entry.getValue(), entry); + stringMap.put(entry.name(), entry); + }); + } + + @Getter private final int value; + + /** + * Fetches the bag tab by its value. + * + * @param value The name of the bag tab. + * @return The bag tab. + */ + public static BagTab getTypeByValue(int value) { + return map.getOrDefault(value, TAB_NONE); + } + + /** + * Fetches the bag tab by its name. + * + * @param name The name of the bag tab. + * @return The bag tab. + */ + public static BagTab getTypeByName(String name) { + return stringMap.getOrDefault(name, TAB_NONE); + } +} diff --git a/src/main/java/emu/grasscutter/game/inventory/Inventory.java b/src/main/java/emu/grasscutter/game/inventory/Inventory.java index a06d55ed1..a49ee4081 100644 --- a/src/main/java/emu/grasscutter/game/inventory/Inventory.java +++ b/src/main/java/emu/grasscutter/game/inventory/Inventory.java @@ -1,7 +1,5 @@ package emu.grasscutter.game.inventory; -import static emu.grasscutter.config.Configuration.INVENTORY_LIMITS; - import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; import emu.grasscutter.data.common.ItemParamData; @@ -17,8 +15,11 @@ import emu.grasscutter.server.packet.send.*; import emu.grasscutter.utils.Utils; import it.unimi.dsi.fastutil.ints.*; import it.unimi.dsi.fastutil.longs.*; + import java.util.*; +import static emu.grasscutter.config.Configuration.INVENTORY_LIMITS; + public class Inventory extends BasePlayerManager implements Iterable { private final Long2ObjectMap store; private final Int2ObjectMap inventoryTypes; @@ -150,6 +151,52 @@ public class Inventory extends BasePlayerManager implements Iterable { getPlayer().sendPacket(new PacketStoreItemChangeNotify(changedItems)); } + /** + * Checks to see if the player has the item in their inventory. + * This will succeed if the player has at least the minimum count of the item. + * + * @param itemGuid The item id to check for. + * @param minCount The minimum count of the item to check for. + * @return True if the player has the item, false otherwise. + */ + public boolean hasItem(long itemGuid, int minCount) { + return hasItem(itemGuid, minCount, false); + } + + /** + * Checks to see if the player has the item in their inventory. + * + * @param itemGuid The item id to check for. + * @param count The count of the item to check for. + * @param enforce If true, the player must have the exact amount. + * If false, the player must have at least the amount. + * @return True if the player has the item, false otherwise. + */ + public boolean hasItem(long itemGuid, int count, boolean enforce) { + var item = this.getItemByGuid(itemGuid); + if (item == null) return false; + + return enforce ? + item.getCount() == count : + item.getCount() >= count; + } + + /** + * Checks to see if the player has the item in their inventory. + * This is exact. + * + * @param items A map of item game IDs to their count. + * @return True if the player has the items, false otherwise. + */ + public boolean hasAllItems(Map items) { + for (var item : items.entrySet()) { + if (!this.hasItem(item.getKey(), item.getValue(), true)) + return false; + } + + return true; + } + private void triggerAddItemEvents(GameItem result) { try { getPlayer() @@ -434,6 +481,17 @@ public class Inventory extends BasePlayerManager implements Iterable { } } + /** + * Performs a bulk delete of items. + * + * @param items A map of item game IDs to the amount of items to remove. + */ + public void removeItems(Map items) { + for (var entry : items.entrySet()) { + this.removeItem(entry.getKey(), entry.getValue()); + } + } + public boolean removeItem(long guid) { return removeItem(guid, 1); } diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 26e091bb2..075545985 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -159,7 +159,7 @@ public class Player implements PlayerHook, FieldFetch { @Getter private transient FriendsList friendsList; @Getter private transient MailHandler mailHandler; @Getter private transient AbilityManager abilityManager; - @Getter @Setter private transient QuestManager questManager; + @Getter private transient QuestManager questManager; @Getter private transient TowerManager towerManager; @Getter private transient SotSManager sotsManager; @Getter private transient MapMarksManager mapMarksManager; diff --git a/src/main/java/emu/grasscutter/game/quest/QuestManager.java b/src/main/java/emu/grasscutter/game/quest/QuestManager.java index 572731edb..e7c21ad7f 100644 --- a/src/main/java/emu/grasscutter/game/quest/QuestManager.java +++ b/src/main/java/emu/grasscutter/game/quest/QuestManager.java @@ -1,6 +1,5 @@ package emu.grasscutter.game.quest; -import dev.morphia.annotations.Transient; import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; import emu.grasscutter.data.binout.MainQuestData; @@ -31,10 +30,13 @@ import static emu.grasscutter.GameConstants.DEBUG; import static emu.grasscutter.config.Configuration.GAME_OPTIONS; import static emu.grasscutter.config.Configuration.SERVER; -public class QuestManager extends BasePlayerManager { +public final class QuestManager extends BasePlayerManager { @Getter private final Player player; + @Getter private final Int2ObjectMap mainQuests; - @Transient @Getter private final List loggedQuests; + @Getter private final List loggedQuests; + + @Getter private final List activeGivings = new ArrayList<>(); private long lastHourCheck = 0; private long lastDayCheck = 0; @@ -45,6 +47,7 @@ public class QuestManager extends BasePlayerManager { 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1000), FastThreadLocalThread::new, new ThreadPoolExecutor.AbortPolicy()); } + /* On SetPlayerBornDataReq, the server sends FinishedParentQuestNotify, with this exact parentQuestList. Captured on Game version 2.7 diff --git a/src/main/java/emu/grasscutter/game/quest/enums/QuestContent.java b/src/main/java/emu/grasscutter/game/quest/enums/QuestContent.java index 3c3f378a3..ba805674e 100644 --- a/src/main/java/emu/grasscutter/game/quest/enums/QuestContent.java +++ b/src/main/java/emu/grasscutter/game/quest/enums/QuestContent.java @@ -34,7 +34,7 @@ public enum QuestContent implements QuestTrigger { QUEST_CONTENT_ADD_QUEST_PROGRESS(24), QUEST_CONTENT_INTERACT_GADGET(25), QUEST_CONTENT_DAILY_TASK_COMP_FINISH(26), // missing, currently unused - QUEST_CONTENT_FINISH_ITEM_GIVING(27), // missing, finish + QUEST_CONTENT_FINISH_ITEM_GIVING(27), QUEST_CONTENT_SKILL(107), QUEST_CONTENT_CITY_LEVEL_UP(109), // missing, finish QUEST_CONTENT_PATTERN_GROUP_CLEAR_MONSTER(110), // missing, finish, for random quests diff --git a/src/main/java/emu/grasscutter/game/quest/enums/QuestExec.java b/src/main/java/emu/grasscutter/game/quest/enums/QuestExec.java index faba81e32..1466c15ff 100644 --- a/src/main/java/emu/grasscutter/game/quest/enums/QuestExec.java +++ b/src/main/java/emu/grasscutter/game/quest/enums/QuestExec.java @@ -35,7 +35,7 @@ public enum QuestExec implements QuestTrigger { QUEST_EXEC_CREATE_PATTERN_GROUP(25), // missing, used for random quests QUEST_EXEC_REMOVE_PATTERN_GROUP(26), // missing, used for random quests QUEST_EXEC_REFRESH_GROUP_SUITE_RANDOM(27), // missing - QUEST_EXEC_ACTIVE_ITEM_GIVING(28), // missing + QUEST_EXEC_ACTIVE_ITEM_GIVING(28), QUEST_EXEC_DEL_ALL_SPECIFIC_PACK_ITEM(29), // missing QUEST_EXEC_ROLLBACK_PARENT_QUEST(30), QUEST_EXEC_LOCK_AVATAR_TEAM(31), // missing @@ -71,7 +71,7 @@ public enum QuestExec implements QuestTrigger { QUEST_EXEC_MODIFY_CLIMATE_AREA(60), // missing QUEST_EXEC_GRANT_TRIAL_AVATAR_AND_LOCK_TEAM(61), // missing QUEST_EXEC_CHANGE_MAP_AREA_STATE(62), // missing - QUEST_EXEC_DEACTIVE_ITEM_GIVING(63), // missing + QUEST_EXEC_DEACTIVE_ITEM_GIVING(63), QUEST_EXEC_CHANGE_SCENE_LEVEL_TAG(64), // missing QUEST_EXEC_UNLOCK_PLAYER_WORLD_SCENE(65), // missing QUEST_EXEC_LOCK_PLAYER_WORLD_SCENE(66), // missing diff --git a/src/main/java/emu/grasscutter/game/quest/exec/ExecActiveItemGiving.java b/src/main/java/emu/grasscutter/game/quest/exec/ExecActiveItemGiving.java new file mode 100644 index 000000000..6b426aa30 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/exec/ExecActiveItemGiving.java @@ -0,0 +1,26 @@ +package emu.grasscutter.game.quest.exec; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.data.excels.quest.QuestData.QuestExecParam; +import emu.grasscutter.game.quest.*; +import emu.grasscutter.game.quest.enums.QuestExec; +import emu.grasscutter.game.quest.handlers.QuestExecHandler; + +@QuestValueExec(QuestExec.QUEST_EXEC_ACTIVE_ITEM_GIVING) +public final class ExecActiveItemGiving extends QuestExecHandler { + @Override + public boolean execute(GameQuest quest, QuestExecParam condition, String... paramStr) { + var questManager = quest.getOwner().getQuestManager(); + var activeGivings = questManager.getActiveGivings(); + + var givingId = Integer.parseInt(condition.getParam()[0]); + if (activeGivings.contains(givingId)) { + Grasscutter.getLogger().debug("Quest {} attempted to add give action {} twice.", + quest.getSubQuestId(), givingId); + return false; + } else { + activeGivings.add(givingId); + return true; + } + } +} diff --git a/src/main/java/emu/grasscutter/game/quest/exec/ExecDeactivateItemGiving.java b/src/main/java/emu/grasscutter/game/quest/exec/ExecDeactivateItemGiving.java new file mode 100644 index 000000000..2298a6570 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/exec/ExecDeactivateItemGiving.java @@ -0,0 +1,26 @@ +package emu.grasscutter.game.quest.exec; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.data.excels.quest.QuestData; +import emu.grasscutter.game.quest.*; +import emu.grasscutter.game.quest.enums.QuestExec; +import emu.grasscutter.game.quest.handlers.QuestExecHandler; + +@QuestValueExec(QuestExec.QUEST_EXEC_DEACTIVE_ITEM_GIVING) +public final class ExecDeactivateItemGiving extends QuestExecHandler { + @Override + public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) { + var questManager = quest.getOwner().getQuestManager(); + var activeGivings = questManager.getActiveGivings(); + + var givingId = Integer.parseInt(condition.getParam()[0]); + if (!activeGivings.contains(givingId)) { + Grasscutter.getLogger().debug("Quest {} attempted to remove give action {} when it isn't active.", + quest.getSubQuestId(), givingId); + return false; + } else { + activeGivings.remove(givingId); + return true; + } + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerItemGivingReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerItemGivingReq.java new file mode 100644 index 000000000..8c9deac7f --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerItemGivingReq.java @@ -0,0 +1,63 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.excels.giving.GivingData.GiveMethod; +import emu.grasscutter.game.quest.enums.QuestContent; +import emu.grasscutter.net.packet.*; +import emu.grasscutter.net.proto.ItemGivingReqOuterClass.ItemGivingReq; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketItemGivingRsp; +import emu.grasscutter.server.packet.send.PacketItemGivingRsp.Mode; + +@Opcodes(PacketOpcodes.ItemGivingReq) +public final class HandlerItemGivingReq extends PacketHandler { + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + var req = ItemGivingReq.parseFrom(payload); + + var player = session.getPlayer(); + var inventory = player.getInventory(); + + var giveId = req.getGivingId(); + var items = req.getItemGuidCountMapMap(); + + switch (req.getItemGivingType()) { + case QUEST -> { + var questManager = player.getQuestManager(); + var activeGivings = questManager.getActiveGivings(); + if (!activeGivings.contains(giveId)) return; + + // Check the items against the resources. + var data = GameData.getGivingDataMap().get(giveId); + if (data == null) throw new IllegalArgumentException("No giving data found for " + giveId + "."); + + if (data.getGivingMethod() == GiveMethod.EXACT) { + if (!inventory.hasAllItems(items)) { + player.sendPacket(new PacketItemGivingRsp()); + return; + } + + // Remove the items if the quest specifies. + if (data.isRemoveItem()) { + inventory.removeItems(items); + } + + // Send the response packet. + player.sendPacket(new PacketItemGivingRsp(giveId, Mode.EXACT_SUCCESS)); + // Remove the action from the active givings. + activeGivings.remove(giveId); + // Queue the content action. + questManager.queueEvent(QuestContent.QUEST_CONTENT_FINISH_ITEM_GIVING, giveId); + } else { + // TODO: Handle group givings. + player.sendPacket(new PacketItemGivingRsp()); + } + } + case GADGET -> { + Grasscutter.getLogger().debug("Unimplemented gadget giving was executed for {}.", giveId); + player.sendPacket(new PacketItemGivingRsp()); + } + } + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketItemGivingRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketItemGivingRsp.java new file mode 100644 index 000000000..250842a3f --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketItemGivingRsp.java @@ -0,0 +1,30 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.*; +import emu.grasscutter.net.proto.ItemGivingRspOuterClass.ItemGivingRsp; + +public final class PacketItemGivingRsp extends BasePacket { + public PacketItemGivingRsp() { + this(0, Mode.FAILURE); + } + + public PacketItemGivingRsp(int value, Mode mode) { + super(PacketOpcodes.ItemGivingRsp); + + var packet = ItemGivingRsp.newBuilder() + .setRetcode(mode == Mode.FAILURE ? 1 : 0); + if (mode == Mode.EXACT_SUCCESS) { + packet.setGivingId(value); + } else if (mode == Mode.GROUP_SUCCESS) { + packet.setGivingGroupId(value); + } + + this.setData(packet); + } + + public enum Mode { + GROUP_SUCCESS, + EXACT_SUCCESS, + FAILURE + } +} From 08284bc669544f454730c46a446efe8ed1cb04f6 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Mon, 31 Jul 2023 16:03:55 -0400 Subject: [PATCH 2/7] Add extra giving method --- .../java/emu/grasscutter/data/excels/giving/GivingData.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/emu/grasscutter/data/excels/giving/GivingData.java b/src/main/java/emu/grasscutter/data/excels/giving/GivingData.java index dab20c6d9..ba42760dd 100644 --- a/src/main/java/emu/grasscutter/data/excels/giving/GivingData.java +++ b/src/main/java/emu/grasscutter/data/excels/giving/GivingData.java @@ -30,9 +30,11 @@ public final class GivingData extends GameResource { private GiveType giveType; public enum GiveMethod { + @SerializedName("GIVING_METHOD_NONE") NONE, @SerializedName("GIVING_METHOD_EXACT") EXACT, @SerializedName("GIVING_METHOD_GROUP") GROUP, - @SerializedName("GIVING_METHOD_VAGUE_GROUP") GROUP_VAGUE + @SerializedName("GIVING_METHOD_VAGUE_GROUP") GROUP_VAGUE, + @SerializedName("GIVING_METHOD_ANY_NO_FINISH") ANY } public enum GiveType { From afc5841596185935f041b07dd0f33f9cb0924e49 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Sat, 12 Aug 2023 22:12:48 -0400 Subject: [PATCH 3/7] Add way to toggle certain spam logs --- .../java/emu/grasscutter/DebugConstants.java | 10 ++++++++++ .../game/ability/AbilityManager.java | 20 ++++++++++++------- .../data/controller/EntityController.java | 18 ++++++++--------- 3 files changed, 32 insertions(+), 16 deletions(-) create mode 100644 src/main/java/emu/grasscutter/DebugConstants.java diff --git a/src/main/java/emu/grasscutter/DebugConstants.java b/src/main/java/emu/grasscutter/DebugConstants.java new file mode 100644 index 000000000..c496ab053 --- /dev/null +++ b/src/main/java/emu/grasscutter/DebugConstants.java @@ -0,0 +1,10 @@ +package emu.grasscutter; + +public final class DebugConstants { + public static boolean LOG_ABILITIES = false; + public static boolean LOG_LUA_SCRIPTS = false; + + private DebugConstants() { + // Prevent instantiation. + } +} diff --git a/src/main/java/emu/grasscutter/game/ability/AbilityManager.java b/src/main/java/emu/grasscutter/game/ability/AbilityManager.java index 5c2bc526f..5125285a2 100644 --- a/src/main/java/emu/grasscutter/game/ability/AbilityManager.java +++ b/src/main/java/emu/grasscutter/game/ability/AbilityManager.java @@ -1,7 +1,7 @@ package emu.grasscutter.game.ability; import com.google.protobuf.*; -import emu.grasscutter.Grasscutter; +import emu.grasscutter.*; import emu.grasscutter.data.GameData; import emu.grasscutter.data.binout.*; import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction; @@ -19,13 +19,13 @@ import emu.grasscutter.net.proto.AbilityScalarTypeOuterClass.AbilityScalarType; import emu.grasscutter.net.proto.AbilityScalarValueEntryOuterClass.AbilityScalarValueEntry; import emu.grasscutter.net.proto.ModifierActionOuterClass.ModifierAction; import io.netty.util.concurrent.FastThreadLocalThread; -import java.util.HashMap; -import java.util.concurrent.*; import lombok.Getter; import org.reflections.Reflections; -public final class AbilityManager extends BasePlayerManager { +import java.util.HashMap; +import java.util.concurrent.*; +public final class AbilityManager extends BasePlayerManager { private static final HashMap actionHandlers = new HashMap<>(); private static final HashMap mixinHandlers = @@ -91,8 +91,11 @@ public final class AbilityManager extends BasePlayerManager { Ability ability, AbilityModifierAction action, ByteString abilityData, GameEntity target) { var handler = actionHandlers.get(action.type); if (handler == null || ability == null) { - Grasscutter.getLogger() + if (DebugConstants.LOG_ABILITIES) { + Grasscutter.getLogger() .debug("Could not execute ability action {} at {}", action.type, ability); + } + return; } @@ -148,7 +151,7 @@ public final class AbilityManager extends BasePlayerManager { invoke.getArgumentType(), invoke.getArgumentTypeValue(), entity.getId()); - } else { + } else if (DebugConstants.LOG_ABILITIES) { Grasscutter.getLogger() .debug( "Invoke type of {} ({}) has no entity. (referring to {})", @@ -375,7 +378,10 @@ public final class AbilityManager extends BasePlayerManager { var entity = this.player.getScene().getEntityById(invoke.getEntityId()); if (entity == null) { - Grasscutter.getLogger().debug("Entity not found: {}", invoke.getEntityId()); + if (DebugConstants.LOG_ABILITIES) { + Grasscutter.getLogger().debug("Entity not found: {}", invoke.getEntityId()); + } + return; } diff --git a/src/main/java/emu/grasscutter/scripts/data/controller/EntityController.java b/src/main/java/emu/grasscutter/scripts/data/controller/EntityController.java index 0435fe44f..4897910b9 100644 --- a/src/main/java/emu/grasscutter/scripts/data/controller/EntityController.java +++ b/src/main/java/emu/grasscutter/scripts/data/controller/EntityController.java @@ -1,14 +1,12 @@ package emu.grasscutter.scripts.data.controller; -import emu.grasscutter.Grasscutter; +import emu.grasscutter.*; import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.props.ElementType; -import emu.grasscutter.scripts.ScriptLib; -import emu.grasscutter.scripts.ScriptLoader; -import javax.script.Bindings; -import javax.script.CompiledScript; -import org.luaj.vm2.LuaError; -import org.luaj.vm2.LuaValue; +import emu.grasscutter.scripts.*; +import org.luaj.vm2.*; + +import javax.script.*; public class EntityController { private transient CompiledScript entityController; @@ -38,9 +36,11 @@ public class EntityController { } public int onClientExecuteRequest(GameEntity entity, int param1, int param2, int param3) { - Grasscutter.getLogger() + if (DebugConstants.LOG_LUA_SCRIPTS) { + Grasscutter.getLogger() .debug( - "Request on {}, {}: {}", entity.getGroupId(), param1, entity.getPosition().toString()); + "Request on {}, {}: {}", entity.getGroupId(), param1, entity.getPosition().toString()); + } LuaValue value = callControllerScriptFunc( entity, From 40bbfd90e1c94d8916c2d1e056b878d50f225aa8 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Sun, 13 Aug 2023 00:32:02 -0400 Subject: [PATCH 4/7] Implement group-based item giving & Add content handler for item giving --- .../java/emu/grasscutter/DebugConstants.java | 1 + .../data/excels/giving/GivingData.java | 12 +- .../grasscutter/game/inventory/Inventory.java | 64 +++++-- .../game/player/PlayerProgress.java | 24 +-- .../emu/grasscutter/game/quest/GameQuest.java | 12 +- .../game/quest/ItemGiveRecord.java | 75 ++++++++ .../grasscutter/game/quest/QuestManager.java | 169 +++++++++++------- .../content/ContentFinishGivingItem.java | 17 ++ .../game/quest/exec/ExecActiveItemGiving.java | 17 +- .../quest/exec/ExecDeactivateItemGiving.java | 11 +- .../packet/recv/HandlerItemGivingReq.java | 90 +++++++--- .../packet/send/PacketGivingRecordNotify.java | 17 ++ 12 files changed, 371 insertions(+), 138 deletions(-) create mode 100644 src/main/java/emu/grasscutter/game/quest/ItemGiveRecord.java create mode 100644 src/main/java/emu/grasscutter/game/quest/content/ContentFinishGivingItem.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketGivingRecordNotify.java diff --git a/src/main/java/emu/grasscutter/DebugConstants.java b/src/main/java/emu/grasscutter/DebugConstants.java index c496ab053..647e58bf7 100644 --- a/src/main/java/emu/grasscutter/DebugConstants.java +++ b/src/main/java/emu/grasscutter/DebugConstants.java @@ -3,6 +3,7 @@ package emu.grasscutter; public final class DebugConstants { public static boolean LOG_ABILITIES = false; public static boolean LOG_LUA_SCRIPTS = false; + public static boolean LOG_QUEST_START = false; private DebugConstants() { // Prevent instantiation. diff --git a/src/main/java/emu/grasscutter/data/excels/giving/GivingData.java b/src/main/java/emu/grasscutter/data/excels/giving/GivingData.java index ba42760dd..560be60e6 100644 --- a/src/main/java/emu/grasscutter/data/excels/giving/GivingData.java +++ b/src/main/java/emu/grasscutter/data/excels/giving/GivingData.java @@ -30,11 +30,13 @@ public final class GivingData extends GameResource { private GiveType giveType; public enum GiveMethod { - @SerializedName("GIVING_METHOD_NONE") NONE, - @SerializedName("GIVING_METHOD_EXACT") EXACT, - @SerializedName("GIVING_METHOD_GROUP") GROUP, - @SerializedName("GIVING_METHOD_VAGUE_GROUP") GROUP_VAGUE, - @SerializedName("GIVING_METHOD_ANY_NO_FINISH") ANY + GIVING_METHOD_NONE, + /** All items are required to succeed. */ + GIVING_METHOD_EXACT, + GIVING_METHOD_GROUP, + /** One in the group is required to succeed. */ + GIVING_METHOD_VAGUE_GROUP, + GIVING_METHOD_ANY_NO_FINISH } public enum GiveType { diff --git a/src/main/java/emu/grasscutter/game/inventory/Inventory.java b/src/main/java/emu/grasscutter/game/inventory/Inventory.java index a49ee4081..d467ae586 100644 --- a/src/main/java/emu/grasscutter/game/inventory/Inventory.java +++ b/src/main/java/emu/grasscutter/game/inventory/Inventory.java @@ -59,6 +59,19 @@ public class Inventory extends BasePlayerManager implements Iterable { this.getInventoryTypes().put(type.getValue(), tab); } + /** + * Finds the first item in the inventory with the given item id. + * + * @param itemId The item id to search for. + * @return The first item found with the given item id, or null if no item was + */ + public GameItem getFirstItem(int itemId) { + return this.getItems().values().stream() + .filter(item -> item.getItemId() == itemId) + .findFirst() + .orElse(null); + } + public GameItem getItemByGuid(long id) { return this.getItems().get(id); } @@ -155,25 +168,25 @@ public class Inventory extends BasePlayerManager implements Iterable { * Checks to see if the player has the item in their inventory. * This will succeed if the player has at least the minimum count of the item. * - * @param itemGuid The item id to check for. + * @param itemId The item id to check for. * @param minCount The minimum count of the item to check for. * @return True if the player has the item, false otherwise. */ - public boolean hasItem(long itemGuid, int minCount) { - return hasItem(itemGuid, minCount, false); + public boolean hasItem(int itemId, int minCount) { + return hasItem(itemId, minCount, false); } /** * Checks to see if the player has the item in their inventory. * - * @param itemGuid The item id to check for. + * @param itemId The item id to check for. * @param count The count of the item to check for. * @param enforce If true, the player must have the exact amount. * If false, the player must have at least the amount. * @return True if the player has the item, false otherwise. */ - public boolean hasItem(long itemGuid, int count, boolean enforce) { - var item = this.getItemByGuid(itemGuid); + public boolean hasItem(int itemId, int count, boolean enforce) { + var item = this.getFirstItem(itemId); if (item == null) return false; return enforce ? @@ -188,9 +201,9 @@ public class Inventory extends BasePlayerManager implements Iterable { * @param items A map of item game IDs to their count. * @return True if the player has the items, false otherwise. */ - public boolean hasAllItems(Map items) { - for (var item : items.entrySet()) { - if (!this.hasItem(item.getKey(), item.getValue(), true)) + public boolean hasAllItems(Collection items) { + for (var item : items) { + if (!this.hasItem(item.getItemId(), item.getCount(), true)) return false; } @@ -486,9 +499,9 @@ public class Inventory extends BasePlayerManager implements Iterable { * * @param items A map of item game IDs to the amount of items to remove. */ - public void removeItems(Map items) { - for (var entry : items.entrySet()) { - this.removeItem(entry.getKey(), entry.getValue()); + public void removeItems(Collection items) { + for (var entry : items) { + this.removeItem(entry.getItemId(), entry.getCount()); } } @@ -496,6 +509,25 @@ public class Inventory extends BasePlayerManager implements Iterable { return removeItem(guid, 1); } + /** + * Removes an item from the player's inventory. + * This uses the item ID to find the first stack of the item's type. + * + * @param itemId The ID of the item to remove. + * @param count The amount of items to remove. + * @return True if the item was removed, false otherwise. + */ + public synchronized boolean removeItem(int itemId, int count) { + var item = this.getItems().values().stream() + .filter(i -> i.getItemId() == itemId) + .findFirst(); + + // Check if the item is in the player's inventory. + return item + .filter(gameItem -> this.removeItem(gameItem, count)) + .isPresent(); + } + public synchronized boolean removeItem(long guid, int count) { var item = this.getItemByGuid(guid); @@ -514,10 +546,14 @@ public class Inventory extends BasePlayerManager implements Iterable { * @return True if the item was removed, false otherwise. */ public synchronized boolean removeItemById(int itemId, int count) { - var item = this.getItems().values().stream().filter(i -> i.getItemId() == itemId).findFirst(); + var item = this.getItems().values().stream() + .filter(i -> i.getItemId() == itemId) + .findFirst(); // Check if the item is in the player's inventory. - return item.filter(gameItem -> this.removeItem(gameItem, count)).isPresent(); + return item + .filter(gameItem -> this.removeItem(gameItem, count)) + .isPresent(); } public synchronized boolean removeItem(GameItem item) { diff --git a/src/main/java/emu/grasscutter/game/player/PlayerProgress.java b/src/main/java/emu/grasscutter/game/player/PlayerProgress.java index 5ac575f5a..0c34eaedb 100644 --- a/src/main/java/emu/grasscutter/game/player/PlayerProgress.java +++ b/src/main/java/emu/grasscutter/game/player/PlayerProgress.java @@ -1,40 +1,40 @@ package emu.grasscutter.game.player; -import dev.morphia.annotations.Entity; -import dev.morphia.annotations.Transient; +import dev.morphia.annotations.*; import emu.grasscutter.Grasscutter; +import emu.grasscutter.game.quest.ItemGiveRecord; import emu.grasscutter.game.quest.enums.QuestContent; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.*; +import lombok.*; + import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.val; /** Tracks progress the player made in the world, like obtained items, seen characters and more */ +@Getter @Entity public class PlayerProgress { - @Getter @Setter @Transient private Player player; - - @Getter private Map itemHistory; + @Setter @Transient private Player player; + private Map itemHistory; /* * A list of dungeon IDs which have been completed. * This only applies to one-time dungeons. */ - @Getter private IntArrayList completedDungeons; + private IntArrayList completedDungeons; // keep track of EXEC_ADD_QUEST_PROGRESS count, will be used in CONTENT_ADD_QUEST_PROGRESS // not sure where to put this, this should be saved to DB but not to individual quest, since // it will be hard to loop and compare private Map questProgressCountMap; + private Map itemGivings; + public PlayerProgress() { this.questProgressCountMap = new ConcurrentHashMap<>(); this.completedDungeons = new IntArrayList(); this.itemHistory = new Int2ObjectOpenHashMap<>(); + this.itemGivings = new Int2ObjectOpenHashMap<>(); } /** diff --git a/src/main/java/emu/grasscutter/game/quest/GameQuest.java b/src/main/java/emu/grasscutter/game/quest/GameQuest.java index 904a7b404..364b4449d 100644 --- a/src/main/java/emu/grasscutter/game/quest/GameQuest.java +++ b/src/main/java/emu/grasscutter/game/quest/GameQuest.java @@ -1,7 +1,7 @@ package emu.grasscutter.game.quest; import dev.morphia.annotations.*; -import emu.grasscutter.Grasscutter; +import emu.grasscutter.*; import emu.grasscutter.data.GameData; import emu.grasscutter.data.excels.*; import emu.grasscutter.data.excels.quest.QuestData; @@ -15,10 +15,11 @@ import emu.grasscutter.scripts.data.SceneGroup; import emu.grasscutter.server.packet.send.*; import emu.grasscutter.utils.Utils; import it.unimi.dsi.fastutil.ints.IntIntImmutablePair; -import java.util.*; -import javax.script.Bindings; import lombok.*; +import javax.script.Bindings; +import java.util.*; + @Entity public class GameQuest { @Transient @Getter @Setter private GameMainQuest mainQuest; @@ -104,7 +105,10 @@ public class GameQuest { .forEach(e -> getOwner().getServer().getQuestSystem().triggerExec(this, e, e.getParam())); this.getOwner().getQuestManager().checkQuestAlreadyFulfilled(this); - Grasscutter.getLogger().debug("Quest {} is started", subQuestId); + if (DebugConstants.LOG_QUEST_START) { + Grasscutter.getLogger().debug("Quest {} is started", subQuestId); + } + this.save(); } diff --git a/src/main/java/emu/grasscutter/game/quest/ItemGiveRecord.java b/src/main/java/emu/grasscutter/game/quest/ItemGiveRecord.java new file mode 100644 index 000000000..1000eac82 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/ItemGiveRecord.java @@ -0,0 +1,75 @@ +package emu.grasscutter.game.quest; + +import dev.morphia.annotations.Entity; +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.excels.giving.GivingData.GiveMethod; +import emu.grasscutter.net.proto.GivingRecordOuterClass.GivingRecord; +import lombok.*; + +import java.util.*; + +@Data +@Entity +@Builder +public final class ItemGiveRecord { + /** + * Provides a builder for an item give record. + * Uses information from game resources. + * + * @param givingId The ID of the giving action. + * @return A builder for an item give record. + */ + public static ItemGiveRecord resolve(int givingId) { + var givingData = GameData.getGivingDataMap().get(givingId); + if (givingData == null) throw new RuntimeException("No giving data found for " + givingId + "."); + + var builder = ItemGiveRecord.builder() + .givingId(givingId) + .finished(false); + + // Create a map. + var givenItems = new HashMap(); + if (givingData.getGivingMethod() == GiveMethod.GIVING_METHOD_EXACT) { + givingData.getExactItems().forEach(item -> + givenItems.put(item.getItemId(), 0)); + } else { + givingData.getGivingGroupIds().forEach(groupId -> { + var groupData = GameData.getGivingGroupDataMap().get((int) groupId); + if (groupData == null) return; + + // Add all items in the group. + groupData.getItemIds().forEach(itemId -> + givenItems.put(itemId, 0)); + builder.groupId(groupId); + }); + } + + return builder + .givenItems(givenItems) + .build(); + } + + private int givingId; + private int configId; + + private int groupId; + private int lastGroupId; + + private boolean finished; + private Map givenItems; + + /** + * @return A serialized protobuf object. + */ + public GivingRecord toProto() { + return GivingRecord.newBuilder() + .setGivingId(this.getGivingId()) + .setConfigId(this.getConfigId()) + .setGroupId(this.getGroupId()) + .setLastGroupId(this.getLastGroupId()) + .setIsFinished(this.isFinished()) + .setIsGadgetGiving(false) + .putAllMaterialCntMap(this.getGivenItems()) + .build(); + } +} diff --git a/src/main/java/emu/grasscutter/game/quest/QuestManager.java b/src/main/java/emu/grasscutter/game/quest/QuestManager.java index ca37d9f8a..b382b1436 100644 --- a/src/main/java/emu/grasscutter/game/quest/QuestManager.java +++ b/src/main/java/emu/grasscutter/game/quest/QuestManager.java @@ -2,33 +2,26 @@ package emu.grasscutter.game.quest; import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; -import emu.grasscutter.data.binout.MainQuestData; -import emu.grasscutter.data.binout.ScenePointEntry; +import emu.grasscutter.data.binout.*; import emu.grasscutter.data.excels.quest.QuestData; import emu.grasscutter.database.DatabaseHelper; -import emu.grasscutter.game.player.BasePlayerManager; -import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.player.*; import emu.grasscutter.game.quest.enums.*; -import emu.grasscutter.server.packet.send.PacketFinishedParentQuestUpdateNotify; -import emu.grasscutter.server.packet.send.PacketQuestGlobalVarNotify; import emu.grasscutter.game.world.Position; +import emu.grasscutter.net.proto.GivingRecordOuterClass.GivingRecord; +import emu.grasscutter.server.packet.send.*; import io.netty.util.concurrent.FastThreadLocalThread; import it.unimi.dsi.fastutil.ints.*; -import lombok.Getter; -import lombok.val; +import lombok.*; import javax.annotation.Nonnull; import java.util.*; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; import java.util.function.Consumer; import java.util.stream.Collectors; import static emu.grasscutter.GameConstants.DEBUG; -import static emu.grasscutter.config.Configuration.GAME_OPTIONS; -import static emu.grasscutter.config.Configuration.SERVER; +import static emu.grasscutter.config.Configuration.*; public final class QuestManager extends BasePlayerManager { @Getter private final Player player; @@ -36,52 +29,13 @@ public final class QuestManager extends BasePlayerManager { @Getter private final Int2ObjectMap mainQuests; @Getter private final List loggedQuests; - @Getter private final List activeGivings = new ArrayList<>(); - private long lastHourCheck = 0; private long lastDayCheck = 0; - public static final ExecutorService eventExecutor; - static { - eventExecutor = new ThreadPoolExecutor(4, 4, - 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1000), - FastThreadLocalThread::new, new ThreadPoolExecutor.AbortPolicy()); - } - - /* - On SetPlayerBornDataReq, the server sends FinishedParentQuestNotify, with this exact - parentQuestList. Captured on Game version 2.7 - Note: quest 40063 is already set to finished, with childQuest 4006406's state set to 3 - */ - - private static Set newPlayerMainQuests = Set.of(303,318,348,349,350,351,416,500, - 501,502,503,504,505,506,507,508,509,20000,20507,20509,21004,21005,21010,21011,21016,21017, - 21020,21021,21025,40063,70121,70124,70511,71010,71012,71013,71015,71016,71017,71555); - - /* - On SetPlayerBornDataReq, the server sends ServerCondMeetQuestListUpdateNotify, with this exact - addQuestIdList. Captured on Game version 2.7 - Total of 161... - */ - /* - private static Set newPlayerServerCondMeetQuestListUpdateNotify = Set.of(3100101, 7104405, 2201601, - 7100801, 1907002, 7293301, 7193801, 7293401, 7193901, 7091001, 7190501, 7090901, 7190401, 7090801, 7190301, - 7195301, 7294801, 7195201, 7293001, 7094001, 7193501, 7293501, 7194001, 7293701, 7194201, 7194301, 7293801, - 7194901, 7194101, 7195001, 7294501, 7294101, 7194601, 7294301, 7194801, 7091301, 7290301, 2102401, 7216801, - 7190201, 7090701, 7093801, 7193301, 7292801, 7227828, 7093901, 7193401, 7292901, 7093701, 7193201, 7292701, - 7082402, 7093601, 7292601, 7193101, 2102301, 7093501, 7292501, 7193001, 7093401, 7292401, 7192901, 7093301, - 7292301, 7192801, 7294201, 7194701, 2100301, 7093201, 7212402, 7292201, 7192701, 7280001, 7293901, 7194401, - 7093101, 7212302, 7292101, 7192601, 7093001, 7292001, 7192501, 7216001, 7195101, 7294601, 2100900, 7092901, - 7291901, 7192401, 7092801, 7291801, 7192301, 2101501, 7092701, 7291701, 7192201, 7106401, 2100716, 7091801, - 7290801, 7191301, 7293201, 7193701, 7094201, 7294001, 7194501, 2102290, 7227829, 7193601, 7094101, 7091401, - 7290401, 7190901, 7106605, 7291601, 7192101, 7092601, 7291501, 7192001, 7092501, 7291401, 7191901, 7092401, - 7291301, 7191801, 7092301, 7211402, 7291201, 7191701, 7092201, 7291101, 7191601, 7092101, 7291001, 7191501, - 7092001, 7290901, 7191401, 7091901, 7290701, 7191201, 7091701, 7290601, 7191101, 7091601, 7290501, 7191001, - 7091501, 7290201, 7190701, 7091201, 7190601, 7091101, 7190101, 7090601, 7090501, 7090401, 7010701, 7090301, - 7090201, 7010103, 7090101 - ); - - */ + public static final ExecutorService eventExecutor + = new ThreadPoolExecutor(4, 4, + 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1000), + FastThreadLocalThread::new, new ThreadPoolExecutor.AbortPolicy()); public static long getQuestKey(int mainQuestId) { QuestEncryptionKey questEncryptionKey = GameData.getMainQuestEncryptionMap().get(mainQuestId); @@ -137,20 +91,99 @@ public final class QuestManager extends BasePlayerManager { return GAME_OPTIONS.questing.enabled; } - public void onPlayerBorn() { - // TODO scan the quest and start the quest with acceptCond fulfilled - // The off send 3 request in that order: - // 1. FinishedParentQuestNotify - // 2. QuestListNotify - // 3. ServerCondMeetQuestListUpdateNotify + /** + * Attempts to add the giving action. + * + * @param givingId The giving action ID. + * @throws IllegalStateException If the giving action is already active. + */ + public void addGiveItemAction(int givingId) + throws IllegalStateException { + var progress = this.player.getPlayerProgress(); + var givings = progress.getItemGivings(); - if (this.isQuestingEnabled()) { - this.enableQuests(); + // Check if the action is already present. + if (givings.containsKey(givingId)) { + throw new IllegalStateException("Giving action " + givingId + " is already active."); } - // this.getPlayer().sendPacket(new PacketFinishedParentQuestUpdateNotify(newQuests)); - // this.getPlayer().sendPacket(new PacketQuestListNotify(subQuests)); - // this.getPlayer().sendPacket(new PacketServerCondMeetQuestListUpdateNotify(newPlayerServerCondMeetQuestListUpdateNotify)); + // Add the action. + givings.put(givingId, ItemGiveRecord.resolve(givingId)); + // Save the givings. + player.save(); + + this.sendGivingRecords(); + } + + /** + * Marks a giving action as completed. + * + * @param givingId The giving action ID. + */ + public void markCompleted(int givingId) { + var progress = this.player.getPlayerProgress(); + var givings = progress.getItemGivings(); + + // Check if the action is already present. + if (!givings.containsKey(givingId)) { + throw new IllegalStateException("Giving action " + givingId + " is not active."); + } + + // Mark the action as finished. + givings.get(givingId).setFinished(true); + // Save the givings. + player.save(); + + this.sendGivingRecords(); + } + + /** + * Attempts to remove the giving action. + * + * @param givingId The giving action ID. + */ + public void removeGivingItemAction(int givingId) { + var progress = this.player.getPlayerProgress(); + var givings = progress.getItemGivings(); + + // Check if the action is already present. + if (!givings.containsKey(givingId)) { + throw new IllegalStateException("Giving action " + givingId + " is not active."); + } + + // Remove the action. + givings.remove(givingId); + // Save the givings. + player.save(); + + this.sendGivingRecords(); + } + + /** + * @return Serialized giving records to be used in a packet. + */ + public Collection getGivingRecords() { + return this.getPlayer().getPlayerProgress() + .getItemGivings().values().stream() + .map(ItemGiveRecord::toProto) + .toList(); + } + + /** + * Attempts to remove the giving action. + */ + public void sendGivingRecords() { + // Send the record to the player. + this.player.sendPacket( + new PacketGivingRecordNotify( + this.getGivingRecords())); + } + + public void onPlayerBorn() { + if (this.isQuestingEnabled()) { + this.enableQuests(); + this.sendGivingRecords(); + } } public void onLogin() { diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentFinishGivingItem.java b/src/main/java/emu/grasscutter/game/quest/content/ContentFinishGivingItem.java new file mode 100644 index 000000000..88f2a7491 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentFinishGivingItem.java @@ -0,0 +1,17 @@ +package emu.grasscutter.game.quest.content; + +import emu.grasscutter.data.excels.quest.QuestData; +import emu.grasscutter.game.quest.*; +import emu.grasscutter.game.quest.enums.QuestContent; + +@QuestValueContent(QuestContent.QUEST_CONTENT_FINISH_ITEM_GIVING) +public final class ContentFinishGivingItem extends BaseContent { + @Override + public boolean execute(GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { + var giveAction = quest.getOwner() + .getPlayerProgress() + .getItemGivings() + .get(condition.getParam()[0]); + return giveAction != null && giveAction.isFinished(); + } +} diff --git a/src/main/java/emu/grasscutter/game/quest/exec/ExecActiveItemGiving.java b/src/main/java/emu/grasscutter/game/quest/exec/ExecActiveItemGiving.java index 6b426aa30..c2f073967 100644 --- a/src/main/java/emu/grasscutter/game/quest/exec/ExecActiveItemGiving.java +++ b/src/main/java/emu/grasscutter/game/quest/exec/ExecActiveItemGiving.java @@ -10,17 +10,20 @@ import emu.grasscutter.game.quest.handlers.QuestExecHandler; public final class ExecActiveItemGiving extends QuestExecHandler { @Override public boolean execute(GameQuest quest, QuestExecParam condition, String... paramStr) { - var questManager = quest.getOwner().getQuestManager(); - var activeGivings = questManager.getActiveGivings(); + var player = quest.getOwner(); + var questManager = player.getQuestManager(); var givingId = Integer.parseInt(condition.getParam()[0]); - if (activeGivings.contains(givingId)) { - Grasscutter.getLogger().debug("Quest {} attempted to add give action {} twice.", + try { + questManager.addGiveItemAction(givingId); + + Grasscutter.getLogger().debug("Quest {} added give action {}.", + quest.getSubQuestId(), givingId); + return true; + } catch (IllegalStateException ignored) { + Grasscutter.getLogger().warn("Quest {} attempted to add give action {} twice.", quest.getSubQuestId(), givingId); return false; - } else { - activeGivings.add(givingId); - return true; } } } diff --git a/src/main/java/emu/grasscutter/game/quest/exec/ExecDeactivateItemGiving.java b/src/main/java/emu/grasscutter/game/quest/exec/ExecDeactivateItemGiving.java index 2298a6570..9f9f8d5ba 100644 --- a/src/main/java/emu/grasscutter/game/quest/exec/ExecDeactivateItemGiving.java +++ b/src/main/java/emu/grasscutter/game/quest/exec/ExecDeactivateItemGiving.java @@ -11,16 +11,15 @@ public final class ExecDeactivateItemGiving extends QuestExecHandler { @Override public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) { var questManager = quest.getOwner().getQuestManager(); - var activeGivings = questManager.getActiveGivings(); var givingId = Integer.parseInt(condition.getParam()[0]); - if (!activeGivings.contains(givingId)) { - Grasscutter.getLogger().debug("Quest {} attempted to remove give action {} when it isn't active.", + try { + questManager.removeGivingItemAction(givingId); + return true; + } catch (IllegalStateException ignored) { + Grasscutter.getLogger().warn("Quest {} attempted to remove give action {} twice.", quest.getSubQuestId(), givingId); return false; - } else { - activeGivings.remove(givingId); - return true; } } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerItemGivingReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerItemGivingReq.java index 8c9deac7f..d80846dda 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerItemGivingReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerItemGivingReq.java @@ -2,7 +2,6 @@ package emu.grasscutter.server.packet.recv; import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; -import emu.grasscutter.data.excels.giving.GivingData.GiveMethod; import emu.grasscutter.game.quest.enums.QuestContent; import emu.grasscutter.net.packet.*; import emu.grasscutter.net.proto.ItemGivingReqOuterClass.ItemGivingReq; @@ -10,6 +9,8 @@ import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.packet.send.PacketItemGivingRsp; import emu.grasscutter.server.packet.send.PacketItemGivingRsp.Mode; +import java.util.*; + @Opcodes(PacketOpcodes.ItemGivingReq) public final class HandlerItemGivingReq extends PacketHandler { @Override @@ -20,38 +21,83 @@ public final class HandlerItemGivingReq extends PacketHandler { var inventory = player.getInventory(); var giveId = req.getGivingId(); - var items = req.getItemGuidCountMapMap(); + var items = req.getItemParamListList(); switch (req.getItemGivingType()) { case QUEST -> { var questManager = player.getQuestManager(); - var activeGivings = questManager.getActiveGivings(); - if (!activeGivings.contains(giveId)) return; + var activeGivings = player.getPlayerProgress().getItemGivings(); + if (!activeGivings.containsKey(giveId)) return; // Check the items against the resources. var data = GameData.getGivingDataMap().get(giveId); if (data == null) throw new IllegalArgumentException("No giving data found for " + giveId + "."); - if (data.getGivingMethod() == GiveMethod.EXACT) { - if (!inventory.hasAllItems(items)) { - player.sendPacket(new PacketItemGivingRsp()); - return; - } + switch (data.getGivingMethod()) { + case GIVING_METHOD_EXACT -> { + // Check if the player has all the items. + if (!inventory.hasAllItems(items)) { + player.sendPacket(new PacketItemGivingRsp()); + return; + } - // Remove the items if the quest specifies. - if (data.isRemoveItem()) { - inventory.removeItems(items); - } + // Remove the items if the quest specifies. + if (data.isRemoveItem()) { + inventory.removeItems(items); + } - // Send the response packet. - player.sendPacket(new PacketItemGivingRsp(giveId, Mode.EXACT_SUCCESS)); - // Remove the action from the active givings. - activeGivings.remove(giveId); - // Queue the content action. - questManager.queueEvent(QuestContent.QUEST_CONTENT_FINISH_ITEM_GIVING, giveId); - } else { - // TODO: Handle group givings. - player.sendPacket(new PacketItemGivingRsp()); + // Send the response packet. + player.sendPacket(new PacketItemGivingRsp(giveId, Mode.EXACT_SUCCESS)); + // Remove the action from the active givings. + questManager.removeGivingItemAction(giveId); + // Queue the content action. + questManager.queueEvent(QuestContent.QUEST_CONTENT_FINISH_ITEM_GIVING, giveId, 0); + } + case GIVING_METHOD_VAGUE_GROUP -> { + var matchedGroups = new ArrayList(); + var givenItems = new HashMap(); + + // Resolve potential item IDs. + var groupData = GameData.getGivingGroupDataMap(); + data.getGivingGroupIds().stream() + .map(groupId -> groupData.get((int) groupId)) + .filter(Objects::nonNull) + .forEach(group -> { + var itemIds = group.getItemIds(); + + // Match item stacks to the group items. + items.forEach(param -> { + // Get the item instance. + var itemInstance = inventory.getFirstItem(param.getItemId()); + if (itemInstance == null) return; + + // Get the item ID. + var itemId = itemInstance.getItemId(); + if (!itemIds.contains(itemId)) return; + + // Add the item to the given items. + givenItems.put(itemId, param.getCount()); + matchedGroups.add(group.getId()); + }); + }); + + // Check if the player has any items. + if (givenItems.isEmpty() && matchedGroups.isEmpty()) { + player.sendPacket(new PacketItemGivingRsp()); + } else { + // Remove the items if the quest specifies. + if (data.isRemoveItem()) { + inventory.removeItems(items); + } + + // Send the response packet. + player.sendPacket(new PacketItemGivingRsp(matchedGroups.get(0), Mode.GROUP_SUCCESS)); + // Mark the giving action as completed. + questManager.markCompleted(giveId); + // Queue the content action. + questManager.queueEvent(QuestContent.QUEST_CONTENT_FINISH_ITEM_GIVING, giveId, 0); + } + } } } case GADGET -> { diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGivingRecordNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGivingRecordNotify.java new file mode 100644 index 000000000..ffbe29e3c --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGivingRecordNotify.java @@ -0,0 +1,17 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.*; +import emu.grasscutter.net.proto.GivingRecordNotifyOuterClass.GivingRecordNotify; +import emu.grasscutter.net.proto.GivingRecordOuterClass.GivingRecord; + +import java.util.Collection; + +public final class PacketGivingRecordNotify extends BasePacket { + public PacketGivingRecordNotify(Collection records) { + super(PacketOpcodes.GivingRecordNotify); + + this.setData(GivingRecordNotify.newBuilder() + .addAllGivingRecordList(records) + .build()); + } +} From 597574dddaef4b1295863e3281b957f5a4c7d4a1 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Sun, 13 Aug 2023 12:28:56 -0400 Subject: [PATCH 5/7] Attempt to implement bargaining (untested) --- .../java/emu/grasscutter/data/GameData.java | 4 + .../grasscutter/data/excels/BargainData.java | 49 ++++++++ .../game/player/PlayerProgress.java | 4 +- .../grasscutter/game/quest/BargainRecord.java | 109 ++++++++++++++++++ .../grasscutter/game/quest/QuestManager.java | 49 +++++++- .../quest/content/ContentBargainFail.java | 20 ++++ .../quest/content/ContentBargainLessThan.java | 20 ++++ .../quest/content/ContentBargainSuccess.java | 20 ++++ .../game/quest/enums/QuestContent.java | 6 +- .../game/quest/enums/QuestExec.java | 4 +- .../game/quest/exec/ExecStartBargain.java | 27 +++++ .../game/quest/exec/ExecStopBargain.java | 27 +++++ .../recv/HandlerBargainOfferPriceReq.java | 43 +++++++ .../HandlerGetAllActivatedBargainDataReq.java | 17 +++ .../packet/recv/HandlerGetBargainDataReq.java | 29 +++++ .../send/PacketBargainOfferPriceRsp.java | 21 ++++ .../packet/send/PacketBargainStartNotify.java | 15 +++ .../send/PacketBargainTerminateNotify.java | 13 +++ .../PacketGetAllActivatedBargainDataRsp.java | 20 ++++ .../packet/send/PacketGetBargainDataRsp.java | 24 ++++ 20 files changed, 514 insertions(+), 7 deletions(-) create mode 100644 src/main/java/emu/grasscutter/data/excels/BargainData.java create mode 100644 src/main/java/emu/grasscutter/game/quest/BargainRecord.java create mode 100644 src/main/java/emu/grasscutter/game/quest/content/ContentBargainFail.java create mode 100644 src/main/java/emu/grasscutter/game/quest/content/ContentBargainLessThan.java create mode 100644 src/main/java/emu/grasscutter/game/quest/content/ContentBargainSuccess.java create mode 100644 src/main/java/emu/grasscutter/game/quest/exec/ExecStartBargain.java create mode 100644 src/main/java/emu/grasscutter/game/quest/exec/ExecStopBargain.java create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerBargainOfferPriceReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerGetAllActivatedBargainDataReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerGetBargainDataReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketBargainOfferPriceRsp.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketBargainStartNotify.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketBargainTerminateNotify.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketGetAllActivatedBargainDataRsp.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketGetBargainDataRsp.java diff --git a/src/main/java/emu/grasscutter/data/GameData.java b/src/main/java/emu/grasscutter/data/GameData.java index a688bf753..023f2977e 100644 --- a/src/main/java/emu/grasscutter/data/GameData.java +++ b/src/main/java/emu/grasscutter/data/GameData.java @@ -140,6 +140,10 @@ public final class GameData { private static final Int2ObjectMap avatarTalentDataMap = new Int2ObjectOpenHashMap<>(); + @Getter + private static final Int2ObjectMap bargainDataMap + = new Int2ObjectOpenHashMap<>(); + @Getter private static final Int2ObjectMap battlePassMissionDataMap = new Int2ObjectOpenHashMap<>(); diff --git a/src/main/java/emu/grasscutter/data/excels/BargainData.java b/src/main/java/emu/grasscutter/data/excels/BargainData.java new file mode 100644 index 000000000..b51912951 --- /dev/null +++ b/src/main/java/emu/grasscutter/data/excels/BargainData.java @@ -0,0 +1,49 @@ +package emu.grasscutter.data.excels; + +import emu.grasscutter.data.*; +import lombok.Getter; + +import java.util.List; + +@Getter +@ResourceType(name = "BargainExcelConfigData.json") +public final class BargainData extends GameResource { + @Getter private int id; + private int questId; + + private List dialogId; + + /** + * This is a list of 2 integers. + * The first integer is the minimum value of the bargain. + * The second integer is the maximum value of the bargain. + */ + private List expectedValue; + private int space; + + private List successTalkId; + private int failTalkId; + private int moodNpcId; + + /** + * This is a list of 2 integers. + * The first integer is the minimum value of the mood. + * The second integer is the maximum value of the mood. + */ + private List randomMood; + private int moodAlertLimit; + private int moodLowLimit; + private int singleFailMoodDeduction; + + private long moodLowLimitTextTextMapHash; + private long titleTextTextMapHash; + private long affordTextTextMapHash; + private long storageTextTextMapHash; + private long moodHintTextTextMapHash; + private long moodDescTextTextMapHash; + + private List singleFailTalkId; + + private boolean deleteItem; + private int itemId; +} diff --git a/src/main/java/emu/grasscutter/game/player/PlayerProgress.java b/src/main/java/emu/grasscutter/game/player/PlayerProgress.java index 0c34eaedb..638d8c5da 100644 --- a/src/main/java/emu/grasscutter/game/player/PlayerProgress.java +++ b/src/main/java/emu/grasscutter/game/player/PlayerProgress.java @@ -2,7 +2,7 @@ package emu.grasscutter.game.player; import dev.morphia.annotations.*; import emu.grasscutter.Grasscutter; -import emu.grasscutter.game.quest.ItemGiveRecord; +import emu.grasscutter.game.quest.*; import emu.grasscutter.game.quest.enums.QuestContent; import it.unimi.dsi.fastutil.ints.*; import lombok.*; @@ -29,12 +29,14 @@ public class PlayerProgress { private Map questProgressCountMap; private Map itemGivings; + private Map bargains; public PlayerProgress() { this.questProgressCountMap = new ConcurrentHashMap<>(); this.completedDungeons = new IntArrayList(); this.itemHistory = new Int2ObjectOpenHashMap<>(); this.itemGivings = new Int2ObjectOpenHashMap<>(); + this.bargains = new Int2ObjectOpenHashMap<>(); } /** diff --git a/src/main/java/emu/grasscutter/game/quest/BargainRecord.java b/src/main/java/emu/grasscutter/game/quest/BargainRecord.java new file mode 100644 index 000000000..d7a74c9b3 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/BargainRecord.java @@ -0,0 +1,109 @@ +package emu.grasscutter.game.quest; + +import dev.morphia.annotations.Entity; +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.excels.BargainData; +import emu.grasscutter.net.proto.BargainResultTypeOuterClass.BargainResultType; +import emu.grasscutter.net.proto.BargainSnapshotOuterClass.BargainSnapshot; +import emu.grasscutter.utils.Utils; +import lombok.*; + +@Data +@Entity +@Builder +public final class BargainRecord { + /** + * Provides an instance of a bargain record. + * Uses information from game resources. + * + * @param bargainId The ID of the bargain. + * @return An instance of a bargain record. + */ + public static BargainRecord resolve(int bargainId) { + var bargainData = GameData.getBargainDataMap().get(bargainId); + if (bargainData == null) throw new RuntimeException("No bargain data found for " + bargainId + "."); + + return BargainRecord.builder() + .bargainId(bargainId) + .build() + .determineBase(bargainData); + } + + private int bargainId; + private int lowestPrice; + private int expectedPrice; + + private int currentMood; + + private boolean finished; + private BargainResultType result; + + /** + * Determines the price of the bargain. + */ + public BargainRecord determineBase(BargainData data) { + // Set the expected price. + var price = data.getExpectedValue(); + this.setExpectedPrice(Utils.randomRange( + price.get(0), price.get(1))); + // Set the lowest price. + this.setLowestPrice(price.get(0)); + + // Set the base mood. + var mood = data.getRandomMood(); + this.setCurrentMood(Utils.randomRange( + mood.get(0), mood.get(1))); + + return this; + } + + /** + * Computes an offer's validity. + * + * @param offer The offer to compute. + * @return The result of the offer. + */ + public BargainResultType applyOffer(int offer) { + if (offer < this.getLowestPrice()) { + // Decrease the mood. + this.currentMood -= Utils.randomRange(1, 3); + // Return a failure. + return this.result = BargainResultType.BARGAIN_SINGLE_FAIL; + } + + if (offer > this.getExpectedPrice()) { + // Complete the bargain. + this.setFinished(true); + // Return a success. + return this.result = BargainResultType.BARGAIN_COMPLETE_SUCC; + } + + // Compare the offer against the mood & expected price. + // The mood is out of 100; 1 mood should decrease the price by 100. + var moodAdjustment = (int) Math.floor(this.getCurrentMood() / 100.0); + var expectedPrice = this.getExpectedPrice() - moodAdjustment; + if (offer < expectedPrice) { + // Decrease the mood. + this.currentMood -= Utils.randomRange(1, 3); + // Return a failure. + return this.result = BargainResultType.BARGAIN_SINGLE_FAIL; + } else { + // Complete the bargain. + this.setFinished(true); + // Return a success. + return this.result = BargainResultType.BARGAIN_COMPLETE_SUCC; + } + } + + /** + * @return A snapshot of this bargain record. + */ + public BargainSnapshot toSnapshot() { + return BargainSnapshot.newBuilder() + .setBargainId(this.getBargainId()) + .setCurMood(this.getCurrentMood()) + .setPJHMEHGELGC(this.getExpectedPrice()) + .setHADMOPEJFIC(this.getLowestPrice()) + .build(); + } +} diff --git a/src/main/java/emu/grasscutter/game/quest/QuestManager.java b/src/main/java/emu/grasscutter/game/quest/QuestManager.java index b382b1436..b7b301160 100644 --- a/src/main/java/emu/grasscutter/game/quest/QuestManager.java +++ b/src/main/java/emu/grasscutter/game/quest/QuestManager.java @@ -170,7 +170,54 @@ public final class QuestManager extends BasePlayerManager { } /** - * Attempts to remove the giving action. + * Attempts to start the bargain. + * + * @param bargainId The bargain ID. + */ + public void startBargain(int bargainId) { + var progress = this.player.getPlayerProgress(); + var bargains = progress.getBargains(); + + // Check if the bargain is already present. + if (bargains.containsKey(bargainId)) { + throw new IllegalStateException("Bargain " + bargainId + " is already active."); + } + + // Add the action. + var bargain = BargainRecord.resolve(bargainId); + bargains.put(bargainId, bargain); + // Save the bargains. + this.player.save(); + + // Send the player the start packet. + this.player.sendPacket(new PacketBargainStartNotify(bargain)); + } + + /** + * Attempts to stop the bargain. + * + * @param bargainId The bargain ID. + */ + public void stopBargain(int bargainId) { + var progress = this.player.getPlayerProgress(); + var bargains = progress.getBargains(); + + // Check if the bargain is already present. + if (!bargains.containsKey(bargainId)) { + throw new IllegalStateException("Bargain " + bargainId + " is not active."); + } + + // Remove the action. + bargains.remove(bargainId); + // Save the bargains. + this.player.save(); + + // Send the player the stop packet. + this.player.sendPacket(new PacketBargainTerminateNotify(bargainId)); + } + + /** + * Sends the giving records to the player. */ public void sendGivingRecords() { // Send the record to the player. diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentBargainFail.java b/src/main/java/emu/grasscutter/game/quest/content/ContentBargainFail.java new file mode 100644 index 000000000..08f1bda24 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentBargainFail.java @@ -0,0 +1,20 @@ +package emu.grasscutter.game.quest.content; + +import emu.grasscutter.data.excels.quest.QuestData; +import emu.grasscutter.game.quest.*; +import emu.grasscutter.game.quest.enums.QuestContent; +import emu.grasscutter.net.proto.BargainResultTypeOuterClass.BargainResultType; + +@QuestValueContent(QuestContent.QUEST_CONTENT_BARGAIN_FAIL) +public final class ContentBargainFail extends BaseContent { + @Override + public boolean execute(GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { + var bargain = quest.getOwner() + .getPlayerProgress() + .getBargains() + .get(condition.getParam()[0]); + if (bargain == null) return false; + + return bargain.getResult() == BargainResultType.BARGAIN_COMPLETE_FAIL; + } +} diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentBargainLessThan.java b/src/main/java/emu/grasscutter/game/quest/content/ContentBargainLessThan.java new file mode 100644 index 000000000..b6da9796d --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentBargainLessThan.java @@ -0,0 +1,20 @@ +package emu.grasscutter.game.quest.content; + +import emu.grasscutter.data.excels.quest.QuestData; +import emu.grasscutter.game.quest.*; +import emu.grasscutter.game.quest.enums.QuestContent; +import emu.grasscutter.net.proto.BargainResultTypeOuterClass.BargainResultType; + +@QuestValueContent(QuestContent.QUEST_CONTENT_ITEM_LESS_THAN_BARGAIN) +public final class ContentBargainLessThan extends BaseContent { + @Override + public boolean execute(GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { + var bargain = quest.getOwner() + .getPlayerProgress() + .getBargains() + .get(condition.getParam()[0]); + if (bargain == null) return false; + + return bargain.getResult() == BargainResultType.BARGAIN_SINGLE_FAIL; + } +} diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentBargainSuccess.java b/src/main/java/emu/grasscutter/game/quest/content/ContentBargainSuccess.java new file mode 100644 index 000000000..1deeeeb52 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentBargainSuccess.java @@ -0,0 +1,20 @@ +package emu.grasscutter.game.quest.content; + +import emu.grasscutter.data.excels.quest.QuestData; +import emu.grasscutter.game.quest.*; +import emu.grasscutter.game.quest.enums.QuestContent; +import emu.grasscutter.net.proto.BargainResultTypeOuterClass.BargainResultType; + +@QuestValueContent(QuestContent.QUEST_CONTENT_BARGAIN_SUCC) +public final class ContentBargainSuccess extends BaseContent { + @Override + public boolean execute(GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { + var bargain = quest.getOwner() + .getPlayerProgress() + .getBargains() + .get(condition.getParam()[0]); + if (bargain == null) return false; + + return bargain.getResult() == BargainResultType.BARGAIN_COMPLETE_SUCC; + } +} diff --git a/src/main/java/emu/grasscutter/game/quest/enums/QuestContent.java b/src/main/java/emu/grasscutter/game/quest/enums/QuestContent.java index ba805674e..ac81fa623 100644 --- a/src/main/java/emu/grasscutter/game/quest/enums/QuestContent.java +++ b/src/main/java/emu/grasscutter/game/quest/enums/QuestContent.java @@ -51,9 +51,9 @@ public enum QuestContent implements QuestTrigger { QUEST_CONTENT_QUEST_VAR_LESS(121), QUEST_CONTENT_OBTAIN_VARIOUS_ITEM(122), // missing, finish QUEST_CONTENT_FINISH_TOWER_LEVEL(123), // missing, currently unused - QUEST_CONTENT_BARGAIN_SUCC(124), // missing, finish - QUEST_CONTENT_BARGAIN_FAIL(125), // missing, fail - QUEST_CONTENT_ITEM_LESS_THAN_BARGAIN(126), // missing, fail + QUEST_CONTENT_BARGAIN_SUCC(124), + QUEST_CONTENT_BARGAIN_FAIL(125), + QUEST_CONTENT_ITEM_LESS_THAN_BARGAIN(126), QUEST_CONTENT_ACTIVITY_TRIGGER_FAILED(127), // missing, fail QUEST_CONTENT_MAIN_COOP_ENTER_SAVE_POINT(128), // missing, finish QUEST_CONTENT_ANY_MANUAL_TRANSPORT(129), diff --git a/src/main/java/emu/grasscutter/game/quest/enums/QuestExec.java b/src/main/java/emu/grasscutter/game/quest/enums/QuestExec.java index 1466c15ff..aa906a63d 100644 --- a/src/main/java/emu/grasscutter/game/quest/enums/QuestExec.java +++ b/src/main/java/emu/grasscutter/game/quest/enums/QuestExec.java @@ -47,8 +47,8 @@ public enum QuestExec implements QuestTrigger { QUEST_EXEC_ACTIVE_ACTIVITY_COND_STATE(37), // missing QUEST_EXEC_INACTIVE_ACTIVITY_COND_STATE(38), // missing QUEST_EXEC_ADD_CUR_AVATAR_ENERGY(39), - QUEST_EXEC_START_BARGAIN(41), // missing - QUEST_EXEC_STOP_BARGAIN(42), // missing + QUEST_EXEC_START_BARGAIN(41), + QUEST_EXEC_STOP_BARGAIN(42), QUEST_EXEC_SET_QUEST_GLOBAL_VAR(43), QUEST_EXEC_INC_QUEST_GLOBAL_VAR(44), QUEST_EXEC_DEC_QUEST_GLOBAL_VAR(45), diff --git a/src/main/java/emu/grasscutter/game/quest/exec/ExecStartBargain.java b/src/main/java/emu/grasscutter/game/quest/exec/ExecStartBargain.java new file mode 100644 index 000000000..87b03ec23 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/exec/ExecStartBargain.java @@ -0,0 +1,27 @@ +package emu.grasscutter.game.quest.exec; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.data.excels.quest.QuestData; +import emu.grasscutter.game.quest.*; +import emu.grasscutter.game.quest.enums.QuestExec; +import emu.grasscutter.game.quest.handlers.QuestExecHandler; + +@QuestValueExec(QuestExec.QUEST_EXEC_START_BARGAIN) +public final class ExecStartBargain extends QuestExecHandler { + @Override + public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) { + // Get the bargain data from the quest parameters. + var bargainId = Integer.parseInt(condition.getParam()[0]); + + try { + // Start the bargain. + quest.getOwner().getQuestManager() + .startBargain(bargainId); + Grasscutter.getLogger().debug("Bargain {} started.", bargainId); + return true; + } catch (RuntimeException ignored) { + Grasscutter.getLogger().debug("Bargain {} does not exist.", bargainId); + return false; + } + } +} diff --git a/src/main/java/emu/grasscutter/game/quest/exec/ExecStopBargain.java b/src/main/java/emu/grasscutter/game/quest/exec/ExecStopBargain.java new file mode 100644 index 000000000..0b5d09531 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/exec/ExecStopBargain.java @@ -0,0 +1,27 @@ +package emu.grasscutter.game.quest.exec; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.data.excels.quest.QuestData; +import emu.grasscutter.game.quest.*; +import emu.grasscutter.game.quest.enums.QuestExec; +import emu.grasscutter.game.quest.handlers.QuestExecHandler; + +@QuestValueExec(QuestExec.QUEST_EXEC_STOP_BARGAIN) +public final class ExecStopBargain extends QuestExecHandler { + @Override + public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) { + // Get the bargain data from the quest parameters. + var bargainId = Integer.parseInt(condition.getParam()[0]); + + try { + // Start the bargain. + quest.getOwner().getQuestManager() + .stopBargain(bargainId); + Grasscutter.getLogger().debug("Bargain {} stopped.", bargainId); + return true; + } catch (RuntimeException ignored) { + Grasscutter.getLogger().debug("Bargain {} does not exist.", bargainId); + return false; + } + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerBargainOfferPriceReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerBargainOfferPriceReq.java new file mode 100644 index 000000000..fbc776154 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerBargainOfferPriceReq.java @@ -0,0 +1,43 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.game.quest.enums.QuestContent; +import emu.grasscutter.net.packet.*; +import emu.grasscutter.net.proto.BargainOfferPriceReqOuterClass.BargainOfferPriceReq; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketBargainOfferPriceRsp; + +@Opcodes(PacketOpcodes.BargainOfferPriceReq) +public final class HandlerBargainOfferPriceReq extends PacketHandler { + @Override + public void handle(GameSession session, byte[] header, byte[] payload) + throws Exception { + var packet = BargainOfferPriceReq.parseFrom(payload); + var player = session.getPlayer(); + + // Fetch the active bargain. + var bargainId = packet.getBargainId(); + var progress = player.getPlayerProgress(); + var bargain = progress.getBargains().get(bargainId); + if (bargain == null) return; + + // Apply the offer. + var result = bargain.applyOffer(packet.getPrice()); + + // Queue the quest content event. + var questManager = player.getQuestManager(); + switch (result) { + case BARGAIN_COMPLETE_SUCC -> questManager.queueEvent( + QuestContent.QUEST_CONTENT_BARGAIN_SUCC, + bargainId, 0); + case BARGAIN_SINGLE_FAIL -> questManager.queueEvent( + QuestContent.QUEST_CONTENT_ITEM_LESS_THAN_BARGAIN, + bargainId, 0); + case BARGAIN_COMPLETE_FAIL -> questManager.queueEvent( + QuestContent.QUEST_CONTENT_BARGAIN_FAIL, + bargainId, 0); + } + + // Return the resulting packet. + session.send(new PacketBargainOfferPriceRsp(result, bargain)); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetAllActivatedBargainDataReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetAllActivatedBargainDataReq.java new file mode 100644 index 000000000..9955f356e --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetAllActivatedBargainDataReq.java @@ -0,0 +1,17 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.net.packet.*; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketGetAllActivatedBargainDataRsp; + +@Opcodes(PacketOpcodes.GetAllActivatedBargainDataReq) +public final class HandlerGetAllActivatedBargainDataReq extends PacketHandler { + @Override + public void handle(GameSession session, byte[] header, byte[] payload) { + session.send(new PacketGetAllActivatedBargainDataRsp( + session.getPlayer() + .getPlayerProgress() + .getBargains() + .values())); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetBargainDataReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetBargainDataReq.java new file mode 100644 index 000000000..aed038239 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetBargainDataReq.java @@ -0,0 +1,29 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.net.packet.*; +import emu.grasscutter.net.proto.GetBargainDataReqOuterClass.GetBargainDataReq; +import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketGetBargainDataRsp; + +@Opcodes(PacketOpcodes.GetBargainDataReq) +public final class HandlerGetBargainDataReq extends PacketHandler { + @Override + public void handle(GameSession session, byte[] header, byte[] payload) + throws Exception { + var packet = GetBargainDataReq.parseFrom(payload); + + var bargainId = packet.getBargainId(); + var bargain = session.getPlayer() + .getPlayerProgress() + .getBargains() + .get(bargainId); + if (bargain == null) { + session.send(new PacketGetBargainDataRsp( + Retcode.RET_BARGAIN_NOT_ACTIVATED)); + return; + } + + session.send(new PacketGetBargainDataRsp(bargain)); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketBargainOfferPriceRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketBargainOfferPriceRsp.java new file mode 100644 index 000000000..a9bdee9ba --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketBargainOfferPriceRsp.java @@ -0,0 +1,21 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.game.quest.BargainRecord; +import emu.grasscutter.net.packet.*; +import emu.grasscutter.net.proto.BargainOfferPriceRspOuterClass.BargainOfferPriceRsp; +import emu.grasscutter.net.proto.BargainResultTypeOuterClass.BargainResultType; +import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode; + +public final class PacketBargainOfferPriceRsp extends BasePacket { + public PacketBargainOfferPriceRsp(BargainResultType result, BargainRecord record) { + super(PacketOpcodes.BargainOfferPriceRsp); + + this.setData(BargainOfferPriceRsp.newBuilder() + .setRetcode(record.isFinished() ? + Retcode.RET_BARGAIN_FINISHED.getNumber() : + Retcode.RET_BARGAIN_NOT_ACTIVATED.getNumber()) + .setCurMood(record.getCurrentMood()) + .setBargainResult(result) + .setResultParam(0)); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketBargainStartNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketBargainStartNotify.java new file mode 100644 index 000000000..ec0a88d1a --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketBargainStartNotify.java @@ -0,0 +1,15 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.game.quest.BargainRecord; +import emu.grasscutter.net.packet.*; +import emu.grasscutter.net.proto.BargainStartNotifyOuterClass.BargainStartNotify; + +public final class PacketBargainStartNotify extends BasePacket { + public PacketBargainStartNotify(BargainRecord record) { + super(PacketOpcodes.BargainStartNotify); + + this.setData(BargainStartNotify.newBuilder() + .setBargainId(record.getBargainId()) + .setSnapshot(record.toSnapshot())); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketBargainTerminateNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketBargainTerminateNotify.java new file mode 100644 index 000000000..1dff443c9 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketBargainTerminateNotify.java @@ -0,0 +1,13 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.*; +import emu.grasscutter.net.proto.BargainTerminateNotifyOuterClass.BargainTerminateNotify; + +public final class PacketBargainTerminateNotify extends BasePacket { + public PacketBargainTerminateNotify(int bargainId) { + super(PacketOpcodes.BargainTerminateNotify); + + this.setData(BargainTerminateNotify.newBuilder() + .setBargainId(bargainId)); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetAllActivatedBargainDataRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetAllActivatedBargainDataRsp.java new file mode 100644 index 000000000..1cb54b6a3 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetAllActivatedBargainDataRsp.java @@ -0,0 +1,20 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.game.quest.BargainRecord; +import emu.grasscutter.net.packet.*; +import emu.grasscutter.net.proto.GetAllActivatedBargainDataRspOuterClass.GetAllActivatedBargainDataRsp; +import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode; + +import java.util.Collection; + +public final class PacketGetAllActivatedBargainDataRsp extends BasePacket { + public PacketGetAllActivatedBargainDataRsp(Collection records) { + super(PacketOpcodes.GetAllActivatedBargainDataRsp); + + this.setData(GetAllActivatedBargainDataRsp.newBuilder() + .setRetcode(Retcode.RET_SUCC.getNumber()) + .addAllSnapshotList(records.stream() + .map(BargainRecord::toSnapshot) + .toList())); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetBargainDataRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetBargainDataRsp.java new file mode 100644 index 000000000..965ae51d4 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetBargainDataRsp.java @@ -0,0 +1,24 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.game.quest.BargainRecord; +import emu.grasscutter.net.packet.*; +import emu.grasscutter.net.proto.GetBargainDataRspOuterClass.GetBargainDataRsp; +import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode; + +public final class PacketGetBargainDataRsp extends BasePacket { + public PacketGetBargainDataRsp(Retcode retcode) { + super(PacketOpcodes.GetBargainDataRsp); + + this.setData(GetBargainDataRsp.newBuilder() + .setRetcode(retcode.getNumber())); + } + + public PacketGetBargainDataRsp(BargainRecord record) { + super(PacketOpcodes.GetBargainDataRsp); + + this.setData(GetBargainDataRsp.newBuilder() + .setRetcode(Retcode.RET_SUCC.getNumber()) + .setBargainId(record.getBargainId()) + .setSnapshot(record.toSnapshot())); + } +} From 948dd5df5949689d9834a04d00e860693569d9fd Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Sun, 13 Aug 2023 12:48:04 -0400 Subject: [PATCH 6/7] Optimize content handlers --- .../game/quest/content/ContentBargainFail.java | 9 ++------- .../game/quest/content/ContentBargainLessThan.java | 9 ++------- .../game/quest/content/ContentBargainSuccess.java | 10 ++-------- .../game/quest/content/ContentFinishGivingItem.java | 7 ++----- 4 files changed, 8 insertions(+), 27 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentBargainFail.java b/src/main/java/emu/grasscutter/game/quest/content/ContentBargainFail.java index 08f1bda24..3f88e0143 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/ContentBargainFail.java +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentBargainFail.java @@ -9,12 +9,7 @@ import emu.grasscutter.net.proto.BargainResultTypeOuterClass.BargainResultType; public final class ContentBargainFail extends BaseContent { @Override public boolean execute(GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { - var bargain = quest.getOwner() - .getPlayerProgress() - .getBargains() - .get(condition.getParam()[0]); - if (bargain == null) return false; - - return bargain.getResult() == BargainResultType.BARGAIN_COMPLETE_FAIL; + return condition.getParam()[0] == params[0] && + condition.getParam()[1] == params[1]; } } diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentBargainLessThan.java b/src/main/java/emu/grasscutter/game/quest/content/ContentBargainLessThan.java index b6da9796d..88ee00356 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/ContentBargainLessThan.java +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentBargainLessThan.java @@ -9,12 +9,7 @@ import emu.grasscutter.net.proto.BargainResultTypeOuterClass.BargainResultType; public final class ContentBargainLessThan extends BaseContent { @Override public boolean execute(GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { - var bargain = quest.getOwner() - .getPlayerProgress() - .getBargains() - .get(condition.getParam()[0]); - if (bargain == null) return false; - - return bargain.getResult() == BargainResultType.BARGAIN_SINGLE_FAIL; + return condition.getParam()[0] == params[0] && + condition.getParam()[1] == params[1]; } } diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentBargainSuccess.java b/src/main/java/emu/grasscutter/game/quest/content/ContentBargainSuccess.java index 1deeeeb52..8200355d1 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/ContentBargainSuccess.java +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentBargainSuccess.java @@ -3,18 +3,12 @@ package emu.grasscutter.game.quest.content; import emu.grasscutter.data.excels.quest.QuestData; import emu.grasscutter.game.quest.*; import emu.grasscutter.game.quest.enums.QuestContent; -import emu.grasscutter.net.proto.BargainResultTypeOuterClass.BargainResultType; @QuestValueContent(QuestContent.QUEST_CONTENT_BARGAIN_SUCC) public final class ContentBargainSuccess extends BaseContent { @Override public boolean execute(GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { - var bargain = quest.getOwner() - .getPlayerProgress() - .getBargains() - .get(condition.getParam()[0]); - if (bargain == null) return false; - - return bargain.getResult() == BargainResultType.BARGAIN_COMPLETE_SUCC; + return condition.getParam()[0] == params[0] && + condition.getParam()[1] == params[1]; } } diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentFinishGivingItem.java b/src/main/java/emu/grasscutter/game/quest/content/ContentFinishGivingItem.java index 88f2a7491..61f6605c9 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/ContentFinishGivingItem.java +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentFinishGivingItem.java @@ -8,10 +8,7 @@ import emu.grasscutter.game.quest.enums.QuestContent; public final class ContentFinishGivingItem extends BaseContent { @Override public boolean execute(GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { - var giveAction = quest.getOwner() - .getPlayerProgress() - .getItemGivings() - .get(condition.getParam()[0]); - return giveAction != null && giveAction.isFinished(); + return condition.getParam()[0] == params[0] && + condition.getParam()[1] == params[1]; } } From e0f8c03e3936c631e6f9eadcab1faad2ad7a171f Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Sun, 13 Aug 2023 15:56:19 -0400 Subject: [PATCH 7/7] Move more logs to debug constants --- .../actions/ActionGenerateElemBall.java | 9 ++++++--- .../game/ability/actions/ActionHealHP.java | 18 ++++++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/ability/actions/ActionGenerateElemBall.java b/src/main/java/emu/grasscutter/game/ability/actions/ActionGenerateElemBall.java index f42018b46..7073e77f2 100644 --- a/src/main/java/emu/grasscutter/game/ability/actions/ActionGenerateElemBall.java +++ b/src/main/java/emu/grasscutter/game/ability/actions/ActionGenerateElemBall.java @@ -2,7 +2,7 @@ package emu.grasscutter.game.ability.actions; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; -import emu.grasscutter.Grasscutter; +import emu.grasscutter.*; import emu.grasscutter.data.GameData; import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction; import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction.DropType; @@ -81,8 +81,11 @@ public final class ActionGenerateElemBall extends AbilityActionHandler { return false; } - Grasscutter.getLogger() - .debug("Generating {} of {} element balls", amountGenerated, action.configID); + if (DebugConstants.LOG_ABILITIES) { + Grasscutter.getLogger() + .debug("Generating {} of {} element balls", amountGenerated, action.configID); + } + for (int i = 0; i < amountGenerated; i++) { EntityItem energyBall = new EntityItem( diff --git a/src/main/java/emu/grasscutter/game/ability/actions/ActionHealHP.java b/src/main/java/emu/grasscutter/game/ability/actions/ActionHealHP.java index baf50f7d6..2a0d22c8c 100644 --- a/src/main/java/emu/grasscutter/game/ability/actions/ActionHealHP.java +++ b/src/main/java/emu/grasscutter/game/ability/actions/ActionHealHP.java @@ -1,7 +1,7 @@ package emu.grasscutter.game.ability.actions; import com.google.protobuf.ByteString; -import emu.grasscutter.Grasscutter; +import emu.grasscutter.*; import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction; import emu.grasscutter.game.ability.Ability; import emu.grasscutter.game.entity.EntityClientGadget; @@ -22,12 +22,14 @@ public final class ActionHealHP extends AbilityActionHandler { ownerGadget .getScene() .getEntityById(ownerGadget.getOwnerEntityId()); // Caster for EntityClientGadget - Grasscutter.getLogger() - .debug( - "Owner {} has top owner {}: {}", - ability.getOwner(), - ownerGadget.getOwnerEntityId(), - owner); + if (DebugConstants.LOG_ABILITIES) { + Grasscutter.getLogger() + .debug( + "Owner {} has top owner {}: {}", + ability.getOwner(), + ownerGadget.getOwnerEntityId(), + owner); + } } if (owner == null) return false; @@ -76,7 +78,7 @@ public final class ActionHealHP extends AbilityActionHandler { amountToRegenerate += amountByTargetMaxHPRatio * target.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); - Grasscutter.getLogger().debug(">>> Healing {} without ratios", amountToRegenerate); + Grasscutter.getLogger().trace("Healing {} without ratios", amountToRegenerate); target.heal( amountToRegenerate * abilityRatio * action.healRatio.get(ability, 1f), action.muteHealEffect);