diff options
| author | Pugdoot <pugmatt@gmail.com> | 2025-05-23 17:16:16 -0400 |
|---|---|---|
| committer | Pugdoot <pugmatt@gmail.com> | 2025-05-24 19:21:57 -0400 |
| commit | f7a20c2e8b9d306d8bc4e39f5383bdadabe3de87 (patch) | |
| tree | 8a006ce76d12aa80524d4bcd1890a3c7db6c02a7 | |
| parent | b0d51faef380b6da1a7337f58837d6568f0de91e (diff) | |
| download | BedrockConnect-f7a20c2e8b9d306d8bc4e39f5383bdadabe3de87.tar.gz BedrockConnect-f7a20c2e8b9d306d8bc4e39f5383bdadabe3de87.tar.bz2 BedrockConnect-f7a20c2e8b9d306d8bc4e39f5383bdadabe3de87.zip | |
Implement optional MOTD screen
6 files changed, 192 insertions, 9 deletions
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/Config.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/Config.java index c723661..7ef67c0 100644 --- a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/Config.java +++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/Config.java @@ -1,7 +1,9 @@ package main.com.pyratron.pugmatt.bedrockconnect; +import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileWriter; +import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Inet4Address; import java.net.InetAddress; @@ -13,6 +15,7 @@ import java.util.List; import java.util.Map; import java.util.Scanner; import java.io.File; +import java.io.FileInputStream; import java.io.FileReader; import org.apache.logging.log4j.Level; @@ -37,6 +40,9 @@ public class Config { private String serverLimit = "100"; private boolean dbAutoReconnect = false; private boolean noDB = false; + private String motdMessage = null; + private boolean motdFirstJoin = true; + private int motdCooldown = 0; private boolean kickInactive = true; private boolean userServers = true; private boolean featuredServers = true; @@ -73,6 +79,7 @@ public class Config { String customServersFile = null; String languageFile = null; String whitelistFile = null; + String motdFile = null; boolean nodbWarning = true; boolean mysqlSettingWarning = false; @@ -234,6 +241,15 @@ public class Config { case "debug": debug = setting.getValue().equalsIgnoreCase("true"); break; + case "motd": + motdFile = setting.getValue(); + break; + case "motd_first_join": + motdFirstJoin = setting.getValue().equalsIgnoreCase("true"); + break; + case "motd_cooldown": + motdCooldown = Integer.parseInt(setting.getValue()); + break; } } @@ -328,7 +344,24 @@ public class Config { } } - BedrockConnect.loadDatabase(dbHost, dbName, dbUser, dbPass, dbType, dbAutoReconnect, noDB); + if (motdFile != null) { + try { + BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(motdFile), "UTF-8")); + String msg = ""; + String line = ""; + while ((line = in.readLine()) != null) { + msg += line + "\n"; + } + motdMessage = msg + "\n"; + in.close(); + BedrockConnect.logger.debug("MOTD data: " + motdMessage.toString()); + } catch (Exception e) { + BedrockConnect.logger.error("An error occurred reading the MOTD file", e); + System.exit(1); + } + } + + BedrockConnect.loadDatasource(dbHost, dbName, dbUser, dbPass, dbType, dbAutoReconnect, noDB); } public String getPort() { @@ -351,6 +384,22 @@ public class Config { return noDB; } + public String getMotdMessage() { + return motdMessage; + } + + public boolean isShowingMotdFirstJoin() { + return motdFirstJoin; + } + + public int getMotdCooldown() { + return motdCooldown; + } + + public boolean isMotdCooldownEnabled() { + return getMotdCooldown() > 0; + } + public boolean canKickInactive() { return kickInactive; } diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/data/DataUtil.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/data/DataUtil.java index 00599ce..cb63906 100644 --- a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/data/DataUtil.java +++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/data/DataUtil.java @@ -13,10 +13,13 @@ import org.json.simple.parser.JSONParser; import java.io.File; import java.io.FileReader; import java.io.PrintWriter; +import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.sql.Timestamp; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -24,11 +27,29 @@ public class DataUtil { private Database database; + // Some optional columns were added in a later version, consider their existance during data retrieval/updating + private boolean viewedMotdExists = false; + public DataUtil(Database database) { this.database = database; if (!BedrockConnect.getConfig().isNoDB()) { try { createTables((database.getType() == DatabaseTypes.postgres)); + + // Check for existance of columns added in later versions + DatabaseMetaData metaData = database.getConnection().getMetaData(); + viewedMotdExists = columnExists(metaData, "viewedMotd"); + + // If configuration is set to consider motd viewing date but viewedMotd column does not currently exist, then add viewedMotd column to table + if (BedrockConnect.getConfig().isMotdCooldownEnabled() && !viewedMotdExists) { + String dateType = "DATETIME"; + if (database.getType() == DatabaseTypes.postgres) dateType = "TIMESTAMP"; + + Statement stmt = database.getConnection().createStatement(); + stmt.execute("ALTER TABLE servers ADD viewedMotd " + dateType + ";"); + + viewedMotdExists = true; + } } catch (Exception e) { errorAlert(e); } @@ -45,6 +66,7 @@ public class DataUtil { + " name TEXT," + " servers TEXT," + " serverLimit INTEGER," + + " viewedMotd DATETIME," + " INDEX (uuid(255))" + ");"; else @@ -56,7 +78,8 @@ public class DataUtil { " uuid TEXT,\n" + " name TEXT,\n" + " servers TEXT,\n" + - " serverLimit INTEGER\n" + + " serverLimit INTEGER,\n" + + " viewedMotd TIMESTAMP\n" + " );\n" + " END IF;\n" + "\n" + @@ -71,8 +94,15 @@ public class DataUtil { private BCPlayer getPlayer(ResultSet rs, String name, String uuid, BedrockServerSession session) { try { + LocalDateTime viewedMotd = null; + if (viewedMotdExists) { + Timestamp ts = rs.getTimestamp("viewedMotd"); + if (ts != null) + viewedMotd = ts.toLocalDateTime(); + } + BCPlayer p = new BCPlayer(name, uuid, session, UIComponents.getFormData(rs.getString("servers")), - rs.getInt("serverLimit")); + rs.getInt("serverLimit"), false, viewedMotd); return p; } catch (SQLException e) { errorAlert(e); @@ -89,7 +119,7 @@ public class DataUtil { s.setInt(3, Integer.parseInt(BedrockConnect.getConfig().getServerLimit())); s.executeUpdate(); BedrockConnect.logger.info("Added new user " + name + " (xuid: " + uuid + ") to Database"); - BCPlayer pl = new BCPlayer(name, uuid, session, new ArrayList<>(), Integer.parseInt(BedrockConnect.getConfig().getServerLimit())); + BCPlayer pl = new BCPlayer(name, uuid, session, new ArrayList<>(), Integer.parseInt(BedrockConnect.getConfig().getServerLimit()), true, null); packetHandler.setPlayer(pl); BedrockConnect.getServer().addPlayer(pl); } catch (Exception e) { @@ -159,7 +189,7 @@ public class DataUtil { BedrockConnect.logger.info("Added new user " + name + " (xuid: " + uuid + ")"); - BCPlayer pl = new BCPlayer(name, uuid, session, new ArrayList<>(), Integer.parseInt(BedrockConnect.getConfig().getServerLimit())); + BCPlayer pl = new BCPlayer(name, uuid, session, new ArrayList<>(), Integer.parseInt(BedrockConnect.getConfig().getServerLimit()), true, null); packetHandler.setPlayer(pl); BedrockConnect.getServer().addPlayer(pl); } else { @@ -171,7 +201,12 @@ public class DataUtil { JSONArray servers = (JSONArray) jo.get("servers"); - BCPlayer p = new BCPlayer(name, uuid, session, servers, serverLimit); + LocalDateTime viewedMotd = null; + if (jo.containsKey("viewedMotd")) { + viewedMotd = LocalDateTime.parse((String) jo.get("viewedMotd")); + } + + BCPlayer p = new BCPlayer(name, uuid, session, servers, serverLimit, false, viewedMotd); packetHandler.setPlayer(p); BedrockConnect.getServer().addPlayer(p); } @@ -226,6 +261,53 @@ public class DataUtil { errorAlert(e); } }).start(); + + } + + public void setViewedMotd(String uuid) { + if (!BedrockConnect.getConfig().isNoDB()) { + if (viewedMotdExists) { + new Thread(() -> { + try { + PreparedStatement s = database.getConnection() + .prepareStatement("UPDATE servers SET viewedMotd = ? WHERE uuid= ?"); + s.setTimestamp(1, Timestamp.valueOf(LocalDateTime.now())); + s.setString(2, uuid); + + s.executeUpdate(); + } catch (Exception e) { + errorAlert(e); + } + }).start(); + } + } else { + try { + Object obj = new JSONParser().parse(new FileReader("players/" + uuid + ".json")); + + JSONObject jo = (JSONObject) obj; + + jo.put("viewedMotd", LocalDateTime.now().toString()); + + PrintWriter pw = new PrintWriter("players/" + uuid + ".json"); + pw.write(jo.toJSONString()); + pw.flush(); + pw.close(); + } catch (Exception e) { + BedrockConnect.logger.error("An error occurred saving to player file", e); + } + } + } + + private boolean columnExists(DatabaseMetaData meta, String columnName) throws SQLException { + try (ResultSet cols = meta.getColumns(null, "%", "servers", "%")) { + while (cols.next()) { + String col = cols.getString("COLUMN_NAME"); + if (col.equalsIgnoreCase(columnName)) { + return true; + } + } + } + return false; } public void errorAlert(Exception e) { diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/server/BCPlayer.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/server/BCPlayer.java index 24446be..5d56c54 100644 --- a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/server/BCPlayer.java +++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/server/BCPlayer.java @@ -20,6 +20,7 @@ import org.cloudburstmc.protocol.common.util.OptionalBoolean; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.time.Duration; +import java.time.LocalDateTime; import java.time.LocalTime; import java.util.*; @@ -34,6 +35,7 @@ public class BCPlayer { private String uuid; private LocalTime lastAction; + private LocalDateTime viewedMotd; private int currentForm = 0; private LocalTime movementOpenCoolDown = LocalTime.now(); @@ -41,6 +43,8 @@ public class BCPlayer { private int editingServer = -1; private int selectedGroup = -1; + private boolean newPlayer = false; + private static final NbtMap EMPTY_TAG = NbtMap.EMPTY; private static final byte[] EMPTY_LEVEL_CHUNK_DATA; @@ -59,13 +63,15 @@ public class BCPlayer { } - public BCPlayer(String displayName, String uuid, BedrockServerSession session, List<String> serverList, int serverLimit) { + public BCPlayer(String displayName, String uuid, BedrockServerSession session, List<String> serverList, int serverLimit, boolean newPlayer, LocalDateTime viewedMotd) { this.displayName = displayName; this.uuid = uuid; this.session = session; this.serverList = serverList; this.serverLimit = serverLimit; this.lastAction = LocalTime.now(); + this.viewedMotd = viewedMotd; + this.newPlayer = newPlayer; if(session != null && session.isConnected()) joinGame(); @@ -160,6 +166,19 @@ public class BCPlayer { public int getSelectedGroup() { return selectedGroup; } + public boolean isNewPlayer() { return newPlayer; } + + public LocalDateTime getViewedMotd() { return viewedMotd; } + + public boolean canShowMotd() { + if (!BedrockConnect.getConfig().isShowingMotdFirstJoin() && isNewPlayer()) return false; + + if (BedrockConnect.getConfig().isMotdCooldownEnabled() && viewedMotd != null) + return LocalDateTime.now().isAfter(viewedMotd.plusDays(BedrockConnect.getConfig().getMotdCooldown())); + + return true; + } + public void movementOpen() { if(canMovementOpen()) { @@ -205,6 +224,9 @@ public class BCPlayer { case UIForms.SERVER_GROUP: form = UIForms.createServerGroup((CustomServerGroup) BedrockConnect.getConfig().getCustomServers()[getSelectedGroup()], session); break; + case UIForms.MOTD: + form = UIForms.createMotd(); + break; default: form = UIForms.createMain(getServerList(), session); break; diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/server/PacketHandler.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/server/PacketHandler.java index b9fbf35..e256c7b 100644 --- a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/server/PacketHandler.java +++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/server/PacketHandler.java @@ -121,6 +121,13 @@ public class PacketHandler implements BedrockPacketHandler { player.resetMovementOpen(); switch (packet.getFormId()) { + case UIForms.MOTD: + // Store datetime of when motd was viewed, if we need it for tracking when to show it again + if (BedrockConnect.getConfig().isMotdCooldownEnabled()) { + BedrockConnect.getDataUtil().setViewedMotd(player.getUuid()); + } + player.openForm(UIForms.MAIN); + break; case UIForms.MAIN: // Re-open window if closed if (packet.getFormData() == null || packet.getFormData().contains("null")) { @@ -429,7 +436,11 @@ public class PacketHandler implements BedrockPacketHandler { @Override public PacketSignal handle(SetLocalPlayerAsInitializedPacket packet) { - session.sendPacketImmediately(UIForms.createMain(player.getServerList(), session)); + if (BedrockConnect.getConfig().getMotdMessage() != null && player.canShowMotd()) { + player.openForm(UIForms.MOTD); + } else { + player.openForm(UIForms.MAIN); + } return PacketSignal.HANDLED; } diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/server/gui/UIForms.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/server/gui/UIForms.java index ee15255..874372f 100644 --- a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/server/gui/UIForms.java +++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/server/gui/UIForms.java @@ -15,7 +15,7 @@ import java.util.ArrayList; import java.util.List; public class UIForms { - public static final int ERROR = 2, MAIN = 0, DIRECT_CONNECT = 1, REMOVE_SERVER = 3, MANAGE_SERVER = 4, EDIT_SERVER = 5, EDIT_CHOOSE_SERVER = 6, ADD_SERVER = 7, SERVER_GROUP = 8; + public static final int ERROR = 2, MAIN = 0, DIRECT_CONNECT = 1, REMOVE_SERVER = 3, MANAGE_SERVER = 4, EDIT_SERVER = 5, EDIT_CHOOSE_SERVER = 6, ADD_SERVER = 7, SERVER_GROUP = 8, MOTD = 9; public static JsonArray mainMenuButtons = new JsonArray(); public static JsonArray manageListButtons = new JsonArray(); @@ -280,4 +280,19 @@ public class UIForms { mf.setFormData(form.toString()); return mf; } + + public static ModalFormRequestPacket createMotd() { + ModalFormRequestPacket mf = new ModalFormRequestPacket(); + mf.setFormId(UIForms.MOTD); + JsonObject form = UIComponents.createForm("form", BedrockConnect.getConfig().getLanguage().getWording("motd", "heading")); + + form.addProperty("content", BedrockConnect.getConfig().getMotdMessage()); + + JsonArray buttons = new JsonArray(); + buttons.add(UIComponents.createButton(BedrockConnect.getConfig().getLanguage().getWording("motd", "continueBtn"))); + form.add("buttons", buttons); + + mf.setFormData(form.toString()); + return mf; + } } diff --git a/serverlist-server/src/main/resources/language.json b/serverlist-server/src/main/resources/language.json index 97db330..6f85e7c 100644 --- a/serverlist-server/src/main/resources/language.json +++ b/serverlist-server/src/main/resources/language.json @@ -1,4 +1,8 @@ { + "motd": { + "heading": "Message of the Day", + "continueBtn": "Continue to Server List" + }, "serverInfo": { "motd": "Join To Open Server List", "subMotd": "BedrockConnect Server List" |
