diff --git a/src/main/java/emu/nebula/data/GameData.java b/src/main/java/emu/nebula/data/GameData.java index 737a419..13bf2c8 100644 --- a/src/main/java/emu/nebula/data/GameData.java +++ b/src/main/java/emu/nebula/data/GameData.java @@ -49,8 +49,9 @@ public class GameData { @Getter private static DataTable ItemDataTable = new DataTable<>(); @Getter private static DataTable ProductionDataTable = new DataTable<>(); @Getter private static DataTable PlayerHeadDataTable = new DataTable<>(); - @Getter private static DataTable titleDataTable = new DataTable<>(); - @Getter private static DataTable honorDataTable = new DataTable<>(); + @Getter private static DataTable TitleDataTable = new DataTable<>(); + @Getter private static DataTable HonorDataTable = new DataTable<>(); + @Getter private static DataTable DropDataTable = new DataTable<>(); // ===== Shops ===== @Getter private static DataTable MallMonthlyCardDataTable = new DataTable<>(); @@ -80,6 +81,7 @@ public class GameData { @Getter private static DataTable GachaATypeProbDataTable = new DataTable<>(); @Getter private static DataTable GachaDataTable = new DataTable<>(); @Getter private static DataTable GachaNewbieDataTable = new DataTable<>(); + @Getter private static DataTable GachaRewardDataTable = new DataTable<>(); @Getter private static DataTable GachaStorageDataTable = new DataTable<>(); @Getter private static DataTable GachaTypeDataTable = new DataTable<>(); diff --git a/src/main/java/emu/nebula/data/resources/DropDef.java b/src/main/java/emu/nebula/data/resources/DropDef.java new file mode 100644 index 0000000..116d03e --- /dev/null +++ b/src/main/java/emu/nebula/data/resources/DropDef.java @@ -0,0 +1,23 @@ +package emu.nebula.data.resources; + +import emu.nebula.data.BaseDef; +import emu.nebula.data.ResourceType; + +import lombok.Getter; + +@Getter +@ResourceType(name = "Drop.json") +public class DropDef extends BaseDef { + private int DropId; + private int PkgId; + + @Override + public int getId() { + return DropId; + } + + @Override + public void onLoad() { + + } +} diff --git a/src/main/java/emu/nebula/data/resources/DropPkgDef.java b/src/main/java/emu/nebula/data/resources/DropPkgDef.java index 89fecd7..163c4a1 100644 --- a/src/main/java/emu/nebula/data/resources/DropPkgDef.java +++ b/src/main/java/emu/nebula/data/resources/DropPkgDef.java @@ -1,6 +1,7 @@ package emu.nebula.data.resources; import emu.nebula.data.BaseDef; +import emu.nebula.data.GameData; import emu.nebula.data.ResourceType; import emu.nebula.util.Utils; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; @@ -31,6 +32,14 @@ public class DropPkgDef extends BaseDef { public static int getRandomDrop(int packageId) { var packageList = PACKAGES.get(packageId); + if (packageList == null) { + // Try and get package id from drop data + var dropData = GameData.getDropDataTable().get(packageId); + if (dropData != null) { + packageList = PACKAGES.get(dropData.getPkgId()); + } + } + if (packageList == null) { return 0; } diff --git a/src/main/java/emu/nebula/data/resources/GachaRewardDef.java b/src/main/java/emu/nebula/data/resources/GachaRewardDef.java new file mode 100644 index 0000000..2b1cc2b --- /dev/null +++ b/src/main/java/emu/nebula/data/resources/GachaRewardDef.java @@ -0,0 +1,22 @@ +package emu.nebula.data.resources; + +import emu.nebula.data.BaseDef; +import emu.nebula.data.ResourceType; +import lombok.Getter; + +@Getter +@ResourceType(name = "GachaReward.json") +public class GachaRewardDef extends BaseDef { + private int Id; + private int GachaId; + private int Index; + private int Num; + private int Tid; + private int Qty; + + @Override + public int getId() { + return this.Id; + } + +} diff --git a/src/main/java/emu/nebula/game/gacha/GachaBannerInfo.java b/src/main/java/emu/nebula/game/gacha/GachaBannerInfo.java index 8e37cad..a620544 100644 --- a/src/main/java/emu/nebula/game/gacha/GachaBannerInfo.java +++ b/src/main/java/emu/nebula/game/gacha/GachaBannerInfo.java @@ -5,6 +5,7 @@ import dev.morphia.annotations.Entity; import emu.nebula.data.GameData; import emu.nebula.data.resources.GachaDef; import emu.nebula.proto.GachaInformation.GachaInfo; +import emu.nebula.util.Bitset; import lombok.Getter; import lombok.Setter; @@ -18,6 +19,7 @@ public class GachaBannerInfo { private int total; private boolean usedFirstTen; private boolean usedGuarantee; + private Bitset rewards; @Deprecated //Morphia only public GachaBannerInfo() { @@ -28,6 +30,14 @@ public class GachaBannerInfo { this.id = data.getId(); } + public Bitset getRewards() { + if (this.rewards == null) { + this.rewards = new Bitset(); + } + + return this.rewards; + } + public GachaBannerDraft copyForSpin() { return new GachaBannerDraft(this.total, this.usedFirstTen, this.usedGuarantee); } @@ -67,7 +77,8 @@ public class GachaBannerInfo { .setAMissTimes(missTimesA) .setAupGuaranteeTimes(aupGuaranteeTimes) .setReveFirstTenReward(!showFirstTenBonusHintText) - .setRecvGuaranteeReward(this.isUsedGuarantee()); + .setRecvGuaranteeReward(this.isUsedGuarantee()) + .setRewardsRecords(this.getRewards().toByteArray()); } public record GachaBannerDraft( diff --git a/src/main/java/emu/nebula/game/gacha/GachaModule.java b/src/main/java/emu/nebula/game/gacha/GachaModule.java index 0371821..e8de7ea 100644 --- a/src/main/java/emu/nebula/game/gacha/GachaModule.java +++ b/src/main/java/emu/nebula/game/gacha/GachaModule.java @@ -35,6 +35,7 @@ public class GachaModule extends GameContextModule { var storage = data.getStorageData(); var manager = player.getGachaManager(); + synchronized (manager) { var info = manager.getBannerInfo(data); var pityState = manager.getPityState(data.getStorageId()); @@ -55,6 +56,7 @@ public class GachaModule extends GameContextModule { public PlayerChangeInfo recvGuarantee(Player player, int bannerId) { var manager = player.getGachaManager(); + synchronized (manager) { var info = manager.findBannerInfo(bannerId); if (info == null) { @@ -79,11 +81,54 @@ public class GachaModule extends GameContextModule { } info.setUsedGuarantee(true); + // Save to database manager.saveBanner(info); + + // Complete return player.getInventory().addItem(data.getGuaranteeTid(), data.getGuaranteeQty()); } } + public PlayerChangeInfo recvReward(Player player, int rewardId) { + // Get reward data + var rewardData = GameData.getGachaRewardDataTable().get(rewardId); + if (rewardData == null) { + return null; + } + + // Get banner data + var data = GameData.getGachaDataTable().get(rewardData.getGachaId()); + if (data == null || !data.isActiveAt(Nebula.getCurrentServerTime())) { + return null; + } + + var manager = player.getGachaManager(); + + synchronized (manager) { + // Get banner info + var info = manager.getBannerInfo(data); + + // Make sure the reward is unlocked + if (info.getTotal() < rewardData.getNum()) { + return null; + } + + // Make sure we haven't already claimed the reward + if (info.getRewards().isSet(rewardData.getIndex())) { + return null; + } + + // Set claimed + info.getRewards().setBit(rewardData.getIndex()); + + // Save to database + manager.saveBanner(info); + + // Complete + return player.getInventory().addItem(rewardData.getTid(), rewardData.getQty()); + } + } + public List listNewbieInfos(Player player) { return this.newbieGachaModule.listInfos(player); } diff --git a/src/main/java/emu/nebula/server/handlers/HandlerGachaRewardGetReq.java b/src/main/java/emu/nebula/server/handlers/HandlerGachaRewardGetReq.java new file mode 100644 index 0000000..9b6e796 --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerGachaRewardGetReq.java @@ -0,0 +1,29 @@ +package emu.nebula.server.handlers; + +import emu.nebula.Nebula; +import emu.nebula.net.GameSession; +import emu.nebula.net.HandlerId; +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.Public.UI32; + +@HandlerId(NetMsgId.gacha_reward_get_req) +public class HandlerGachaRewardGetReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Parse req + var req = UI32.parseFrom(message); + + // Receive reward + var change = Nebula.getGameContext().getGachaModule().recvReward(session.getPlayer(), req.getValue()); + + if (change == null) { + return session.encodeMsg(NetMsgId.gacha_reward_get_failed_ack); + } + + // Encode and send + return session.encodeMsg(NetMsgId.gacha_reward_get_succeed_ack, change.toProto()); + } + +}