diff --git a/proto/ForgeDataNotify.proto b/proto/ForgeDataNotify.proto new file mode 100644 index 000000000..d5b06ba24 --- /dev/null +++ b/proto/ForgeDataNotify.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; + +option java_package = "emu.grasscutter.net.proto"; + +import "ForgeQueueData.proto"; + +// CmdId: 648 +// EnetChannelId: 0 +// EnetIsReliable: true +message ForgeDataNotify { + repeated uint32 forge_id_list = 13; + uint32 max_queue_num = 15; + map forge_queue_map = 1; +} diff --git a/proto/ForgeFormulaDataNotify.proto b/proto/ForgeFormulaDataNotify.proto new file mode 100644 index 000000000..940764c02 --- /dev/null +++ b/proto/ForgeFormulaDataNotify.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +option java_package = "emu.grasscutter.net.proto"; + +// CmdId: 673 +// EnetChannelId: 0 +// EnetIsReliable: true +message ForgeFormulaDataNotify { + uint32 forge_id = 11; + bool is_locked = 8; +} diff --git a/proto/ForgeQueueData.proto b/proto/ForgeQueueData.proto new file mode 100644 index 000000000..c05e110ef --- /dev/null +++ b/proto/ForgeQueueData.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +option java_package = "emu.grasscutter.net.proto"; + +message ForgeQueueData { + uint32 queue_id = 1; + uint32 forge_id = 2; + uint32 finish_count = 3; + uint32 unfinish_count = 4; + uint32 next_finish_timestamp = 5; + uint32 total_finish_timestamp = 6; + uint32 avatar_id = 7; +} diff --git a/src/main/java/emu/grasscutter/data/common/ItemUseData.java b/src/main/java/emu/grasscutter/data/common/ItemUseData.java new file mode 100644 index 000000000..7f905c206 --- /dev/null +++ b/src/main/java/emu/grasscutter/data/common/ItemUseData.java @@ -0,0 +1,24 @@ +package emu.grasscutter.data.common; + +import java.util.List; + +public class ItemUseData { + private String useOp; + private List useParam; + + public String getUseOp() { + return useOp; + } + + public void setUseOp(String useOp) { + this.useOp = useOp; + } + + public List getUseParam() { + return useParam; + } + + public void setUseParam(List useParam) { + this.useParam = useParam; + } +} diff --git a/src/main/java/emu/grasscutter/data/excels/ItemData.java b/src/main/java/emu/grasscutter/data/excels/ItemData.java index adeec4357..fba8d9ec0 100644 --- a/src/main/java/emu/grasscutter/data/excels/ItemData.java +++ b/src/main/java/emu/grasscutter/data/excels/ItemData.java @@ -1,7 +1,10 @@ package emu.grasscutter.data.excels; +import java.util.List; + import emu.grasscutter.data.GameResource; import emu.grasscutter.data.ResourceType; +import emu.grasscutter.data.common.ItemUseData; import emu.grasscutter.game.props.FightProperty; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; @@ -21,6 +24,8 @@ public class ItemData extends GameResource { private int[] destroyReturnMaterial; private int[] destroyReturnMaterialCount; + + private List itemUse; // Food private String foodQuality; @@ -112,7 +117,11 @@ public class ItemData extends GameResource { public int[] getDestroyReturnMaterialCount(){ return this.destroyReturnMaterialCount; } - + + public List getItemUse() { + return itemUse; + } + public long getNameTextMapHash(){ return this.nameTextMapHash; } diff --git a/src/main/java/emu/grasscutter/game/managers/InventoryManager.java b/src/main/java/emu/grasscutter/game/managers/InventoryManager.java index f32299ee8..054d350d5 100644 --- a/src/main/java/emu/grasscutter/game/managers/InventoryManager.java +++ b/src/main/java/emu/grasscutter/game/managers/InventoryManager.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; import emu.grasscutter.data.binout.OpenConfigEntry; import emu.grasscutter.data.binout.OpenConfigEntry.SkillPointModifier; @@ -28,6 +29,7 @@ import emu.grasscutter.game.shop.ShopChestBatchUseTable; import emu.grasscutter.game.shop.ShopChestTable; import emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam; import emu.grasscutter.net.proto.MaterialInfoOuterClass.MaterialInfo; +import emu.grasscutter.server.packet.send.PacketForgeFormulaDataNotify; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.packet.send.*; import emu.grasscutter.utils.Utils; @@ -822,6 +824,7 @@ public class InventoryManager { int used = 0; // Use + Grasscutter.getLogger().info("Item: {}", useItem.getItemData().getId()); switch (useItem.getItemData().getMaterialType()) { case MATERIAL_FOOD: if (useItem.getItemData().getUseTarget().equals("ITEM_USE_TARGET_SPECIFY_DEAD_AVATAR")) { @@ -842,6 +845,24 @@ public class InventoryManager { used = player.getTeamManager().healAvatar(target, SatiationParams[0], SatiationParams[1]) ? 1 : 0; } break; + case MATERIAL_CONSUME: + // Make sure we have usage data for this material. + if (useItem.getItemData().getItemUse() == null) { + break; + } + + // Handle forging blueprints. + if (useItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_FORGE")) { + // Determine the forging item we should unlock. + int forgeId = Integer.parseInt(useItem.getItemData().getItemUse().get(0).getUseParam().get(0)); + + // Tell the client that this blueprint is now unlocked. + player.sendPacket(new PacketForgeFormulaDataNotify(forgeId)); + + // Use up the blueprint item. + used = 1; + } + break; case MATERIAL_CHEST: List shopChestTableList = player.getServer().getShopManager().getShopChestData(); List rewardItemList = new ArrayList<>(); diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index d2d865468..b5ab55e33 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -1264,6 +1264,7 @@ public class Player { session.send(new PacketWidgetGadgetAllDataNotify()); session.send(new PacketPlayerHomeCompInfoNotify(this)); session.send(new PacketHomeComfortInfoNotify(this)); + session.send(new PacketForgeDataNotify(this)); getTodayMoonCard(); // The timer works at 0:0, some users log in after that, use this method to check if they have received a reward today or not. If not, send the reward. diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketForgeDataNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketForgeDataNotify.java new file mode 100644 index 000000000..3f22e62a9 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketForgeDataNotify.java @@ -0,0 +1,31 @@ +package emu.grasscutter.server.packet.send; + +import java.util.List; + +import dev.morphia.AdvancedDatastore; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.ForgeDataNotifyOuterClass.ForgeDataNotify; +import emu.grasscutter.net.proto.ForgeQueueDataOuterClass.ForgeQueueData; + +public class PacketForgeDataNotify extends BasePacket { + + public PacketForgeDataNotify(Player player) { + super(PacketOpcodes.ForgeDataNotify); + + int adventureRank = player.getLevel(); + int numQueues = + (adventureRank >= 15) ? 4 + : (adventureRank >= 10) ? 3 + : (adventureRank >= 5) ? 2 + : 1; + + ForgeDataNotify proto = ForgeDataNotify.newBuilder() + .addAllForgeIdList(List.of(14017, 14009, 14008)) + .setMaxQueueNum(numQueues) + .build(); + + this.setData(proto); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketForgeFormulaDataNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketForgeFormulaDataNotify.java new file mode 100644 index 000000000..46f180280 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketForgeFormulaDataNotify.java @@ -0,0 +1,19 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.ForgeFormulaDataNotifyOuterClass.ForgeFormulaDataNotify; + +public class PacketForgeFormulaDataNotify extends BasePacket { + + public PacketForgeFormulaDataNotify(int itemId) { + super(PacketOpcodes.ForgeFormulaDataNotify); + + ForgeFormulaDataNotify proto = ForgeFormulaDataNotify.newBuilder() + .setForgeId(itemId) + .setIsLocked(false) + .build(); + + this.setData(proto); + } +}