Implement basic mail system

This commit is contained in:
Melledy
2023-10-17 11:02:58 -07:00
parent cde7b37707
commit 0bbd30eb17
18 changed files with 3978 additions and 1 deletions

View File

@@ -0,0 +1,28 @@
package emu.lunarcore.command.commands;
import emu.lunarcore.command.Command;
import emu.lunarcore.command.CommandArgs;
import emu.lunarcore.command.CommandHandler;
import emu.lunarcore.game.mail.Mail;
import emu.lunarcore.game.player.Player;
@Command(label = "mail", aliases = {"m"}, permission = "player.mail", desc = "/mail [content]. Sends the targeted player a system mail.")
public class MailCommand implements CommandHandler {
@Override
public void execute(Player sender, CommandArgs args) {
// Check target
if (args.getTarget() == null) {
this.sendMessage(sender, "Error: Targeted player not found or offline");
return;
}
String content = String.join(" ", args.getList());
Mail mail = new Mail("Test", "System Mail", content);
args.getTarget().getMailbox().sendMail(mail);
sender.sendMessage("Sending mail to " + args.getTarget().getName());
}
}

View File

@@ -0,0 +1,83 @@
package emu.lunarcore.game.mail;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.bson.types.ObjectId;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import dev.morphia.annotations.Indexed;
import emu.lunarcore.LunarRail;
import emu.lunarcore.game.inventory.GameItem;
import emu.lunarcore.game.player.Player;
import emu.lunarcore.proto.ClientMailOuterClass.ClientMail;
import emu.lunarcore.proto.ItemListOuterClass.ItemList;
import lombok.Getter;
import lombok.Setter;
@Getter
@Entity(value = "mail", useDiscriminator = false)
public class Mail {
@Id private ObjectId id;
@Indexed private int ownerUid; // Uid of player that this mail belongs to
@Setter
private transient int uniqueId;
private String title;
private String sender;
private String content;
private long time;
private long expiry;
private boolean isRead;
private List<GameItem> attachments;
@Deprecated // Morphia only!
public Mail() {}
public Mail(String title, String sender, String content) {
this.title = title;
this.sender = sender;
this.content = content;
this.time = System.currentTimeMillis() / 1000;
this.expiry = this.time + TimeUnit.DAYS.toSeconds(30);
}
public void setOwner(Player player) {
this.ownerUid = player.getUid();
}
public void setRead() {
if (!this.isRead) {
this.isRead = true;
this.save();
}
}
// Database
public void save() {
LunarRail.getGameDatabase().save(this);
}
public void delete() {
LunarRail.getGameDatabase().delete(this);
}
// Proto
public ClientMail toProto() {
var proto = ClientMail.newInstance()
.setId(this.getUniqueId())
.setTitle(this.getTitle())
.setContent(this.getContent())
.setSender(this.getSender())
.setTime(this.getTime())
.setExpireTime(this.getExpiry())
.setIsRead(this.isRead())
.setAttachment(ItemList.newInstance());
return proto;
}
}

View File

@@ -0,0 +1,94 @@
package emu.lunarcore.game.mail;
import java.util.Iterator;
import java.util.stream.Stream;
import emu.lunarcore.LunarRail;
import emu.lunarcore.game.player.BasePlayerManager;
import emu.lunarcore.game.player.Player;
import emu.lunarcore.server.packet.send.PacketNewMailScNotify;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import lombok.AccessLevel;
import lombok.Getter;
import us.hebi.quickbuf.RepeatedInt;
@Getter(AccessLevel.PRIVATE)
public class Mailbox extends BasePlayerManager implements Iterable<Mail> {
private final Int2ObjectMap<Mail> map;
private int lastMailId;
public Mailbox(Player player) {
super(player);
this.map = new Int2ObjectOpenHashMap<>();
}
private int getNextMailId() {
return ++lastMailId;
}
public synchronized int size() {
return getMap().size();
}
public synchronized void readMail(int id) {
Mail mail = getMap().get(id);
if (mail != null) {
mail.setRead();
}
}
public synchronized void sendMail(Mail mail) {
// Set owner for mail first before we save
mail.setOwner(this.getPlayer());
// Put mail into our backing hash map
this.putMail(mail);
// Save mail to database
mail.save();
// Send packet
this.getPlayer().sendPacket(new PacketNewMailScNotify(mail));
}
public synchronized IntList deleteMail(RepeatedInt idList) {
IntList deleteList = new IntArrayList();
for (int id : idList) {
Mail mail = getMap().remove(id);
if (mail != null) {
// Delete from database
mail.delete();
// Add to delete result list
deleteList.add(mail.getUniqueId());
}
}
return deleteList;
}
// Internal method to put mail into the hash map
private void putMail(Mail mail) {
mail.setUniqueId(this.getNextMailId());
getMap().put(mail.getUniqueId(), mail);
}
@Override
public synchronized Iterator<Mail> iterator() {
return getMap().values().iterator();
}
// Database
public void loadFromDatabase() {
Stream<Mail> stream = LunarRail.getGameDatabase().getObjects(Mail.class, "ownerUid", this.getPlayer().getUid());
stream.forEach(this::putMail);
}
}

View File

