diff --git a/src/main/java/emu/nebula/game/character/CharacterStorage.java b/src/main/java/emu/nebula/game/character/CharacterStorage.java index ba1945e..fb5488f 100644 --- a/src/main/java/emu/nebula/game/character/CharacterStorage.java +++ b/src/main/java/emu/nebula/game/character/CharacterStorage.java @@ -134,8 +134,6 @@ public class CharacterStorage extends PlayerManager { this.characters.put(character.getCharId(), character); }); - - db.getObjects(GameDisc.class, "playerUid", getPlayerUid()).forEach(disc -> { // Get data var data = GameData.getDiscDataTable().get(disc.getDiscId()); diff --git a/src/main/java/emu/nebula/game/formation/Formation.java b/src/main/java/emu/nebula/game/formation/Formation.java index 71f1341..30eb69a 100644 --- a/src/main/java/emu/nebula/game/formation/Formation.java +++ b/src/main/java/emu/nebula/game/formation/Formation.java @@ -44,6 +44,30 @@ public class Formation { return this.discIds[i]; } + public int getCharCount() { + int count = 0; + + for (int id : this.getCharIds()) { + if (id > 0) { + count++; + } + } + + return count; + } + + public int getDiscCount() { + int count = 0; + + for (int id : this.getDiscIds()) { + if (id > 0) { + count++; + } + } + + return count; + } + // Proto public FormationInfo toProto() { diff --git a/src/main/java/emu/nebula/game/tower/StarTowerBuild.java b/src/main/java/emu/nebula/game/tower/StarTowerBuild.java index 9aa71a7..e01302f 100644 --- a/src/main/java/emu/nebula/game/tower/StarTowerBuild.java +++ b/src/main/java/emu/nebula/game/tower/StarTowerBuild.java @@ -1,25 +1,38 @@ package emu.nebula.game.tower; import dev.morphia.annotations.Entity; +import dev.morphia.annotations.Id; +import dev.morphia.annotations.Indexed; +import emu.nebula.data.GameData; +import emu.nebula.database.GameDatabaseObject; import emu.nebula.proto.PublicStarTower.BuildPotential; +import emu.nebula.proto.PublicStarTower.StarTowerBuildBrief; +import emu.nebula.proto.PublicStarTower.StarTowerBuildDetail; import emu.nebula.proto.PublicStarTower.StarTowerBuildInfo; import emu.nebula.proto.PublicStarTower.TowerBuildChar; +import emu.nebula.util.Snowflake; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import lombok.Getter; @Getter -@Entity(useDiscriminator = false) -public class StarTowerBuild { - private int id; +@Entity(value = "star_tower_builds", useDiscriminator = false) +public class StarTowerBuild implements GameDatabaseObject { + @Id + private int uid; + @Indexed + private int playerUid; + private String name; private boolean lock; private boolean preference; private int score; - private int[] charIds; + + private Int2IntMap chars; private int[] discIds; private Int2IntMap potentials; + private Int2IntMap subNoteSkills; @Deprecated public StarTowerBuild() { @@ -27,59 +40,78 @@ public class StarTowerBuild { } public StarTowerBuild(StarTowerInstance instance) { + this.uid = Snowflake.newUid(); + this.playerUid = instance.getPlayer().getUid(); this.name = ""; this.potentials = new Int2IntOpenHashMap(); + this.subNoteSkills = new Int2IntOpenHashMap(); - this.charIds = instance.getChars().stream() - .filter(c -> c.getId() > 0) - .mapToInt(c -> c.getId()) - .toArray(); + // Discs this.discIds = instance.getDiscs().stream() .filter(d -> d.getId() > 0) .mapToInt(d -> d.getId()) .toArray(); + // Characters + this.chars = new Int2IntOpenHashMap(); + + instance.getChars().stream() + .forEach(c -> this.getChars().put(c.getId(), 0)); + // Add potentials for (int id : instance.getPotentials()) { + // Add to potential map this.getPotentials().put(id, instance.getItemCount(id)); + + // Add to character + var potentialData = GameData.getPotentialDataTable().get(id); + if (potentialData != null) { + int charId = potentialData.getCharId(); + this.getChars().put(charId, this.getChars().get(charId) + 1); + } } } - public void setId(StarTowerManager manager) { - this.id = manager.getNextBuildId(); - } - // Proto public StarTowerBuildInfo toProto() { - var proto = StarTowerBuildInfo.newInstance(); - - // Basic data - proto.getMutableBrief() - .setId(this.getId()) - .setName(this.getName()) - .setLock(this.isLock()) - .setPreference(this.isPreference()) - .setScore(this.getScore()) - .addAllDiscIds(this.getDiscIds()); + var proto = StarTowerBuildInfo.newInstance() + .setBrief(this.toBriefProto()) + .setDetail(this.toDetailProto()); + + return proto; + } + + public StarTowerBuildBrief toBriefProto() { + var proto = StarTowerBuildBrief.newInstance() + .setId(this.getUid()) + .setName(this.getName()) + .setLock(this.isLock()) + .setPreference(this.isPreference()) + .setScore(this.getScore()) + .addAllDiscIds(this.getDiscIds()); // Add characters - for (int id : charIds) { + for (var character : this.getChars().int2IntEntrySet()) { var charProto = TowerBuildChar.newInstance() - .setCharId(id); + .setCharId(character.getIntKey()) + .setPotentialCnt(character.getIntValue()); - proto.getMutableBrief().addChars(charProto); + proto.addChars(charProto); } - // Build detail - var detail = proto.getMutableDetail(); + return proto; + } + + public StarTowerBuildDetail toDetailProto() { + var proto = StarTowerBuildDetail.newInstance(); for (var entry : this.getPotentials().int2IntEntrySet()) { var potential = BuildPotential.newInstance() .setPotentialId(entry.getIntKey()) .setLevel(entry.getIntValue()); - detail.getMutablePotentials().add(potential); + proto.getMutablePotentials().add(potential); } return proto; diff --git a/src/main/java/emu/nebula/game/tower/StarTowerManager.java b/src/main/java/emu/nebula/game/tower/StarTowerManager.java index 2b2794b..070be76 100644 --- a/src/main/java/emu/nebula/game/tower/StarTowerManager.java +++ b/src/main/java/emu/nebula/game/tower/StarTowerManager.java @@ -2,11 +2,14 @@ package emu.nebula.game.tower; import dev.morphia.annotations.Entity; import dev.morphia.annotations.Id; +import emu.nebula.Nebula; import emu.nebula.data.GameData; import emu.nebula.database.GameDatabaseObject; import emu.nebula.game.player.Player; import emu.nebula.game.player.PlayerManager; import emu.nebula.proto.StarTowerApply.StarTowerApplyReq; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import lombok.Getter; @Getter @@ -14,9 +17,10 @@ import lombok.Getter; public class StarTowerManager extends PlayerManager implements GameDatabaseObject { @Id private int uid; - private int lastBuildId; + private transient Int2ObjectMap builds; private transient StarTowerInstance instance; + private transient StarTowerBuild lastBuild; @Deprecated // Morphia only public StarTowerManager() { @@ -30,8 +34,12 @@ public class StarTowerManager extends PlayerManager implements GameDatabaseObjec this.save(); } - public int getNextBuildId() { - return ++this.lastBuildId; + public Int2ObjectMap getBuilds() { + if (this.builds == null) { + this.loadFromDatabase(); + } + + return builds; } public StarTowerInstance apply(StarTowerApplyReq req) { @@ -47,6 +55,11 @@ public class StarTowerManager extends PlayerManager implements GameDatabaseObjec return null; } + // Make sure player has at least 3 chars and 3 discs + if (formation.getCharCount() != 3 || formation.getDiscCount() < 3) { + return null; + } + // Create instance this.instance = new StarTowerInstance(this, data, formation, req); @@ -55,12 +68,57 @@ public class StarTowerManager extends PlayerManager implements GameDatabaseObjec } public StarTowerInstance giveUp() { + // Cache instance var instance = this.instance; if (instance != null) { + // Set last build + this.lastBuild = instance.getBuild(); + + // Clear instance this.instance = null; } return instance; } + + public boolean saveBuild(boolean delete, String name, boolean lock) { + // Sanity check + if (this.getLastBuild() == null) { + return false; + } + + // Cache build and clear reference + var build = this.lastBuild; + this.lastBuild = null; + + // Check if the player wants this build or not + if (delete) { + return true; + } + + // Check limit + if (this.getBuilds().size() >= 50) { + return false; + } + + // Add to builds + this.getBuilds().put(build.getUid(), build); + + // Save build to database + build.save(); + + // + return true; + } + + // Database + + private void loadFromDatabase() { + this.builds = new Int2ObjectOpenHashMap<>(); + + Nebula.getGameDatabase().getObjects(StarTowerBuild.class, "playerUid", getPlayerUid()).forEach(build -> { + this.builds.put(build.getUid(), build); + }); + } } diff --git a/src/main/java/emu/nebula/server/handlers/HandlerStarTowerBuildBriefListGetReq.java b/src/main/java/emu/nebula/server/handlers/HandlerStarTowerBuildBriefListGetReq.java index 5d39a78..3efa93e 100644 --- a/src/main/java/emu/nebula/server/handlers/HandlerStarTowerBuildBriefListGetReq.java +++ b/src/main/java/emu/nebula/server/handlers/HandlerStarTowerBuildBriefListGetReq.java @@ -2,6 +2,7 @@ package emu.nebula.server.handlers; import emu.nebula.net.NetHandler; import emu.nebula.net.NetMsgId; +import emu.nebula.proto.StarTowerBuildBriefListGet.StarTowerBuildBriefListGetResp; import emu.nebula.net.HandlerId; import emu.nebula.net.GameSession; @@ -10,7 +11,17 @@ public class HandlerStarTowerBuildBriefListGetReq extends NetHandler { @Override public byte[] handle(GameSession session, byte[] message) throws Exception { - return this.encodeMsg(NetMsgId.star_tower_build_brief_list_get_succeed_ack); + // Build response + var rsp = StarTowerBuildBriefListGetResp.newInstance(); + + // Add star tower builds + var builds = session.getPlayer().getStarTowerManager().getBuilds().values(); + for (var build : builds) { + rsp.addBriefs(build.toBriefProto()); + } + + // Finish + return this.encodeMsg(NetMsgId.star_tower_build_brief_list_get_succeed_ack, rsp); } } diff --git a/src/main/java/emu/nebula/server/handlers/HandlerStarTowerBuildDetailGetReq.java b/src/main/java/emu/nebula/server/handlers/HandlerStarTowerBuildDetailGetReq.java new file mode 100644 index 0000000..b06eae1 --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerStarTowerBuildDetailGetReq.java @@ -0,0 +1,33 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.StarTowerBuildDetailGet.StarTowerBuildDetailGetReq; +import emu.nebula.proto.StarTowerBuildDetailGet.StarTowerBuildDetailGetResp; +import emu.nebula.net.HandlerId; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.star_tower_build_detail_get_req) +public class HandlerStarTowerBuildDetailGetReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Parse request + var req = StarTowerBuildDetailGetReq.parseFrom(message); + + // Get build + int buildId = (int) req.getBuildId(); + var build = session.getPlayer().getStarTowerManager().getBuilds().get(buildId); + + if (build == null) { + return this.encodeMsg(NetMsgId.star_tower_build_detail_get_failed_ack); + } + + // Build response + var rsp = StarTowerBuildDetailGetResp.newInstance() + .setDetail(build.toDetailProto()); + + return this.encodeMsg(NetMsgId.star_tower_build_detail_get_succeed_ack, rsp); + } + +} diff --git a/src/main/java/emu/nebula/server/handlers/HandlerStarTowerBuildWhetherSaveReq.java b/src/main/java/emu/nebula/server/handlers/HandlerStarTowerBuildWhetherSaveReq.java index 325d4df..2bea6eb 100644 --- a/src/main/java/emu/nebula/server/handlers/HandlerStarTowerBuildWhetherSaveReq.java +++ b/src/main/java/emu/nebula/server/handlers/HandlerStarTowerBuildWhetherSaveReq.java @@ -3,6 +3,7 @@ package emu.nebula.server.handlers; import emu.nebula.net.NetHandler; import emu.nebula.net.NetMsgId; import emu.nebula.proto.StarTowerBuildWhetherSave.StarTowerBuildWhetherSaveReq; +import emu.nebula.proto.StarTowerBuildWhetherSave.StarTowerBuildWhetherSaveResp; import emu.nebula.net.HandlerId; import emu.nebula.net.GameSession; @@ -11,10 +12,24 @@ public class HandlerStarTowerBuildWhetherSaveReq extends NetHandler { @Override public byte[] handle(GameSession session, byte[] message) throws Exception { + // Parse request var req = StarTowerBuildWhetherSaveReq.parseFrom(message); - // TODO - return this.encodeMsg(NetMsgId.star_tower_build_whether_save_succeed_ack); + // Save build + boolean result = session.getPlayer().getStarTowerManager().saveBuild( + req.getDelete(), + req.getBuildName(), + req.getLock() + ); + + if (!result) { + return this.encodeMsg(NetMsgId.star_tower_build_whether_save_failed_ack); + } + + // Build response + var rsp = StarTowerBuildWhetherSaveResp.newInstance(); + + return this.encodeMsg(NetMsgId.star_tower_build_whether_save_succeed_ack, rsp); } }