From d40b2d1b3beef844faa33920e8832078710e4890 Mon Sep 17 00:00:00 2001 From: Alessandro Proto Date: Tue, 6 Aug 2024 10:27:18 +0200 Subject: [PATCH] Add PlayerData DB table --- gradle.properties | 2 +- src/main/java/ct/server/CtServer.java | 50 +++++++- .../java/ct/server/database/PlayerData.java | 65 ++++++++++ .../java/ct/server/database/PlayerTable.java | 116 ++++++++++++++++++ 4 files changed, 227 insertions(+), 6 deletions(-) create mode 100644 src/main/java/ct/server/database/PlayerData.java create mode 100644 src/main/java/ct/server/database/PlayerTable.java diff --git a/gradle.properties b/gradle.properties index 5659aa3..4b0bdfa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ yarn_mappings=1.21+build.9 loader_version=0.15.11 # Mod Properties -mod_version=1.3.1 +mod_version=1.4.0 maven_group=ct archives_base_name=ct-server diff --git a/src/main/java/ct/server/CtServer.java b/src/main/java/ct/server/CtServer.java index 3f83276..67dcd87 100644 --- a/src/main/java/ct/server/CtServer.java +++ b/src/main/java/ct/server/CtServer.java @@ -1,18 +1,26 @@ package ct.server; import ct.server.database.DatabaseClient; +import ct.server.database.PlayerData; +import ct.server.database.PlayerTable; import ct.server.http.ServiceServer; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.text.TextColor; +import net.minecraft.text.Texts; +import net.minecraft.util.Formatting; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.sql.SQLException; +import java.util.Date; public class CtServer implements ModInitializer { @@ -28,18 +36,27 @@ public class CtServer implements ModInitializer { public static CtServer getInstance() { return INSTANCE; } + private static CtServer INSTANCE; private ServiceServer serviceServer; + public ServiceServer serviceServer() { return serviceServer; } private DatabaseClient database; + public DatabaseClient database() { return database; } + private PlayerTable playerTable; + + public PlayerTable playerTable() { + return playerTable; + } + @Override public void onInitialize() { INSTANCE = this; @@ -48,8 +65,11 @@ public class CtServer implements ModInitializer { try { database = new DatabaseClient(); - } catch(SQLException e) { - LOGGER.error("Could not connect to the database", e); + playerTable = new PlayerTable(); + + playerTable.ensureDatabaseCreated(); + } catch (SQLException e) { + LOGGER.error("Database error", e); } try { @@ -65,17 +85,37 @@ public class CtServer implements ModInitializer { } }); - ServerEntityEvents.ENTITY_LOAD.register((entity, world) -> { - if(entity instanceof ServerPlayerEntity) { - currentPlayerCount = world.getServer().getCurrentPlayerCount(); + ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { + currentPlayerCount = server.getCurrentPlayerCount() + 1; + var player = handler.getPlayer(); + var playerData = playerTable.getPlayerData(player.getUuid()); + if(playerData == null) { + // new player! + playerData = new PlayerData(handler.getPlayer().getUuid()); + playerData.firstJoinedDate(new Date()); + playerData.name(player.getName().getString()); + playerTable.updatePlayerData(playerData); + broadcastMessage(server, Text.literal("Welcome " + player.getName().getString() + " to the server!").formatted(Formatting.GREEN)); + } else { + if (!playerData.name().equals(player.getName().getString())) { + playerData.name(player.getName().getString()); + playerTable.updatePlayerData(playerData); + } } }); ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> { + currentPlayerCount = server.getCurrentPlayerCount() - 1; }); } + public void broadcastMessage(MinecraftServer server, Text message) { + for(ServerPlayerEntity player : server.getPlayerManager().getPlayerList()) { + player.sendMessage(message, false); + } + } + public static float getTPS() { return currentTps; } diff --git a/src/main/java/ct/server/database/PlayerData.java b/src/main/java/ct/server/database/PlayerData.java new file mode 100644 index 0000000..c8f2ab5 --- /dev/null +++ b/src/main/java/ct/server/database/PlayerData.java @@ -0,0 +1,65 @@ +package ct.server.database; + +import org.jetbrains.annotations.Nullable; + +import java.util.Date; +import java.util.UUID; + +public class PlayerData { + private final UUID uuid; + @Nullable + private String name; + private Date firstJoinedDate; + @Nullable + private String discordId; + + private boolean isBot = false; + private boolean isAlt = false; + + public PlayerData(UUID uuid) { + this.uuid = uuid; + } + + public UUID uuid() { + return uuid; + } + + + public String name() { + if (name == null) { + return uuid.toString(); + } + return name; + } + public void name(@Nullable String name) { + this.name = name; + } + + public Date firstJoinedDate() { + return firstJoinedDate; + } + public void firstJoinedDate(Date firstJoinedDate) { + this.firstJoinedDate = firstJoinedDate; + } + + public @Nullable String discordId() { + return discordId; + } + public void discordId(@Nullable String discordId) { + this.discordId = discordId; + } + + public boolean isBot() { + return isBot; + } + public void isBot(boolean isBot) { + this.isBot = isBot; + } + + public boolean isAlt() { + return isAlt; + } + public void isAlt(boolean isAlt) { + this.isAlt = isAlt; + } +} diff --git a/src/main/java/ct/server/database/PlayerTable.java b/src/main/java/ct/server/database/PlayerTable.java new file mode 100644 index 0000000..79d2e5c --- /dev/null +++ b/src/main/java/ct/server/database/PlayerTable.java @@ -0,0 +1,116 @@ +package ct.server.database; + +import ct.server.CtServer; +import org.jetbrains.annotations.Nullable; + +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.Date; +import java.util.HashMap; +import java.util.UUID; + +public class PlayerTable { + private final DatabaseClient database = CtServer.getInstance().database(); + private final HashMap cache = new HashMap<>(); + + public void ensureDatabaseCreated() { + try { + var conn = database.connection(); + + var stmt = conn.prepareStatement( + "CREATE TABLE IF NOT EXISTS players (" + + "uuid UUID NOT NULL PRIMARY KEY," + + "firstJoined TIMESTAMP DEFAULT CURRENT_TIMESTAMP," + + "lastKnownName VARCHAR(16)," + + "discordId VARCHAR," + + "isBot BOOL DEFAULT FALSE," + + "isAlt BOOL DEFAULT FALSE" + + ");"); + + stmt.executeUpdate(); + stmt.close(); + + } catch (SQLException e) { + CtServer.LOGGER.error("Could not create players data tables", e); + } + } + + public void refreshPlayerData(UUID uuid) { + cache.remove(uuid); + } + + @Nullable + public PlayerData getPlayerData(UUID uuid) { + if (cache.containsKey(uuid)) { + return cache.get(uuid); + } + + try { + var conn = database.connection(); + + var stmt = conn.prepareStatement("SELECT * FROM players WHERE uuid = ?;"); + stmt.setObject(1, uuid); + var set = stmt.executeQuery(); + if (!set.next()) { + return null; + } + + var playerData = new PlayerData(set.getObject("uuid", UUID.class)); + var firstJoinTimestamp = set.getObject("firstJoined", Timestamp.class); + playerData.firstJoinedDate(new Date(firstJoinTimestamp.getTime())); + playerData.name(set.getString("lastKnownName")); + playerData.discordId(set.getString("discordId")); + playerData.isBot(set.getBoolean("isBot")); + playerData.isAlt(set.getBoolean("isAlt")); + + stmt.close(); + + cache.put(uuid, playerData); + return playerData; + } catch (SQLException e) { + CtServer.LOGGER.error("Could not get player data from database", e); + return null; + } + } + + public boolean deletePlayerData(UUID uuid) { + try { + var conn = database.connection(); + + var stmt = conn.prepareStatement("DELETE FROM players WHERE uuid = ?;"); + stmt.setObject(1, uuid); + stmt.execute(); + stmt.close(); + + cache.remove(uuid); + return true; + } catch(SQLException e) { + CtServer.LOGGER.error("Could not delete player data from database", e); + return false; + } + } + + public boolean updatePlayerData(PlayerData playerData) { + deletePlayerData(playerData.uuid()); + try { + var conn = database.connection(); + + var stmt = conn.prepareStatement("INSERT INTO players(uuid, firstJoined, lastKnownName, discordId, isBot, isAlt) VALUES (?,?,?,?,?,?);"); + stmt.setObject(1, playerData.uuid()); + var timestamp = new Timestamp(playerData.firstJoinedDate().getTime()); + stmt.setTimestamp(2, timestamp); + stmt.setString(3, playerData.name()); + stmt.setString(4, playerData.discordId()); + stmt.setBoolean(5, playerData.isBot()); + stmt.setBoolean(6, playerData.isAlt()); + stmt.execute(); + stmt.close(); + + cache.put(playerData.uuid(), playerData); + return true; + } catch (SQLException e) { + CtServer.LOGGER.error("Could not get player data from database", e); + return false; + } + } +}