@@ -27,6 +27,7 @@ import emu.lunarcore.game.chat.ChatMessage;
import emu.lunarcore.game.enums.PropState;
import emu.lunarcore.game.gacha.PlayerGachaInfo;
import emu.lunarcore.game.inventory.Inventory;
import emu.lunarcore.game.mail.Mailbox;
import emu.lunarcore.game.scene.Scene;
import emu.lunarcore.game.scene.entity.EntityProp;
import emu.lunarcore.game.scene.entity.GameEntity;
@@ -81,6 +82,7 @@ public class Player {
private transient final AvatarStorage avatars;
private transient final Inventory inventory;
private transient final ChatManager chatManager;
private transient final Mailbox mailbox;
private transient final ChallengeManager challengeManager;
// Database persistent data
@@ -101,6 +103,7 @@ public class Player {
this.avatars = new AvatarStorage(this);
this.inventory = new Inventory(this);
this.chatManager = new ChatManager(this);
this.mailbox = new Mailbox(this);
this.challengeManager = new ChallengeManager(this);
}
@@ -515,6 +518,7 @@ public class Player {
// Load avatars and inventory first
this.getAvatars().loadFromDatabase();
this.getInventory().loadFromDatabase();
this.getMailbox().loadFromDatabase();
this.getChallengeManager().loadFromDatabase();
// Load Etc

View File

@@ -0,0 +1,23 @@
package emu.lunarcore.server.packet.recv;
import emu.lunarcore.proto.DelMailCsReqOuterClass.DelMailCsReq;
import emu.lunarcore.server.game.GameSession;
import emu.lunarcore.server.packet.CmdId;
import emu.lunarcore.server.packet.Opcodes;
import emu.lunarcore.server.packet.PacketHandler;
import emu.lunarcore.server.packet.send.PacketDelMailScRsp;
import it.unimi.dsi.fastutil.ints.IntList;
@Opcodes(CmdId.DelMailCsReq)
public class HandlerDelMailCsReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] data) throws Exception {
var req = DelMailCsReq.parseFrom(data);
IntList deleted = session.getPlayer().getMailbox().deleteMail(req.getIdList());
session.send(new PacketDelMailScRsp(deleted));
}
}

View File

@@ -4,13 +4,14 @@ import emu.lunarcore.server.game.GameSession;
import emu.lunarcore.server.packet.CmdId;
import emu.lunarcore.server.packet.Opcodes;
import emu.lunarcore.server.packet.PacketHandler;
import emu.lunarcore.server.packet.send.PacketGetMailScRsp;
@Opcodes(CmdId.GetMailCsReq)
public class HandlerGetMailCsReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] data) throws Exception {
session.send(CmdId.GetMailScRsp);
session.send(new PacketGetMailScRsp(session.getPlayer()));
}
}

View File

@@ -0,0 +1,20 @@
package emu.lunarcore.server.packet.recv;
import emu.lunarcore.proto.MarkReadMailCsReqOuterClass.MarkReadMailCsReq;
import emu.lunarcore.server.game.GameSession;
import emu.lunarcore.server.packet.CmdId;
import emu.lunarcore.server.packet.Opcodes;
import emu.lunarcore.server.packet.PacketHandler;
@Opcodes(CmdId.MarkReadMailCsReq)
public class HandlerMarkReadMailCsReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] data) throws Exception {
var req = MarkReadMailCsReq.parseFrom(data);
session.getPlayer().getMailbox().readMail(req.getId());
session.send(CmdId.MarkReadMailScRsp);
}
}

View File

@@ -0,0 +1,19 @@
package emu.lunarcore.server.packet.send;
import emu.lunarcore.proto.DelMailScRspOuterClass.DelMailScRsp;
import emu.lunarcore.server.packet.BasePacket;
import emu.lunarcore.server.packet.CmdId;
import it.unimi.dsi.fastutil.ints.IntList;
public class PacketDelMailScRsp extends BasePacket {
public PacketDelMailScRsp(IntList deleteList) {
super(CmdId.DelMailScRsp);
var data = DelMailScRsp.newInstance();
deleteList.forEach(data::addIdList);
this.setData(data);
}
}

View File

@@ -0,0 +1,24 @@
package emu.lunarcore.server.packet.send;
import emu.lunarcore.game.mail.Mail;
import emu.lunarcore.game.player.Player;
import emu.lunarcore.proto.GetMailScRspOuterClass.GetMailScRsp;
import emu.lunarcore.server.packet.BasePacket;
import emu.lunarcore.server.packet.CmdId;
public class PacketGetMailScRsp extends BasePacket {
public PacketGetMailScRsp(Player player) {
super(CmdId.GetMailScRsp);
var data = GetMailScRsp.newInstance()
.setIsEnd(true)
.setTotalNum(player.getMailbox().size());
for (Mail mail : player.getMailbox()) {
data.addMailList(mail.toProto());
}
this.setData(data);
}
}

View File

@@ -0,0 +1,18 @@
package emu.lunarcore.server.packet.send;
import emu.lunarcore.game.mail.Mail;
import emu.lunarcore.proto.NewMailScNotifyOuterClass.NewMailScNotify;
import emu.lunarcore.server.packet.BasePacket;
import emu.lunarcore.server.packet.CmdId;
public class PacketNewMailScNotify extends BasePacket {
public PacketNewMailScNotify(Mail mail) {
super(CmdId.NewMailScNotify);
var data = NewMailScNotify.newInstance()
.addMailIdList(mail.getUniqueId());
this.setData(data);
}
}