From 48d1e026ef055e1b01ad99e150526be1c07d63f0 Mon Sep 17 00:00:00 2001 From: Akka <104902222+Akka0@users.noreply.github.com> Date: Thu, 5 May 2022 01:06:13 +0800 Subject: [PATCH] Add Support of Item Combine (#513) * Add Support of Item Combine * Add Support of Item Combine Co-authored-by: Melledy <52122272+Melledy@users.noreply.github.com> --- .../java/emu/grasscutter/data/GameData.java | 10 +- .../emu/grasscutter/data/def/CombineData.java | 167 +++++++++++++++++- .../game/combine/CombineManger.java | 83 +++++++++ .../game/combine/CombineResult.java | 45 +++++ .../grasscutter/server/game/GameServer.java | 11 +- .../server/packet/recv/HandlerCombineReq.java | 27 +++ 6 files changed, 335 insertions(+), 8 deletions(-) create mode 100644 src/main/java/emu/grasscutter/game/combine/CombineManger.java create mode 100644 src/main/java/emu/grasscutter/game/combine/CombineResult.java diff --git a/src/main/java/emu/grasscutter/data/GameData.java b/src/main/java/emu/grasscutter/data/GameData.java index 6572ab673..e97e1e7de 100644 --- a/src/main/java/emu/grasscutter/data/GameData.java +++ b/src/main/java/emu/grasscutter/data/GameData.java @@ -66,8 +66,9 @@ public class GameData { private static final Int2ObjectMap dailyDungeonDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap dungeonDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap shopGoodsDataMap = new Int2ObjectOpenHashMap<>(); + private static final Int2ObjectMap combineDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap rewardPreviewDataMap = new Int2ObjectOpenHashMap<>(); - + // Cache private static Map> fetters = new HashMap<>(); private static Map> shopGoods = new HashMap<>(); @@ -301,9 +302,6 @@ public class GameData { return shopGoods; } - /** - * @return the rewardpreviewdatamap - */ public static Int2ObjectMap getRewardPreviewDataMap() { return rewardPreviewDataMap; } @@ -311,4 +309,8 @@ public class GameData { public static IntList getScenePointIdList() { return scenePointIdList; } + + public static Int2ObjectMap getCombineDataMap() { + return combineDataMap; + } } diff --git a/src/main/java/emu/grasscutter/data/def/CombineData.java b/src/main/java/emu/grasscutter/data/def/CombineData.java index c4c19794f..bfcf6af68 100644 --- a/src/main/java/emu/grasscutter/data/def/CombineData.java +++ b/src/main/java/emu/grasscutter/data/def/CombineData.java @@ -1,10 +1,173 @@ package emu.grasscutter.data.def; +import emu.grasscutter.data.GameResource; import emu.grasscutter.data.ResourceType; +import java.util.List; +import java.util.stream.Collectors; + @ResourceType(name = "CombineExcelConfigData.json") -public class CombineData { +public class CombineData extends GameResource { - + private int CombineId; + private int PlayerLevel; + + private boolean IsDefaultShow; + + private int CombineType; + + private int SubCombineType; + + private int ResultItemId; + + private int ResultItemCount; + + private int ScoinCost; + + private List RandomItems; + + private List MaterialItems; + + private long EffectDescTextMapHash; + + private String RecipeType; + + @Override + public int getId() { + return this.CombineId; + } + + @Override + public void onLoad() { + super.onLoad(); + // clean data + RandomItems = RandomItems.stream().filter(item -> item.Id > 0).collect(Collectors.toList()); + MaterialItems = MaterialItems.stream().filter(item -> item.Id > 0).collect(Collectors.toList()); + } + + public static class CombineItemPair { + + private int Id; + + private int Count; + + public CombineItemPair(int id, int count) { + Id = id; + Count = count; + } + + public int getId() { + return Id; + } + + public void setId(int id) { + Id = id; + } + + public int getCount() { + return Count; + } + + public void setCount(int count) { + Count = count; + } + } + + public int getCombineId() { + return CombineId; + } + + public void setCombineId(int combineId) { + CombineId = combineId; + } + + public int getPlayerLevel() { + return PlayerLevel; + } + + public void setPlayerLevel(int playerLevel) { + PlayerLevel = playerLevel; + } + + public boolean isDefaultShow() { + return IsDefaultShow; + } + + public void setDefaultShow(boolean defaultShow) { + IsDefaultShow = defaultShow; + } + + public int getCombineType() { + return CombineType; + } + + public void setCombineType(int combineType) { + CombineType = combineType; + } + + public int getSubCombineType() { + return SubCombineType; + } + + public void setSubCombineType(int subCombineType) { + SubCombineType = subCombineType; + } + + public int getResultItemId() { + return ResultItemId; + } + + public void setResultItemId(int resultItemId) { + ResultItemId = resultItemId; + } + + public int getResultItemCount() { + return ResultItemCount; + } + + public void setResultItemCount(int resultItemCount) { + ResultItemCount = resultItemCount; + } + + public int getScoinCost() { + return ScoinCost; + } + + public void setScoinCost(int scoinCost) { + ScoinCost = scoinCost; + } + + public List getRandomItems() { + return RandomItems; + } + + public void setRandomItems(List randomItems) { + RandomItems = randomItems; + } + + public List getMaterialItems() { + return MaterialItems; + } + + public void setMaterialItems(List materialItems) { + MaterialItems = materialItems; + } + + public long getEffectDescTextMapHash() { + return EffectDescTextMapHash; + } + + public void setEffectDescTextMapHash(long effectDescTextMapHash) { + EffectDescTextMapHash = effectDescTextMapHash; + } + + public String getRecipeType() { + return RecipeType; + } + + public void setRecipeType(String recipeType) { + RecipeType = recipeType; + } } + diff --git a/src/main/java/emu/grasscutter/game/combine/CombineManger.java b/src/main/java/emu/grasscutter/game/combine/CombineManger.java new file mode 100644 index 000000000..478edfedb --- /dev/null +++ b/src/main/java/emu/grasscutter/game/combine/CombineManger.java @@ -0,0 +1,83 @@ +package emu.grasscutter.game.combine; + +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.def.CombineData; +import emu.grasscutter.game.inventory.ItemType; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.net.proto.RetcodeOuterClass; +import emu.grasscutter.server.game.GameServer; +import emu.grasscutter.server.packet.send.PacketCombineRsp; +import it.unimi.dsi.fastutil.Pair; + +import java.util.List; + +public class CombineManger { + private final GameServer gameServer; + + public GameServer getGameServer() { + return gameServer; + } + + public CombineManger(GameServer gameServer) { + this.gameServer = gameServer; + } + + public CombineResult combineItem(Player player, int cid, int count){ + // check config exist + if(!GameData.getCombineDataMap().containsKey(cid)){ + player.getWorld().getHost().sendPacket(new PacketCombineRsp()); + return null; + } + + CombineData combineData = GameData.getCombineDataMap().get(cid); + + if(combineData.getPlayerLevel() > player.getLevel()){ + return null; + } + // check enough + var enough = combineData.getMaterialItems().stream() + .filter(item -> player.getInventory() + .getInventoryTab(ItemType.ITEM_MATERIAL) + .getItemById(item.getId()) + .getCount() < item.getCount() * count + ) + .findAny() + .isEmpty(); + + // if not enough + if(!enough){ + player.getWorld().getHost().sendPacket( + new PacketCombineRsp(RetcodeOuterClass.Retcode.RET_ITEM_COMBINE_COUNT_NOT_ENOUGH_VALUE) + ); + return null; + } + if (player.getMora() >= combineData.getScoinCost()) { + player.setMora(player.getMora() - combineData.getScoinCost() * count); + } else { + return null; + } + // try to remove materials + combineData.getMaterialItems().stream() + .map(item -> Pair.of(player.getInventory() + .getInventoryTab(ItemType.ITEM_MATERIAL) + .getItemById(item.getId()) + ,item.getCount() * count) + ) + .forEach(item -> player.getInventory().removeItem(item.first(), item.second())); + + // make the result + player.getInventory().addItem(combineData.getResultItemId(), + combineData.getResultItemCount() * count); + + CombineResult result = new CombineResult(); + result.setMaterial(List.of()); + result.setResult(List.of(new CombineData.CombineItemPair(combineData.getResultItemId(), + combineData.getResultItemCount() * count))); + // TODO lucky characters + result.setExtra(List.of()); + result.setBack(List.of()); + + return result; + } + +} diff --git a/src/main/java/emu/grasscutter/game/combine/CombineResult.java b/src/main/java/emu/grasscutter/game/combine/CombineResult.java new file mode 100644 index 000000000..f67a64737 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/combine/CombineResult.java @@ -0,0 +1,45 @@ +package emu.grasscutter.game.combine; + +import emu.grasscutter.data.def.CombineData; + +import java.util.List; + +public class CombineResult { + private List material; + private List result; + private List extra; + private List back; + + public List getMaterial() { + return material; + } + + public void setMaterial(List material) { + this.material = material; + } + + public List getResult() { + return result; + } + + public void setResult(List result) { + this.result = result; + } + + public List getExtra() { + return extra; + } + + public void setExtra(List extra) { + this.extra = extra; + } + + public List getBack() { + return back; + } + + public void setBack(List back) { + this.back = back; + } + +} diff --git a/src/main/java/emu/grasscutter/server/game/GameServer.java b/src/main/java/emu/grasscutter/server/game/GameServer.java index c2ddcf1bb..db4a8c32b 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServer.java +++ b/src/main/java/emu/grasscutter/server/game/GameServer.java @@ -5,6 +5,7 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.command.CommandMap; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.Account; +import emu.grasscutter.game.combine.CombineManger; import emu.grasscutter.game.drop.DropManager; import emu.grasscutter.game.dungeons.DungeonManager; import emu.grasscutter.game.gacha.GachaManager; @@ -44,7 +45,9 @@ public final class GameServer extends KcpServer { private final CommandMap commandMap; private final TaskMap taskMap; private final DropManager dropManager; - + + private final CombineManger combineManger; + public GameServer(InetSocketAddress address) { super(address); @@ -63,7 +66,8 @@ public final class GameServer extends KcpServer { this.commandMap = new CommandMap(true); this.taskMap = new TaskMap(true); this.dropManager = new DropManager(this); - + this.combineManger = new CombineManger(this); + // Schedule game loop. Timer gameLoop = new Timer(); gameLoop.scheduleAtFixedRate(new TimerTask() { @@ -125,6 +129,9 @@ public final class GameServer extends KcpServer { return this.commandMap; } + public CombineManger getCombineManger(){ + return this.combineManger; + } public TaskMap getTaskMap() { return this.taskMap; } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombineReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombineReq.java index d5ff27a15..23a522b25 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombineReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombineReq.java @@ -1,10 +1,16 @@ package emu.grasscutter.server.packet.recv; +import emu.grasscutter.data.def.CombineData; import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.CombineReqOuterClass; +import emu.grasscutter.net.proto.ItemParamOuterClass; import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketCombineRsp; + +import java.util.List; +import java.util.stream.Collectors; @Opcodes(PacketOpcodes.CombineReq) public class HandlerCombineReq extends PacketHandler { @@ -14,7 +20,28 @@ public class HandlerCombineReq extends PacketHandler { CombineReqOuterClass.CombineReq req = CombineReqOuterClass.CombineReq.parseFrom(payload); + var result = session.getServer().getCombineManger() + .combineItem(session.getPlayer(), req.getCombineId(), req.getCombineCount()); + + if(result == null){ + return; + } + + session.send(new PacketCombineRsp(req, + toItemParamList(result.getMaterial()), + toItemParamList(result.getResult()), + toItemParamList(result.getExtra()), + toItemParamList(result.getBack()), + toItemParamList(result.getBack()))); } + private List toItemParamList(List list){ + return list.stream() + .map(item -> ItemParamOuterClass.ItemParam.newBuilder() + .setItemId(item.getId()) + .setCount(item.getCount()) + .build()) + .collect(Collectors.toList()); + } }