From 3f7b0d366d9e42e20738b49c20d9653e9b9647b0 Mon Sep 17 00:00:00 2001 From: Melledy <121644117+Melledy@users.noreply.github.com> Date: Sun, 9 Nov 2025 07:22:21 -0800 Subject: [PATCH] Implement infinite arena --- src/main/java/emu/nebula/data/GameData.java | 3 + .../data/resources/InfinityTowerLevelDef.java | 72 ++++++++++++++++ .../infinitytower/InfinityTowerManager.java | 82 +++++++++++++++++++ .../java/emu/nebula/game/player/Player.java | 3 + .../HandlerInfinityTowerApplyReq.java | 28 +++++++ .../handlers/HandlerInfinityTowerInfoReq.java | 22 +++++ .../HandlerInfinityTowerSettleReq.java | 49 +++++++++++ 7 files changed, 259 insertions(+) create mode 100644 src/main/java/emu/nebula/data/resources/InfinityTowerLevelDef.java create mode 100644 src/main/java/emu/nebula/game/infinitytower/InfinityTowerManager.java create mode 100644 src/main/java/emu/nebula/server/handlers/HandlerInfinityTowerApplyReq.java create mode 100644 src/main/java/emu/nebula/server/handlers/HandlerInfinityTowerInfoReq.java create mode 100644 src/main/java/emu/nebula/server/handlers/HandlerInfinityTowerSettleReq.java diff --git a/src/main/java/emu/nebula/data/GameData.java b/src/main/java/emu/nebula/data/GameData.java index 8673e2f..0af9899 100644 --- a/src/main/java/emu/nebula/data/GameData.java +++ b/src/main/java/emu/nebula/data/GameData.java @@ -80,6 +80,9 @@ public class GameData { @Getter private static DataTable PotentialDataTable = new DataTable<>(); @Getter private static DataTable SubNoteSkillPromoteGroupDataTable = new DataTable<>(); + // Infinity Tower + @Getter private static DataTable InfinityTowerLevelDataTable = new DataTable<>(); + // Vampire survivor @Getter private static DataTable VampireSurvivorDataTable = new DataTable<>(); @Getter private static DataTable FateCardDataTable = new DataTable<>(); diff --git a/src/main/java/emu/nebula/data/resources/InfinityTowerLevelDef.java b/src/main/java/emu/nebula/data/resources/InfinityTowerLevelDef.java new file mode 100644 index 0000000..9dda7eb --- /dev/null +++ b/src/main/java/emu/nebula/data/resources/InfinityTowerLevelDef.java @@ -0,0 +1,72 @@ +package emu.nebula.data.resources; + +import java.util.ArrayList; +import java.util.List; + +import emu.nebula.data.BaseDef; +import emu.nebula.data.ResourceType; +import emu.nebula.game.instance.InstanceRewardParam; +import emu.nebula.game.inventory.ItemParamMap; +import emu.nebula.util.JsonUtils; + +import lombok.Getter; + +@Getter +@ResourceType(name = "InfinityTowerLevel.json") +public class InfinityTowerLevelDef extends BaseDef { + private int Id; + private String BaseAwardPreview; + + private transient List rewards; + + @Override + public int getId() { + return Id; + } + + public int getEnergyConsume() { + return 0; + } + + public ItemParamMap generateRewards() { + var map = new ItemParamMap(); + + for (var param : this.getRewards()) { + map.add(param.getId(), param.getRandomCount()); + } + + return map; + } + + @Override + public void onLoad() { + // Init reward lists + this.rewards = new ArrayList<>(); + + // Parse rewards + var awards = JsonUtils.decodeList(this.BaseAwardPreview, int[].class); + if (awards == null) { + return; + } + + for (int[] award : awards) { + int itemId = award[0]; + int min = award[1]; + int max = award.length >= 4 ? award[2] : min; + boolean isFirst = award[award.length - 1] == 1; + + if (min == -1) { + min = 0; + max = 1; + } + + var reward = new InstanceRewardParam(itemId, min, max); + + if (isFirst) { + + } else { + this.rewards.add(reward); + } + } + } +} diff --git a/src/main/java/emu/nebula/game/infinitytower/InfinityTowerManager.java b/src/main/java/emu/nebula/game/infinitytower/InfinityTowerManager.java new file mode 100644 index 0000000..d2610ee --- /dev/null +++ b/src/main/java/emu/nebula/game/infinitytower/InfinityTowerManager.java @@ -0,0 +1,82 @@ +package emu.nebula.game.infinitytower; + +import dev.morphia.annotations.Id; +import emu.nebula.data.GameData; +import emu.nebula.game.player.Player; +import emu.nebula.game.player.PlayerChangeInfo; +import emu.nebula.game.player.PlayerManager; + +import lombok.Getter; + +@Getter +public class InfinityTowerManager extends PlayerManager { + @Id + private int uid; + + private transient int levelId; + private transient long buildId; + + @Deprecated // Morphia only + public InfinityTowerManager() { + + } + + public InfinityTowerManager(Player player) { + super(player); + this.uid = player.getUid(); + + //this.save(); + } + + public int getBountyLevel() { + return 1; + } + + public boolean apply(int levelId, long buildId) { + // Verify level data + var data = GameData.getInfinityTowerLevelDataTable().get(levelId); + if (data == null) { + return false; + } + + // Set level id + this.levelId = levelId; + + // Set build id + if (buildId >= 0) { + this.buildId = buildId; + } + + // Success + return true; + } + + public PlayerChangeInfo settle(int value) { + // Verify level data + var data = GameData.getInfinityTowerLevelDataTable().get(this.getLevelId()); + if (data == null) { + return null; + } + + // Init change info + var change = new PlayerChangeInfo(); + + // TODO + if (value != 1) { + return change; + } + + // Calculate rewards + var rewards = data.generateRewards(); + + // Add items + this.getPlayer().getInventory().addItems(rewards, change); + + // Set in change info + change.setExtraData(rewards); + + // Success + return change.setSuccess(true); + } + +} diff --git a/src/main/java/emu/nebula/game/player/Player.java b/src/main/java/emu/nebula/game/player/Player.java index 77cb904..1736553 100644 --- a/src/main/java/emu/nebula/game/player/Player.java +++ b/src/main/java/emu/nebula/game/player/Player.java @@ -14,6 +14,7 @@ import emu.nebula.game.account.Account; import emu.nebula.game.character.CharacterStorage; import emu.nebula.game.formation.FormationManager; import emu.nebula.game.gacha.GachaManager; +import emu.nebula.game.infinitytower.InfinityTowerManager; import emu.nebula.game.instance.InstanceManager; import emu.nebula.game.inventory.Inventory; import emu.nebula.game.mail.Mailbox; @@ -71,6 +72,7 @@ public class Player implements GameDatabaseObject { // Managers private final transient CharacterStorage characters; private final transient GachaManager gachaManager; + private final transient InfinityTowerManager infinityTowerManager; private final transient VampireSurvivorManager vampireSurvivorManager; private final transient ScoreBossManager scoreBossManager; @@ -91,6 +93,7 @@ public class Player implements GameDatabaseObject { // Init player managers this.characters = new CharacterStorage(this); this.gachaManager = new GachaManager(this); + this.infinityTowerManager = new InfinityTowerManager(this); this.vampireSurvivorManager = new VampireSurvivorManager(this); this.scoreBossManager = new ScoreBossManager(this); diff --git a/src/main/java/emu/nebula/server/handlers/HandlerInfinityTowerApplyReq.java b/src/main/java/emu/nebula/server/handlers/HandlerInfinityTowerApplyReq.java new file mode 100644 index 0000000..bd97287 --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerInfinityTowerApplyReq.java @@ -0,0 +1,28 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.InfinityTowerApply.InfinityTowerApplyReq; +import emu.nebula.net.HandlerId; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.infinity_tower_apply_req) +public class HandlerInfinityTowerApplyReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Template hanlder + var req = InfinityTowerApplyReq.parseFrom(message); + + // Apply + boolean success = session.getPlayer().getInfinityTowerManager().apply(req.getLevelId(), req.getBuildId()); + + if (!success) { + return session.encodeMsg(NetMsgId.infinity_tower_apply_failed_ack); + } + + // Encode and send + return session.encodeMsg(NetMsgId.infinity_tower_apply_succeed_ack); + } + +} diff --git a/src/main/java/emu/nebula/server/handlers/HandlerInfinityTowerInfoReq.java b/src/main/java/emu/nebula/server/handlers/HandlerInfinityTowerInfoReq.java new file mode 100644 index 0000000..2d4f3f6 --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerInfinityTowerInfoReq.java @@ -0,0 +1,22 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.InfinityTowerInfo.InfinityTowerInfoResp; +import emu.nebula.net.HandlerId; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.infinity_tower_info_req) +public class HandlerInfinityTowerInfoReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Build response + var rsp = InfinityTowerInfoResp.newInstance() + .setBountyLevel(0); + + // Encode and send + return session.encodeMsg(NetMsgId.infinity_tower_info_succeed_ack, rsp); + } + +} diff --git a/src/main/java/emu/nebula/server/handlers/HandlerInfinityTowerSettleReq.java b/src/main/java/emu/nebula/server/handlers/HandlerInfinityTowerSettleReq.java new file mode 100644 index 0000000..cc6a916 --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerInfinityTowerSettleReq.java @@ -0,0 +1,49 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.InfinityTowerSettle.InfinityTowerSettleReq; +import emu.nebula.proto.InfinityTowerSettle.InfinityTowerSettleResp; +import emu.nebula.net.HandlerId; +import emu.nebula.game.inventory.ItemParamMap; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.infinity_tower_settle_req) +public class HandlerInfinityTowerSettleReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Parse request + var req = InfinityTowerSettleReq.parseFrom(message); + + // Settle + var manager = session.getPlayer().getInfinityTowerManager(); + var change = manager.settle(req.getValue()); + + if (change == null) { + return session.encodeMsg(NetMsgId.infinity_tower_settle_failed_ack); + } + + // Get next level + int nextLevel = manager.getLevelId() + 1; + + // Try to apply for next level + if (!manager.apply(nextLevel, -1)) { + nextLevel = 0; + } + + // Build response + var rsp = InfinityTowerSettleResp.newInstance() + .setNextLevelId(nextLevel) + .setBountyLevel(manager.getBountyLevel()) + .setChange(change.toProto()); + + if (change.getExtraData() != null && change.getExtraData() instanceof ItemParamMap rewards) { + rewards.toItemTemplateStream().forEach(rsp::addShow); + } + + // Encode and send + return session.encodeMsg(NetMsgId.infinity_tower_settle_succeed_ack, rsp); + } + +}