From fd8e8925cad7c1ab4c87541cc4aae91abaf9abba Mon Sep 17 00:00:00 2001 From: Melledy <121644117+Melledy@users.noreply.github.com> Date: Tue, 25 Nov 2025 22:33:25 -0800 Subject: [PATCH] Implement heartlink invite --- README.md | 4 +- src/main/java/emu/nebula/data/GameData.java | 14 ++-- .../data/resources/DatingBranchDef.java | 32 +++++++++ .../resources/DatingCharacterEventDef.java | 11 ++++ .../data/resources/DatingLandmarkDef.java | 61 +++++++++++++++++ .../resources/DatingLandmarkEventDef.java | 66 +++++++++++++++++++ .../nebula/game/character/GameCharacter.java | 10 +++ .../emu/nebula/game/dating/DatingEvent.java | 7 ++ .../nebula/game/dating/DatingEventType.java | 35 ++++++++++ .../emu/nebula/game/dating/DatingGame.java | 31 +++++++++ .../emu/nebula/game/dating/DatingManager.java | 39 +++++++++++ .../java/emu/nebula/game/player/Player.java | 3 + .../HandlerCharAffinityGiftSendReq.java | 8 +-- .../HandlerCharDatingBranchASelectReq.java | 43 ++++++++++++ .../HandlerCharDatingBranchBSelectReq.java | 37 +++++++++++ .../HandlerCharDatingGiftSendReq.java | 52 +++++++++++++++ .../HandlerCharDatingLandmarkSelectReq.java | 43 ++++++++++++ 17 files changed, 484 insertions(+), 12 deletions(-) create mode 100644 src/main/java/emu/nebula/data/resources/DatingBranchDef.java create mode 100644 src/main/java/emu/nebula/data/resources/DatingCharacterEventDef.java create mode 100644 src/main/java/emu/nebula/data/resources/DatingLandmarkDef.java create mode 100644 src/main/java/emu/nebula/data/resources/DatingLandmarkEventDef.java create mode 100644 src/main/java/emu/nebula/game/dating/DatingEvent.java create mode 100644 src/main/java/emu/nebula/game/dating/DatingEventType.java create mode 100644 src/main/java/emu/nebula/game/dating/DatingGame.java create mode 100644 src/main/java/emu/nebula/game/dating/DatingManager.java create mode 100644 src/main/java/emu/nebula/server/handlers/HandlerCharDatingBranchASelectReq.java create mode 100644 src/main/java/emu/nebula/server/handlers/HandlerCharDatingBranchBSelectReq.java create mode 100644 src/main/java/emu/nebula/server/handlers/HandlerCharDatingGiftSendReq.java create mode 100644 src/main/java/emu/nebula/server/handlers/HandlerCharDatingLandmarkSelectReq.java diff --git a/README.md b/README.md index 743339b..0bbbd0d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ For any extra support, questions, or discussions, check out our [Discord](https: ### Notable features - Basic profile features -- Character system implemented (except for affinity) +- Character system - Inventory/Discs working - Energy system - Mail system @@ -17,7 +17,7 @@ For any extra support, questions, or discussions, check out our [Discord](https: - Friend system (sending energy not implemented) - Shop (using only in-game currency) - Commissions -- Heartlink (missing advanced affinity related features) +- Heartlink - Monoliths (completeable but many other features missing) - Bounty Trials - Menance Arena diff --git a/src/main/java/emu/nebula/data/GameData.java b/src/main/java/emu/nebula/data/GameData.java index a13fe4e..444a91e 100644 --- a/src/main/java/emu/nebula/data/GameData.java +++ b/src/main/java/emu/nebula/data/GameData.java @@ -28,18 +28,24 @@ public class GameData { @Getter private static DataTable TalentGroupDataTable = new DataTable<>(); @Getter private static DataTable TalentDataTable = new DataTable<>(); - @Getter private static DataTable AffinityLevelDataTable = new DataTable<>(); - @Getter private static DataTable AffinityGiftDataTable = new DataTable<>(); - @Getter private static DataTable PlotDataTable = new DataTable<>(); - + // Character emblems @Getter private static DataTable CharGemDataTable = new DataTable<>(); @Getter private static DataTable CharGemSlotControlDataTable = new DataTable<>(); @Getter private static DataTable CharGemAttrGroupDataTable = new DataTable<>(); @Getter private static DataTable CharGemAttrTypeDataTable = new DataTable<>(); @Getter private static DataTable CharGemAttrValueDataTable = new DataTable<>(); + // Character affinity + @Getter private static DataTable AffinityLevelDataTable = new DataTable<>(); + @Getter private static DataTable AffinityGiftDataTable = new DataTable<>(); + @Getter private static DataTable PlotDataTable = new DataTable<>(); + @Getter private static DataTable ChatDataTable = new DataTable<>(); + @Getter private static DataTable DatingLandmarkDataTable = new DataTable<>(); + @Getter private static DataTable DatingLandmarkEventDataTable = new DataTable<>(); + @Getter private static DataTable DatingCharacterEventDataTable = new DataTable<>(); + // Discs @Getter private static DataTable DiscDataTable = new DataTable<>(); @Getter private static DataTable DiscStrengthenDataTable = new DataTable<>(); diff --git a/src/main/java/emu/nebula/data/resources/DatingBranchDef.java b/src/main/java/emu/nebula/data/resources/DatingBranchDef.java new file mode 100644 index 0000000..f7300f7 --- /dev/null +++ b/src/main/java/emu/nebula/data/resources/DatingBranchDef.java @@ -0,0 +1,32 @@ +package emu.nebula.data.resources; + +import emu.nebula.data.BaseDef; +import emu.nebula.data.ResourceType; +import emu.nebula.data.ResourceType.LoadPriority; +import lombok.Getter; + +@Getter +@ResourceType(name = "DatingBranch.json", loadPriority = LoadPriority.LOW) +public class DatingBranchDef extends BaseDef { + private int Id; + private int DatingEventType; + private int[] DatingEventParams; + + @Override + public int getId() { + return Id; + } + + public int getLandmarkId() { + if (this.DatingEventParams.length <= 0) { + return 0; + } + + return this.DatingEventParams[0]; + } + + @Override + public void onLoad() { + + } +} diff --git a/src/main/java/emu/nebula/data/resources/DatingCharacterEventDef.java b/src/main/java/emu/nebula/data/resources/DatingCharacterEventDef.java new file mode 100644 index 0000000..55c24a0 --- /dev/null +++ b/src/main/java/emu/nebula/data/resources/DatingCharacterEventDef.java @@ -0,0 +1,11 @@ +package emu.nebula.data.resources; + +import emu.nebula.data.ResourceType; +import emu.nebula.data.ResourceType.LoadPriority; +import lombok.Getter; + +@Getter +@ResourceType(name = "DatingCharacterEvent.json", loadPriority = LoadPriority.LOW) +public class DatingCharacterEventDef extends DatingLandmarkEventDef { + +} diff --git a/src/main/java/emu/nebula/data/resources/DatingLandmarkDef.java b/src/main/java/emu/nebula/data/resources/DatingLandmarkDef.java new file mode 100644 index 0000000..e791bc9 --- /dev/null +++ b/src/main/java/emu/nebula/data/resources/DatingLandmarkDef.java @@ -0,0 +1,61 @@ +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.dating.DatingEvent; +import emu.nebula.util.Utils; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import lombok.Getter; + +@Getter +@ResourceType(name = "DatingLandmark.json") +public class DatingLandmarkDef extends BaseDef { + private int Id; + + private transient List afterBranches; + private transient Object2ObjectMap> characterEvents; + private transient Object2ObjectMap> landmarkEvents; + + @Override + public int getId() { + return Id; + } + + public int getRandomAfterBranchId() { + var event = Utils.randomElement(this.afterBranches); + + if (event == null) { + return 0; + } + + return event.getId(); + } + + public int getRandomCharacterEventId() { + var list = new ArrayList(); + + for (var events : this.characterEvents.values()) { + list.addAll(events); + } + + // Get random event + var event = Utils.randomElement(list); + + if (event == null) { + return 0; + } + + return event.getId(); + } + + @Override + public void onLoad() { + this.afterBranches = new ArrayList<>(); + this.characterEvents = new Object2ObjectOpenHashMap<>(); + this.landmarkEvents = new Object2ObjectOpenHashMap<>(); + } +} diff --git a/src/main/java/emu/nebula/data/resources/DatingLandmarkEventDef.java b/src/main/java/emu/nebula/data/resources/DatingLandmarkEventDef.java new file mode 100644 index 0000000..701ed79 --- /dev/null +++ b/src/main/java/emu/nebula/data/resources/DatingLandmarkEventDef.java @@ -0,0 +1,66 @@ +package emu.nebula.data.resources; + +import java.util.ArrayList; + +import emu.nebula.data.BaseDef; +import emu.nebula.data.GameData; +import emu.nebula.data.ResourceType; +import emu.nebula.data.ResourceType.LoadPriority; +import emu.nebula.game.dating.DatingEvent; +import lombok.Getter; + +@Getter +@ResourceType(name = "DatingLandmarkEvent.json", loadPriority = LoadPriority.LOW) +public class DatingLandmarkEventDef extends BaseDef implements DatingEvent { + private int Id; + private int DatingEventType; + private int Affinity; + private int[] DatingEventParams; + private String Response; + + private transient emu.nebula.game.dating.DatingEventType type; + + @Override + public int getId() { + return Id; + } + + public int getLandmarkId() { + if (this.DatingEventParams.length <= 0) { + return 0; + } + + return this.DatingEventParams[0]; + } + + @Override + public void onLoad() { + // Cache dating event type + this.type = emu.nebula.game.dating.DatingEventType.getByValue(this.getDatingEventType()); + + // Add to landmark data + var data = GameData.getDatingLandmarkDataTable().get(this.getLandmarkId()); + if (data == null) { + return; + } + + switch (this.getType()) { + case Landmark -> { + data.getLandmarkEvents() + .computeIfAbsent(this.getResponse(), s -> new ArrayList<>()) + .add(this); + } + case Regular -> { + data.getCharacterEvents() + .computeIfAbsent(this.getResponse(), s -> new ArrayList<>()) + .add(this); + } + case AfterBranch -> { + data.getAfterBranches().add(this); + } + default -> { + // Ignored + } + } + } +} diff --git a/src/main/java/emu/nebula/game/character/GameCharacter.java b/src/main/java/emu/nebula/game/character/GameCharacter.java index 5f64fea..65984af 100644 --- a/src/main/java/emu/nebula/game/character/GameCharacter.java +++ b/src/main/java/emu/nebula/game/character/GameCharacter.java @@ -25,6 +25,7 @@ import emu.nebula.game.quest.QuestCondType; import emu.nebula.net.NetMsgId; import emu.nebula.proto.Notify.Skin; import emu.nebula.proto.Notify.SkinChange; +import emu.nebula.proto.Public.AffinityInfo; import emu.nebula.proto.Public.Char; import emu.nebula.proto.Public.CharGemPreset; import emu.nebula.proto.Public.CharGemSlot; @@ -861,6 +862,15 @@ public class GameCharacter implements GameDatabaseObject { return proto; } + public AffinityInfo getAffinityProto() { + var proto = AffinityInfo.newInstance() + .setCharId(this.getCharId()) + .setAffinityLevel(this.getAffinityLevel()) + .setAffinityExp(this.getAffinityExp()); + + return proto; + } + // Database fix @PreLoad diff --git a/src/main/java/emu/nebula/game/dating/DatingEvent.java b/src/main/java/emu/nebula/game/dating/DatingEvent.java new file mode 100644 index 0000000..8e2631a --- /dev/null +++ b/src/main/java/emu/nebula/game/dating/DatingEvent.java @@ -0,0 +1,7 @@ +package emu.nebula.game.dating; + +public interface DatingEvent { + + public int getId(); + +} diff --git a/src/main/java/emu/nebula/game/dating/DatingEventType.java b/src/main/java/emu/nebula/game/dating/DatingEventType.java new file mode 100644 index 0000000..955c3ef --- /dev/null +++ b/src/main/java/emu/nebula/game/dating/DatingEventType.java @@ -0,0 +1,35 @@ +package emu.nebula.game.dating; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import lombok.Getter; + +public enum DatingEventType { + Start (1), + End (2), + Landmark (3), + Regular (4), + LimitedLandmark (5), + BranchA (6), + BranchB (7), + BeforeBranch (8), + AfterBranch (9); + + @Getter + private final int value; + private final static Int2ObjectMap map = new Int2ObjectOpenHashMap<>(); + + static { + for (DatingEventType type : DatingEventType.values()) { + map.put(type.getValue(), type); + } + } + + private DatingEventType(int value) { + this.value = value; + } + + public static DatingEventType getByValue(int value) { + return map.get(value); + } +} diff --git a/src/main/java/emu/nebula/game/dating/DatingGame.java b/src/main/java/emu/nebula/game/dating/DatingGame.java new file mode 100644 index 0000000..4799f46 --- /dev/null +++ b/src/main/java/emu/nebula/game/dating/DatingGame.java @@ -0,0 +1,31 @@ +package emu.nebula.game.dating; + +import emu.nebula.data.resources.DatingLandmarkDef; +import emu.nebula.game.character.GameCharacter; +import lombok.Getter; + +@Getter +public class DatingGame { + private GameCharacter character; + private DatingLandmarkDef landmark; + + private int[] branchOptionsA; + private int[] branchOptionsB; + + public DatingGame(GameCharacter character, DatingLandmarkDef landmark) { + this.character = character; + this.landmark = landmark; + this.branchOptionsA = new int[] {1, 2}; + this.branchOptionsB = new int[] {1, 2}; + } + + public boolean selectDatingBranchA(int optionId) { + // TODO + return true; + } + + public boolean selectDatingBranchB(int optionId) { + // TODO + return true; + } +} diff --git a/src/main/java/emu/nebula/game/dating/DatingManager.java b/src/main/java/emu/nebula/game/dating/DatingManager.java new file mode 100644 index 0000000..06b2143 --- /dev/null +++ b/src/main/java/emu/nebula/game/dating/DatingManager.java @@ -0,0 +1,39 @@ +package emu.nebula.game.dating; + +import emu.nebula.data.GameData; +import emu.nebula.game.character.GameCharacter; +import emu.nebula.game.player.Player; +import emu.nebula.game.player.PlayerManager; +import emu.nebula.game.quest.QuestCondType; +import lombok.Getter; + +@Getter +public class DatingManager extends PlayerManager { + private DatingGame game; + + public DatingManager(Player player) { + super(player); + } + + public DatingGame selectLandmark(GameCharacter character, int landmarkId) { + // Get landmark data + var data = GameData.getDatingLandmarkDataTable().get(landmarkId); + + if (data == null) { + return null; + } + + // Set landmark + character + this.game = new DatingGame(character, data); + + // Trigger quest + this.getPlayer().triggerQuest(QuestCondType.CharactersDatingTotal, 1); + + // Success + return this.game; + } + + public void endDatingGame() { + this.game = null; + } +} diff --git a/src/main/java/emu/nebula/game/player/Player.java b/src/main/java/emu/nebula/game/player/Player.java index 6b6def5..745b16d 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.agent.AgentManager; import emu.nebula.game.battlepass.BattlePassManager; import emu.nebula.game.character.CharacterStorage; +import emu.nebula.game.dating.DatingManager; import emu.nebula.game.formation.FormationManager; import emu.nebula.game.friends.FriendList; import emu.nebula.game.gacha.GachaManager; @@ -83,6 +84,7 @@ public class Player implements GameDatabaseObject { private final transient CharacterStorage characters; private final transient FriendList friendList; private final transient BattlePassManager battlePassManager; + private final transient DatingManager datingManager; private final transient StarTowerManager starTowerManager; private final transient InstanceManager instanceManager; private final transient InfinityTowerManager infinityTowerManager; @@ -110,6 +112,7 @@ public class Player implements GameDatabaseObject { this.characters = new CharacterStorage(this); this.friendList = new FriendList(this); this.battlePassManager = new BattlePassManager(this); + this.datingManager = new DatingManager(this); this.starTowerManager = new StarTowerManager(this); this.instanceManager = new InstanceManager(this); this.infinityTowerManager = new InfinityTowerManager(this); diff --git a/src/main/java/emu/nebula/server/handlers/HandlerCharAffinityGiftSendReq.java b/src/main/java/emu/nebula/server/handlers/HandlerCharAffinityGiftSendReq.java index 38e8129..b1166fe 100644 --- a/src/main/java/emu/nebula/server/handlers/HandlerCharAffinityGiftSendReq.java +++ b/src/main/java/emu/nebula/server/handlers/HandlerCharAffinityGiftSendReq.java @@ -34,12 +34,8 @@ public class HandlerCharAffinityGiftSendReq extends NetHandler { // Build response var rsp = CharAffinityGiftSendResp.newInstance() - .setChange(change.toProto()); - - rsp.getMutableInfo() - .setCharId(character.getCharId()) - .setAffinityLevel(character.getAffinityLevel()) - .setAffinityExp(character.getAffinityExp()); + .setChange(change.toProto()) + .setInfo(character.getAffinityProto()); // Encode and send return session.encodeMsg(NetMsgId.char_affinity_gift_send_succeed_ack, rsp); diff --git a/src/main/java/emu/nebula/server/handlers/HandlerCharDatingBranchASelectReq.java b/src/main/java/emu/nebula/server/handlers/HandlerCharDatingBranchASelectReq.java new file mode 100644 index 0000000..0fbd292 --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerCharDatingBranchASelectReq.java @@ -0,0 +1,43 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.CharDatingBranchASelect.CharDatingBranchASelectReq; +import emu.nebula.proto.CharDatingBranchASelect.CharDatingBranchASelectResp; +import emu.nebula.util.Utils; +import emu.nebula.net.HandlerId; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.char_dating_branch_a_select_req) +public class HandlerCharDatingBranchASelectReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Parse request + var req = CharDatingBranchASelectReq.parseFrom(message); + + // Get dating game + var game = session.getPlayer().getDatingManager().getGame(); + + if (game == null) { + return session.encodeMsg(NetMsgId.char_dating_branch_a_select_failed_ack); + } + + // Select branch A + game.selectDatingBranchA(req.getOptionId()); + + // Build response + var rsp = CharDatingBranchASelectResp.newInstance() + .addAllBranchBOptionIds(game.getBranchOptionsB()); + + // Add random events + for (var events : game.getLandmark().getLandmarkEvents().values()) { + var event = Utils.randomElement(events); + rsp.addLandmarkEventIds(event.getId()); + } + + // Encode and send + return session.encodeMsg(NetMsgId.char_dating_branch_a_select_succeed_ack, rsp); + } + +} diff --git a/src/main/java/emu/nebula/server/handlers/HandlerCharDatingBranchBSelectReq.java b/src/main/java/emu/nebula/server/handlers/HandlerCharDatingBranchBSelectReq.java new file mode 100644 index 0000000..cb7a3f7 --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerCharDatingBranchBSelectReq.java @@ -0,0 +1,37 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.CharDatingBranchBSelect.CharDatingBranchBSelectReq; +import emu.nebula.proto.CharDatingBranchBSelect.CharDatingBranchBSelectResp; +import emu.nebula.net.HandlerId; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.char_dating_branch_b_select_req) +public class HandlerCharDatingBranchBSelectReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Parse request + var req = CharDatingBranchBSelectReq.parseFrom(message); + + // Get dating game + var game = session.getPlayer().getDatingManager().getGame(); + + if (game == null) { + return session.encodeMsg(NetMsgId.char_dating_branch_b_select_failed_ack); + } + + // Select branch B + game.selectDatingBranchB(req.getOptionId()); + + // Build response + var rsp = CharDatingBranchBSelectResp.newInstance() + .setAfterBranchId(game.getLandmark().getRandomAfterBranchId()) + .setCharacterEventId(game.getLandmark().getRandomCharacterEventId()); + + // Encode and send + return session.encodeMsg(NetMsgId.char_dating_branch_b_select_succeed_ack, rsp); + } + +} diff --git a/src/main/java/emu/nebula/server/handlers/HandlerCharDatingGiftSendReq.java b/src/main/java/emu/nebula/server/handlers/HandlerCharDatingGiftSendReq.java new file mode 100644 index 0000000..9680af5 --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerCharDatingGiftSendReq.java @@ -0,0 +1,52 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.CharDatingGiftSend.CharDatingGiftSendReq; +import emu.nebula.proto.CharDatingGiftSend.CharDatingGiftSendResp; +import emu.nebula.net.HandlerId; +import emu.nebula.game.inventory.ItemParamMap; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.char_dating_gift_send_req) +public class HandlerCharDatingGiftSendReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Parse Request + var req = CharDatingGiftSendReq.parseFrom(message); + + // Get dating game + var game = session.getPlayer().getDatingManager().getGame(); + + if (game == null) { + return session.encodeMsg(NetMsgId.char_dating_gift_send_failed_ack); + } + + // Get character + var character = game.getCharacter(); + + if (character == null || character.getCharId() != req.getCharId()) { + return session.encodeMsg(NetMsgId.char_dating_gift_send_failed_ack); + } + + // Parse item templates + var items = ItemParamMap.fromTemplates(req.getItems()); + + // Send gifts + var change = character.sendGift(items); + + if (change == null) { + return session.encodeMsg(NetMsgId.char_affinity_gift_send_failed_ack); + } + + // Build response + var rsp = CharDatingGiftSendResp.newInstance() + .setChange(change.toProto()) + .setInfo(character.getAffinityProto()); + + // Encode and send + return session.encodeMsg(NetMsgId.char_dating_gift_send_succeed_ack, rsp); + } + +} diff --git a/src/main/java/emu/nebula/server/handlers/HandlerCharDatingLandmarkSelectReq.java b/src/main/java/emu/nebula/server/handlers/HandlerCharDatingLandmarkSelectReq.java new file mode 100644 index 0000000..35ca8cd --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerCharDatingLandmarkSelectReq.java @@ -0,0 +1,43 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.CharDatingLandmarkSelect.CharDatingLandmarkSelectReq; +import emu.nebula.proto.CharDatingLandmarkSelect.CharDatingLandmarkSelectResp; +import emu.nebula.net.HandlerId; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.char_dating_landmark_select_req) +public class HandlerCharDatingLandmarkSelectReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Parse Request + var req = CharDatingLandmarkSelectReq.parseFrom(message); + + // Get character + var character = session.getPlayer().getCharacters().getCharacterById(req.getCharId()); + + if (character == null) { + return session.encodeMsg(NetMsgId.char_dating_landmark_select_failed_ack); + } + + // Set landmark + var game = session.getPlayer().getDatingManager().selectLandmark(character, req.getLandmarkId()); + + if (game == null) { + return session.encodeMsg(NetMsgId.char_dating_landmark_select_failed_ack); + } + + // Build response + var rsp = CharDatingLandmarkSelectResp.newInstance() + .setInfo(character.getAffinityProto()) + .addAllBranchAOptionIds(game.getBranchOptionsB()); + + rsp.getMutableChange(); + + // Encode and send + return session.encodeMsg(NetMsgId.char_dating_landmark_select_succeed_ack, rsp); + } + +}