diff --git a/src/main/java/emu/nebula/Config.java b/src/main/java/emu/nebula/Config.java index ec341cc..e19c7af 100644 --- a/src/main/java/emu/nebula/Config.java +++ b/src/main/java/emu/nebula/Config.java @@ -101,7 +101,7 @@ public class Config { public boolean skipIntro = false; public boolean unlockInstances = true; public int dailyResetHour = 0; - public int leaderboardRefreshTime = 60; + public int leaderboardRefreshTime = 60; // Leaderboard refresh time in seconds public WelcomeMail welcomeMail = new WelcomeMail(); } diff --git a/src/main/java/emu/nebula/GameConstants.java b/src/main/java/emu/nebula/GameConstants.java index 9b5080c..fc4554d 100644 --- a/src/main/java/emu/nebula/GameConstants.java +++ b/src/main/java/emu/nebula/GameConstants.java @@ -24,4 +24,7 @@ public class GameConstants { public static final int MAX_SHOWCASE_IDS = 5; public static final int BATTLE_PASS_ID = 1; + + public static final int MAX_FRIENDSHIPS = 50; + public static final int MAX_PENDING_FRIENDSHIPS = 30; } diff --git a/src/main/java/emu/nebula/game/friends/FriendList.java b/src/main/java/emu/nebula/game/friends/FriendList.java new file mode 100644 index 0000000..329e66b --- /dev/null +++ b/src/main/java/emu/nebula/game/friends/FriendList.java @@ -0,0 +1,311 @@ +package emu.nebula.game.friends; + +import java.util.ArrayList; +import java.util.List; + +import emu.nebula.GameConstants; +import emu.nebula.Nebula; +import emu.nebula.game.GameContext; +import emu.nebula.game.player.Player; +import emu.nebula.game.player.PlayerManager; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.FriendListGet.FriendListGetResp; +import emu.nebula.proto.Public.FriendDetail; +import emu.nebula.proto.Public.FriendState; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import lombok.Getter; + +@Getter +public class FriendList extends PlayerManager { + private final Int2ObjectMap friends; + private final Int2ObjectMap pendingFriends; + + private long cacheCooldown; + private FriendListGetResp cachedProto; + + public FriendList(Player player) { + super(player); + this.friends = new Int2ObjectOpenHashMap(); + this.pendingFriends = new Int2ObjectOpenHashMap(); + } + + private GameContext getGameContext() { + return Nebula.getGameContext(); + } + + public boolean isLoaded() { + return this.getPlayer().isLoaded(); + } + + private synchronized Friendship getFriendById(int id) { + if (this.isLoaded()) { + return this.getFriends().get(id); + } else { + return Nebula.getGameDatabase().getObjectByUid(Friendship.class, Friendship.generateUniqueKey(getPlayerUid(), id)); + } + } + + private synchronized Friendship getPendingFriendById(int id) { + if (this.isLoaded()) { + return this.getPendingFriends().get(id); + } else { + return Nebula.getGameDatabase().getObjectByUid(Friendship.class, Friendship.generateUniqueKey(getPlayerUid(), id)); + } + } + + public synchronized boolean hasPendingRequests() { + return this.getPendingFriends().values() + .stream() + .filter(f -> f.getAskerUid() != this.getPlayerUid()) + .findAny() + .isPresent(); + } + + private void addFriendship(Friendship friendship) { + getFriends().put(friendship.getFriendUid(), friendship); + this.cacheCooldown = 0; + } + + private void addPendingFriendship(Friendship friendship) { + getPendingFriends().put(friendship.getFriendUid(), friendship); + this.cacheCooldown = 0; + } + + private void removeFriendship(int uid) { + getFriends().remove(uid); + this.cacheCooldown = 0; + } + + private void removePendingFriendship(int uid) { + getPendingFriends().remove(uid); + this.cacheCooldown = 0; + } + + /** + * Gets total amount of potential friends + */ + public int getFullFriendCount() { + return this.getPendingFriends().size() + this.getFriends().size(); + } + + public synchronized Player handleFriendRequest(int targetUid, boolean action) { + // Make sure we have enough room + if (this.getFriends().size() >= GameConstants.MAX_FRIENDSHIPS) { + return null; + } + + // Check if player has sent friend request + Friendship myFriendship = this.getPendingFriendById(targetUid); + if (myFriendship == null) { + return null; + } + + // Make sure this player is not the asker + if (myFriendship.getAskerUid() == this.getPlayer().getUid()) { + return null; + } + + // Get target player + Player target = getGameContext().getPlayerModule().getPlayer(targetUid); + if (target == null) return null; + + // Get target player's friendship + Friendship theirFriendship = target.getFriendList().getPendingFriendById(getPlayer().getUid()); + + if (theirFriendship == null) { + // They dont have us on their friends list anymore, rip + this.removePendingFriendship(target.getUid()); + myFriendship.delete(); + return null; + } + + // Handle action + if (action) { + // Request accepted + myFriendship.setFriend(true); + theirFriendship.setFriend(true); + + this.removePendingFriendship(myFriendship.getFriendUid()); + this.addFriendship(myFriendship); + + if (target.isLoaded()) { + target.getFriendList().removePendingFriendship(this.getPlayer().getUid()); + target.getFriendList().addFriendship(theirFriendship); + } + + // Save friendships to the database + myFriendship.save(); + theirFriendship.save(); + } else { + // Request declined - Delete from my pending friends + this.removePendingFriendship(myFriendship.getOwnerUid()); + + if (target.isLoaded()) { + target.getFriendList().removePendingFriendship(getPlayer().getUid()); + } + + // Delete friendships from the database + myFriendship.delete(); + theirFriendship.delete(); + } + + // Success + return target; + } + + public List acceptAll() { + // Results + List results = new ArrayList<>(); + + // Get list of friendships to accept + List list = getPendingFriends().values() + .stream() + .toList(); + + for (var invite : list) { + var target = this.handleFriendRequest(invite.getFriendUid(), true); + + if (target != null) { + results.add(target); + } + } + + return results; + } + + public synchronized boolean sendFriendRequest(int targetUid) { + // Get target and sanity check + Player target = getGameContext().getPlayerModule().getPlayer(targetUid); + if (target == null || target == this.getPlayer()) { + return false; + } + + // Check if friend already exists + if (getPendingFriends().containsKey(targetUid) || getFriends().containsKey(targetUid)) { + return false; + } + + // Create friendships + Friendship myFriendship = new Friendship(getPlayer(), target, getPlayer()); + Friendship theirFriendship = new Friendship(target, getPlayer(), getPlayer()); + + // Add to our pending friendship list + this.addPendingFriendship(myFriendship); + + if (target.isLoaded()) { + target.getFriendList().addPendingFriendship(theirFriendship); + + // Send message to notify target + target.addNextPackage( + NetMsgId.friend_state_notify, + FriendState.newInstance() + .setId(this.getPlayerUid()) + .setAction(1) + ); + } + + // Save friendships to the database + myFriendship.save(); + theirFriendship.save(); + + // Success + return true; + } + + public synchronized boolean deleteFriend(int targetUid) { + // Get friendship + Friendship myFriendship = this.getFriendById(targetUid); + if (myFriendship == null) return false; + + // Remove from friends list + this.removeFriendship(targetUid); + myFriendship.delete(); + + // Delete from friend's friend list + Player friend = getGameContext().getPlayerModule().getPlayer(targetUid); + + if (friend != null) { + // Friend online + Friendship theirFriendship = friend.getFriendList().getFriendById(this.getPlayer().getUid()); + + if (theirFriendship != null) { + // Delete friendship on friends side + theirFriendship.delete(); + + if (friend.isLoaded()) { + // Remove from online friend's friend list + friend.getFriendList().removeFriendship(theirFriendship.getFriendUid()); + } + } + } + + // Success + return true; + } + + // Database + + public synchronized void loadFromDatabase() { + var friendships = Nebula.getGameDatabase().getObjects(Friendship.class, "ownerUid", this.getPlayer().getUid()); + + friendships.forEach(friendship -> { + // Set ownership first + friendship.setOwner(getPlayer()); + + // Finally, load to our friends list + if (friendship.isFriend()) { + getFriends().put(friendship.getFriendUid(), friendship); + } else { + getPendingFriends().put(friendship.getFriendUid(), friendship); + } + }); + } + + // Proto + + public synchronized FriendListGetResp toProto() { + if (this.cachedProto == null || System.currentTimeMillis() > this.cacheCooldown) { + this.cachedProto = this.updateCache(); + this.cacheCooldown = System.currentTimeMillis() + 60_000; + } + + return this.cachedProto; + } + + private FriendListGetResp updateCache() { + var proto = FriendListGetResp.newInstance(); + + // Encode friends list + for (var friend : getFriends().values()) { + // Get base friend info + var base = friend.toProto(); + if (base == null) continue; + + // Create info + var info = FriendDetail.newInstance() + .setBase(base) + .setGetEnergy(friend.getEnergy()); + + // Add + proto.addFriends(info); + } + + // Encode pending invites + for (var friend : getPendingFriends().values()) { + // Skip if this is us + if (friend.getAskerUid() == this.getPlayerUid()) { + continue; + } + + // Get base friend info + var base = friend.toProto(); + if (base == null) continue; + + // Add + proto.addInvites(base); + } + + return proto; + } +} diff --git a/src/main/java/emu/nebula/game/friends/Friendship.java b/src/main/java/emu/nebula/game/friends/Friendship.java new file mode 100644 index 0000000..2cd18d8 --- /dev/null +++ b/src/main/java/emu/nebula/game/friends/Friendship.java @@ -0,0 +1,65 @@ +package emu.nebula.game.friends; + +import dev.morphia.annotations.Entity; +import dev.morphia.annotations.Id; +import dev.morphia.annotations.Indexed; +import emu.nebula.Nebula; +import emu.nebula.database.GameDatabaseObject; +import emu.nebula.game.player.Player; +import emu.nebula.proto.Public.Friend; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Entity(value = "friendships", useDiscriminator = false) +public class Friendship implements GameDatabaseObject { + @Id private long key; + + @Indexed private int ownerUid; + @Indexed private int friendUid; + private int askerUid; + + @Setter + private boolean isFriend; + private boolean star; + private int energy; + + @Setter private transient Player owner; + + @Deprecated // Morphia use only + public Friendship() { } + + public Friendship(Player owner, Player friend, Player asker) { + this.owner = owner; + this.ownerUid = owner.getUid(); + this.friendUid = friend.getUid(); + this.askerUid = asker.getUid(); + this.key = Friendship.generateUniqueKey(owner.getUid(), friend.getUid()); + } + + // Database functions + + public void delete() { + Nebula.getGameDatabase().delete(this); + } + + // Proto + + public Friend toProto() { + // Get target player + var target = Nebula.getGameContext().getPlayerModule().getPlayer(this.getFriendUid()); + if (target == null) return null; + + // Encode player to simple friend proto + return target.getFriendProto(); + } + + // Extra + + /** + * Creates an unique key for a friendship object using 2 player uids + */ + public static long generateUniqueKey(int ownerUid, int targetUid) { + return ((long) ownerUid << 32) + targetUid; + } +} diff --git a/src/main/java/emu/nebula/game/player/Player.java b/src/main/java/emu/nebula/game/player/Player.java index e635410..cd9cb8d 100644 --- a/src/main/java/emu/nebula/game/player/Player.java +++ b/src/main/java/emu/nebula/game/player/Player.java @@ -15,6 +15,7 @@ import emu.nebula.game.agent.AgentManager; import emu.nebula.game.battlepass.BattlePassManager; import emu.nebula.game.character.CharacterStorage; import emu.nebula.game.formation.FormationManager; +import emu.nebula.game.friends.FriendList; import emu.nebula.game.gacha.GachaManager; import emu.nebula.game.infinitytower.InfinityTowerManager; import emu.nebula.game.instance.InstanceManager; @@ -34,6 +35,7 @@ import emu.nebula.proto.PlayerData.DictionaryTab; import emu.nebula.proto.PlayerData.PlayerInfo; import emu.nebula.proto.Public.CharShow; import emu.nebula.proto.Public.Energy; +import emu.nebula.proto.Public.Friend; import emu.nebula.proto.Public.HonorInfo; import emu.nebula.proto.Public.NewbieInfo; import emu.nebula.proto.Public.QuestType; @@ -73,10 +75,12 @@ public class Player implements GameDatabaseObject { private long energyLastUpdate; private long lastEpochDay; + private long lastLogin; private long createTime; // Managers private final transient CharacterStorage characters; + private final transient FriendList friendList; private final transient GachaManager gachaManager; private final transient BattlePassManager battlePassManager; private final transient StarTowerManager starTowerManager; @@ -94,13 +98,15 @@ public class Player implements GameDatabaseObject { private transient QuestManager questManager; private transient AgentManager agentManager; - // Next packages + // Extra private transient Stack nextPackages; + private transient boolean loaded; @Deprecated // Morphia only public Player() { // Init player managers this.characters = new CharacterStorage(this); + this.friendList = new FriendList(this); this.gachaManager = new GachaManager(this); this.battlePassManager = new BattlePassManager(this); this.starTowerManager = new StarTowerManager(this); @@ -126,6 +132,7 @@ public class Player implements GameDatabaseObject { // Set basic info this.accountUid = account.getUid(); this.createTime = Nebula.getCurrentTime(); + this.name = name; this.signature = ""; this.gender = gender; @@ -576,6 +583,7 @@ public class Player implements GameDatabaseObject { public void onLoad() { // Load from database this.getCharacters().loadFromDatabase(); + this.getFriendList().loadFromDatabase(); this.getStarTowerManager().loadFromDatabase(); this.getBattlePassManager().loadFromDatabase(); @@ -598,6 +606,9 @@ public class Player implements GameDatabaseObject { this.showChars = new int[3]; this.save(); } + + // Load complete + this.loaded = true; } public void onLogin() { @@ -606,6 +617,10 @@ public class Player implements GameDatabaseObject { // Trigger quest login this.triggerQuest(QuestCondType.LoginTotal, 1); + + // Update last login time + this.lastLogin = System.currentTimeMillis(); + Nebula.getGameDatabase().update(this, this.getUid(), "lastLogin", this.getLastLogin()); } // Next packages @@ -696,7 +711,8 @@ public class Player implements GameDatabaseObject { // Set player states var state = proto.getMutableState() - .setStorySet(true); + .setStorySet(true) + .setFriend(this.getFriendList().hasPendingRequests()); state.getMutableMail() .setNew(this.getMailbox().hasNewMail()); @@ -791,6 +807,36 @@ public class Player implements GameDatabaseObject { return proto; } + public Friend getFriendProto() { + var proto = Friend.newInstance() + .setId(this.getUid()) + .setWorldClass(this.getLevel()) + .setHeadIcon(this.getHeadIcon()) + .setNickName(this.getName()) + .setSignature(this.getSignature()) + .setTitlePrefix(this.getTitlePrefix()) + .setTitleSuffix(this.getTitleSuffix()) + .setLastLoginTime(this.getLastLogin() * 1_000_000L); + + for (int charId : this.getShowChars()) { + var info = CharShow.newInstance() + .setCharId(charId) + .setLevel(1) // TODO + .setSkin((charId * 100) + 1); // TODO + + proto.addCharShows(info); + } + + for (int honorId : this.getHonor()) { + var info = HonorInfo.newInstance() + .setId(honorId); + + proto.addHonors(info); + } + + return proto; + } + public Energy getEnergyProto() { long nextDuration = Math.max(GameConstants.ENERGY_REGEN_TIME - (Nebula.getCurrentTime() - getEnergyLastUpdate()), 1); diff --git a/src/main/java/emu/nebula/game/player/PlayerModule.java b/src/main/java/emu/nebula/game/player/PlayerModule.java index 452cccc..cfef704 100644 --- a/src/main/java/emu/nebula/game/player/PlayerModule.java +++ b/src/main/java/emu/nebula/game/player/PlayerModule.java @@ -49,12 +49,30 @@ public class PlayerModule extends GameContextModule { return getCachedPlayers().get(uid); } + /** + * Returns a player object with the given uid. Returns null if the player doesnt exist. + * Warning: Does NOT cache or load the playerdata if the player was loaded from the database. + * @param uid User id of the player + * @return + */ + public synchronized Player getPlayer(int uid) { + // Get player from cache + Player player = this.cachedPlayers.get(uid); + + if (player == null) { + // Retrieve player object from database if its not there + player = Nebula.getGameDatabase().getObjectByUid(Player.class, uid); + } + + return player; + } + /** * Returns a player object with the given account. Returns null if the player doesnt exist. * @param uid User id of the player * @return */ - public synchronized Player getPlayerByAccount(Account account) { + public synchronized Player loadPlayer(Account account) { // Get player from cache Player player = this.cachedPlayersByAccount.get(account.getUid()); @@ -108,12 +126,17 @@ public class PlayerModule extends GameContextModule { } /** - * Returns a list of recent players that have logged on (for followers) + * Returns a list of recent players that have logged on * @param player Player that requested this */ public synchronized List getRandomPlayerList(Player player) { - List list = getCachedPlayers().values().stream().filter(p -> p != player).collect(Collectors.toList()); + List list = getCachedPlayers().values().stream() + .filter(p -> p != player) + .limit(10) + .collect(Collectors.toList()); + Collections.shuffle(list); - return list.stream().limit(15).toList(); + + return list.stream().toList(); } } diff --git a/src/main/java/emu/nebula/net/GameSession.java b/src/main/java/emu/nebula/net/GameSession.java index 3f5adc4..503cf82 100644 --- a/src/main/java/emu/nebula/net/GameSession.java +++ b/src/main/java/emu/nebula/net/GameSession.java @@ -121,7 +121,7 @@ public class GameSession { // Note: We should cache players in case multiple sessions try to login to the same player at the time // Get player by account - var player = Nebula.getGameContext().getPlayerModule().getPlayerByAccount(account); + var player = Nebula.getGameContext().getPlayerModule().loadPlayer(account); // Skip intro if (player == null && Nebula.getConfig().getServerOptions().skipIntro) { diff --git a/src/main/java/emu/nebula/server/handlers/HandlerFriendAddAgreeReq.java b/src/main/java/emu/nebula/server/handlers/HandlerFriendAddAgreeReq.java new file mode 100644 index 0000000..609bb1d --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerFriendAddAgreeReq.java @@ -0,0 +1,33 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.FriendAddAgree.FriendAddAgreeReq; +import emu.nebula.proto.FriendAddAgree.FriendAddAgreeResp; +import emu.nebula.net.HandlerId; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.friend_add_agree_req) +public class HandlerFriendAddAgreeReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Parse request + var req = FriendAddAgreeReq.parseFrom(message); + + // Handle friend request + var target = session.getPlayer().getFriendList().handleFriendRequest((int) req.getUId(), true); + + if (target == null) { + return session.encodeMsg(NetMsgId.friend_add_agree_failed_ack); + } + + // Build response + var rsp = FriendAddAgreeResp.newInstance() + .setFriend(target.getFriendProto()); + + // Encode and send + return session.encodeMsg(NetMsgId.friend_add_agree_succeed_ack, rsp); + } + +} diff --git a/src/main/java/emu/nebula/server/handlers/HandlerFriendAddReq.java b/src/main/java/emu/nebula/server/handlers/HandlerFriendAddReq.java new file mode 100644 index 0000000..6d9cf20 --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerFriendAddReq.java @@ -0,0 +1,25 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.FriendAdd.FriendAddReq; +import emu.nebula.net.HandlerId; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.friend_add_req) +public class HandlerFriendAddReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Parse request + var req = FriendAddReq.parseFrom(message); + int uid = (int) req.getUId(); + + // Send friend request + boolean success = session.getPlayer().getFriendList().sendFriendRequest(uid); + + // Encode and send + return session.encodeMsg(success ? NetMsgId.friend_add_succeed_ack : NetMsgId.friend_add_failed_ack); + } + +} diff --git a/src/main/java/emu/nebula/server/handlers/HandlerFriendAllAgreeReq.java b/src/main/java/emu/nebula/server/handlers/HandlerFriendAllAgreeReq.java new file mode 100644 index 0000000..539be92 --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerFriendAllAgreeReq.java @@ -0,0 +1,35 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.FriendAllAgree.FriendAllAgreeResp; +import emu.nebula.net.HandlerId; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.friend_all_agree_req) +public class HandlerFriendAllAgreeReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Agree to all friend requests + var results = session.getPlayer().getFriendList().acceptAll(); + + // Scuffed way of getting friend data + var proto = session.getPlayer().getFriendList().getCachedProto(); + + // Build response + var rsp = FriendAllAgreeResp.newInstance(); + + for (var f : results) { + rsp.addFriends(f.getFriendProto()); + } + + for (var i : proto.getInvites()) { + rsp.addInvites(i); + } + + // Encode and send + return session.encodeMsg(NetMsgId.friend_all_agree_succeed_ack, rsp); + } + +} diff --git a/src/main/java/emu/nebula/server/handlers/HandlerFriendDeleteReq.java b/src/main/java/emu/nebula/server/handlers/HandlerFriendDeleteReq.java new file mode 100644 index 0000000..87d9bcd --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerFriendDeleteReq.java @@ -0,0 +1,24 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.FriendDelete.FriendDeleteReq; +import emu.nebula.net.HandlerId; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.friend_delete_req) +public class HandlerFriendDeleteReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Parse request + var req = FriendDeleteReq.parseFrom(message); + + // Delete friend + boolean success = session.getPlayer().getFriendList().deleteFriend((int) req.getUId()); + + // Encode and send + return session.encodeMsg(success ? NetMsgId.friend_delete_succeed_ack : NetMsgId.friend_delete_failed_ack); + } + +} \ No newline at end of file diff --git a/src/main/java/emu/nebula/server/handlers/HandlerFriendInvitesDeleteReq.java b/src/main/java/emu/nebula/server/handlers/HandlerFriendInvitesDeleteReq.java new file mode 100644 index 0000000..3503339 --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerFriendInvitesDeleteReq.java @@ -0,0 +1,26 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.FriendInvitesDelete.FriendInvitesDeleteReq; +import emu.nebula.net.HandlerId; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.friend_invites_delete_req) +public class HandlerFriendInvitesDeleteReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Parse request + var req = FriendInvitesDeleteReq.parseFrom(message); + + // Delete all invites + for (long uid : req.getMutableUIds()) { + session.getPlayer().getFriendList().handleFriendRequest((int) uid, false); + } + + // Encode and send + return session.encodeMsg(NetMsgId.friend_invites_delete_succeed_ack); + } + +} diff --git a/src/main/java/emu/nebula/server/handlers/HandlerFriendListGetReq.java b/src/main/java/emu/nebula/server/handlers/HandlerFriendListGetReq.java index bd75d32..a577f0a 100644 --- a/src/main/java/emu/nebula/server/handlers/HandlerFriendListGetReq.java +++ b/src/main/java/emu/nebula/server/handlers/HandlerFriendListGetReq.java @@ -2,7 +2,6 @@ package emu.nebula.server.handlers; import emu.nebula.net.NetHandler; import emu.nebula.net.NetMsgId; -import emu.nebula.proto.FriendListGet.FriendListGetResp; import emu.nebula.net.HandlerId; import emu.nebula.net.GameSession; @@ -11,8 +10,10 @@ public class HandlerFriendListGetReq extends NetHandler { @Override public byte[] handle(GameSession session, byte[] message) throws Exception { - var rsp = FriendListGetResp.newInstance(); + // Build response + var rsp = session.getPlayer().getFriendList().toProto(); + // Encode and send return session.encodeMsg(NetMsgId.friend_list_get_succeed_ack, rsp); } diff --git a/src/main/java/emu/nebula/server/handlers/HandlerFriendRecommendationGetReq.java b/src/main/java/emu/nebula/server/handlers/HandlerFriendRecommendationGetReq.java new file mode 100644 index 0000000..fe52daf --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerFriendRecommendationGetReq.java @@ -0,0 +1,29 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.FriendRecommendationGet.FriendRecommendationGetResp; +import emu.nebula.net.HandlerId; +import emu.nebula.Nebula; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.friend_recommendation_get_req) +public class HandlerFriendRecommendationGetReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Build response + var rsp = FriendRecommendationGetResp.newInstance(); + + // Get players + var players = Nebula.getGameContext().getPlayerModule().getRandomPlayerList(session.getPlayer()); + + for (var player : players) { + rsp.addFriends(player.getFriendProto()); + } + + // Encode and send + return session.encodeMsg(NetMsgId.friend_recommendation_get_succeed_ack, rsp); + } + +} diff --git a/src/main/java/emu/nebula/server/handlers/HandlerFriendUidSearchReq.java b/src/main/java/emu/nebula/server/handlers/HandlerFriendUidSearchReq.java new file mode 100644 index 0000000..c6810b0 --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerFriendUidSearchReq.java @@ -0,0 +1,35 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.FriendUidSearch.FriendUIdSearchReq; +import emu.nebula.proto.FriendUidSearch.FriendUIdSearchResp; +import emu.nebula.net.HandlerId; +import emu.nebula.Nebula; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.friend_uid_search_req) +public class HandlerFriendUidSearchReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Parse request + var req = FriendUIdSearchReq.parseFrom(message); + int uid = (int) req.getId(); + + // Get target player + var target = Nebula.getGameContext().getPlayerModule().getPlayer(uid); + + if (target == null) { + return session.encodeMsg(NetMsgId.friend_uid_search_failed_ack); + } + + // Build response + var rsp = FriendUIdSearchResp.newInstance() + .setFriend(target.getFriendProto()); + + // Encode and send + return session.encodeMsg(NetMsgId.friend_uid_search_succeed_ack, rsp); + } + +}