commit ea7abbfc845ddb8ff63005c3e27fa52f5ccca5e4 Author: coooookies <1164557342@qq.com> Date: Tue May 3 05:14:22 2022 +0800 commmit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2d513a0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/.idea/ +/target/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..eaaf684 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 ButterCookies + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d68d534 Binary files /dev/null and b/README.md differ diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 0000000..f7b4edd --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,48 @@ +# MeaNotice - Grasscutter 定时公告插件 +MeaNotice 是一个使用于 [Grasscutter](https://github.com/Grasscutters/Grasscutter) 的插件,你可以使用这个插件在游戏内发送定时公告。 + +[English](./README.md) | 简体中文 + +## 开始 +### 安装插件 +1. [下载插件本体](https://github.com/Coooookies/MeaNotice/releases) +2. 将插件本体放置在 `服务器根目录/plugins` 目录下 +3. 启动服务器,插件将会在你的服务器根目录下创建一个 `MeaNotice` 文件夹. +``` +Root +│ lib +│ keys +│ resources +│ plugins +│ ... +└───MeaNotice + └───config.json +``` + +### 配置 +```json +{ + "interval": 30000, + "notices": [ + "Welcome to this server! If you want to learn how to use commands, please type /help in chatroom.", + "Hey! Do you need help? Add UID1 as a friend, the admin will help you." + ] +} +``` +``` +说明: + interval: 必填项,用于设置定时公告的时间间隔,单位为毫秒,默认为 30000 毫秒(30 秒)。 + notices: 用于设置定时公告的内容,格式为字符串数组,每条公告都会以上到下顺序发送给玩家。 +``` + +### 命令 & 权限 +命令: +``` +/meanotice reload +重载插件配置 +``` + +权限: +``` +mea.notice | 控制插件功能 +``` diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..7dcd94d --- /dev/null +++ b/pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + + io.github + MeaMailPlus + 1.0-SNAPSHOT + + + 17 + 17 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 17 + 17 + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + package + + shade + + + false + + + + + + + + src/main/resources + true + + + + + + + emu.grasscutter + Grasscutter-api + 1.0 + system + D:/Grasscutter/GrasscutterFork/grasscutter-1.0.3-dev.jar + + + + com.google.code.gson + gson + 2.9.0 + + + + + \ No newline at end of file diff --git a/src/main/java/io/github/gmw/MeaMailPlusCore.java b/src/main/java/io/github/gmw/MeaMailPlusCore.java new file mode 100644 index 0000000..7e4b349 --- /dev/null +++ b/src/main/java/io/github/gmw/MeaMailPlusCore.java @@ -0,0 +1,76 @@ +package io.github.gmw; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.command.CommandMap; +import emu.grasscutter.plugin.Plugin; +import emu.grasscutter.server.game.GameServerPacketHandler; +import io.github.gmw.module.ConfigParser; +import io.github.gmw.module.PluginCommand; +import io.github.gmw.packetHandler.PlayerBornHook; +import io.github.gmw.packetHandler.PlayerJoinHook; +import io.github.gmw.module.TaskManager; + +public class MeaMailPlusCore extends Plugin { + + private static MeaMailPlusCore instance; + public ConfigParser config; + public TaskManager task; + + + @Override + public void onLoad() { + this.logger("Loading..."); + instance = this; + + this.config = new ConfigParser(); + this.config.loadConfig(); + this.config.loadTemplates(); + this.task = new TaskManager(); + + this.logger("Loaded!"); + } + + @Override + public void onEnable() { + CommandMap.getInstance().registerCommand("meamail", new PluginCommand()); + + // register packet handler + GameServerPacketHandler packetHandler = Grasscutter.getGameServer().getPacketHandler(); + packetHandler.registerPacketHandler(PlayerJoinHook.class); + packetHandler.registerPacketHandler(PlayerBornHook.class); + + this.task.enable(); + } + + @Override + public void onDisable() { + CommandMap.getInstance().unregisterCommand("meamail"); + this.task.disable(); + } + + public static MeaMailPlusCore getInstance() { + return instance; + } + + public void reloadConfig() { + this.task.disable(); + this.config.loadConfig(); + this.config.loadTemplates(); + this.task.enable(); + } + + public void logger(String message) { + this.logger(message, "info"); + } + + public void logger(String message, String type) { + if (Grasscutter.getLogger() == null) return; + + String msg = "[MeaMailPlusCore] " + message; + switch (type) { + case "info" -> Grasscutter.getLogger().info(msg); + case "warn" -> Grasscutter.getLogger().warn(msg); + case "error" -> Grasscutter.getLogger().error(msg); + } + } +} diff --git a/src/main/java/io/github/gmw/config/MeaMailConfig.java b/src/main/java/io/github/gmw/config/MeaMailConfig.java new file mode 100644 index 0000000..97d265d --- /dev/null +++ b/src/main/java/io/github/gmw/config/MeaMailConfig.java @@ -0,0 +1,42 @@ +package io.github.gmw.config; + +public final class MeaMailConfig { + public int[] updateTime = {4,0,0}; + public int[] initialMail = {1001}; + public int[] birthDayMail = {1004}; + + public DailySignInMailTask[] dailySignInMail = { + new DailySignInMailTask(1002,0) + }; + + public DailyRepetitionTask[] dailyRepetitionMail = { + new DailyRepetitionTask(1003,0,false, new int[]{12, 0, 0}) + }; + + public static class DailyRepetitionTask extends MailTask { + public boolean onlineOnly; + public int[] triggerTime; + + public DailyRepetitionTask(int templateId, int minLevel, boolean onlineOnly, int[] triggerTime) { + super(templateId, minLevel); + this.onlineOnly = onlineOnly; + this.triggerTime = triggerTime; + } + } + + public static class DailySignInMailTask extends MailTask { + public DailySignInMailTask(int templateId, int minLevel) { + super(templateId, minLevel); + } + } + + public static class MailTask { + public int templateId; + public int minLevel; // 0 - 60 + + public MailTask(int templateId, int minLevel) { + this.templateId = templateId; + this.minLevel = minLevel; + } + } +} diff --git a/src/main/java/io/github/gmw/config/MeaMailTemplate.java b/src/main/java/io/github/gmw/config/MeaMailTemplate.java new file mode 100644 index 0000000..e939c2f --- /dev/null +++ b/src/main/java/io/github/gmw/config/MeaMailTemplate.java @@ -0,0 +1,32 @@ +package io.github.gmw.config; + +public final class MeaMailTemplate { + public int templateId = 0; + public String title = ""; + public String sender = "Server"; + public long expireTime = 0; + + public long remainTime = 2592000; // 31 days + public int importance = 0; // Starred mail, 0 = No star, 1 = Star. + public MailBody body = new MailBody(); + public static class MailBody { + public String content = ""; + public ItemInfo[] items = {}; + + public static class ItemInfo { + public int id; + public int count; + public int level; + + public ItemInfo(int id, int count) { + this(id, count, 1); + } + + public ItemInfo(int id, int count, int level) { + this.id = id; + this.count = count; + this.level = level; + } + } + } +} diff --git a/src/main/java/io/github/gmw/module/ConfigParser.java b/src/main/java/io/github/gmw/module/ConfigParser.java new file mode 100644 index 0000000..5915a30 --- /dev/null +++ b/src/main/java/io/github/gmw/module/ConfigParser.java @@ -0,0 +1,191 @@ +package io.github.gmw.module; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Calendar; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import io.github.gmw.MeaMailPlusCore; +import io.github.gmw.config.MeaMailConfig; +import io.github.gmw.config.MeaMailTemplate; + +public class ConfigParser { + private MeaMailConfig config; + private ArrayList templates; + private final String configPath = "./plugins/MeaMailPlus"; + private final String templatePath = this.configPath + "/template"; + private final File configFile = new File( this.configPath + "/config.json"); + private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + public void loadTemplates() { + switch (this.createConfigFolder(this.templatePath)){ + case -1: return; + case 0: { // Without Template + this.createTemplate(); + break; + } + case 1: { + break; + } + } + + + ArrayList templates = new ArrayList<>(); + File[] files = new File(this.templatePath) + .listFiles(); + + if (files == null) return; // No Template + else { + for (File file : files) { + try (FileReader fileReader = new FileReader(file)) { + MeaMailTemplate template = gson.fromJson(fileReader, MeaMailTemplate.class); + templates.add(template); // 加入模板列表 + MeaMailPlusCore.getInstance() + .logger("Loaded template: " + file.getName() + " (TemplateId: " + template.templateId + ")"); + } catch (Exception e) { + MeaMailPlusCore.getInstance() + .logger("Unable to load template file: " + file.getName(),"error"); + } + } + } + + this.templates = templates; + MeaMailPlusCore.getInstance() + .logger("Loaded " + templates.size() + " templates. :D"); + + } + + // get template by templateId + public MeaMailTemplate getTemplate(int templateId) { + for (MeaMailTemplate template : this.templates) { + if (template.templateId == templateId) return template; + } + return null; + } + + public void createTemplate() { + MeaMailTemplate template_initialMail = new MeaMailTemplate(); + MeaMailTemplate template_dailySignInMail = new MeaMailTemplate(); + MeaMailTemplate template_dailyRepetitionMail = new MeaMailTemplate(); + MeaMailTemplate template_birthDayMail = new MeaMailTemplate(); + + template_initialMail.templateId = 1001; + template_initialMail.remainTime = 2592000; // 一个月后过期 + template_initialMail.title = "Thank you for using MeaMailPlus!"; + template_initialMail.sender= "MeaKiritaniIwako"; + template_initialMail.importance = 1; + template_initialMail.body.content = + "Hi!\n\n" + + "Thank you for using MeaMailPlus! You can use MeaMailPlus to send mail to your friends more conveniently.\r\n\r\n" + + "Github HomePage" + + "\r\n" + + "Grasscutter Discord" + + ""; + template_initialMail.body.items = new MeaMailTemplate.MailBody.ItemInfo[]{ + new MeaMailTemplate.MailBody.ItemInfo(80544, 1, 20), + new MeaMailTemplate.MailBody.ItemInfo(223, 150) + }; + + template_dailySignInMail.templateId = 1002; + template_dailySignInMail.remainTime = 604800; // 1 week + template_dailySignInMail.title = "Daily-Bonus"; + template_dailySignInMail.body.content = "Have a nice day!"; + template_dailySignInMail.body.items = new MeaMailTemplate.MailBody.ItemInfo[]{ + new MeaMailTemplate.MailBody.ItemInfo(223, 20), + new MeaMailTemplate.MailBody.ItemInfo(224, 20) + }; + + template_dailyRepetitionMail.templateId = 1003; + template_dailyRepetitionMail.remainTime = 1209600; // 2 weeks later + template_dailyRepetitionMail.title = "Have a question?"; + template_dailyRepetitionMail.sender= "TeamDarkshin"; + template_dailyRepetitionMail.body.content = + "Join Grasscutter Discord server to ask questions and get answers:" + + ""; + + template_birthDayMail.templateId = 1004; + template_birthDayMail.remainTime = 2592000; // 1 month + template_birthDayMail.title = "Best Wishes on Your Birthday"; + template_birthDayMail.sender = "Mailing System"; + template_birthDayMail.importance = 1; + template_birthDayMail.body.content = + "Happy Birthday,Traveler! Please find your gift attached to this message.\r\n" + + "Thank you for all your support. We wish you a wonderful day, wherever in this world you may roam."; + template_birthDayMail.body.items = new MeaMailTemplate.MailBody.ItemInfo[]{ + new MeaMailTemplate.MailBody.ItemInfo(118003, 1) + }; + + + this.saveTemplate("InitialMail", template_initialMail); + this.saveTemplate("DailySignInMail", template_dailySignInMail); + this.saveTemplate("DailyRepetitionMail", template_dailyRepetitionMail); + this.saveTemplate("BirthDayMail", template_birthDayMail); + } + + public boolean saveTemplate(String fileName, MeaMailTemplate templateClass) { + try (FileWriter file = new FileWriter(this.templatePath + "/" + fileName + ".json")) { + file.write(gson.toJson(templateClass)); + return true; + } catch (Exception e) { + return false; + } + } + + // load config.json + public void loadConfig() { + try (FileReader file = new FileReader(this.configFile)) { + this.config = gson.fromJson(file, MeaMailConfig.class); + MeaMailPlusCore.getInstance().logger("Config Loaded!"); + } catch (Exception e) { + this.config = new MeaMailConfig(); + MeaMailPlusCore.getInstance().logger("Basic config creating..."); + } + + if (!saveConfig()) { + MeaMailPlusCore.getInstance().logger("Unable to save config file.","error"); + } + } + + // save config.json + + public int createConfigFolder(String path) { + File dir = new File(path); + + if (!dir.exists() || !dir.isDirectory()) { + if(new File(String.valueOf(dir)).mkdirs()) return 0; + else return -1; + } + + return 1; + } + + public boolean saveConfig() { + if (this.createConfigFolder(this.configPath) == -1) return false; + + try (FileWriter file = new FileWriter(this.configFile)) { + file.write(gson.toJson(this.config)); + } catch (Exception e) { + return false; + } + + return true; + } + + public MeaMailConfig getConfig() { + return this.config; + } + + public long getTomorrowUpdateTime() { + // get tomorrow's update time + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DATE, 1); + cal.set(Calendar.HOUR_OF_DAY, this.config.updateTime[0]); + cal.set(Calendar.MINUTE, this.config.updateTime[1]); + cal.set(Calendar.SECOND, this.config.updateTime[2]); + return cal.getTimeInMillis() / 1000; + } +} diff --git a/src/main/java/io/github/gmw/module/PluginCommand.java b/src/main/java/io/github/gmw/module/PluginCommand.java new file mode 100644 index 0000000..d3ba11a --- /dev/null +++ b/src/main/java/io/github/gmw/module/PluginCommand.java @@ -0,0 +1,118 @@ +package io.github.gmw.module; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.command.Command; +import emu.grasscutter.command.CommandHandler; +import emu.grasscutter.game.player.Player; +import io.github.gmw.MeaMailPlusCore; +import io.github.gmw.config.MeaMailConfig; +import io.github.gmw.config.MeaMailTemplate; +import io.github.gmw.utils.MailCore; + +import java.util.*; + +@Command(label = "meamail", usage = "meamail help", + description = "MeaMailPlusCore command", aliases = {"mmail"}, permission = "meo.mail") + +public class PluginCommand implements CommandHandler { + @Override + public void execute(Player sender, List args) { + switch (args.size()) { + default -> // *No args* + showHelpList(sender); + case 1 -> { + switch (args.get(0)) { + case "reload" -> { + MeaMailPlusCore.getInstance().reloadConfig(); + if (sender == null) + Grasscutter.getLogger().info("[MeaNoticeCore] Reloaded!"); + else + CommandHandler.sendMessage(sender, "MeaNoticeCore config reloaded"); + } + case "help" -> showHelpList(sender); + default -> CommandHandler.sendMessage(sender, "Invalid args."); + } + } + case 2 -> { + int templateId = Integer.parseInt(args.get(1)); + MeaMailTemplate template = MeaMailPlusCore.getInstance().config.getTemplate(templateId); + + + switch (args.get(0)) { + case "sendall" -> { + if (template == null) { + CommandHandler.sendMessage(sender, "Invalid template id."); + return; + } + + MailCore.sendMailToAllPlayers(template); + CommandHandler.sendMessage(sender, "Mail Sended!"); + } + default -> CommandHandler.sendMessage(sender, "Invalid args."); + } + } + case 3 -> { + int templateId = Integer.parseInt(args.get(1)); + MeaMailTemplate template = MeaMailPlusCore.getInstance().config.getTemplate(templateId); + + switch (args.get(0)) { + case "send" -> { + if (template == null) { + CommandHandler.sendMessage(sender, "Invalid template id."); + return; + } + + int uid = Integer.parseInt(args.get(2)); + CommandHandler.sendMessage(sender, "Mail Sending..."); + Grasscutter.getGameServer().getPlayers().forEach((index, player) -> { + if (player.getUid() == uid) { + MailCore.sendMailToPlayer(player, template); + } + }); + } + case "sendall" -> { + if (template == null) { + CommandHandler.sendMessage(sender, "Invalid template id."); + return; + } + + int minLevel = Integer.parseInt(args.get(2)); + MailCore.sendMailToAllPlayers(template, minLevel); + CommandHandler.sendMessage(sender, "Mail Sended!"); + } + case "sendallonline" -> { + if (template == null) { + CommandHandler.sendMessage(sender, "Invalid template id."); + return; + } + + int minLevel = Integer.parseInt(args.get(2)); + MailCore.sendMailToAllPlayers(template, minLevel, true); + CommandHandler.sendMessage(sender, "Mail Sended!"); + } + default -> CommandHandler.sendMessage(sender, "Invalid args."); + } + } + } + } + + public void showHelpList(Player sender) { + String[] helpMap = new String[]{ + "Send Mail:", + " /meamail send ", + " /meamail sendall ", + " /meamail sendallonline ", +// " /meamail welcomemail ", +// " /meamail dailymail ", +// " /meamail initialmail ", + "Other:", + " /meamail reload", + " /meamail help", + }; + + for (String text : helpMap) { + CommandHandler.sendMessage(sender, text); + } + } +} + diff --git a/src/main/java/io/github/gmw/module/TaskManager.java b/src/main/java/io/github/gmw/module/TaskManager.java new file mode 100644 index 0000000..be5b34a --- /dev/null +++ b/src/main/java/io/github/gmw/module/TaskManager.java @@ -0,0 +1,76 @@ +package io.github.gmw.module; + +import io.github.gmw.MeaMailPlusCore; +import io.github.gmw.config.MeaMailConfig; +import io.github.gmw.utils.MailCore; + +import java.util.Calendar; +import java.util.Date; +import java.util.Timer; +import java.util.TimerTask; + +import io.github.gmw.config.MeaMailConfig.DailyRepetitionTask; + +public class TaskManager { + private Timer timer; + + private static class dailyBeginTask extends TimerTask { + @Override + public void run() { + // new day + MailCore.dailyUpdate(); + } + } + + private static class dailyRepetitionTask extends TimerTask { + private DailyRepetitionTask task; + + public dailyRepetitionTask(DailyRepetitionTask task) { + this.task = task; + } + + @Override + public void run() { + MailCore.repetitionUpdate(task); + } + } + + public Date getTaskStartTime(int hour, int minute, int second) { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.HOUR_OF_DAY, hour); + cal.set(Calendar.MINUTE, minute); + cal.set(Calendar.SECOND, second); + + if (cal.getTime().before(new Date())) { + cal.add(Calendar.DATE, 1); + } + + return cal.getTime(); + } + + public void enable() { + DailyRepetitionTask[] tasks = MeaMailPlusCore.getInstance().config.getConfig().dailyRepetitionMail; + int[] updateTime = MeaMailPlusCore.getInstance().config.getConfig().updateTime; + int cycleTime = 1000 * 60 * 60 * 24; + + // create timer and task + this.timer = new Timer(); + this.timer.schedule( + new dailyBeginTask(), + getTaskStartTime(updateTime[0], updateTime[1], updateTime[2]), + cycleTime + ); + + for(DailyRepetitionTask task : tasks) { + this.timer.schedule( + new dailyRepetitionTask(task), + getTaskStartTime(task.triggerTime[0], task.triggerTime[1], task.triggerTime[2]), + cycleTime + ); + } + } + + public void disable() { + this.timer.cancel(); + } +} diff --git a/src/main/java/io/github/gmw/packetHandler/PlayerBornHook.java b/src/main/java/io/github/gmw/packetHandler/PlayerBornHook.java new file mode 100644 index 0000000..cab6961 --- /dev/null +++ b/src/main/java/io/github/gmw/packetHandler/PlayerBornHook.java @@ -0,0 +1,25 @@ +package io.github.gmw.packetHandler; + +import emu.grasscutter.game.player.Player; +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.recv.HandlerSetPlayerBornDataReq; +import io.github.gmw.utils.MailCore; +import io.github.gmw.utils.PlayerUtils; + +@Opcodes(PacketOpcodes.SetPlayerBornDataReq) +public class PlayerBornHook extends HandlerSetPlayerBornDataReq { + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + super.handle(session, header, payload); + int playerUid = session.getAccount().getPlayerUid(); + + // 第一次加入 + if(playerUid != 0) { + MailCore.sendInitialMailToPlayer(playerUid); + MailCore.sendDailySignInMailToPlayer(playerUid); + } + } +} diff --git a/src/main/java/io/github/gmw/packetHandler/PlayerJoinHook.java b/src/main/java/io/github/gmw/packetHandler/PlayerJoinHook.java new file mode 100644 index 0000000..7219924 --- /dev/null +++ b/src/main/java/io/github/gmw/packetHandler/PlayerJoinHook.java @@ -0,0 +1,29 @@ +package io.github.gmw.packetHandler; + +import emu.grasscutter.game.player.Player; +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.server.packet.recv.HandlerPlayerLoginReq; +import emu.grasscutter.server.game.GameSession; +import io.github.gmw.utils.MailCore; +import io.github.gmw.utils.PlayerUtils; + +@Opcodes(PacketOpcodes.PlayerLoginReq) +public class PlayerJoinHook extends HandlerPlayerLoginReq { + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + super.handle(session, header, payload); + Player player = session.getPlayer(); + + if (player == null) return; // new player + if(PlayerUtils.isFirstLoginToday(player)) { // first login today + if (PlayerUtils.isPlayerBirthDay(player)) { // is player birthday + MailCore.sendBirthDayMailToPlayer(player); + } + + // daily mail + MailCore.sendDailySignInMailToPlayer(player); + } + } +} diff --git a/src/main/java/io/github/gmw/utils/MailCore.java b/src/main/java/io/github/gmw/utils/MailCore.java new file mode 100644 index 0000000..54ac103 --- /dev/null +++ b/src/main/java/io/github/gmw/utils/MailCore.java @@ -0,0 +1,177 @@ +package io.github.gmw.utils; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.database.DatabaseHelper; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.mail.Mail; +import io.github.gmw.MeaMailPlusCore; +import io.github.gmw.config.MeaMailConfig; +import io.github.gmw.config.MeaMailTemplate; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + + +public final class MailCore { + public static void sendMailToPlayer(Player player, MeaMailTemplate template) { + sendMailToPlayer(player, template, 0); + } + + public static void sendMailToPlayer(Player player, int templateId) { + sendMailToPlayer(player, templateId, 0); + } + + public static void sendMailToPlayer(Player player, int templateId, int minLevel) { + MeaMailTemplate template = getTemplateById(templateId); + if(template == null) { + MeaMailPlusCore.getInstance().logger("Template with id " + templateId + " not found"); + return; + } + sendMailToPlayer(player, template, minLevel); + } + + public static void sendMailToPlayer(Player player, MeaMailTemplate template, int minLevel) { + if (player.getLevel() >= minLevel) { + player.sendMail(templateToMail(template)); + MeaMailPlusCore.getInstance().logger("Mail sent to " + player.getUid() + ": " + template.title); + } else { + MeaMailPlusCore.getInstance().logger("Player " + player.getUid() + " is not level " + minLevel + " and mail was not sent"); + } + } + + private static Mail templateToMail(MeaMailTemplate mailTemplate) { + Mail mail = new Mail(); + mail.mailContent.content = mailTemplate.body.content; + mail.mailContent.title = mailTemplate.title; + mail.mailContent.sender = mailTemplate.sender; + mail.importance = mailTemplate.importance; + + if (mailTemplate.remainTime == 0) { + mail.expireTime = mailTemplate.expireTime; + } else { + mail.expireTime = (int) Instant.now().getEpochSecond() + mailTemplate.remainTime; + } + + mail.itemList = Arrays.stream(mailTemplate.body.items) + .map(item -> new Mail.MailItem(item.id, item.count, item.level)) + .collect(Collectors.toList()); + return mail; + } + + private static MeaMailConfig getConfig() { + return MeaMailPlusCore.getInstance().config.getConfig(); + } + + private static MeaMailTemplate getTemplateById(int id) { + return MeaMailPlusCore.getInstance().config.getTemplate(id); + } + + public static void sendMailToAllPlayers(int templateId) { + sendMailToAllPlayers(templateId, 0); + } + + public static void sendMailToAllPlayers(MeaMailTemplate template) { + sendMailToAllPlayers(template, 0); + } + + public static void sendMailToAllPlayers(int templateId, int minLevel) { + sendMailToAllPlayers(templateId, minLevel, false); + } + + public static void sendMailToAllPlayers(MeaMailTemplate template, int minLevel) { + sendMailToAllPlayers(template, minLevel, false); + } + + public static void sendMailToAllPlayers(int templateId, int minLevel, boolean onlineOnly) { + MeaMailTemplate template = getTemplateById(templateId); + if(template == null) { + MeaMailPlusCore.getInstance().logger("Template with id " + templateId + " not found"); + return; + } + sendMailToAllPlayers(template, minLevel, onlineOnly); + } + + public static void sendMailToAllPlayers(MeaMailTemplate template, int minLevel, boolean onlineOnly) { + if (template == null) return; + + List onlinePlayers = new ArrayList<>(); + List offlinePlayers = new ArrayList<>(); + Grasscutter.getGameServer().getPlayers().forEach((index, player) -> onlinePlayers.add(player)); + + if (!onlineOnly) { + DatabaseHelper.getAllPlayers().forEach(player -> { + if (onlinePlayers.stream().noneMatch(onlinePlayer -> onlinePlayer.getUid() == player.getUid())) { + offlinePlayers.add(player); + } + }); + } + + // two methods to send mail + onlinePlayers.forEach(player -> sendMailToPlayer(player, template, minLevel)); + offlinePlayers.forEach(player -> sendMailToPlayer(player, template, minLevel)); + } + + public static void sendDailySignInMailToPlayer(int uid) { + Grasscutter.getGameServer().getPlayers().forEach((index, player) -> { + if (player.getUid() == uid) + sendDailySignInMailToPlayer(player); + }); + } + + public static void sendDailySignInMailToPlayer(Player player) { + MeaMailConfig.DailySignInMailTask[] dailyTasks = getConfig().dailySignInMail; + for(MeaMailConfig.DailySignInMailTask task : dailyTasks) { + sendMailToPlayer(player, task.templateId, task.minLevel); + } + } + + public static void sendBirthDayMailToPlayer(int uid) { + Grasscutter.getGameServer().getPlayers().forEach((index, player) -> { + if (player.getUid() == uid) + sendBirthDayMailToPlayer(player); + }); + } + + public static void sendBirthDayMailToPlayer(Player player) { + int[] BirthdayMailTemplateIds = getConfig().birthDayMail; + for(int templateId : BirthdayMailTemplateIds) { + sendMailToPlayer(player, templateId); + } + } + + public static void sendInitialMailToPlayer(int uid) { + Grasscutter.getGameServer().getPlayers().forEach((index, player) -> { + if (player.getUid() == uid) + sendInitialMailToPlayer(player); + }); + } + + public static void sendInitialMailToPlayer(Player player) { + int[] InitialMailTemplateIds = getConfig().initialMail; + for(int templateId : InitialMailTemplateIds) { + sendMailToPlayer(player, templateId); + } + } + + public static void dailyUpdate() { + // update daily + Grasscutter.getGameServer().getPlayers().forEach((index, player) -> { + // birthday mail + if (PlayerUtils.isPlayerBirthDay(player)) { + sendBirthDayMailToPlayer(player); + } + + // daily sign in + sendDailySignInMailToPlayer(player); + }); + } + + public static void repetitionUpdate(MeaMailConfig.DailyRepetitionTask task) { + // update daily on time + sendMailToAllPlayers(task.templateId, task.minLevel, task.onlineOnly); + } +} diff --git a/src/main/java/io/github/gmw/utils/PlayerUtils.java b/src/main/java/io/github/gmw/utils/PlayerUtils.java new file mode 100644 index 0000000..f00ffe5 --- /dev/null +++ b/src/main/java/io/github/gmw/utils/PlayerUtils.java @@ -0,0 +1,42 @@ +package io.github.gmw.utils; + +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.player.PlayerBirthday; +import io.github.gmw.MeaMailPlusCore; + +import java.util.Calendar; + +public final class PlayerUtils { + public static long getPlayerBirthDayTime(Player player) { + int[] updateTime = MeaMailPlusCore.getInstance().config.getConfig().updateTime; + PlayerBirthday date = player.getBirthday(); + Calendar cal = Calendar.getInstance(); + + cal.set(Calendar.DAY_OF_MONTH, date.getDay()); + cal.set(Calendar.MONTH, date.getMonth() - 1); + + cal.set(Calendar.HOUR_OF_DAY, updateTime[0]); + cal.set(Calendar.MINUTE, updateTime[1]); + cal.set(Calendar.SECOND, updateTime[2]); + return cal.getTimeInMillis() / 1000; + } + + public static boolean isPlayerBirthDay(Player player) { + if (player.hasBirthday()) { + long playerBirthDayTime = getPlayerBirthDayTime(player); + long playerEndBirthDayTime = playerBirthDayTime + 24 * 60 * 60; + long currentTime = System.currentTimeMillis() / 1000; + + return currentTime >= playerBirthDayTime && currentTime < playerEndBirthDayTime; + } + return false; + } + + public static boolean isFirstLoginToday(Player player) { + long startOfDayTime = MeaMailPlusCore.getInstance().config.getTomorrowUpdateTime() - 24 * 60 * 60; + long playerLastActiveTime = player.getProfile().getLastActiveTime(); + long currentTime = System.currentTimeMillis() / 1000; + + return playerLastActiveTime < startOfDayTime && currentTime >= startOfDayTime; + } +} diff --git a/src/main/resources/plugin.json b/src/main/resources/plugin.json new file mode 100644 index 0000000..bc3d472 --- /dev/null +++ b/src/main/resources/plugin.json @@ -0,0 +1,10 @@ +{ + "name": "MeaMailPlus", + "description": "A plugin to send some notices to players", + "version": "1.0", + "mainClass": "io.github.gmw.MeaMailPlusCore", + "authors": [ + "Hell", + "ButterCookies" + ] +} \ No newline at end of file