Commit 19396a63 authored by Melledy's avatar Melledy
Browse files

Move player mail to MailHandler class

This is so we dont have to save the entire player to the db every time we send mail
parent afa8fb7a
...@@ -12,6 +12,7 @@ import emu.grasscutter.game.avatar.Avatar; ...@@ -12,6 +12,7 @@ import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.friends.Friendship; import emu.grasscutter.game.friends.Friendship;
import emu.grasscutter.game.gacha.GachaRecord; import emu.grasscutter.game.gacha.GachaRecord;
import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.mail.Mail;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
public final class DatabaseHelper { public final class DatabaseHelper {
...@@ -166,6 +167,7 @@ public final class DatabaseHelper { ...@@ -166,6 +167,7 @@ public final class DatabaseHelper {
public static List<GameItem> getInventoryItems(Player player) { public static List<GameItem> getInventoryItems(Player player) {
return DatabaseManager.getDatastore().find(GameItem.class).filter(Filters.eq("ownerId", player.getUid())).stream().toList(); return DatabaseManager.getDatastore().find(GameItem.class).filter(Filters.eq("ownerId", player.getUid())).stream().toList();
} }
public static List<Friendship> getFriends(Player player) { public static List<Friendship> getFriends(Player player) {
return DatabaseManager.getDatastore().find(Friendship.class).filter(Filters.eq("ownerId", player.getUid())).stream().toList(); return DatabaseManager.getDatastore().find(Friendship.class).filter(Filters.eq("ownerId", player.getUid())).stream().toList();
} }
...@@ -220,5 +222,18 @@ public final class DatabaseHelper { ...@@ -220,5 +222,18 @@ public final class DatabaseHelper {
DatabaseManager.getDatastore().save(gachaRecord); DatabaseManager.getDatastore().save(gachaRecord);
} }
public static List<Mail> getAllMail(Player player) {
return DatabaseManager.getDatastore().find(Mail.class).filter(Filters.eq("ownerUid", player.getUid())).stream().toList();
}
public static void saveMail(Mail mail) {
DatabaseManager.getDatastore().save(mail);
}
public static boolean deleteMail(Mail mail) {
DeleteResult result = DatabaseManager.getDatastore().delete(mail);
return result.wasAcknowledged();
}
public static char AWJVN = 'e'; public static char AWJVN = 'e';
} }
...@@ -18,6 +18,7 @@ import emu.grasscutter.game.avatar.Avatar; ...@@ -18,6 +18,7 @@ import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.friends.Friendship; import emu.grasscutter.game.friends.Friendship;
import emu.grasscutter.game.gacha.GachaRecord; import emu.grasscutter.game.gacha.GachaRecord;
import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.mail.Mail;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
public final class DatabaseManager { public final class DatabaseManager {
...@@ -29,7 +30,7 @@ public final class DatabaseManager { ...@@ -29,7 +30,7 @@ public final class DatabaseManager {
private static Datastore dispatchDatastore; private static Datastore dispatchDatastore;
private static final Class<?>[] mappedClasses = new Class<?>[] { private static final Class<?>[] mappedClasses = new Class<?>[] {
DatabaseCounter.class, Account.class, Player.class, Avatar.class, GameItem.class, Friendship.class, GachaRecord.class DatabaseCounter.class, Account.class, Player.class, Avatar.class, GameItem.class, Friendship.class, GachaRecord.class, Mail.class
}; };
public static Datastore getDatastore() { public static Datastore getDatastore() {
......
package emu.grasscutter.game.mail; package emu.grasscutter.game.mail;
import dev.morphia.annotations.Entity; import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import dev.morphia.annotations.Indexed;
import dev.morphia.annotations.Transient;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@Entity import org.bson.types.ObjectId;
public class Mail {
@Entity(value = "mail", useDiscriminator = false)
public class Mail {
@Id private ObjectId id;
@Indexed private int ownerUid;
public MailContent mailContent; public MailContent mailContent;
public List<MailItem> itemList; public List<MailItem> itemList;
public long sendTime; public long sendTime;
...@@ -18,6 +25,7 @@ public class Mail { ...@@ -18,6 +25,7 @@ public class Mail {
public boolean isRead; public boolean isRead;
public boolean isAttachmentGot; public boolean isAttachmentGot;
public int stateValue; public int stateValue;
@Transient private boolean shouldDelete;
public Mail() { public Mail() {
this(new MailContent(), new ArrayList<MailItem>(), (int) Instant.now().getEpochSecond() + 604800); // TODO: add expire time to send mail command this(new MailContent(), new ArrayList<MailItem>(), (int) Instant.now().getEpochSecond() + 604800); // TODO: add expire time to send mail command
...@@ -42,6 +50,18 @@ public class Mail { ...@@ -42,6 +50,18 @@ public class Mail {
this.stateValue = state; // Different mailboxes, 1 = Default, 3 = Gift-box. this.stateValue = state; // Different mailboxes, 1 = Default, 3 = Gift-box.
} }
public ObjectId getId() {
return id;
}
public int getOwnerUid() {
return ownerUid;
}
public void setOwnerUid(int ownerUid) {
this.ownerUid = ownerUid;
}
@Entity @Entity
public static class MailContent { public static class MailContent {
public String title; public String title;
...@@ -93,4 +113,12 @@ public class Mail { ...@@ -93,4 +113,12 @@ public class Mail {
this.itemLevel = itemLevel; this.itemLevel = itemLevel;
} }
} }
public void save() {
if (this.expireTime * 1000 < System.currentTimeMillis()) {
DatabaseHelper.deleteMail(this);
} else {
DatabaseHelper.saveMail(this);
}
}
} }
package emu.grasscutter.game.mail;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.event.player.PlayerReceiveMailEvent;
import emu.grasscutter.server.packet.send.PacketDelMailRsp;
import emu.grasscutter.server.packet.send.PacketMailChangeNotify;
public class MailHandler {
private final Player player;
private final List<Mail> mail;
public MailHandler(Player player) {
this.player = player;
this.mail = new ArrayList<>();
}
public Player getPlayer() {
return player;
}
public List<Mail> getMail() {
return mail;
}
// ---------------------MAIL------------------------
public void sendMail(Mail message) {
// Call mail receive event.
PlayerReceiveMailEvent event = new PlayerReceiveMailEvent(this.getPlayer(), message); event.call();
if(event.isCanceled()) return; message = event.getMessage();
message.setOwnerUid(this.getPlayer().getUid());
this.mail.add(message);
Grasscutter.getLogger().debug("Mail sent to user [" + this.getPlayer().getUid() + ":" + this.getPlayer().getNickname() + "]!");
if (this.getPlayer().isOnline()) {
this.getPlayer().sendPacket(new PacketMailChangeNotify(this.getPlayer(), message));
} // TODO: setup a way for the mail notification to show up when someone receives mail when they were offline
}
public boolean deleteMail(int mailId) {
Mail message = getMailById(mailId);
if (message != null) {
this.getMail().remove(mailId);
message.expireTime = 0;
message.save();
return true;
}
return false;
}
public void deleteMail(List<Integer> mailList) {
List<Integer> sortedMailList = new ArrayList<>();
sortedMailList.addAll(mailList);
Collections.sort(sortedMailList, Collections.reverseOrder());
List<Integer> deleted = new ArrayList<>();
for (int id : sortedMailList) {
if (this.deleteMail(id)) {
deleted.add(id);
}
}
player.getSession().send(new PacketDelMailRsp(player, deleted));
player.getSession().send(new PacketMailChangeNotify(player, null, deleted));
}
public Mail getMailById(int index) { return this.mail.get(index); }
public int getMailIndex(Mail message) {
return this.mail.indexOf(message);
}
public boolean replaceMailByIndex(int index, Mail message) {
if(getMailById(index) != null) {
this.mail.set(index, message);
message.save();
return true;
} else {
return false;
}
}
public void loadFromDatabase() {
List<Mail> mailList = DatabaseHelper.getAllMail(this.getPlayer());
for (Mail mail : mailList) {
this.getMail().add(mail);
}
}
}
...@@ -19,6 +19,7 @@ import emu.grasscutter.game.gacha.PlayerGachaInfo; ...@@ -19,6 +19,7 @@ import emu.grasscutter.game.gacha.PlayerGachaInfo;
import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.inventory.Inventory; import emu.grasscutter.game.inventory.Inventory;
import emu.grasscutter.game.mail.Mail; import emu.grasscutter.game.mail.Mail;
import emu.grasscutter.game.mail.MailHandler;
import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.shop.ShopLimit; import emu.grasscutter.game.shop.ShopLimit;
...@@ -78,6 +79,7 @@ public class Player { ...@@ -78,6 +79,7 @@ public class Player {
@Transient private AvatarStorage avatars; @Transient private AvatarStorage avatars;
@Transient private Inventory inventory; @Transient private Inventory inventory;
@Transient private FriendsList friendsList; @Transient private FriendsList friendsList;
@Transient private MailHandler mailHandler;
private TeamManager teamManager; private TeamManager teamManager;
private PlayerGachaInfo gachaInfo; private PlayerGachaInfo gachaInfo;
...@@ -85,7 +87,6 @@ public class Player { ...@@ -85,7 +87,6 @@ public class Player {
private boolean showAvatar; private boolean showAvatar;
private ArrayList<AvatarProfileData> shownAvatars; private ArrayList<AvatarProfileData> shownAvatars;
private Set<Integer> rewardedLevels; private Set<Integer> rewardedLevels;
private ArrayList<Mail> mail;
private ArrayList<ShopLimit> shopLimit; private ArrayList<ShopLimit> shopLimit;
private int sceneId; private int sceneId;
...@@ -118,6 +119,7 @@ public class Player { ...@@ -118,6 +119,7 @@ public class Player {
this.inventory = new Inventory(this); this.inventory = new Inventory(this);
this.avatars = new AvatarStorage(this); this.avatars = new AvatarStorage(this);
this.friendsList = new FriendsList(this); this.friendsList = new FriendsList(this);
this.mailHandler = new MailHandler(this);
this.pos = new Position(); this.pos = new Position();
this.rotation = new Position(); this.rotation = new Position();
this.properties = new HashMap<>(); this.properties = new HashMap<>();
...@@ -133,8 +135,6 @@ public class Player { ...@@ -133,8 +135,6 @@ public class Player {
this.flyCloakList = new HashSet<>(); this.flyCloakList = new HashSet<>();
this.costumeList = new HashSet<>(); this.costumeList = new HashSet<>();
this.mail = new ArrayList<>();
this.setSceneId(3); this.setSceneId(3);
this.setRegionId(1); this.setRegionId(1);
this.sceneState = SceneLoadState.NONE; this.sceneState = SceneLoadState.NONE;
...@@ -437,6 +437,10 @@ public class Player { ...@@ -437,6 +437,10 @@ public class Player {
return this.friendsList; return this.friendsList;
} }
public MailHandler getMailHandler() {
return mailHandler;
}
public int getEnterSceneToken() { public int getEnterSceneToken() {
return enterSceneToken; return enterSceneToken;
} }
...@@ -725,47 +729,24 @@ public class Player { ...@@ -725,47 +729,24 @@ public class Player {
// ---------------------MAIL------------------------ // ---------------------MAIL------------------------
public List<Mail> getAllMail() { return this.mail; } public List<Mail> getAllMail() { return this.getMailHandler().getMail(); }
public void sendMail(Mail message) { public void sendMail(Mail message) {
// Call mail receive event. this.getMailHandler().sendMail(message);
PlayerReceiveMailEvent event = new PlayerReceiveMailEvent(this, message); event.call();
if(event.isCanceled()) return; message = event.getMessage();
this.mail.add(message);
this.save();
Grasscutter.getLogger().debug("Mail sent to user [" + this.getUid() + ":" + this.getNickname() + "]!");
if(this.isOnline()) {
this.sendPacket(new PacketMailChangeNotify(this, message));
} // TODO: setup a way for the mail notification to show up when someone receives mail when they were offline
} }
public boolean deleteMail(int mailId) { public boolean deleteMail(int mailId) {
Mail message = getMail(mailId); return this.getMailHandler().deleteMail(mailId);
if(message != null) {
int index = getMailId(message);
message.expireTime = (int) Instant.now().getEpochSecond(); // Just set the mail as expired for now. I don't want to implement a counter specifically for an account...
this.replaceMailByIndex(index, message);
return true;
} }
return false; public Mail getMail(int index) { return this.getMailHandler().getMailById(index); }
}
public Mail getMail(int index) { return this.mail.get(index); }
public int getMailId(Mail message) { public int getMailId(Mail message) {
return this.mail.indexOf(message); return this.getMailHandler().getMailIndex(message);
} }
public boolean replaceMailByIndex(int index, Mail message) { public boolean replaceMailByIndex(int index, Mail message) {
if(getMail(index) != null) { return this.getMailHandler().replaceMailByIndex(index, message);
this.mail.set(index, message);
this.save();
return true;
} else {
return false;
}
} }
public void interactWith(int gadgetEntityId) { public void interactWith(int gadgetEntityId) {
...@@ -1015,6 +996,7 @@ public class Player { ...@@ -1015,6 +996,7 @@ public class Player {
this.getAvatars().postLoad(); this.getAvatars().postLoad();
this.getFriendsList().loadFromDatabase(); this.getFriendsList().loadFromDatabase();
this.getMailHandler().loadFromDatabase();
// Create world // Create world
World world = new World(this); World world = new World(this);
......
package emu.grasscutter.server.packet.recv; package emu.grasscutter.server.packet.recv;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketOpcodes;
...@@ -15,7 +16,7 @@ public class HandlerDelMailReq extends PacketHandler { ...@@ -15,7 +16,7 @@ public class HandlerDelMailReq extends PacketHandler {
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
DelMailReqOuterClass.DelMailReq req = DelMailReqOuterClass.DelMailReq.parseFrom(payload); DelMailReqOuterClass.DelMailReq req = DelMailReqOuterClass.DelMailReq.parseFrom(payload);
session.send(new PacketDelMailRsp(session.getPlayer(), req.getMailIdListList())); session.getPlayer().getMailHandler().deleteMail(req.getMailIdListList());
} }
} }
...@@ -13,17 +13,10 @@ public class PacketDelMailRsp extends BasePacket { ...@@ -13,17 +13,10 @@ public class PacketDelMailRsp extends BasePacket {
public PacketDelMailRsp(Player player, List<Integer> toDeleteIds) { public PacketDelMailRsp(Player player, List<Integer> toDeleteIds) {
super(PacketOpcodes.DelMailRsp); super(PacketOpcodes.DelMailRsp);
DelMailRsp.Builder proto = DelMailRsp.newBuilder(); DelMailRsp proto = DelMailRsp.newBuilder()
.addAllMailIdList(toDeleteIds)
.build();
List<Integer> deletedIds = new ArrayList<>(); this.setData(proto);
for(int mailId : toDeleteIds) {
if(player.deleteMail(mailId)) {
deletedIds.add(mailId);
}
}
this.setData(proto.build());
player.getSession().send(new PacketMailChangeNotify(player, null, deletedIds));
} }
} }
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment